Documentation
¶
Index ¶
- Constants
- Variables
- func ValidateTodoStatus(status TodoStatus) error
- type AssistantToolCall
- type CompressionRecord
- type Message
- type Plan
- type SearchResult
- type Store
- func (s *Store) AppendAssistantMessageWithToolCalls(threadID string, content *string, toolCalls []AssistantToolCall) (*Message, error)
- func (s *Store) AppendMessage(threadID, role string, content *string, toolCallID *string) (*Message, error)
- func (s *Store) AppendToolCall(messageID int, callID, toolName, arguments string, seq int) error
- func (s *Store) Close() error
- func (s *Store) CreatePlan(threadID string, items []TodoItem) (plan *Plan, err error)
- func (s *Store) CreateThread(title, model *string) (*Thread, error)
- func (s *Store) CreateThreadWithWorkspace(title, model *string, workspace string) (*Thread, error)
- func (s *Store) CreateTodos(threadID string, items []TodoItem) (updated []TodoItem, err error)
- func (s *Store) DB() *sql.DB
- func (s *Store) DeleteMessagesAfter(threadID string, seq int) error
- func (s *Store) DeletePlan(threadID string) error
- func (s *Store) DeleteThread(id string) error
- func (s *Store) DeleteTodos(threadID string, ids []string) (updated []TodoItem, err error)
- func (s *Store) ForkThread(srcID string) (newID string, err error)
- func (s *Store) GetLatestCompression(threadID string) (*CompressionRecord, error)
- func (s *Store) GetPlan(threadID string) (*Plan, error)
- func (s *Store) GetThread(id string) (*Thread, error)
- func (s *Store) GetThreadWithMessages(id string) (*Thread, []Message, error)
- func (s *Store) GetThreadWithMessagesFromSeq(threadID string, firstSeq int) (*Thread, []Message, error)
- func (s *Store) GetToolCallsForMessage(messageID int) ([]ToolCall, error)
- func (s *Store) InvalidateCompressionsAfterSeq(threadID string, seq int) error
- func (s *Store) ListThreads() ([]Thread, error)
- func (s *Store) ListThreadsByWorkspace(workspace string, includeLegacy bool) ([]Thread, error)
- func (s *Store) ListTodos(threadID string) ([]TodoItem, error)
- func (s *Store) ReplaceTodos(threadID string, items []TodoItem) (updated []TodoItem, err error)
- func (s *Store) SaveCompression(rec CompressionRecord) error
- func (s *Store) SearchMessages(query string, limit int) ([]SearchResult, error)
- func (s *Store) SetThreadPlanMode(id, mode string) error
- func (s *Store) SetThreadTitle(id, title string) error
- func (s *Store) SubagentTranscript(taskID string) (string, error)
- func (s *Store) UpdateThreadTitle(id, title string) error
- func (s *Store) UpdateTodos(threadID string, updates []TodoUpdate) (updated []TodoItem, err error)
- type Thread
- type TodoItem
- type TodoStatus
- type TodoUpdate
- type ToolCall
Constants ¶
const ( // PlanModeOff means no plan turn is active or pending. PlanModeOff = "" // PlanModePlanning means a read-only plan turn was requested and is // running (or was interrupted before completing). PlanModePlanning = "planning" // PlanModePendingApproval means a plan turn completed and the presented // plan awaits the user's approve/reject decision. PlanModePendingApproval = "pending_approval" // PlanModeApproved means the user approved the pending plan; the next // turn injects the execution directive exactly once, then clears it. PlanModeApproved = "approved" )
Plan-mode lifecycle states for Thread.PlanMode.
Variables ¶
var ( // ErrPlanExists is returned when CreatePlan is called for a thread that // already owns a plan. ErrPlanExists = errors.New("plan already exists") // ErrTodoNotFound is wrapped when a todo mutation names an unknown ID. ErrTodoNotFound = errors.New("todo not found") )
Functions ¶
func ValidateTodoStatus ¶
func ValidateTodoStatus(status TodoStatus) error
ValidateTodoStatus returns a descriptive error for an unsupported state.
Types ¶
type AssistantToolCall ¶
AssistantToolCall is one provider tool call to persist with an assistant message. Slice order becomes the stored tool-call sequence.
type CompressionRecord ¶
type CompressionRecord struct {
ID int64
ThreadID string
Summary string
FirstKeptSeq int
CompressedMessageCount int
PrunedToolOutputs int
BeforeTokens int
AfterTokens int
BudgetTokens int
SummaryModelAlias string
SummaryModelID string
SummaryPromptTokens int
SummaryCompletionTokens int
SummaryTotalTokens int
FallbackUsed bool
FallbackReason string
CreatedAt time.Time
}
CompressionRecord represents one persisted compression event for a thread.
type Message ¶
type Message struct {
ID int `json:"id"`
ThreadID string `json:"thread_id"`
Role string `json:"role"`
Content *string `json:"content"`
ToolCallID *string `json:"tool_call_id"`
CreatedAt time.Time `json:"created_at"`
Seq int `json:"seq"`
}
Message represents a single message in a thread.
type Plan ¶
type Plan struct {
ThreadID string `json:"thread_id"`
Revision int64 `json:"revision"`
Items []TodoItem `json:"items"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Plan is the current durable task plan for a conversation thread. Revision is incremented once for each successful batch mutation, making snapshots safe to reconcile in a CLI or web client.
type SearchResult ¶
type SearchResult struct {
MessageID int `json:"message_id"`
ThreadID string `json:"thread_id"`
ThreadTitle *string `json:"thread_title"`
Role string `json:"role"`
Content string `json:"content"`
Snippet string `json:"snippet"`
CreatedAt time.Time `json:"created_at"`
}
SearchResult represents a single message match from FTS5 search.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store wraps the SQLite database.
func Open ¶
Open opens or creates the SQLite database at path and applies the migrations embedded in the binary. This works regardless of the working directory or where the config file lives.
func OpenWithMigrations ¶
OpenWithMigrations opens the database and applies migrations from a directory on disk. Kept for tests that point at the repo's migrations/ folder.
func OpenWithMigrationsFS ¶
OpenWithMigrationsFS opens the database and applies migrations read from fsys.
func (*Store) AppendAssistantMessageWithToolCalls ¶
func (s *Store) AppendAssistantMessageWithToolCalls(threadID string, content *string, toolCalls []AssistantToolCall) (*Message, error)
AppendAssistantMessageWithToolCalls atomically persists an assistant message and every tool call it contains. If any tool-call insert fails (including a globally duplicate call ID), the assistant message and all earlier calls in the same group are rolled back together.
func (*Store) AppendMessage ¶
func (s *Store) AppendMessage(threadID, role string, content *string, toolCallID *string) (*Message, error)
AppendMessage adds a message to a thread and updates the thread timestamp.
Uses BEGIN IMMEDIATE to acquire the write lock before reading, preventing the deferred-transaction lock-upgrade issue that causes SQLITE_BUSY. The UNIQUE(thread_id, seq) constraint (migration 0003) is the hard guarantee against duplicate seq values.
func (*Store) AppendToolCall ¶
AppendToolCall records a tool call for an assistant message.
func (*Store) CreatePlan ¶
CreatePlan creates the sole plan belonging to threadID. Empty plans are valid. Items with an empty ID receive deterministic IDs starting at "1"; supplied IDs are useful when importing a snapshot.
func (*Store) CreateThread ¶
CreateThread creates a new thread with optional title and model.
func (*Store) CreateThreadWithWorkspace ¶
CreateThreadWithWorkspace creates a new thread and records the workspace directory its tools run in ("" for unknown/legacy).
func (*Store) CreateTodos ¶
CreateTodos appends items to a thread's plan, creating the plan on demand. Input IDs and positions must be empty: IDs are allocated atomically and positions are derived from the existing list. Empty status defaults to pending. The returned slice is the complete updated list.
func (*Store) DeleteMessagesAfter ¶
DeleteMessagesAfter removes all messages in a thread from seq onward (inclusive). It also invalidates any compression records whose first_kept_seq >= seq, because undo can remove the messages that the compression boundary references.
func (*Store) DeletePlan ¶
DeletePlan deletes a thread's plan and all its todos. It is idempotent.
func (*Store) DeleteThread ¶
DeleteThread removes a thread and cascades messages + tool_calls.
func (*Store) DeleteTodos ¶
DeleteTodos atomically removes the named items, compacts positions, and returns the remaining ordered list. All IDs must exist.
func (*Store) ForkThread ¶
ForkThread creates a new thread that copies the source thread's title, model, messages, assistant tool calls, and current persisted plan. Tool-call IDs are globally unique, so the fork receives fresh IDs and all copied tool-result messages are rewritten to reference them. The entire copy is one transaction: a failed fork never leaves behind a partial thread.
func (*Store) GetLatestCompression ¶
func (s *Store) GetLatestCompression(threadID string) (*CompressionRecord, error)
GetLatestCompression returns the most recent compression record for a thread, or nil if none exists.
func (*Store) GetPlan ¶
GetPlan returns the current plan and its ordered items. A thread without a plan returns (nil, nil).
func (*Store) GetThreadWithMessages ¶
GetThreadWithMessages returns a thread with its ordered messages.
func (*Store) GetThreadWithMessagesFromSeq ¶
func (s *Store) GetThreadWithMessagesFromSeq(threadID string, firstSeq int) (*Thread, []Message, error)
GetThreadWithMessagesFromSeq returns a thread with messages starting from firstSeq (inclusive), ordered by seq ASC. This is used to rebuild the message list after a compression record with first_kept_seq.
func (*Store) GetToolCallsForMessage ¶
GetToolCallsForMessage returns all tool calls for a given message, ordered by seq.
func (*Store) InvalidateCompressionsAfterSeq ¶
InvalidateCompressionsAfterSeq deletes compression records whose first_kept_seq is >= the given seq. This is called by DeleteMessagesAfter because undo can remove messages at or after the kept boundary, making those compression records point to nonexistent messages.
func (*Store) ListThreads ¶
ListThreads returns all threads ordered by most recent update.
func (*Store) ListThreadsByWorkspace ¶
ListThreadsByWorkspace returns threads whose recorded workspace matches, ordered by most recent update. When includeLegacy is true, threads with an unknown workspace ("") are included too — they predate workspace tracking and can't be attributed, so they surface in the default view only.
func (*Store) ListTodos ¶
ListTodos returns a thread's todo items in stable plan order. A thread with no plan has an empty list.
func (*Store) ReplaceTodos ¶
ReplaceTodos atomically replaces a plan's complete item list. Slice order is authoritative. Existing IDs may be retained; blank IDs receive fresh, monotonic IDs. An empty slice clears the list but keeps the plan.
func (*Store) SaveCompression ¶
func (s *Store) SaveCompression(rec CompressionRecord) error
SaveCompression persists a compression record. It sets CreatedAt to now. The caller should set FirstKeptSeq to the Seq of the first retained non-synthetic thread message after the compressed span.
func (*Store) SearchMessages ¶
func (s *Store) SearchMessages(query string, limit int) ([]SearchResult, error)
SearchMessages performs a full-text search across all messages. Uses SQLite FTS5 with the bm25 ranking function.
NOTE: Compression summaries are intentionally excluded from FTS search. They live in the `compressions` table, not `messages`, and are not indexed into `messages_fts`. This follows the robustness spec recommendation: do not index synthetic compression summaries into user-facing search unless clearly labeled as summaries.
func (*Store) SetThreadPlanMode ¶
SetThreadPlanMode sets the thread's plan-approval lifecycle state (one of the PlanMode* constants). It deliberately does not touch updated_at: a lifecycle transition is not conversation activity and must not reorder the session list.
func (*Store) SetThreadTitle ¶
SetThreadTitle unconditionally overwrites the thread title (for manual rename or regeneration).
func (*Store) SubagentTranscript ¶
SubagentTranscript renders the persisted transcript of one subagent task (migration 0004's subagent_tasks row) for agent:// reads: goal header, role sections, tool calls and results, in stored order. It resolves an unknown id as a not-found error so file_read can surface it.
func (*Store) UpdateThreadTitle ¶
UpdateThreadTitle sets the thread title unless it was already set (conditional for auto-title).
func (*Store) UpdateTodos ¶
func (s *Store) UpdateTodos(threadID string, updates []TodoUpdate) (updated []TodoItem, err error)
UpdateTodos atomically applies a batch of patches and returns the complete ordered list. Every ID is checked before the first write, so an unknown ID or invalid patch leaves the plan unchanged.
type Thread ¶
type Thread struct {
ID string `json:"id"`
Title *string `json:"title"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Model *string `json:"model"`
// Workspace is the directory the thread's tools run in. Empty means
// unknown — threads created before migration 0005 have no record.
Workspace string `json:"workspace"`
// PlanMode is the thread's plan-approval lifecycle state (migration 0007):
// one of the PlanMode* constants. Empty means plan mode is off.
PlanMode string `json:"plan_mode"`
}
Thread represents a conversation thread.
type TodoItem ¶
type TodoItem struct {
ID string `json:"id"`
ThreadID string `json:"thread_id"`
Content string `json:"content"`
Status TodoStatus `json:"status"`
Position int `json:"position"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
TodoItem is one ordered step in a thread's plan. IDs are monotonic decimal strings generated per plan. Position is one-based and follows slice order.
type TodoStatus ¶
type TodoStatus string
TodoStatus is the durable lifecycle state of one plan item.
const ( TodoPending TodoStatus = "pending" TodoInProgress TodoStatus = "in_progress" TodoCompleted TodoStatus = "completed" TodoCancelled TodoStatus = "cancelled" )
func (TodoStatus) Valid ¶
func (status TodoStatus) Valid() bool
Valid reports whether status is one of the persisted todo states.
type TodoUpdate ¶
type TodoUpdate struct {
ID string `json:"id"`
Content *string `json:"content,omitempty"`
Status *TodoStatus `json:"status,omitempty"`
}
TodoUpdate changes one existing item. A nil field is left unchanged.