Documentation
¶
Overview ¶
Package memory provides conversation memory storage and session archiving.
The package has two main subsystems:
Active memory (SQLiteStore) manages the working conversation context — messages that are actively used for LLM context windows. Messages can be compacted (summarized) when the context grows too large.
Session archive (ArchiveStore) provides immutable, long-term storage of all conversation transcripts. Messages are archived before any destructive operation (compaction, reset, shutdown), ensuring primary source data is never lost. The archive supports full-text search with gap-aware context expansion — search results include surrounding conversation bounded by natural silence gaps rather than rigid message counts.
Index ¶
- func ShortID(id string) string
- type ArchiveAdapter
- func (a *ArchiveAdapter) ActiveConversationIDs() []string
- func (a *ArchiveAdapter) ActiveSessionID(conversationID string) string
- func (a *ArchiveAdapter) ActiveSessionStartedAt(conversationID string) time.Time
- func (a *ArchiveAdapter) ArchiveConversation(conversationID string, messages []Message, reason string) error
- func (a *ArchiveAdapter) ArchiveIterations(iterations []ArchivedIteration) error
- func (a *ArchiveAdapter) EndSession(sessionID string, reason string) error
- func (a *ArchiveAdapter) EnsureSession(conversationID string) string
- func (a *ArchiveAdapter) LinkPendingIterationToolCalls(sessionID string) error
- func (a *ArchiveAdapter) OnMessage(_ string)
- func (a *ArchiveAdapter) StartSession(conversationID string) (string, error)
- func (a *ArchiveAdapter) Store() *ArchiveStore
- type ArchiveConfig
- type ArchiveContextProvider
- type ArchiveReader
- type ArchiveReason
- type ArchiveSearcher
- type ArchiveStore
- func (s *ArchiveStore) ActiveSession(conversationID string) (*Session, error)
- func (s *ArchiveStore) ActiveSessionCount() (int, error)
- func (s *ArchiveStore) ActiveSessionsWithLastActivity() ([]IdleSessionInfo, error)
- func (s *ArchiveStore) ArchiveIterations(iterations []ArchivedIteration) error
- func (s *ArchiveStore) ArchiveMessages(messages []Message) error
- func (s *ArchiveStore) ArchiveToolCalls(calls []ArchivedToolCall) error
- func (s *ArchiveStore) ClaimActiveMessages(conversationID, sessionID string) (int64, error)
- func (s *ArchiveStore) Close() error
- func (s *ArchiveStore) CloseOrphanedSessions(before time.Time) (int64, error)
- func (s *ArchiveStore) DB() *sql.DB
- func (s *ArchiveStore) EndSession(sessionID string, reason string) error
- func (s *ArchiveStore) EndSessionAt(sessionID string, reason string, endedAt time.Time) error
- func (s *ArchiveStore) ExportSessionMarkdown(sessionID string) (string, error)
- func (s *ArchiveStore) FTSEnabled() bool
- func (s *ArchiveStore) GetMessagesByTimeRange(from, to time.Time, conversationID string, limit int) ([]Message, error)
- func (s *ArchiveStore) GetSession(sessionID string) (*Session, error)
- func (s *ArchiveStore) GetSessionIterations(sessionID string) ([]ArchivedIteration, error)
- func (s *ArchiveStore) GetSessionToolCalls(sessionID string) ([]ArchivedToolCall, error)
- func (s *ArchiveStore) GetSessionTranscript(sessionID string) ([]Message, error)
- func (s *ArchiveStore) ImportMessages(messages []Message) error
- func (s *ArchiveStore) ImportToolCalls(calls []ArchivedToolCall) error
- func (s *ArchiveStore) IsImported(sourceID, sourceType string) (bool, error)
- func (s *ArchiveStore) LinkPendingIterationToolCalls(sessionID string) error
- func (s *ArchiveStore) LinkToolCallsToIteration(sessionID string, iterationIndex int, toolCallIDs []string) error
- func (s *ArchiveStore) ListChildSessions(parentSessionID string) ([]*Session, error)
- func (s *ArchiveStore) ListSessions(conversationID string, limit int) ([]*Session, error)
- func (s *ArchiveStore) PurgeImported(sourceType string) (int, error)
- func (s *ArchiveStore) RecordImport(sourceID, sourceType, archiveSessionID string) error
- func (s *ArchiveStore) Search(opts SearchOptions) ([]SearchResult, error)
- func (s *ArchiveStore) SetSessionMetadata(sessionID string, meta *SessionMetadata, title string, tags []string) error
- func (s *ArchiveStore) SetSessionSummary(sessionID string, summary string) error
- func (s *ArchiveStore) StartSession(conversationID string) (*Session, error)
- func (s *ArchiveStore) StartSessionAt(conversationID string, startedAt time.Time) (*Session, error)
- func (s *ArchiveStore) StartSessionWithOptions(conversationID string, opts ...SessionOption) (*Session, error)
- func (s *ArchiveStore) Stats() (map[string]any, error)
- func (s *ArchiveStore) UnsummarizedSessions(limit int) ([]*Session, error)
- type ArchivedIteration
- type ArchivedToolCall
- type ChannelBinding
- type CompactableStore
- type CompactionConfig
- type Compactor
- func (c *Compactor) Compact(ctx context.Context, conversationID string) error
- func (c *Compactor) CompactionStats(conversationID string) map[string]any
- func (c *Compactor) CompactionThreshold() int
- func (c *Compactor) NeedsCompaction(conversationID string) bool
- func (c *Compactor) SetWorkingMemoryStore(wm WorkingMemoryReader)
- type Conversation
- type ConversationMetadata
- type DelegationMetadata
- type EpisodicConfig
- type EpisodicProvider
- type ExtractFunc
- type ExtractedFact
- type ExtractionResult
- type Extractor
- func (e *Extractor) Extract(ctx context.Context, userMsg, assistantResp string, recentHistory []Message) error
- func (e *Extractor) SetExtractFunc(fn ExtractFunc)
- func (e *Extractor) SetTimeout(d time.Duration)
- func (e *Extractor) ShouldExtract(userMsg, assistantResp string, messageCount int, skipContext bool) bool
- func (e *Extractor) Timeout() time.Duration
- type FactSetter
- type IdleSessionInfo
- type InteractionCallback
- type LLMSummarizer
- type MemoryStore
- type Message
- type MessageArchiver
- type SQLiteStore
- func (s *SQLiteStore) AddCompactionSummary(conversationID, summary string) error
- func (s *SQLiteStore) AddMessage(conversationID, role, content string) error
- func (s *SQLiteStore) ArchiveMessages(conversationID, sessionID, reason string) (int64, error)
- func (s *SQLiteStore) ArchiveToolCalls(conversationID, sessionID string) (int64, error)
- func (s *SQLiteStore) BindConversationChannel(conversationID string, binding *ChannelBinding) error
- func (s *SQLiteStore) Clear(conversationID string) error
- func (s *SQLiteStore) ClearToolCalls(conversationID string) error
- func (s *SQLiteStore) Close() error
- func (s *SQLiteStore) CompleteToolCall(toolCallID, result, errMsg string) error
- func (s *SQLiteStore) DB() *sql.DB
- func (s *SQLiteStore) GetAllConversations() []*Conversation
- func (s *SQLiteStore) GetAllMessages(conversationID string) []Message
- func (s *SQLiteStore) GetConversation(id string) *Conversation
- func (s *SQLiteStore) GetMessages(conversationID string) []Message
- func (s *SQLiteStore) GetMessagesForCompaction(conversationID string, keep int) []Message
- func (s *SQLiteStore) GetOrCreateConversation(id string) (*Conversation, error)
- func (s *SQLiteStore) GetTokenCount(conversationID string) int
- func (s *SQLiteStore) GetToolCalls(conversationID string, limit int) []ToolCall
- func (s *SQLiteStore) GetToolCallsByName(toolName string, limit int) []ToolCall
- func (s *SQLiteStore) MarkCompacted(conversationID string, before time.Time) error
- func (s *SQLiteStore) NeedsCompaction(conversationID string, maxTokens int) bool
- func (s *SQLiteStore) PutConversationMetadata(conversationID string, metadata *ConversationMetadata) error
- func (s *SQLiteStore) RecordToolCall(conversationID, messageID, toolCallID, toolName, arguments string) error
- func (s *SQLiteStore) Stats() map[string]any
- func (s *SQLiteStore) ToolCallStats() map[string]any
- type SearchOptions
- type SearchResult
- type Session
- type SessionMetadata
- type SessionOption
- type SimpleSummarizer
- type Store
- func (s *Store) AddMessage(conversationID string, role, content string) error
- func (s *Store) BindConversationChannel(conversationID string, binding *ChannelBinding) error
- func (s *Store) Clear(conversationID string) error
- func (s *Store) GetAllConversations() []*Conversation
- func (s *Store) GetConversation(id string) *Conversation
- func (s *Store) GetMessages(conversationID string) []Message
- func (s *Store) GetOrCreateConversation(id string) *Conversation
- func (s *Store) GetTokenCount(conversationID string) int
- func (s *Store) PutConversationMetadata(conversationID string, metadata *ConversationMetadata) error
- func (s *Store) RestoreConversations(convs []*Conversation)
- func (s *Store) Stats() map[string]any
- type Summarizer
- type SummarizerConfig
- type SummarizerWorker
- type ToolCall
- type ToolCallArchiver
- type WorkingMemoryProvider
- type WorkingMemoryReader
- type WorkingMemoryStore
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type ArchiveAdapter ¶ added in v0.3.0
type ArchiveAdapter struct {
// contains filtered or unexported fields
}
ArchiveAdapter bridges the ArchiveStore to the agent.SessionArchiver interface. It manages session lifecycle and coordinates message archival in the unified messages table.
func NewArchiveAdapter ¶ added in v0.3.0
func NewArchiveAdapter(store *ArchiveStore, msgStore MessageArchiver, tcStore ToolCallArchiver, logger *slog.Logger) *ArchiveAdapter
NewArchiveAdapter creates an adapter that implements agent.SessionArchiver. The msgStore and tcStore are used to set lifecycle status when archiving messages and tool calls in the unified table.
func (*ArchiveAdapter) ActiveConversationIDs ¶ added in v0.9.1
func (a *ArchiveAdapter) ActiveConversationIDs() []string
ActiveConversationIDs returns the conversation IDs with currently open sessions. It prefers the in-memory cache for hot-path accuracy and merges in any active sessions found in the store so startup recovery and direct store writes are also reflected.
func (*ArchiveAdapter) ActiveSessionID ¶ added in v0.3.0
func (a *ArchiveAdapter) ActiveSessionID(conversationID string) string
ActiveSessionID returns the current session ID for a conversation, or empty.
func (*ArchiveAdapter) ActiveSessionStartedAt ¶ added in v0.7.0
func (a *ArchiveAdapter) ActiveSessionStartedAt(conversationID string) time.Time
ActiveSessionStartedAt returns when the active session for a conversation began, or the zero time if there is no active session. Uses the in-memory cache populated by StartSession and ActiveSessionID to avoid per-turn database lookups.
func (*ArchiveAdapter) ArchiveConversation ¶ added in v0.3.0
func (a *ArchiveAdapter) ArchiveConversation(conversationID string, messages []Message, reason string) error
ArchiveConversation archives all messages and tool calls from a conversation by setting their status to 'archived' in the unified table.
func (*ArchiveAdapter) ArchiveIterations ¶ added in v0.8.0
func (a *ArchiveAdapter) ArchiveIterations(iterations []ArchivedIteration) error
ArchiveIterations persists a batch of iteration records to the archive store.
func (*ArchiveAdapter) EndSession ¶ added in v0.3.0
func (a *ArchiveAdapter) EndSession(sessionID string, reason string) error
EndSession ends a session. Session metadata is generated by the background summarizer worker, not here — this avoids a race with process shutdown that previously caused summaries to be lost.
func (*ArchiveAdapter) EnsureSession ¶ added in v0.3.0
func (a *ArchiveAdapter) EnsureSession(conversationID string) string
EnsureSession starts a session if none is active for the conversation.
func (*ArchiveAdapter) LinkPendingIterationToolCalls ¶ added in v0.8.0
func (a *ArchiveAdapter) LinkPendingIterationToolCalls(sessionID string) error
LinkPendingIterationToolCalls links archived tool calls to their parent iterations using the tool_call_ids stored on the iteration records.
func (*ArchiveAdapter) OnMessage ¶ added in v0.3.0
func (a *ArchiveAdapter) OnMessage(_ string)
OnMessage is a no-op retained for interface compatibility. Session message counts are now computed from the unified messages table.
func (*ArchiveAdapter) StartSession ¶ added in v0.3.0
func (a *ArchiveAdapter) StartSession(conversationID string) (string, error)
StartSession begins a new session and returns its ID.
func (*ArchiveAdapter) Store ¶ added in v0.3.0
func (a *ArchiveAdapter) Store() *ArchiveStore
Store returns the underlying ArchiveStore for direct access (API endpoints, etc.)
type ArchiveConfig ¶ added in v0.3.0
type ArchiveConfig struct {
// SilenceThreshold is the gap duration that signals a conversation boundary.
// Default: 10 minutes.
SilenceThreshold time.Duration
// MaxContextMessages is the hard cap on context messages per direction.
// Default: 50.
MaxContextMessages int
// MaxContextDuration is the time-based hard cap on context expansion.
// Default: 1 hour.
MaxContextDuration time.Duration
}
ArchiveConfig configures the archive store.
func DefaultArchiveConfig ¶ added in v0.3.0
func DefaultArchiveConfig() ArchiveConfig
DefaultArchiveConfig returns sensible defaults.
type ArchiveContextProvider ¶ added in v0.8.0
type ArchiveContextProvider struct {
// contains filtered or unexported fields
}
ArchiveContextProvider implements the agent.ContextProvider interface for injecting relevant past conversation excerpts into the system prompt. This is Layer 2 of the pre-warming system: Layer 1 provides knowledge (facts + KB docs), Layer 2 provides experiential judgment (prior reasoning about similar situations).
func NewArchiveContextProvider ¶ added in v0.8.0
func NewArchiveContextProvider(store ArchiveSearcher, maxResults, maxBytes int, logger *slog.Logger) *ArchiveContextProvider
NewArchiveContextProvider creates a context provider that searches the conversation archive for relevant past exchanges. maxResults caps the number of search hits; maxBytes caps the formatted output size to prevent context flooding.
func (*ArchiveContextProvider) GetContext ¶ added in v0.8.0
func (p *ArchiveContextProvider) GetContext(ctx context.Context, userMessage string) (string, error)
GetContext searches the conversation archive for excerpts relevant to the current wake context. Subjects are extracted from ctx (set by the wake bridge); if no subjects are available but the user message is short, it falls back to searching by message content.
Returns empty string when there is nothing to search for or no results are found. Errors from the archive store are logged and swallowed — archive injection should never block a wake.
type ArchiveReader ¶ added in v0.8.0
type ArchiveReader interface {
// ListSessions returns sessions ordered newest-first. Pass empty
// conversationID to list sessions across all conversations.
ListSessions(conversationID string, limit int) ([]*Session, error)
// GetSessionTranscript returns all archived messages for a session
// in chronological order.
GetSessionTranscript(sessionID string) ([]Message, error)
}
ArchiveReader is the subset of ArchiveStore needed by the episodic memory provider. Defined as an interface for testability.
type ArchiveReason ¶ added in v0.3.0
type ArchiveReason string
ArchiveReason describes why messages were archived.
const ( ArchiveReasonCompaction ArchiveReason = "compaction" ArchiveReasonReset ArchiveReason = "reset" ArchiveReasonShutdown ArchiveReason = "shutdown" ArchiveReasonManual ArchiveReason = "manual" )
type ArchiveSearcher ¶ added in v0.8.0
type ArchiveSearcher interface {
Search(opts SearchOptions) ([]SearchResult, error)
}
ArchiveSearcher abstracts archive search for testing. ArchiveStore satisfies this interface — no adapter needed.
type ArchiveStore ¶ added in v0.3.0
type ArchiveStore struct {
// contains filtered or unexported fields
}
ArchiveStore handles immutable session transcript archiving.
func NewArchiveStore ¶ added in v0.3.0
func NewArchiveStore(dbPath string, messagesDB *sql.DB, cfg *ArchiveConfig, logger *slog.Logger) (*ArchiveStore, error)
NewArchiveStore creates a new archive store at the given database path. Pass nil for cfg to use DefaultArchiveConfig(). Pass nil for logger to suppress startup logging.
When messagesDB is non-nil (unified mode), message queries use that connection against the "messages" table. When nil (legacy mode), message queries use the archive database's "archive_messages" table.
func NewArchiveStoreFromDB ¶ added in v0.8.0
func NewArchiveStoreFromDB(db *sql.DB, cfg *ArchiveConfig, logger *slog.Logger) (*ArchiveStore, error)
NewArchiveStoreFromDB creates an ArchiveStore backed by an existing database connection (typically the main thane.db). The store does NOT own the connection and Close will not close it. All session, iteration, message, and tool-call queries go to the shared connection. This is the "consolidated" mode where archive.db no longer exists.
func (*ArchiveStore) ActiveSession ¶ added in v0.3.0
func (s *ArchiveStore) ActiveSession(conversationID string) (*Session, error)
ActiveSession returns the most recent unclosed session for a conversation, if any.
func (*ArchiveStore) ActiveSessionCount ¶ added in v0.8.4
func (s *ArchiveStore) ActiveSessionCount() (int, error)
ActiveSessionCount returns the number of unclosed (active) sessions. This is a lightweight query for telemetry dashboards — use ArchiveStore.ActiveSessionsWithLastActivity when per-session details are needed.
func (*ArchiveStore) ActiveSessionsWithLastActivity ¶ added in v0.8.0
func (s *ArchiveStore) ActiveSessionsWithLastActivity() ([]IdleSessionInfo, error)
ActiveSessionsWithLastActivity returns all unclosed sessions and the timestamp of the most recent message in each. Sessions with no messages use the session's started_at as the last activity time. This powers the summarizer's idle session detection — it survives crashes because it reads from the database rather than relying on in-memory state.
func (*ArchiveStore) ArchiveIterations ¶ added in v0.8.0
func (s *ArchiveStore) ArchiveIterations(iterations []ArchivedIteration) error
ArchiveIterations copies iteration records to the immutable archive. Iteration indices are automatically offset so that sessions spanning multiple Run() calls never collide on the (session_id, iteration_index) primary key.
func (*ArchiveStore) ArchiveMessages ¶ added in v0.3.0
func (s *ArchiveStore) ArchiveMessages(messages []Message) error
ArchiveMessages copies messages to the immutable archive. This is the core "never throw data away" operation.
In unified mode (messagesDB set), this is a no-op — messages already live in the unified table and are archived via status UPDATE by SQLiteStore.
func (*ArchiveStore) ArchiveToolCalls ¶ added in v0.3.0
func (s *ArchiveStore) ArchiveToolCalls(calls []ArchivedToolCall) error
ArchiveToolCalls copies tool call records to the immutable archive.
In unified mode (messagesDB set), this is a no-op — tool call archival is handled via status UPDATE by SQLiteStore.ArchiveToolCalls.
func (*ArchiveStore) ClaimActiveMessages ¶ added in v0.8.0
func (s *ArchiveStore) ClaimActiveMessages(conversationID, sessionID string) (int64, error)
ClaimActiveMessages stamps session_id on active messages for a conversation so they become retrievable by GetSessionTranscript. This is needed when the summarizer's idle backstop closes a session — active messages in the unified table have session_id=NULL until archival, so without this step the transcript query returns nothing and the session is marked empty.
In legacy mode (archive_messages), session_id is always set at insert time, so this is a no-op. In unified mode, the status column distinguishes active messages from compacted/archived ones.
func (*ArchiveStore) Close ¶ added in v0.3.0
func (s *ArchiveStore) Close() error
Close closes the underlying database connection. If the store was created via NewArchiveStoreFromDB with a shared connection, Close is a no-op — the caller owns the connection lifetime.
func (*ArchiveStore) CloseOrphanedSessions ¶ added in v0.7.0
func (s *ArchiveStore) CloseOrphanedSessions(before time.Time) (int64, error)
CloseOrphanedSessions ends any sessions that are still open (ended_at IS NULL) but were started before the given cutoff time. This recovers sessions orphaned by crashes (SIGKILL, OOM, panics) where EndSession was never called. Returns the number of sessions closed.
func (*ArchiveStore) DB ¶ added in v0.5.0
func (s *ArchiveStore) DB() *sql.DB
DB returns the underlying database connection. This allows other stores (e.g. WorkingMemoryStore) to share the archive database without opening a separate connection.
func (*ArchiveStore) EndSession ¶ added in v0.3.0
func (s *ArchiveStore) EndSession(sessionID string, reason string) error
EndSession marks a session as ended at the current time.
func (*ArchiveStore) EndSessionAt ¶ added in v0.3.0
EndSessionAt marks a session as ended at a specific time.
func (*ArchiveStore) ExportSessionMarkdown ¶ added in v0.3.0
func (s *ArchiveStore) ExportSessionMarkdown(sessionID string) (string, error)
ExportSessionMarkdown exports a session transcript as human-readable markdown. Includes tool call records interleaved chronologically with messages.
func (*ArchiveStore) FTSEnabled ¶ added in v0.3.0
func (s *ArchiveStore) FTSEnabled() bool
FTSEnabled returns whether FTS5 full-text search is available.
func (*ArchiveStore) GetMessagesByTimeRange ¶ added in v0.3.0
func (s *ArchiveStore) GetMessagesByTimeRange(from, to time.Time, conversationID string, limit int) ([]Message, error)
GetMessagesByTimeRange returns archived messages within a time range.
func (*ArchiveStore) GetSession ¶ added in v0.3.0
func (s *ArchiveStore) GetSession(sessionID string) (*Session, error)
GetSession retrieves a session by ID.
func (*ArchiveStore) GetSessionIterations ¶ added in v0.8.0
func (s *ArchiveStore) GetSessionIterations(sessionID string) ([]ArchivedIteration, error)
GetSessionIterations returns archived iterations for a session ordered by iteration index.
func (*ArchiveStore) GetSessionToolCalls ¶ added in v0.3.0
func (s *ArchiveStore) GetSessionToolCalls(sessionID string) ([]ArchivedToolCall, error)
GetSessionToolCalls returns archived tool calls for a session in chronological order.
func (*ArchiveStore) GetSessionTranscript ¶ added in v0.3.0
func (s *ArchiveStore) GetSessionTranscript(sessionID string) ([]Message, error)
GetSessionTranscript returns all archived messages for a session in chronological order.
func (*ArchiveStore) ImportMessages ¶ added in v0.8.0
func (s *ArchiveStore) ImportMessages(messages []Message) error
ImportMessages inserts externally-sourced messages (e.g. from openclaw-import) into the archive. Unlike ArchiveMessages, which is a no-op in unified mode (since archival is a status UPDATE on existing rows), ImportMessages performs real INSERTs in both modes — the data doesn't already exist in any table.
In legacy mode, this delegates to ArchiveMessages. In unified mode, rows are inserted directly into the messages table with status='archived'. FTS triggers keep the full-text index in sync automatically.
func (*ArchiveStore) ImportToolCalls ¶ added in v0.8.0
func (s *ArchiveStore) ImportToolCalls(calls []ArchivedToolCall) error
ImportToolCalls inserts externally-sourced tool calls (e.g. from openclaw-import) into the archive. Like ImportMessages, this performs real INSERTs in both modes rather than being a no-op in unified mode.
func (*ArchiveStore) IsImported ¶ added in v0.3.0
func (s *ArchiveStore) IsImported(sourceID, sourceType string) (bool, error)
IsImported checks whether an external source ID has already been imported.
func (*ArchiveStore) LinkPendingIterationToolCalls ¶ added in v0.8.0
func (s *ArchiveStore) LinkPendingIterationToolCalls(sessionID string) error
LinkPendingIterationToolCalls reads iterations for a session, and for each iteration with stored tool_call_ids, updates the corresponding archive_tool_calls rows. Call this after tool calls have been archived so the UPDATE finds matching rows.
func (*ArchiveStore) LinkToolCallsToIteration ¶ added in v0.8.0
func (s *ArchiveStore) LinkToolCallsToIteration(sessionID string, iterationIndex int, toolCallIDs []string) error
LinkToolCallsToIteration sets the iteration_index on tool calls that belong to a specific iteration within a session. In unified mode, this updates the working DB's tool_calls table.
func (*ArchiveStore) ListChildSessions ¶ added in v0.8.0
func (s *ArchiveStore) ListChildSessions(parentSessionID string) ([]*Session, error)
ListChildSessions returns sessions whose parent_session_id matches the given ID, ordered chronologically. Used by the session inspector to show delegate sub-sessions.
func (*ArchiveStore) ListSessions ¶ added in v0.3.0
func (s *ArchiveStore) ListSessions(conversationID string, limit int) ([]*Session, error)
ListSessions returns sessions, newest first.
func (*ArchiveStore) PurgeImported ¶ added in v0.3.0
func (s *ArchiveStore) PurgeImported(sourceType string) (int, error)
PurgeImported removes all archive data that was imported from a given source type. This deletes sessions, messages, tool calls, and import metadata — a clean slate so the import can be re-run with improved logic.
In unified mode, messages live in a different database than sessions and metadata. The method handles this by deleting messages from the messages DB first, then cleaning up sessions and metadata from the archive DB in a transaction.
func (*ArchiveStore) RecordImport ¶ added in v0.3.0
func (s *ArchiveStore) RecordImport(sourceID, sourceType, archiveSessionID string) error
RecordImport creates a mapping from an external source ID to an archive session ID. Used by importers to track which external sessions have already been imported, enabling idempotent re-runs.
func (*ArchiveStore) Search ¶ added in v0.3.0
func (s *ArchiveStore) Search(opts SearchOptions) ([]SearchResult, error)
Search performs a full-text search with gap-aware context expansion.
func (*ArchiveStore) SetSessionMetadata ¶ added in v0.3.0
func (s *ArchiveStore) SetSessionMetadata(sessionID string, meta *SessionMetadata, title string, tags []string) error
SetSessionMetadata updates the full rich metadata for a session, including title, tags, summary, and structured metadata JSON.
func (*ArchiveStore) SetSessionSummary ¶ added in v0.3.0
func (s *ArchiveStore) SetSessionSummary(sessionID string, summary string) error
SetSessionSummary updates only the summary text for a session. For richer metadata, use SetSessionMetadata.
func (*ArchiveStore) StartSession ¶ added in v0.3.0
func (s *ArchiveStore) StartSession(conversationID string) (*Session, error)
StartSession creates a new session record with the current time.
func (*ArchiveStore) StartSessionAt ¶ added in v0.3.0
StartSessionAt creates a new session record with a specific start time. Use for imports where the original timestamp must be preserved.
func (*ArchiveStore) StartSessionWithOptions ¶ added in v0.8.0
func (s *ArchiveStore) StartSessionWithOptions(conversationID string, opts ...SessionOption) (*Session, error)
StartSessionWithOptions creates a new session record with optional parent linkage and metadata snapshots. Use WithParentSession, WithParentToolCall, and WithChannelBinding to stamp archive-only session context at creation time.
func (*ArchiveStore) Stats ¶ added in v0.3.0
func (s *ArchiveStore) Stats() (map[string]any, error)
Stats returns archive statistics.
func (*ArchiveStore) UnsummarizedSessions ¶ added in v0.7.0
func (s *ArchiveStore) UnsummarizedSessions(limit int) ([]*Session, error)
UnsummarizedSessions returns ended sessions that have no metadata yet, ordered oldest-first for catch-up processing. Only sessions with at least one message are returned — the message count is checked via a post-query filter because messages may live in a different database than sessions in unified mode.
type ArchivedIteration ¶ added in v0.8.0
type ArchivedIteration struct {
SessionID string `json:"session_id"`
IterationIndex int `json:"iteration_index"`
Model string `json:"model"`
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
ToolCallCount int `json:"tool_call_count"`
ToolCallIDs []string `json:"tool_call_ids,omitempty"`
ToolsOffered []string `json:"tools_offered,omitempty"`
StartedAt time.Time `json:"started_at"`
DurationMs int64 `json:"duration_ms"`
HasToolCalls bool `json:"has_tool_calls"`
BreakReason string `json:"break_reason,omitempty"`
}
ArchivedIteration represents one pass through an agent or delegate loop preserved in the archive. Each iteration corresponds to one LLM call plus any tool calls that follow.
type ArchivedToolCall ¶ added in v0.3.0
type ArchivedToolCall struct {
ID string `json:"id"`
ConversationID string `json:"conversation_id"`
SessionID string `json:"session_id"`
ToolName string `json:"tool_name"`
Arguments string `json:"arguments"`
Result string `json:"result,omitempty"`
Error string `json:"error,omitempty"`
StartedAt time.Time `json:"started_at"`
CompletedAt *time.Time `json:"completed_at,omitempty"`
DurationMs int64 `json:"duration_ms,omitempty"`
ArchivedAt time.Time `json:"archived_at"`
IterationIndex *int `json:"iteration_index,omitempty"`
}
ArchivedToolCall represents a tool call preserved in the archive.
type ChannelBinding ¶ added in v0.9.1
type ChannelBinding struct {
Channel string `json:"channel,omitempty"`
Address string `json:"address,omitempty"`
ContactID string `json:"contact_id,omitempty"`
ContactName string `json:"contact_name,omitempty"`
TrustZone string `json:"trust_zone,omitempty"`
LinkSource string `json:"link_source,omitempty"`
IsOwner bool `json:"is_owner,omitempty"`
}
ChannelBinding captures the runtime identity of a channel-backed conversation. It links a live channel/address pair to any known contact record so downstream code can gate on a typed binding instead of reconstructing identity from hints.
func (*ChannelBinding) Clone ¶ added in v0.9.1
func (b *ChannelBinding) Clone() *ChannelBinding
Clone returns a deep copy of the binding.
func (*ChannelBinding) Normalize ¶ added in v0.9.1
func (b *ChannelBinding) Normalize() *ChannelBinding
Normalize returns a trimmed copy of the binding, or nil when the binding carries no meaningful channel identity.
type CompactableStore ¶
type CompactableStore interface {
GetTokenCount(conversationID string) int
GetMessagesForCompaction(conversationID string, keep int) []Message
MarkCompacted(conversationID string, before time.Time) error
AddCompactionSummary(conversationID, summary string) error
}
CompactableStore is the interface for stores that support compaction.
type CompactionConfig ¶
type CompactionConfig struct {
MaxTokens int // Context window size
TriggerRatio float64 // Trigger compaction at this ratio (e.g., 0.7 = 70%)
KeepRecent int // Number of recent messages to always keep
MinMessagesToCompact int // Minimum messages before considering compaction
}
CompactionConfig controls compaction behavior.
func DefaultCompactionConfig ¶
func DefaultCompactionConfig() CompactionConfig
DefaultCompactionConfig returns sensible defaults.
type Compactor ¶
type Compactor struct {
// contains filtered or unexported fields
}
Compactor handles conversation compaction.
func NewCompactor ¶
func NewCompactor(store CompactableStore, config CompactionConfig, summarizer Summarizer, logger *slog.Logger) *Compactor
NewCompactor creates a new compactor.
func (*Compactor) CompactionStats ¶
CompactionStats returns stats about compaction for a conversation.
func (*Compactor) CompactionThreshold ¶ added in v0.8.2
CompactionThreshold returns the token count at which compaction triggers.
func (*Compactor) NeedsCompaction ¶
NeedsCompaction checks if a conversation needs compaction.
func (*Compactor) SetWorkingMemoryStore ¶ added in v0.5.0
func (c *Compactor) SetWorkingMemoryStore(wm WorkingMemoryReader)
SetWorkingMemoryStore configures a working memory store so that the compactor can include experiential context in the compaction prompt.
type Conversation ¶
type Conversation struct {
ID string `json:"id"`
Messages []Message `json:"messages"`
Metadata *ConversationMetadata `json:"metadata,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Conversation holds the state of a single conversation.
type ConversationMetadata ¶ added in v0.9.1
type ConversationMetadata struct {
ChannelBinding *ChannelBinding `json:"channel_binding,omitempty"`
}
ConversationMetadata holds typed metadata associated with a live conversation. It is stored as JSON so new fields can be added without schema churn.
func (*ConversationMetadata) Clone ¶ added in v0.9.1
func (m *ConversationMetadata) Clone() *ConversationMetadata
Clone returns a deep copy of the metadata.
func (*ConversationMetadata) Normalize ¶ added in v0.9.1
func (m *ConversationMetadata) Normalize() *ConversationMetadata
Normalize returns a cleaned copy of the metadata, or nil when it contains no meaningful fields.
type DelegationMetadata ¶ added in v0.8.0
type DelegationMetadata struct {
Task string `json:"task"`
Guidance string `json:"guidance,omitempty"`
Profile string `json:"profile"`
Model string `json:"model"`
Iterations int `json:"iterations"`
MaxIterations int `json:"max_iterations"`
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
Exhausted bool `json:"exhausted"`
ExhaustReason string `json:"exhaust_reason,omitempty"`
ResultContent string `json:"result_content,omitempty"`
DurationMs int64 `json:"duration_ms"`
Error string `json:"error,omitempty"`
// Messages is the raw JSON-serialized conversation history from the
// legacy delegations table. Preserved to avoid data loss — these
// messages predate the per-message storage in the messages table.
Messages string `json:"messages,omitempty"`
}
DelegationMetadata holds delegation-specific fields preserved from the legacy delegations table during migration (#446).
type EpisodicConfig ¶ added in v0.8.0
type EpisodicConfig struct {
// Timezone is the IANA timezone string (e.g. "America/Chicago").
Timezone string
// DailyDir is the directory containing YYYY-MM-DD.md daily memory
// files. Supports ~ expansion. Empty disables daily file injection.
DailyDir string
// LookbackDays is how many days of daily memory files to include.
LookbackDays int
// HistoryTokens is the approximate token budget for recent
// conversation history.
HistoryTokens int
// SessionGapMinutes is the silence duration between sessions that
// triggers a gap annotation in the output.
SessionGapMinutes int
}
EpisodicConfig holds configuration for the episodic memory provider.
type EpisodicProvider ¶ added in v0.8.0
type EpisodicProvider struct {
// contains filtered or unexported fields
}
EpisodicProvider implements the agent.ContextProvider interface for episodic memory. It injects daily memory notes and recent conversation history into the system prompt.
func NewEpisodicProvider ¶ added in v0.8.0
func NewEpisodicProvider(archive ArchiveReader, logger *slog.Logger, cfg EpisodicConfig) *EpisodicProvider
NewEpisodicProvider creates an episodic memory context provider.
func (*EpisodicProvider) GetContext ¶ added in v0.8.0
GetContext returns episodic memory context for injection into the system prompt. It assembles daily memory notes and recent conversation history from the session archive.
type ExtractFunc ¶ added in v0.5.0
type ExtractFunc func(ctx context.Context, userMessage, assistantResponse string, recentHistory []Message) (*ExtractionResult, error)
ExtractFunc calls an LLM to extract facts from a single interaction. It receives the current user message, assistant response, and recent conversation history for context.
type ExtractedFact ¶ added in v0.5.0
type ExtractedFact struct {
Category string `json:"category"`
Key string `json:"key"`
Value string `json:"value"`
Confidence float64 `json:"confidence"`
}
ExtractedFact is a single fact parsed from the LLM extraction response. Category must be one of the valid fact categories (user, home, device, routine, preference, architecture). Confidence is 0–1.
type ExtractionResult ¶ added in v0.5.0
type ExtractionResult struct {
Facts []ExtractedFact `json:"facts"`
WorthPersisting bool `json:"worth_persisting"`
}
ExtractionResult is the structured JSON response from an LLM fact extraction call. WorthPersisting acts as a top-level gate: when false, the Facts slice is ignored even if populated.
type Extractor ¶ added in v0.5.0
type Extractor struct {
// contains filtered or unexported fields
}
Extractor runs automatic fact extraction after each interaction. It is fully async and best-effort — failures are logged but never propagate to the caller or affect the user-facing response.
func NewExtractor ¶ added in v0.5.0
func NewExtractor(facts FactSetter, logger *slog.Logger, minMessages int) *Extractor
NewExtractor creates an Extractor that persists facts via the given FactSetter. The minMessages threshold controls the minimum conversation length before extraction is attempted.
func (*Extractor) Extract ¶ added in v0.5.0
func (e *Extractor) Extract(ctx context.Context, userMsg, assistantResp string, recentHistory []Message) error
Extract calls the configured ExtractFunc and persists any discovered facts via the FactSetter. Incomplete facts (missing category, key, or value) are silently skipped. Errors from individual SetFact calls are logged but do not stop processing of remaining knowledge.
func (*Extractor) SetExtractFunc ¶ added in v0.5.0
func (e *Extractor) SetExtractFunc(fn ExtractFunc)
SetExtractFunc configures the LLM extraction function.
func (*Extractor) SetTimeout ¶ added in v0.5.0
SetTimeout configures the LLM call timeout for extraction.
func (*Extractor) ShouldExtract ¶ added in v0.5.0
func (e *Extractor) ShouldExtract(userMsg, assistantResp string, messageCount int, skipContext bool) bool
ShouldExtract reports whether the given interaction is worth analyzing for knowledge. It filters out simple device commands, short responses, and auxiliary requests to keep LLM extraction calls to roughly 30–50% of interactions.
type FactSetter ¶ added in v0.5.0
type FactSetter interface {
SetFact(category, key, value, source string, confidence float64) error
}
FactSetter persists extracted facts to long-term storage. Implementations may apply additional logic such as confidence reinforcement on upsert.
type IdleSessionInfo ¶ added in v0.8.0
IdleSessionInfo holds an active session's identity and last activity time for idle timeout evaluation by the summarizer worker.
type InteractionCallback ¶ added in v0.8.0
type InteractionCallback func(conversationID string, sessionID string, endedAt time.Time, topics []string)
InteractionCallback is called after successful session summarization to update the contact's last interaction metadata. Parameters: conversationID, sessionID, endedAt, topics (tags).
type LLMSummarizer ¶
type LLMSummarizer struct {
// contains filtered or unexported fields
}
LLMSummarizer uses an LLM to generate summaries.
func NewLLMSummarizer ¶
func NewLLMSummarizer(llmFunc func(ctx context.Context, prompt string) (string, error)) *LLMSummarizer
NewLLMSummarizer creates a summarizer that uses an LLM.
func (*LLMSummarizer) Summarize ¶
func (s *LLMSummarizer) Summarize(ctx context.Context, messages []Message, workingMemory string) (string, error)
Summarize generates a summary of the messages using an LLM. When workingMemory is non-empty, it is included in the prompt so the summarizer preserves experiential context through compaction.
type MemoryStore ¶
type MemoryStore interface {
GetMessages(conversationID string) []Message
AddMessage(conversationID, role, content string) error
GetConversation(id string) *Conversation
Clear(conversationID string) error
Stats() map[string]any
}
MemoryStore is the interface for memory storage backends (in-memory and SQLite). Both Store and SQLiteStore satisfy it.
type Message ¶
type Message struct {
ID string `json:"id"` // Stable UUIDv7 assigned at creation time
ConversationID string `json:"conversation_id,omitempty"` // Set for archived messages
SessionID string `json:"session_id,omitempty"` // Set for archived messages
Role string `json:"role"` // system, user, assistant, tool
Content string `json:"content"`
Timestamp time.Time `json:"timestamp"`
TokenCount int `json:"token_count,omitempty"` // Estimated token count
ToolCalls string `json:"tool_calls,omitempty"` // JSON array of tool calls (assistant messages)
ToolCallID string `json:"tool_call_id,omitempty"` // Tool call ID (tool response messages)
ArchivedAt time.Time `json:"archived_at,omitzero"` // When the message was archived
ArchiveReason string `json:"archive_reason,omitempty"` // Why: compaction, reset, shutdown, import
}
Message represents a conversation message. This is the unified type for both active working-memory messages and archived session transcripts. Archive-specific fields (ConversationID, SessionID, TokenCount, ArchivedAt, ArchiveReason) are zero-valued for active messages.
type MessageArchiver ¶ added in v0.8.0
type MessageArchiver interface {
ArchiveMessages(conversationID, sessionID, reason string) (int64, error)
}
MessageArchiver sets lifecycle status on messages in the unified table.
type SQLiteStore ¶
type SQLiteStore struct {
// contains filtered or unexported fields
}
SQLiteStore is a SQLite-backed memory store.
func NewSQLiteStore ¶
func NewSQLiteStore(dbPath string, maxMessages int) (*SQLiteStore, error)
NewSQLiteStore creates a new SQLite-backed store.
func NewSQLiteStoreWithLogger ¶ added in v0.9.1
func NewSQLiteStoreWithLogger(dbPath string, maxMessages int, logger *slog.Logger) (*SQLiteStore, error)
NewSQLiteStoreWithLogger creates a new SQLite-backed store and uses logger for non-fatal data-integrity warnings encountered while reading existing rows. Nil falls back to slog.Default.
func (*SQLiteStore) AddCompactionSummary ¶
func (s *SQLiteStore) AddCompactionSummary(conversationID, summary string) error
AddCompactionSummary adds a compaction summary message.
func (*SQLiteStore) AddMessage ¶
func (s *SQLiteStore) AddMessage(conversationID, role, content string) error
AddMessage adds a message to a conversation.
func (*SQLiteStore) ArchiveMessages ¶ added in v0.8.0
func (s *SQLiteStore) ArchiveMessages(conversationID, sessionID, reason string) (int64, error)
ArchiveMessages updates messages in the unified table to archived status. This replaces the cross-DB copy that the legacy archive flow used.
func (*SQLiteStore) ArchiveToolCalls ¶ added in v0.8.0
func (s *SQLiteStore) ArchiveToolCalls(conversationID, sessionID string) (int64, error)
ArchiveToolCalls updates tool calls in the unified table to archived status. This replaces the cross-DB copy that the legacy archive flow used.
func (*SQLiteStore) BindConversationChannel ¶ added in v0.9.1
func (s *SQLiteStore) BindConversationChannel(conversationID string, binding *ChannelBinding) error
BindConversationChannel updates only the channel-binding portion of a conversation's typed metadata.
func (*SQLiteStore) Clear ¶
func (s *SQLiteStore) Clear(conversationID string) error
Clear removes a conversation and its messages.
func (*SQLiteStore) ClearToolCalls ¶ added in v0.7.0
func (s *SQLiteStore) ClearToolCalls(conversationID string) error
ClearToolCalls deletes tool call records for a conversation from the working store. Called after archiving to prevent re-archival on the next session split.
func (*SQLiteStore) Close ¶
func (s *SQLiteStore) Close() error
Close closes the database connection.
func (*SQLiteStore) CompleteToolCall ¶
func (s *SQLiteStore) CompleteToolCall(toolCallID, result, errMsg string) error
CompleteToolCall records the result of a tool call.
func (*SQLiteStore) DB ¶ added in v0.8.0
func (s *SQLiteStore) DB() *sql.DB
DB returns the underlying database connection for use by the unification migration and by ArchiveStore when reading from the unified messages table.
func (*SQLiteStore) GetAllConversations ¶
func (s *SQLiteStore) GetAllConversations() []*Conversation
GetAllConversations returns all conversations for checkpointing.
func (*SQLiteStore) GetAllMessages ¶ added in v0.3.0
func (s *SQLiteStore) GetAllMessages(conversationID string) []Message
GetAllMessages retrieves ALL messages for a conversation, including compacted ones. Includes tool call data for full-fidelity archiving — never lose primary sources.
func (*SQLiteStore) GetConversation ¶
func (s *SQLiteStore) GetConversation(id string) *Conversation
GetConversation retrieves a conversation by ID.
func (*SQLiteStore) GetMessages ¶
func (s *SQLiteStore) GetMessages(conversationID string) []Message
GetMessages retrieves messages for a conversation.
func (*SQLiteStore) GetMessagesForCompaction ¶
func (s *SQLiteStore) GetMessagesForCompaction(conversationID string, keep int) []Message
GetMessagesForCompaction retrieves messages that should be compacted. Keeps the most recent 'keep' messages.
func (*SQLiteStore) GetOrCreateConversation ¶
func (s *SQLiteStore) GetOrCreateConversation(id string) (*Conversation, error)
GetOrCreateConversation ensures a conversation exists and returns it.
func (*SQLiteStore) GetTokenCount ¶
func (s *SQLiteStore) GetTokenCount(conversationID string) int
GetTokenCount returns the total token count for a conversation.
func (*SQLiteStore) GetToolCalls ¶
func (s *SQLiteStore) GetToolCalls(conversationID string, limit int) []ToolCall
GetToolCalls retrieves tool calls, optionally filtered by conversation. If conversationID is empty, returns all recent tool calls.
func (*SQLiteStore) GetToolCallsByName ¶
func (s *SQLiteStore) GetToolCallsByName(toolName string, limit int) []ToolCall
GetToolCallsByName retrieves tool calls filtered by tool name.
func (*SQLiteStore) MarkCompacted ¶
func (s *SQLiteStore) MarkCompacted(conversationID string, before time.Time) error
MarkCompacted marks messages as compacted.
func (*SQLiteStore) NeedsCompaction ¶
func (s *SQLiteStore) NeedsCompaction(conversationID string, maxTokens int) bool
NeedsCompaction checks if a conversation needs compaction.
func (*SQLiteStore) PutConversationMetadata ¶ added in v0.9.1
func (s *SQLiteStore) PutConversationMetadata(conversationID string, metadata *ConversationMetadata) error
PutConversationMetadata replaces the typed metadata for a conversation, creating the conversation row if needed.
func (*SQLiteStore) RecordToolCall ¶
func (s *SQLiteStore) RecordToolCall(conversationID, messageID, toolCallID, toolName, arguments string) error
RecordToolCall records a tool call execution. messageID can be empty - it will be stored as NULL.
func (*SQLiteStore) Stats ¶
func (s *SQLiteStore) Stats() map[string]any
Stats returns memory statistics.
func (*SQLiteStore) ToolCallStats ¶
func (s *SQLiteStore) ToolCallStats() map[string]any
ToolCallStats returns statistics about tool usage.
type SearchOptions ¶ added in v0.3.0
type SearchOptions struct {
Query string
ConversationID string // optional filter
SilenceThreshold time.Duration // gap that stops context expansion
MaxMessages int // hard cap per direction
MaxDuration time.Duration // time-based cap per direction
Limit int // max results
NoContext bool // if true, return matches only (no surrounding context)
}
SearchOptions configures a search query.
type SearchResult ¶ added in v0.3.0
type SearchResult struct {
Match Message `json:"match"`
SessionID string `json:"session_id"`
ContextBefore []Message `json:"context_before"`
ContextAfter []Message `json:"context_after"`
Highlight string `json:"highlight,omitempty"`
}
SearchResult represents a search hit with surrounding context.
type Session ¶ added in v0.3.0
type Session struct {
ID string `json:"id"`
ConversationID string `json:"conversation_id"`
StartedAt time.Time `json:"started_at"`
EndedAt *time.Time `json:"ended_at,omitempty"`
EndReason string `json:"end_reason,omitempty"`
MessageCount int `json:"message_count"`
Summary string `json:"summary,omitempty"`
Title string `json:"title,omitempty"`
Tags []string `json:"tags,omitempty"`
Metadata *SessionMetadata `json:"metadata,omitempty"`
ParentSessionID string `json:"parent_session_id,omitempty"`
ParentToolCallID string `json:"parent_tool_call_id,omitempty"`
}
Session represents a conversation session with boundaries.
type SessionMetadata ¶ added in v0.3.0
type SessionMetadata struct {
// ChannelBinding is the channel/contact binding snapshot active when
// the session was created. This preserves the security-policy
// identity view Thane had at the time for later forensics.
ChannelBinding *ChannelBinding `json:"channel_binding,omitempty"`
// Summaries at different lengths for different display contexts.
OneLiner string `json:"one_liner,omitempty"` // ~10 words
Paragraph string `json:"paragraph,omitempty"` // 2-4 sentences
Detailed string `json:"detailed,omitempty"` // full summary
// Key decisions or outcomes from the session.
KeyDecisions []string `json:"key_decisions,omitempty"`
// People involved or mentioned.
Participants []string `json:"participants,omitempty"`
// Characterization of the session's nature.
SessionType string `json:"session_type,omitempty"` // e.g. "debugging", "architecture", "philosophy", "casual"
// Tools used during the session (tool name → call count).
ToolsUsed map[string]int `json:"tools_used,omitempty"`
// Files touched or discussed during the session.
FilesTouched []string `json:"files_touched,omitempty"`
// Model(s) used, if known.
Models []string `json:"models,omitempty"`
// Legacy delegation execution details, preserved from the delegations
// table migration (#446). Only populated for imported delegation records.
Delegation *DelegationMetadata `json:"delegation,omitempty"`
}
SessionMetadata holds rich, LLM-generated metadata for human-oriented search and browsing. Stored as JSON in the database for flexibility — new fields can be added without schema migrations.
type SessionOption ¶ added in v0.8.0
type SessionOption func(*Session)
SessionOption configures optional fields when starting a session.
func WithChannelBinding ¶ added in v0.9.1
func WithChannelBinding(binding *ChannelBinding) SessionOption
WithChannelBinding snapshots the effective conversation/channel binding onto the archived session at creation time.
func WithParentSession ¶ added in v0.8.0
func WithParentSession(id string) SessionOption
WithParentSession sets the parent session ID for a child session (e.g. a delegate spawned from a parent session).
func WithParentToolCall ¶ added in v0.8.0
func WithParentToolCall(id string) SessionOption
WithParentToolCall sets the tool call ID that triggered this child session (e.g. the thane_delegate tool call in the parent).
type SimpleSummarizer ¶
type SimpleSummarizer struct{}
SimpleSummarizer creates a basic summary without LLM (fallback).
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is an in-memory conversation memory backend. For persistent storage see SQLiteStore.
func (*Store) AddMessage ¶
AddMessage adds a message to a conversation.
func (*Store) BindConversationChannel ¶ added in v0.9.1
func (s *Store) BindConversationChannel(conversationID string, binding *ChannelBinding) error
BindConversationChannel updates only the channel-binding portion of a conversation's typed metadata.
func (*Store) GetAllConversations ¶
func (s *Store) GetAllConversations() []*Conversation
GetAllConversations returns all conversations for checkpointing.
func (*Store) GetConversation ¶
func (s *Store) GetConversation(id string) *Conversation
GetConversation retrieves a conversation by ID. Returns nil if not found.
func (*Store) GetMessages ¶
GetMessages retrieves messages for a conversation. Returns empty slice if conversation doesn't exist.
func (*Store) GetOrCreateConversation ¶
func (s *Store) GetOrCreateConversation(id string) *Conversation
GetOrCreateConversation retrieves or creates a conversation.
func (*Store) GetTokenCount ¶
GetTokenCount returns estimated token count for a conversation.
func (*Store) PutConversationMetadata ¶ added in v0.9.1
func (s *Store) PutConversationMetadata(conversationID string, metadata *ConversationMetadata) error
PutConversationMetadata replaces the typed metadata for a conversation, creating the conversation record if needed.
func (*Store) RestoreConversations ¶
func (s *Store) RestoreConversations(convs []*Conversation)
RestoreConversations replaces all conversations from a checkpoint.
type Summarizer ¶
type Summarizer interface {
Summarize(ctx context.Context, messages []Message, workingMemory string) (string, error)
}
Summarizer generates summaries from messages. When workingMemory is non-empty, it is included in the prompt so the summarizer preserves experiential context through compaction.
type SummarizerConfig ¶ added in v0.8.0
type SummarizerConfig struct {
// Interval between periodic scans for unsummarized sessions.
// Default: 5 minutes.
Interval time.Duration
// Timeout per individual session summarization LLM call.
// Default: 60 seconds.
Timeout time.Duration
// PauseBetween is the delay between processing consecutive sessions
// to avoid overwhelming the LLM or starving interactive requests.
// Default: 5 seconds.
PauseBetween time.Duration
// BatchSize is the max number of unsummarized sessions to fetch per scan.
// Default: 10.
BatchSize int
// ModelPreference is a soft hint for which model to use.
// Passed as HintModelPreference to the router. If empty, the router
// picks freely based on other hints.
ModelPreference string
// IdleTimeout is the duration of inactivity after which an open
// session is silently closed by the summarizer as a backstop.
// Zero disables idle session closing. This complements the
// interactive idle check in the channel bridge, which sends
// farewell messages. The summarizer-based check recovers from
// crashes where in-memory state was lost.
IdleTimeout time.Duration
}
SummarizerConfig controls the summarizer worker behavior.
func DefaultSummarizerConfig ¶ added in v0.8.0
func DefaultSummarizerConfig() SummarizerConfig
DefaultSummarizerConfig returns sensible defaults for the summarizer worker.
type SummarizerWorker ¶ added in v0.8.0
type SummarizerWorker struct {
// contains filtered or unexported fields
}
SummarizerWorker periodically scans for unsummarized sessions and generates metadata (title, tags, summaries) using an LLM via the model router.
func NewSummarizerWorker ¶ added in v0.8.0
func NewSummarizerWorker(store *ArchiveStore, llmClient llm.Client, rtr *router.Router, logger *slog.Logger, cfg SummarizerConfig) *SummarizerWorker
NewSummarizerWorker creates a summarizer worker. Call Start to begin processing.
func (*SummarizerWorker) SetInteractionCallback ¶ added in v0.8.0
func (w *SummarizerWorker) SetInteractionCallback(cb InteractionCallback)
SetInteractionCallback registers a callback invoked after each successful session summarization. The callback receives the conversation ID, session ID, session end time, and LLM-generated topic tags, allowing callers to update contact interaction history without coupling the memory package to the contacts package.
func (*SummarizerWorker) Start ¶ added in v0.8.0
func (w *SummarizerWorker) Start(ctx context.Context)
Start begins the background summarization worker. It performs an immediate scan on startup (to catch up on missed sessions), then scans periodically at the configured interval.
func (*SummarizerWorker) Stop ¶ added in v0.8.0
func (w *SummarizerWorker) Stop()
Stop cancels the worker and waits for its goroutine to exit.
type ToolCall ¶
type ToolCall struct {
ID string `json:"id"`
MessageID string `json:"message_id"`
ConversationID string `json:"conversation_id"`
ToolName string `json:"tool_name"`
Arguments string `json:"arguments"`
Result string `json:"result,omitempty"`
Error string `json:"error,omitempty"`
StartedAt time.Time `json:"started_at"`
CompletedAt *time.Time `json:"completed_at,omitempty"`
DurationMs int64 `json:"duration_ms,omitempty"`
}
ToolCall represents a recorded tool invocation.
type ToolCallArchiver ¶ added in v0.8.0
type ToolCallArchiver interface {
ArchiveToolCalls(conversationID, sessionID string) (int64, error)
}
ToolCallArchiver sets lifecycle status on tool calls in the unified table.
type WorkingMemoryProvider ¶ added in v0.5.0
type WorkingMemoryProvider struct {
// contains filtered or unexported fields
}
WorkingMemoryProvider implements the agent.ContextProvider interface for auto-injecting working memory into the system prompt. When the current conversation has working memory content, it is included under a "### Working Memory" heading so the agent has experiential continuity without needing to explicitly read it.
func NewWorkingMemoryProvider ¶ added in v0.5.0
func NewWorkingMemoryProvider(store *WorkingMemoryStore, convFunc func(context.Context) string) *WorkingMemoryProvider
NewWorkingMemoryProvider creates a context provider that auto-injects working memory for the current conversation. The convFunc parameter extracts the conversation ID from the request context — typically [tools.ConversationIDFromContext].
func (*WorkingMemoryProvider) GetContext ¶ added in v0.5.0
GetContext returns the working memory content for the current conversation, formatted for system prompt injection. Returns empty string if no working memory exists.
type WorkingMemoryReader ¶ added in v0.5.0
WorkingMemoryReader is the subset of WorkingMemoryStore needed by the compactor. Defined as an interface for testability and to avoid coupling the compactor to the concrete store type.
type WorkingMemoryStore ¶ added in v0.5.0
type WorkingMemoryStore struct {
// contains filtered or unexported fields
}
WorkingMemoryStore persists free-form working memory per conversation. Working memory captures experiential context that mechanical summarisation destroys: emotional tone, conversational arc, relationship temperature, and unresolved threads. The table lives in archive.db alongside session transcripts.
func NewWorkingMemoryStore ¶ added in v0.5.0
func NewWorkingMemoryStore(db *sql.DB) (*WorkingMemoryStore, error)
NewWorkingMemoryStore creates a working memory store using the given database connection (typically from ArchiveStore.DB). It creates the working_memory table if it does not already exist.
func (*WorkingMemoryStore) Delete ¶ added in v0.5.0
func (s *WorkingMemoryStore) Delete(conversationID string) error
Delete removes the working memory for a conversation.
func (*WorkingMemoryStore) Get ¶ added in v0.5.0
Get returns the working memory content and last-updated timestamp for a conversation. If no working memory exists, it returns an empty string and zero time with no error.
func (*WorkingMemoryStore) Set ¶ added in v0.5.0
func (s *WorkingMemoryStore) Set(conversationID, content string) error
Set writes or replaces the working memory content for a conversation.