Documentation
¶
Overview ¶
Package store is the agents pipeline sink: it consumes AgentEvent values produced by a Parser and writes them to the on-disk session folder (conversation.jsonl, raw.jsonl, agents.json cli_session_id).
The store buffers TextDelta chunks until Done, then writes one assistant turn — that matches how UI / Slack want to display messages and keeps conversation.jsonl one-line-per-turn instead of one-line-per-character.
One Store per active session. Not safe for concurrent Apply from multiple goroutines; the agent lifecycle pipes events through a single reader goroutine.
Index ¶
- Constants
- func RecoverInflight(layout config.Layout, sessionID, agentName, provider string, ...) (bool, error)
- type Attachment
- type ConversationTurn
- type InflightEntry
- type Options
- type Store
- func (s *Store) AppendUserTurn(role, source, text string) error
- func (s *Store) AppendUserTurnWithAttachments(role, source, text string, atts []Attachment) error
- func (s *Store) Apply(ev event.AgentEvent) (bool, error)
- func (s *Store) Flush() error
- func (s *Store) InFlightEvents() []TurnEvent
- func (s *Store) PartialText() string
- type TurnEvent
Constants ¶
const MaxAssistantTurnBytes = 32 * 1024
MaxAssistantTurnBytes caps one assistant turn's body before it gets written to conversation.jsonl. Anything beyond is truncated with a note pointing at raw.jsonl. Matches §13 cap.
Variables ¶
This section is empty.
Functions ¶
func RecoverInflight ¶ added in v0.14.3
func RecoverInflight(layout config.Layout, sessionID, agentName, provider string, now func() time.Time) (bool, error)
RecoverInflight merges a leftover inflight.jsonl (turn was mid-stream when the previous wick process died) into conversation.jsonl as one truncated assistant turn, then deletes the inflight file. Called from registry boot so the next chat continues from a consistent history instead of branching off a partial turn.
agentName goes onto the assistant turn record so the UI groups it under the right agent; pass session.Meta.ActiveAgent or the first entry of session.Agents. provider is "type/name" of the agent that owned the inflight stream — stamped onto the recovered turn so the UI can label it like any other assistant turn.
Returns true when a recovery write actually happened (caller may want to log). Missing file or empty entries → (false, nil). Any disk error in append OR delete propagates so the caller knows the file is still there (registry boot can choose to keep going).
Types ¶
type Attachment ¶ added in v0.14.18
type Attachment struct {
Name string `json:"name"` // original filename (display)
StoredName string `json:"stored_name"` // filename under uploads dir
URL string `json:"url,omitempty"` // GET path for the UI
AbsPath string `json:"abs_path,omitempty"` // absolute disk path for CLI
MIME string `json:"mime,omitempty"`
Size int64 `json:"size,omitempty"`
}
Attachment is one file uploaded with a user turn. The file content lives under <SessionDir>/uploads/<StoredName>; URL is the path the UI uses to fetch it (served via /tools/agents/sessions/<id>/uploads/...). AbsPath is the on-disk path passed to the CLI subprocess so it can Read the file via tool calls.
type ConversationTurn ¶
type ConversationTurn struct {
Timestamp time.Time `json:"ts"`
Role string `json:"role"` // "user" | "assistant" | "system"
Agent string `json:"agent,omitempty"` // assistant turn only
Provider string `json:"provider,omitempty"` // assistant turn only — "type/name" snapshot at turn time
Source string `json:"source,omitempty"`
Text string `json:"text"`
Truncated bool `json:"truncated,omitempty"`
Events []TurnEvent `json:"events,omitempty"` // tool/thinking trace
Attachments []Attachment `json:"attachments,omitempty"` // user turn only
}
ConversationTurn is the on-disk shape of one user/assistant turn.
type InflightEntry ¶ added in v0.14.3
type InflightEntry struct {
Type string `json:"type"` // "text_delta" | "thinking" | "tool_use" | "tool_result"
Text string `json:"text,omitempty"`
ToolName string `json:"tool_name,omitempty"`
ToolInput string `json:"tool_input,omitempty"`
ToolUseID string `json:"tool_use_id,omitempty"`
IsError bool `json:"is_error,omitempty"`
At time.Time `json:"at,omitempty"`
}
InflightEntry is one line of inflight.jsonl. Mirrors TurnEvent + text_delta chunks so a crash mid-stream leaves a full replay log on disk. Provider-agnostic — claude TextDelta, codex item.updated, and future CLIs all serialise through the same shape via store.Apply.
func LoadInflight ¶ added in v0.14.3
func LoadInflight(layout config.Layout, sessionID string) ([]InflightEntry, error)
LoadInflight reads inflight.jsonl for a session and returns every entry in order. Used at boot/snapshot time to repaint a turn that was mid-stream when the process died. Missing file is treated as "no inflight" (returns nil, nil) so callers don't need to stat.
type Options ¶
type Options struct {
Layout config.Layout
SessionID string
AgentName string
Provider string
RecordRaw bool
Now func() time.Time // optional; defaults to time.Now
}
Options configures a Store. AgentName ties assistant turns to the agents.json entry that emitted them. Provider is "type/name" and is stamped on every assistant turn so the UI can render which model produced it even after the active provider switches.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store collects events for one session+agent and persists them.
func New ¶
New returns a Store ready to consume events. Caller owns the session/agent CRUD; the store only writes turns + cli_session_id.
func (*Store) AppendUserTurn ¶
AppendUserTurn records a user / system message before it's sent to the subprocess. Source is the transport label ("ui", "slack", "api"). Role is normally "user"; "system" for operator instructions.
func (*Store) AppendUserTurnWithAttachments ¶ added in v0.14.18
func (s *Store) AppendUserTurnWithAttachments(role, source, text string, atts []Attachment) error
AppendUserTurnWithAttachments is AppendUserTurn plus a list of uploaded files. The attachments are persisted alongside the text so the UI can re-render thumbnails / file chips after reload.
func (*Store) Apply ¶
func (s *Store) Apply(ev event.AgentEvent) (bool, error)
Apply consumes one parser event. Returns true when an assistant turn was just flushed (caller may want to notify Slack / SSE).
Side effects per event type:
- SessionStart → persists cli_session_id into agents.json (if AgentName is set) so resume works after kill.
- TextDelta → appended to turnBuf.
- Done / Error → flush turnBuf as one assistant turn.
- Anything else → optionally mirrored to raw.jsonl.
func (*Store) Flush ¶
Flush is the explicit drain hook for callers that want to write whatever's buffered (e.g. subprocess crashed mid-stream, no Done arrived). Marks the turn as truncated since it didn't end naturally.
func (*Store) InFlightEvents ¶ added in v0.13.3
InFlightEvents returns a snapshot of events buffered in the current turn that have not yet been flushed to disk (no Done received yet). Safe to call from any goroutine — returns a copy.
func (*Store) PartialText ¶ added in v0.14.3
PartialText returns the assistant text accumulated so far for the in-flight turn (everything appended via TextDelta since the last flushAssistantTurn). Empty string when no turn is in progress.
Used by the SSE snapshot endpoint so a page refresh mid-stream can repaint the partial bubble instead of waiting for the next delta or losing the text entirely until Done writes it to conversation.jsonl.
Safe to call from any goroutine — returns a defensive copy.
type TurnEvent ¶ added in v0.13.0
type TurnEvent struct {
Type string `json:"type"` // "tool_use" | "tool_result" | "thinking"
ToolName string `json:"tool_name,omitempty"` // tool_use only
ToolInput string `json:"tool_input,omitempty"` // tool_use only
ToolUseID string `json:"tool_use_id,omitempty"`
IsError bool `json:"is_error,omitempty"` // tool_result only
Text string `json:"text,omitempty"` // tool_result body / thinking text
At time.Time `json:"at,omitempty"` // when this event arrived
EndAt time.Time `json:"end_at,omitempty"` // tool_result: when tool finished
}
TurnEvent is one tool_use, tool_result, or thinking event recorded within an assistant turn. Stored alongside the text so the UI can replay the full trace on reload.