Class: LittleGhost::SessionStore
- Inherits:
-
Object
- Object
- LittleGhost::SessionStore
- Defined in:
- lib/little_ghost/session_store.rb
Overview
SessionStore connects LittleGhost conversations to application persistence. Subclass it to keep sessions in a database, remote service, or other durable store.
class DatabaseSessionStore < LittleGhost::SessionStore
def load(id, actor_id: nil)
Conversation.find_by(external_id: id, actor_id:)&.snapshot
end
def append(id, messages:, state:, metadata:, expected_count:, actor_id: nil)
Conversation.append!(
id, messages:, state:, metadata:, expected_count:, actor_id:
)
end
def replace(id, messages:, state:, metadata:, actor_id: nil)
Conversation.replace!(id, messages:, state:, metadata:, actor_id:)
end
end
A snapshot contains :messages, :state, and :metadata. Implementations
provide #load, #append, and #replace; #append must check expected_count
atomically so two writers cannot silently lose a turn.
Actor identity always comes from the caller. A store must not infer it from ambient process state.
Direct Known Subclasses
LittleGhost::SessionStores::AgentCoreMemory, LittleGhost::SessionStores::Memory
Instance Method Summary collapse
-
#append(_id, messages:, state:, metadata:, expected_count:, actor_id: nil) ⇒ Object
Atomically appends sanitized messages and stores state and metadata.
-
#initialize ⇒ SessionStore
constructor
Prepares the per-session synchronization used by #synchronize.
-
#load(_id, actor_id: nil) ⇒ Object
Finds the snapshot for
id, or returns nil when it does not exist. -
#project_conversation(_id, messages:, metadata:, actor_id: nil) ⇒ Object
Stores may expose a clean conversational view without changing the stored session transcript.
-
#replace(_id, messages:, state:, metadata:, actor_id: nil) ⇒ Object
Replaces the complete snapshot for
idatomically. -
#synchronize(id, actor_id: nil) ⇒ Object
Serializes work for one actor/session key within this store instance.
-
#with_operation_context(_operation_id) ⇒ Object
Wraps a store operation with an optional telemetry parent operation.
Constructor Details
#initialize ⇒ SessionStore
Prepares the per-session synchronization used by #synchronize.
32 33 34 35 |
# File 'lib/little_ghost/session_store.rb', line 32 def initialize @session_locks = {} @session_locks_mutex = Mutex.new end |
Instance Method Details
#append(_id, messages:, state:, metadata:, expected_count:, actor_id: nil) ⇒ Object
Atomically appends sanitized messages and stores state and metadata.
Implementations raise ProtocolError if the persisted message count differs
from expected_count.
45 46 47 |
# File 'lib/little_ghost/session_store.rb', line 45 def append(_id, messages:, state:, metadata:, expected_count:, actor_id: nil) raise AbstractMethodError, "#{self.class} must implement #append" end |
#load(_id, actor_id: nil) ⇒ Object
Finds the snapshot for id, or returns nil when it does not exist.
38 39 40 |
# File 'lib/little_ghost/session_store.rb', line 38 def load(_id, actor_id: nil) raise AbstractMethodError, "#{self.class} must implement #load" end |
#project_conversation(_id, messages:, metadata:, actor_id: nil) ⇒ Object
Stores may expose a clean conversational view without changing the stored session transcript. The default implementation is a no-op.
56 57 58 |
# File 'lib/little_ghost/session_store.rb', line 56 def project_conversation(_id, messages:, metadata:, actor_id: nil) nil end |
#replace(_id, messages:, state:, metadata:, actor_id: nil) ⇒ Object
Replaces the complete snapshot for id atomically.
50 51 52 |
# File 'lib/little_ghost/session_store.rb', line 50 def replace(_id, messages:, state:, metadata:, actor_id: nil) raise AbstractMethodError, "#{self.class} must implement #replace" end |
#synchronize(id, actor_id: nil) ⇒ Object
Serializes work for one actor/session key within this store instance.
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/little_ghost/session_store.rb', line 67 def synchronize(id, actor_id: nil) key = [actor_id&.to_s, id.to_s].freeze entry = @session_locks_mutex.synchronize do current = (@session_locks[key] ||= [Mutex.new, 0]) current[1] += 1 current end entry.first.synchronize { yield } ensure if entry @session_locks_mutex.synchronize do entry[1] -= 1 @session_locks.delete(key) if entry[1].zero? end end end |
#with_operation_context(_operation_id) ⇒ Object
Wraps a store operation with an optional telemetry parent operation. Custom stores may override this while preserving the block's return value.
62 63 64 |
# File 'lib/little_ghost/session_store.rb', line 62 def with_operation_context(_operation_id) yield end |