store

package
v0.14.21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 3, 2026 License: MIT Imports: 10 Imported by: 0

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

View Source
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

func New(opt Options) *Store

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

func (s *Store) AppendUserTurn(role, source, text string) error

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

func (s *Store) Flush() error

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

func (s *Store) InFlightEvents() []TurnEvent

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

func (s *Store) PartialText() string

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL