session

package
v0.12.3 Latest Latest
Warning

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

Go to latest
Published: Aug 10, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// MaxOutputBytes is the maximum byte size of a tool output before truncation.
	MaxOutputBytes = 50 * 1024 // 50 KB
	// MaxOutputLines is the maximum line count of a tool output before truncation.
	MaxOutputLines = 2000
	// HeadLines is the number of lines to preserve from the beginning.
	HeadLines = 200
	// TailLines is the number of lines to preserve from the end.
	TailLines = 500
)
View Source
const InterruptedToolOutput = "[Interrupted before result was recorded]"

InterruptedToolOutput is the placeholder content backfilled for tool calls whose result never made it to disk (user stop, process kill, or a recording gap). It tells the model what happened instead of fabricating an output. The runner records the same marker for interrupted calls so live sessions and reconstructed history stay identical.

Variables

View Source
var (
	// ErrDispatchSessionLimit means the durable consume count already reached
	// the policy cap. Callers must not invoke the provider.
	ErrDispatchSessionLimit = errors.New("provider call limit reached for this session")
	// ErrDispatchOperationExists prevents reuse of an operation identifier from
	// creating another provider side effect while counting as one operation.
	ErrDispatchOperationExists = errors.New("provider operation already exists")
)
View Source
var (
	// ErrArtifactNotFound reports that an opaque artifact ID is not present in
	// the requested session.
	ErrArtifactNotFound = errors.New("artifact not found")
	// ErrArtifactRevisionMismatch prevents a stale viewer from marking a newer
	// artifact revision as read.
	ErrArtifactRevisionMismatch = errors.New("artifact revision changed")
)
View Source
var ErrSessionToolOverrideRevision = errors.New("session tool override revision conflict")

Functions

func CountDispatchedProviderToolOperations added in v0.12.3

func CountDispatchedProviderToolOperations(
	snapshots []ProviderToolOperationSnapshot,
	capabilityKey, providerProfileID string,
) int

CountDispatchedProviderToolOperations counts durable consume points for one capability/provider pair. Empty filters match all values.

func DeleteSessionByUUID added in v0.6.1

func DeleteSessionByUUID(uuid string) (bool, error)

DeleteSessionByUUID removes a session (index entry + JSONL file) located by uuid across ALL projects. The web task tree can delete a task that does not belong to the active project, so we must not assume a single project key. Returns false if no session with that uuid exists. The JSONL file is only removed when the uuid was actually found in the index, which also prevents a crafted uuid from deleting an arbitrary file.

func IsConfigurableSessionTool added in v0.12.3

func IsConfigurableSessionTool(SessionTool) bool

IsConfigurableSessionTool always returns false. ParseSessionTool and the journal replay/CAS methods remain available only for historical records.

func ListAllSessions added in v0.3.4

func ListAllSessions() (map[string][]SessionMeta, error)

ListAllSessions returns all sessions across all projects, keyed by project path.

func ListProjectMeta added in v0.11.1

func ListProjectMeta() (map[string]ProjectMeta, error)

ListProjectMeta returns the per-project metadata (last-activity timestamps) keyed by project path. A nil map (legacy install: no projects.json yet) is returned as-is; callers fall back to deriving recency from sessions. Lock-free like ListSessions/ListAllSessions: writers persist via atomic rename, so readers always observe a complete file.

func LoadArtifactRecords added in v0.12.1

func LoadArtifactRecords(id string) ([]artifact.Record, error)

LoadArtifactRecords rebuilds the latest metadata revision for every Artifact in a session. Entry order is not trusted: the greatest revision wins, with a later timestamp breaking ties for defensive recovery from duplicated lines.

func LoadLastSession added in v0.10.1

func LoadLastSession(project string) string

LoadLastSession returns the last foregrounded session uuid for project, or "" when none is recorded — or when the recorded session no longer exists on disk (deleted, or a "new chat" that was never written), so callers fall back to a fresh session instead of resurrecting a stale id.

func LoadSessionModeStrict added in v0.12.3

func LoadSessionModeStrict(id string) (string, error)

LoadSessionModeStrict reads the latest durable unified mode without the conversational replay loader's corrupt-line tolerance. A malformed line could itself be a newer mode transition, so authorization restore must fail closed rather than silently skipping it and reviving an older Full access value. An empty result is the legacy/default Approval mode.

func LoadSessionToolOverrides added in v0.12.3

func LoadSessionToolOverrides(id string) (map[SessionTool]SessionToolOverride, error)

LoadSessionToolOverrides replays the latest persisted override for a session.

func MarkArtifactViewed added in v0.12.3

func MarkArtifactViewed(sessionID, artifactID string, revision int) error

MarkArtifactViewed advances exactly one artifact's revision cursor. It is serialized with artifact journal appends so a concurrent new revision is always left unseen. The operation never advances the legacy session-wide timestamp.

func PruneOldToolOutputs added in v0.4.6

func PruneOldToolOutputs(msgs []adk.Message, protectTurns int) []adk.Message

PruneOldToolOutputs replaces old tool result outputs with actionable placeholders, protecting the most recent turns from pruning. This implements the Tier 1.5 "placeholder compression" strategy: recent tool outputs are preserved verbatim; older ones are replaced with hints telling the model how to recover the data.

protectTurns is the number of recent user turns to protect (default 2). Returns the pruned messages slice (same backing array, modified in place).

func ReplayGenerationOperations added in v0.12.3

func ReplayGenerationOperations(entries []Entry) map[string]GenerationOperationSnapshot

ReplayGenerationOperations rebuilds the latest monotonic projection for each operation and separately remembers whether its durable consume point was observed. It tolerates corrupted/out-of-order lines conservatively: terminal evidence never regresses to a progress state, while dispatch evidence is sticky for ledger reconstruction.

func ReplayProviderToolOperations added in v0.12.3

func ReplayProviderToolOperations(entries []Entry) map[string]ProviderToolOperationSnapshot

ReplayProviderToolOperations conservatively rebuilds one snapshot per operation. Terminal evidence always outranks a later nonterminal line; malformed entries are ignored and dispatch evidence remains sticky.

func ReplaySessionToolOverrides added in v0.12.3

func ReplaySessionToolOverrides(entries []Entry) map[SessionTool]SessionToolOverride

ReplaySessionToolOverrides projects the latest valid revision for each allowlisted tool. The greatest revision wins rather than line order, so a duplicated or out-of-order line cannot roll state backwards.

func SaveLastSession added in v0.10.1

func SaveLastSession(project, id string)

SaveLastSession records id as the last foregrounded session for project. Best-effort: persistence must never break session switching, and callers run outside any engine lock (file I/O).

func TruncateToolOutput added in v0.4.6

func TruncateToolOutput(output, sessionUUID, toolCallID string) string

TruncateToolOutput truncates a tool output string if it exceeds size limits. It preserves head + tail lines and writes the full content to disk. Returns the (possibly truncated) output. If no truncation is needed, the original string is returned unchanged.

sessionUUID is used to namespace the overflow files. toolCallID identifies the specific tool call.

func ValidateGenerationStart added in v0.12.3

func ValidateGenerationStart(operation GenerationOperation) error

ValidateGenerationStart is the pre-dispatch guard used before the first journal append. Recovery code may append a terminal repair entry to a legacy transcript, so RecordGenerationOperation validates shape but deliberately leaves first-state policy to this explicit helper.

func ValidateGenerationTransition added in v0.12.3

func ValidateGenerationTransition(previous, next GenerationOperation) error

ValidateGenerationTransition enforces monotonic state and immutable intent. Duplicate transitions are allowed so crash recovery can append idempotently.

func ValidateProviderToolStart added in v0.12.3

func ValidateProviderToolStart(operation ProviderToolOperation) error

ValidateProviderToolStart must be called before the first synchronous journal append and before invoking the external endpoint.

func ValidateProviderToolTransition added in v0.12.3

func ValidateProviderToolTransition(previous, next ProviderToolOperation) error

ValidateProviderToolTransition permits exactly one terminal transition and enforces immutable approved intent. Duplicate state writes are accepted for idempotent repair, but a terminal state can never change.

func ValidateSessionID added in v0.3.3

func ValidateSessionID(id string) error

ValidateSessionID checks that a session ID is safe for use as a filename. It rejects empty IDs, path traversal sequences, and path separators.

Types

type DispatchPolicy added in v0.12.3

type DispatchPolicy struct {
	Tool          SessionTool
	MaxPerSession int
}

DispatchPolicy binds a prepared billable tool to its hard session cap.

type Entry

type Entry struct {
	Type       EntryType `json:"type"`
	UUID       string    `json:"uuid,omitempty"`
	Project    string    `json:"project,omitempty"`
	Provider   string    `json:"provider,omitempty"`
	Model      string    `json:"model,omitempty"`
	Agent      string    `json:"agent,omitempty"`
	Content    string    `json:"content,omitempty"`
	Name       string    `json:"name,omitempty"`         // tool name
	Args       string    `json:"args,omitempty"`         // tool args JSON
	Output     string    `json:"output,omitempty"`       // tool output
	Error      string    `json:"error,omitempty"`        // tool error
	ToolCallID string    `json:"tool_call_id,omitempty"` // links tool_call ↔ tool_result
	Timestamp  string    `json:"timestamp"`
	// Typed tool/generation correlation. These additive fields are shared by
	// operation journal and enhanced tool-result entries.
	OperationID string   `json:"operation_id,omitempty"`
	Outcome     string   `json:"outcome,omitempty"`
	ErrorCode   string   `json:"error_code,omitempty"`
	ArtifactIDs []string `json:"artifact_ids,omitempty"`

	// Tool-call batch fields. Tool calls issued by one assistant message share
	// a BatchID; legacy files simply lack these keys (unmarshal to zero values,
	// i.e. "no batch info").
	BatchID    string `json:"batch_id,omitempty"`
	BatchIndex int    `json:"batch_index,omitempty"`
	BatchSize  int    `json:"batch_size,omitempty"`

	// tool_result semantics. Denied marks a user-rejected approval (replay
	// renders it struck-through, not as an error); DurationMs is the runner's
	// approval-wait-adjusted execution latency. Legacy files lack both keys.
	Denied     bool  `json:"denied,omitempty"`
	DurationMs int64 `json:"duration_ms,omitempty"`

	// Images attached to a user message.
	Images []EntryImage `json:"images,omitempty"`

	// OpaqueResponseItems carries only bounded encrypted Responses API
	// reasoning items. Cleartext ReasoningContent is intentionally never
	// persisted. Legacy JSONL files simply omit this additive field.
	OpaqueResponseItems []json.RawMessage `json:"opaque_response_items,omitempty"`

	// plan_update fields
	PlanStatus  string `json:"plan_status,omitempty"`
	PlanTitle   string `json:"plan_title,omitempty"`
	PlanContent string `json:"plan_content,omitempty"`
	Feedback    string `json:"feedback,omitempty"`

	// todo_snapshot fields
	Todos []TodoSnapshotItem `json:"todos,omitempty"`

	// subagent_start / subagent_result fields
	SubagentName string `json:"subagent_name,omitempty"`
	SubagentType string `json:"subagent_type,omitempty"`

	// mode_change field
	Mode string `json:"mode,omitempty"`

	// compact fields. KeptN is the number of trailing messages the live agent
	// kept verbatim after the summary; replay re-attaches that many entries
	// from before the compact event. Legacy files lack kept_n (unmarshals to
	// 0), which replays as "summary only" — the pre-KeptN behaviour.
	Summary    string `json:"summary,omitempty"`
	CompactedN int    `json:"compacted_n,omitempty"`
	KeptN      int    `json:"kept_n,omitempty"`

	// system_prompt fields
	EnvInfo string `json:"env_info,omitempty"` // serialized environment snapshot

	// goal_update fields. GoalStatus == "cleared" marks goal removal.
	GoalObjective  string `json:"goal_objective,omitempty"`
	GoalStatus     string `json:"goal_status,omitempty"`
	GoalTokensUsed int64  `json:"goal_tokens_used,omitempty"`
	GoalCreatedAt  int64  `json:"goal_created_at,omitempty"`
	GoalUpdatedAt  int64  `json:"goal_updated_at,omitempty"`

	// tool_observation fields
	ToolObservation *ToolObservation `json:"tool_observation,omitempty"`

	// Artifact fields. Content and absolute paths are never persisted. A missing
	// storage kind is a legacy workspace record.
	ArtifactID          string `json:"artifact_id,omitempty"`
	ArtifactPath        string `json:"artifact_path,omitempty"`
	ArtifactStorageKind string `json:"artifact_storage_kind,omitempty"`
	ArtifactKey         string `json:"artifact_key,omitempty"`
	ArtifactTitle       string `json:"artifact_title,omitempty"`
	ArtifactKind        string `json:"artifact_kind,omitempty"`
	ArtifactMediaType   string `json:"artifact_media_type,omitempty"`
	ArtifactSize        int64  `json:"artifact_size,omitempty"`
	ArtifactWidth       int    `json:"artifact_width,omitempty"`
	ArtifactHeight      int    `json:"artifact_height,omitempty"`
	ArtifactSHA256      string `json:"artifact_sha256,omitempty"`
	ArtifactProviderID  string `json:"artifact_provider_id,omitempty"`
	ArtifactModelID     string `json:"artifact_model_id,omitempty"`
	ArtifactParentID    string `json:"artifact_parent_id,omitempty"`
	ArtifactRevision    int    `json:"artifact_revision,omitempty"`
	ArtifactFocus       bool   `json:"artifact_focus,omitempty"`
	ArtifactShareable   bool   `json:"artifact_shareable,omitempty"`

	// generation_operation fields.
	OperationState                 string                  `json:"operation_state,omitempty"`
	OperationCapabilityKey         *OperationCapabilityKey `json:"operation_capability_key,omitempty"`
	OperationCredentialFingerprint string                  `json:"operation_credential_fingerprint,omitempty"`
	OperationConfigEpoch           uint64                  `json:"operation_config_epoch,omitempty"`
	OperationIdempotencyKey        string                  `json:"operation_idempotency_key,omitempty"`
	OperationProviderRequestIDHash string                  `json:"operation_provider_request_id_hash,omitempty"`
	OperationUpdatedAt             string                  `json:"operation_updated_at,omitempty"`

	// provider_tool_operation fields. These entries deliberately persist only
	// metadata hashes and stable identifiers: never tool arguments, raw
	// credentials, endpoint URLs, response bodies, or result content.
	ProviderToolState             string `json:"provider_tool_state,omitempty"`
	ProviderToolRunID             string `json:"provider_tool_run_id,omitempty"`
	ProviderToolCapabilityKey     string `json:"provider_tool_capability_key,omitempty"`
	ProviderToolProviderProfileID string `json:"provider_tool_provider_profile_id,omitempty"`
	ProviderToolName              string `json:"provider_tool_name,omitempty"`
	ProviderToolIntentHash        string `json:"provider_tool_intent_hash,omitempty"`
	ProviderToolConfigEpoch       string `json:"provider_tool_config_epoch,omitempty"`
	ProviderToolIdempotencyKey    string `json:"provider_tool_idempotency_key,omitempty"`
	ProviderToolUpdatedAt         string `json:"provider_tool_updated_at,omitempty"`

	// session_tool_override fields. Persisted is deliberately separate from
	// runtime availability/effectiveness: those are evaluated from the current
	// engine configuration and must never be replayed as durable truth.
	SessionToolOverrideTool      string `json:"session_tool_override_tool,omitempty"`
	SessionToolOverridePersisted bool   `json:"session_tool_override_persisted,omitempty"`
	SessionToolOverrideRevision  uint64 `json:"session_tool_override_revision,omitempty"`
}

Entry is one line of the JSONL session file.

func LoadSession

func LoadSession(id string) ([]Entry, error)

LoadSession reads all entries from a session JSONL file identified by uuid.

type EntryImage added in v0.4.1

type EntryImage struct {
	MimeType string `json:"media_type"`
	Data     string `json:"data"` // base64-encoded
}

EntryImage stores a single image attached to a user message.

type EntryType

type EntryType string

EntryType identifies the kind of JSONL record.

const (
	EntrySessionStart EntryType = "session_start"
	EntryUser         EntryType = "user"
	EntryAssistant    EntryType = "assistant"
	EntryToolCall     EntryType = "tool_call"
	EntryToolResult   EntryType = "tool_result"

	// Extended entry types for structured state tracking.
	EntryPlanUpdate            EntryType = "plan_update"
	EntryTodoSnapshot          EntryType = "todo_snapshot"
	EntrySubagentStart         EntryType = "subagent_start"
	EntrySubagentResult        EntryType = "subagent_result"
	EntrySubagentAsync         EntryType = "subagent_async"
	EntryModeChange            EntryType = "mode_change"
	EntryAgentChange           EntryType = "agent_change"
	EntryCompact               EntryType = "compact"
	EntryBudgetWarning         EntryType = "budget_warning"
	EntrySystemPrompt          EntryType = "system_prompt"
	EntryGoalUpdate            EntryType = "goal_update"
	EntryToolObservation       EntryType = "tool_observation"
	EntryArtifact              EntryType = "artifact"
	EntryGenerationOperation   EntryType = "generation_operation"
	EntryProviderToolOperation EntryType = "provider_tool_operation"
	EntrySessionToolOverride   EntryType = "session_tool_override"
)

type GenerationOperation added in v0.12.3

type GenerationOperation struct {
	OperationID           string                   `json:"operation_id"`
	ToolCallID            string                   `json:"tool_call_id"`
	State                 GenerationOperationState `json:"state"`
	CapabilityKey         OperationCapabilityKey   `json:"capability_key"`
	CredentialFingerprint string                   `json:"credential_fingerprint"`
	ConfigEpoch           uint64                   `json:"config_epoch"`
	IdempotencyKey        string                   `json:"idempotency_key"`
	ProviderRequestIDHash string                   `json:"provider_request_id_hash,omitempty"`
	ArtifactIDs           []string                 `json:"artifact_ids,omitempty"`
	ErrorCode             string                   `json:"error_code,omitempty"`
	UpdatedAt             time.Time                `json:"updated_at"`
}

GenerationOperation is one immutable-intent state transition. Secret credentials, prompts, signed URLs, and provider response bodies are never persisted here.

type GenerationOperationSnapshot added in v0.12.3

type GenerationOperationSnapshot struct {
	Latest     GenerationOperation `json:"latest"`
	Dispatched bool                `json:"dispatched"`
}

GenerationOperationSnapshot is the replay projection used to rebuild the atomic session ledger. Dispatched remains true once a dispatch_attempted entry was observed, independent of later success or failure.

func LoadGenerationOperations added in v0.12.3

func LoadGenerationOperations(id string) ([]GenerationOperationSnapshot, error)

LoadGenerationOperations reads one session and returns snapshots sorted by operation ID for deterministic callers and tests.

type GenerationOperationState added in v0.12.3

type GenerationOperationState string

GenerationOperationState is a durable provider-dispatch state. Progress UI phases are ephemeral; these states exist to answer the crash-recovery question "could the provider already have accepted a billable request?".

const (
	GenerationDispatchAttempted GenerationOperationState = "dispatch_attempted"
	GenerationAccepted          GenerationOperationState = "accepted"
	GenerationSaving            GenerationOperationState = "saving"
	GenerationSucceeded         GenerationOperationState = "succeeded"
	GenerationFailed            GenerationOperationState = "failed"
	GenerationUncertain         GenerationOperationState = "uncertain"
)

func (GenerationOperationState) IsTerminal added in v0.12.3

func (state GenerationOperationState) IsTerminal() bool

type GenerationRecoveryPriority added in v0.12.3

type GenerationRecoveryPriority int

GenerationRecoveryPriority formalizes the release ordering. Higher evidence wins: terminal operation > artifact > terminal tool result > nonterminal op.

const (
	GenerationRecoveryNone GenerationRecoveryPriority = iota
	GenerationRecoveryNonTerminalOperation
	GenerationRecoveryTerminalToolResult
	GenerationRecoveryArtifact
	GenerationRecoveryTerminalOperation
)

func GenerationRecoveryEvidencePriority added in v0.12.3

func GenerationRecoveryEvidencePriority(
	snapshot GenerationOperationSnapshot,
	hasVerifiedArtifact bool,
	hasTerminalToolResult bool,
) GenerationRecoveryPriority

GenerationRecoveryEvidencePriority returns the fixed reconciliation ordering without deciding transport presentation. A terminal operation always wins; otherwise a safely verified artifact outranks a typed terminal tool result, which outranks a nonterminal operation.

type GoalSnapshot added in v0.5.0

type GoalSnapshot struct {
	Objective  string
	Status     string
	TokensUsed int64
	CreatedAt  int64
	UpdatedAt  int64
}

GoalSnapshot is the recoverable state of a session goal.

type OperationCapabilityKey added in v0.12.3

type OperationCapabilityKey struct {
	ProviderProfileID string `json:"provider_profile_id"`
	CredentialKind    string `json:"credential_kind,omitempty"`
	EndpointProfile   string `json:"endpoint_profile"`
	ModelID           string `json:"model_id"`
}

OperationCapabilityKey is the metadata-only snapshot used by the durable journal. Runtime capability implementations map their key into this neutral representation; session replay never imports provider/config packages.

type PlanSnapshot

type PlanSnapshot struct {
	Status   string
	Title    string
	Content  string
	Feedback string
}

PlanSnapshot holds the last known plan state from a session.

type ProjectMeta added in v0.11.1

type ProjectMeta struct {
	UpdatedAt string `json:"updated_at,omitempty"` // RFC3339
}

ProjectMeta is project-level metadata kept in its own file (projects.json, alongside the session index). UpdatedAt is the project's "last activity" timestamp: it is bumped when a session is created or when a session's own UpdatedAt moves (a real turn), and — deliberately — is NEVER rolled back when a session is deleted. The sidebar sorts projects by this timestamp, so deleting a conversation must not reorder the project list.

Stored separately from session.json on purpose: older binaries rewriting the index don't know this data exists, and would silently drop an embedded "projects" section on their next read-modify-write (the index is shared across processes — desktop sidecar + CLI may run different versions). A sidecar file they never touch is immune; losing it only degrades the sidebar to session-derived recency, and the next turn re-stamps it.

type ProviderToolOperation added in v0.12.3

type ProviderToolOperation struct {
	OperationID       string                     `json:"operation_id"`
	ToolCallID        string                     `json:"tool_call_id"`
	RunID             string                     `json:"run_id"`
	State             ProviderToolOperationState `json:"state"`
	CapabilityKey     string                     `json:"capability_key"`
	ProviderProfileID string                     `json:"provider_profile_id"`
	ToolName          string                     `json:"tool_name"`
	IntentHash        string                     `json:"intent_hash"`
	ConfigEpoch       string                     `json:"config_epoch"`
	IdempotencyKey    string                     `json:"idempotency_key"`
	ErrorCode         string                     `json:"error_code,omitempty"`
	UpdatedAt         time.Time                  `json:"updated_at"`
}

ProviderToolOperation is metadata-only durable evidence for a provider tool call. IntentHash binds the approved post-hook arguments and credential fingerprint without persisting either value. Tool arguments, credentials, endpoint URLs, provider bodies, and tool results must never be added here.

type ProviderToolOperationSnapshot added in v0.12.3

type ProviderToolOperationSnapshot struct {
	Latest     ProviderToolOperation `json:"latest"`
	Dispatched bool                  `json:"dispatched"`
}

ProviderToolOperationSnapshot is the replay projection used to reconstruct usage limits. Dispatched is sticky once dispatch_attempted was durably observed, even if later terminal evidence is corrupt or missing.

func LoadProviderToolOperations added in v0.12.3

func LoadProviderToolOperations(id string) ([]ProviderToolOperationSnapshot, error)

LoadProviderToolOperations returns replay snapshots sorted by operation ID.

type ProviderToolOperationState added in v0.12.3

type ProviderToolOperationState string

ProviderToolOperationState is the durable lifecycle for a billable provider-managed tool call. There is intentionally no pre-dispatch state in the journal: dispatch_attempted is the atomic consume point written and fsynced immediately before the wrapped endpoint is invoked.

const (
	ProviderToolDispatchAttempted ProviderToolOperationState = "dispatch_attempted"
	ProviderToolSucceeded         ProviderToolOperationState = "succeeded"
	ProviderToolFailed            ProviderToolOperationState = "failed"
	ProviderToolUncertain         ProviderToolOperationState = "uncertain"
)

func (ProviderToolOperationState) IsTerminal added in v0.12.3

func (state ProviderToolOperationState) IsTerminal() bool

type Recorder

type Recorder struct {
	// contains filtered or unexported fields
}

Recorder appends events to a JSONL session file synchronously. The file and index entry are created lazily on the first real message so that sessions with no conversation are never persisted. Call Close() (or defer it) to finalize.

func NewRecorder

func NewRecorder(project, provider, model string) (*Recorder, error)

NewRecorder returns a Recorder that will create the session file only when the first message is recorded. Never returns an error — recording is best-effort and must not break normal operation.

func NewTeammateRecorder

func NewTeammateRecorder(leaderUUID, agentID, model string) (*Recorder, error)

NewTeammateRecorder creates a Recorder that stores its JSONL transcript under the leader session's subagents directory:

~/.jcode/sessions/{leaderUUID}/subagents/agent-{agentID}.jsonl

This mirrors Claude Code's per-agent transcript pattern.

func (*Recorder) Close

func (r *Recorder) Close()

Close flushes and closes the underlying file. Safe to call multiple times. If no messages were ever recorded the file is never created.

func (*Recorder) CompareAndSwapSessionToolOverride added in v0.12.3

func (r *Recorder) CompareAndSwapSessionToolOverride(
	tool SessionTool,
	persisted bool,
	expectedRevision uint64,
) (SessionToolOverride, error)

CompareAndSwapSessionToolOverride persists one monotonic revision. The in-memory replay cache is published only after write+fsync succeeds.

func (*Recorder) HasRecording added in v0.0.4

func (r *Recorder) HasRecording() bool

HasRecording reports whether any message has been recorded (i.e. the session file has been created). Returns false for sessions where the user quit without any conversation.

func (*Recorder) Model added in v0.6.3

func (r *Recorder) Model() string

Model returns the model currently attributed to recorded usage. It is the model the session was opened with unless SetModel updated it after a switch.

func (*Recorder) Project added in v0.6.3

func (r *Recorder) Project() string

Project returns the workspace path this recorder is scoped to.

func (*Recorder) Provider added in v0.6.3

func (r *Recorder) Provider() string

Provider returns the provider the session was opened with.

func (*Recorder) RecordArtifact added in v0.12.1

func (r *Recorder) RecordArtifact(record artifact.Record) error

RecordArtifact durably appends one metadata-only Artifact revision. Unlike the historical best-effort recorder helpers, it returns append failures so the show_artifact tool cannot report a revision that was never persisted.

func (*Recorder) RecordAssistant

func (r *Recorder) RecordAssistant(content string)

RecordAssistant appends an assistant message entry.

func (*Recorder) RecordAssistantMessage added in v0.12.3

func (r *Recorder) RecordAssistantMessage(message *schema.Message)

RecordAssistantMessage appends the persistable subset of an assistant message. Cleartext reasoning and arbitrary Extra fields are never written; only canonical encrypted Responses continuation items are retained.

func (*Recorder) RecordCompact

func (r *Recorder) RecordCompact(summary string, compactedN, keptN int)

RecordCompact appends a compact/summarization event entry. keptN is the number of trailing messages preserved verbatim alongside the summary, so a resume can rebuild the same tail from the entries already on disk.

func (*Recorder) RecordGenerationDispatch added in v0.12.3

func (r *Recorder) RecordGenerationDispatch(
	operation GenerationOperation,
	policy DispatchPolicy,
) error

RecordGenerationDispatch atomically performs strict replay, hard session-cap enforcement, and the fsynced consume append under the per-session OS lock. A nil result is the sole permission to invoke the external image provider.

func (*Recorder) RecordGenerationOperation added in v0.12.3

func (r *Recorder) RecordGenerationOperation(operation GenerationOperation) error

RecordGenerationOperation synchronously appends and fsyncs one provider dispatch transition. Callers must receive nil before initiating the billable POST. The operation contains fingerprints only, never raw credentials.

func (*Recorder) RecordGoalUpdate added in v0.5.0

func (r *Recorder) RecordGoalUpdate(objective, status string, tokensUsed, createdAt, updatedAt int64)

RecordGoalUpdate appends a goal state change entry. An empty status records a "cleared" marker so resume knows the goal was removed.

func (*Recorder) RecordModeChange

func (r *Recorder) RecordModeChange(mode string)

RecordModeChange appends a mode transition entry on a best-effort basis. Authorization-sensitive callers that must not publish an in-memory mode before it is durable use RecordModeChangeStrict instead.

func (*Recorder) RecordModeChangeStrict added in v0.12.3

func (r *Recorder) RecordModeChangeStrict(mode string) error

RecordModeChangeStrict durably appends a canonical unified mode transition. Mode is authorization state (Full access removes per-call approval), so it is serialized with transcript replacement and bound to the current on-disk inode just like the other append-only session metadata. A nil return is the caller's permission to publish the corresponding in-memory/UI transition.

func (*Recorder) RecordPlanUpdate

func (r *Recorder) RecordPlanUpdate(status, title, content, feedback string)

RecordPlanUpdate appends a plan state change entry.

func (*Recorder) RecordProviderToolDispatch added in v0.12.3

func (r *Recorder) RecordProviderToolDispatch(
	operation ProviderToolOperation,
	policy DispatchPolicy,
) error

RecordProviderToolDispatch is the provider-managed equivalent of RecordGenerationDispatch. Its durable count is scoped to the capability and provider profile, matching ledger reconstruction.

func (*Recorder) RecordProviderToolOperation added in v0.12.3

func (r *Recorder) RecordProviderToolOperation(operation ProviderToolOperation) error

RecordProviderToolOperation synchronously appends and fsyncs one metadata- only state transition. Callers must receive nil for dispatch_attempted before invoking the external endpoint.

func (*Recorder) RecordSubagentAsync

func (r *Recorder) RecordSubagentAsync(name, taskID, agentType string)

RecordSubagentAsync appends an async subagent launch entry with the task ID.

func (*Recorder) RecordSubagentResult

func (r *Recorder) RecordSubagentResult(name, output string, err error)

RecordSubagentResult appends a subagent completion entry.

func (*Recorder) RecordSubagentStart

func (r *Recorder) RecordSubagentStart(name, agentType string)

RecordSubagentStart appends a subagent launch entry.

func (*Recorder) RecordSystemPrompt added in v0.4.6

func (r *Recorder) RecordSystemPrompt(prompt, envInfo string)

RecordSystemPrompt buffers the system prompt so it can be written together with the first real message. This avoids creating a session file when the user opens and immediately closes jcode without any conversation.

func (*Recorder) RecordTodoSnapshot

func (r *Recorder) RecordTodoSnapshot(todos []TodoSnapshotItem)

RecordTodoSnapshot appends a full todo list snapshot entry.

func (*Recorder) RecordToolCall

func (r *Recorder) RecordToolCall(name, args, toolCallID, batchID string, batchIndex, batchSize int)

RecordToolCall appends a tool-call entry. The batch fields group tool calls issued by the same assistant message so replay can rebuild batch boundaries (batchSize > 1 means a concurrent batch).

func (*Recorder) RecordToolObservation added in v0.10.1

func (r *Recorder) RecordToolObservation(observation ToolObservation)

RecordToolObservation appends metadata-only progressive-disclosure evidence.

func (*Recorder) RecordToolResult

func (r *Recorder) RecordToolResult(name, output, toolCallID string, err error, denied bool, duration time.Duration) (string, error)

RecordToolResult appends a tool-result entry and returns the exact output stored in the transcript. denied marks a user-rejected approval; duration is the approval-wait-adjusted execution latency (0 when unknown). Large outputs are automatically truncated (head+tail preserved) and the full content is saved to an overflow file on disk. Callers should use the returned output in live model history so live and replayed sessions have the same context. A persistence failure is returned so callers do not treat an unstored result as durable conversation history.

func (*Recorder) RecordToolResultWithDetails added in v0.12.3

func (r *Recorder) RecordToolResultWithDetails(
	name, output, toolCallID string,
	err error,
	denied bool,
	duration time.Duration,
	details ToolResultDetails,
) (string, error)

func (*Recorder) RecordUser

func (r *Recorder) RecordUser(content string, images ...EntryImage)

RecordUser appends a user message entry. On the first user message, the title is auto-generated from the content. Optional images are persisted alongside the text so they survive session restore.

func (*Recorder) SessionToolOverrides added in v0.12.3

func (r *Recorder) SessionToolOverrides() (map[SessionTool]SessionToolOverride, error)

SessionToolOverrides returns a snapshot for this recorder. A brand-new recorder has an empty snapshot without forcing creation of a session file.

func (*Recorder) SetAgent added in v0.11.3

func (r *Recorder) SetAgent(agent string)

SetAgent records the selected top-level custom agent. Empty means the default agent. Before the first message it is buffered into session_start; after a session exists it also appends an agent_change event for replay.

func (*Recorder) SetModel added in v0.6.4

func (r *Recorder) SetModel(model string)

SetModel updates the model attributed to subsequently recorded usage so a mid-session model switch attributes new turns to the new model rather than the one the session was opened with. The session-start header is unchanged (it records the opening model).

func (*Recorder) SetTitleFor added in v0.9.5

func (r *Recorder) SetTitleFor(id, title string)

SetTitleFor overrides the session title and persists it to the shared index — but only while the recorder still records session id. A title computed for one session (e.g. by the async LLM refiner) must never clobber another session's index entry after SetUUID re-points this recorder (the TUI /resume path reuses the live recorder). Empty titles are ignored.

func (*Recorder) SetTitleRefiner added in v0.9.5

func (r *Recorder) SetTitleRefiner(fn func(firstUserMsg string))

SetTitleRefiner installs a hook invoked once with the first user message, right after the truncated fallback title is persisted. The hook must not block; it upgrades the title asynchronously via SetTitleFor.

func (*Recorder) SetUUID added in v0.3.3

func (r *Recorder) SetUUID(id string)

SetUUID overrides the session identifier. Used when resuming an existing session so that new messages are appended to the same session file. If the session file does not yet exist on disk, the recorder is NOT marked as resuming, so the first user message will still generate a title.

func (*Recorder) TruncateAtUserMessage added in v0.4.2

func (r *Recorder) TruncateAtUserMessage(beforeCount int) error

TruncateAtUserMessage rewrites the conversational projection, keeping only entries that appear before the (beforeCount)th user message (0-indexed). Security-critical provider dispatch journals and session tool policy entries are append-only and survive truncation wherever they occur in the file. If beforeCount == 0, conversational history is truncated to session_start. The recorder is reset to append mode on the (now shorter) file. This preserves the session UUID and index entry — no new session is created.

func (*Recorder) UUID

func (r *Recorder) UUID() string

UUID returns the session identifier. Locked because SetUUID can update it concurrently (a resumed web task swaps the recorder's UUID under r.mu).

type SessionMeta

type SessionMeta struct {
	UUID      string `json:"uuid"`
	Project   string `json:"project"`
	Provider  string `json:"provider"`
	Model     string `json:"model"`
	Agent     string `json:"agent,omitempty"`
	StartTime string `json:"start_time"` // RFC3339
	Title     string `json:"title,omitempty"`
	// Task metadata. Additive — legacy index files simply lack these keys, which
	// unmarshal to zero values (not pinned / not archived / read).
	Pinned    bool   `json:"pinned,omitempty"`
	Archived  bool   `json:"archived,omitempty"`
	Unread    bool   `json:"unread,omitempty"`
	Status    string `json:"status,omitempty"`     // idle/running/done/error (set by the web layer)
	UpdatedAt string `json:"updated_at,omitempty"` // RFC3339
	// Automation metadata. A run launched by an automation is a normal session
	// tagged here: AutomationID is the correlation key for the "Recent runs"
	// list, and the main task list excludes any session with AutomationID set so
	// nightly runs don't pollute the sidebar. TerminalStatus/EndTime/ErrorReason
	// are the run-outcome audit fields (success|error|interrupted) that back the
	// Status filter — Status alone is only idle/running.
	AutomationID   string `json:"automation_id,omitempty"`
	TriggerKind    string `json:"trigger_kind,omitempty"` // scheduled|manual
	TerminalStatus string `json:"terminal_status,omitempty"`
	EndTime        string `json:"end_time,omitempty"`
	ErrorReason    string `json:"error_reason,omitempty"`
	// Artifact summary is a repairable materialized view over artifact entries.
	ArtifactCount     int    `json:"artifact_count,omitempty"`
	ArtifactUnseen    bool   `json:"artifact_unseen,omitempty"`
	ArtifactUpdatedAt string `json:"artifact_updated_at,omitempty"`
	ArtifactViewedAt  string `json:"artifact_viewed_at,omitempty"`
	// ArtifactViewedRevisions is the durable per-artifact read cursor. The
	// legacy ArtifactViewedAt timestamp remains a read-only fallback for index
	// files written by older versions; new views never advance that global
	// timestamp because doing so would mark unrelated artifacts as read.
	ArtifactViewedRevisions map[string]int `json:"artifact_viewed_revisions,omitempty"`
}

SessionMeta is stored in the index for fast listing.

func ListSessions

func ListSessions(project string) ([]SessionMeta, error)

ListSessions returns all sessions recorded for a given project path, newest last.

func UpdateSessionMeta added in v0.6.1

func UpdateSessionMeta(uuid string, mutate func(*SessionMeta)) (*SessionMeta, error)

UpdateSessionMeta finds a session by uuid across all projects, applies mutate to its metadata, and persists the index atomically. Returns the updated meta, or (nil, nil) if no session with that uuid exists. uuid is only compared in memory (never used as a path), so no path validation is required here.

type SessionState

type SessionState struct {
	History      []adk.Message
	Plan         *PlanSnapshot      // nil if no plan events found
	Todos        []TodoSnapshotItem // last todo snapshot, nil if none
	Goal         *GoalSnapshot      // nil if no goal events or last event cleared it
	Mode         string             // last unified session mode (approval/plan/full_access); empty = approval
	Agent        string             // selected top-level custom agent; empty = default
	EnvTarget    string             // last environment (local/ssh alias)
	SystemPrompt string             // recorded system prompt for KV-cache-friendly resume
	EnvInfo      string             // environment snapshot at recording time
}

SessionState is the full recoverable state from a session file, including conversation history, plan, todos, mode, and environment.

func ReconstructState

func ReconstructState(entries []Entry) *SessionState

ReconstructState rebuilds the full session state from recorded entries. It is compact-aware: if a compact entry is found, messages before it are replaced with the compact summary.

Subagent marker entries (subagent_start/result/async) carry no conversation content and are skipped — but entries BETWEEN them are NOT skipped: subagent internal tool calls are never persisted (only the main runner records tool_call/tool_result), so entries in that window are the main agent's own parallel tool calls and must be kept.

type SessionTool added in v0.12.3

type SessionTool string

SessionTool identifies historical provider-backed task preferences in durable journals. Both identifiers remain parseable for replay compatibility, but neither is a current product configuration surface.

const (
	SessionToolImageGeneration SessionTool = "image_generation"
	SessionToolWebSearch       SessionTool = "web_search"
)

func ParseSessionTool added in v0.12.3

func ParseSessionTool(raw string) (SessionTool, error)

ParseSessionTool validates the exact persisted/API identifier.

func SupportedSessionTools added in v0.12.3

func SupportedSessionTools() []SessionTool

SupportedSessionTools is empty because provider tools are no longer user-selectable per session. Retained so older integrations compile while discovering that the product exposes no configurable session tools.

type SessionToolOverride added in v0.12.3

type SessionToolOverride struct {
	Tool      SessionTool `json:"tool"`
	Persisted bool        `json:"persisted"`
	Revision  uint64      `json:"revision"`
}

SessionToolOverride is the historical durable preference projection. It is parsed for compatibility and does not gate current runtime availability.

type SessionToolOverrideRevisionError added in v0.12.3

type SessionToolOverrideRevisionError struct {
	Tool     SessionTool
	Expected uint64
	Actual   uint64
}

SessionToolOverrideRevisionError reports a failed compare-and-swap without losing the actual current revision needed by a client to resynchronize.

func (*SessionToolOverrideRevisionError) Error added in v0.12.3

func (*SessionToolOverrideRevisionError) Unwrap added in v0.12.3

type TodoSnapshotItem

type TodoSnapshotItem struct {
	ID     int    `json:"id"`
	Title  string `json:"title"`
	Status string `json:"status"`
}

TodoSnapshotItem is a single todo entry stored in a todo_snapshot event.

type ToolObservation added in v0.10.1

type ToolObservation struct {
	Kind string `json:"kind"`

	ModelRequestSeq      int      `json:"model_request_seq,omitempty"`
	VisibleNames         []string `json:"visible_names,omitempty"`
	VisibleCount         int      `json:"visible_count,omitempty"`
	SchemaBytes          int      `json:"schema_bytes,omitempty"`
	SchemaTokensEstimate int64    `json:"schema_tokens_estimate,omitempty"`
	NewlyVisibleDeferred []string `json:"newly_visible_deferred,omitempty"`

	ToolCallID           string   `json:"tool_call_id,omitempty"`
	QueryMode            string   `json:"query_mode,omitempty"`
	QueryBytes           int      `json:"query_bytes,omitempty"`
	TermCount            int      `json:"term_count,omitempty"`
	RequiredTermCount    int      `json:"required_term_count,omitempty"`
	MaxResults           int      `json:"max_results,omitempty"`
	ValidatedSelectNames []string `json:"validated_select_names,omitempty"`
	UnknownSelectCount   int      `json:"unknown_select_count,omitempty"`
	MatchNames           []string `json:"match_names,omitempty"`
	NewMatchNames        []string `json:"new_match_names,omitempty"`
	RepeatedQuery        bool     `json:"repeated_query,omitempty"`
	Redundant            bool     `json:"redundant,omitempty"`
	Success              bool     `json:"success,omitempty"`

	ToolName string `json:"tool_name,omitempty"`
	Reason   string `json:"reason,omitempty"`
}

ToolObservation stores metadata-only evidence about progressive tool disclosure. It intentionally contains no raw query, arguments, schema, output, model content, or error text.

type ToolResultDetails added in v0.12.3

type ToolResultDetails struct {
	OperationID string
	Outcome     string
	ErrorCode   string
	Provider    string
	Model       string
	ArtifactIDs []string
}

ToolResultDetails persists the transport-neutral terminal evidence needed to reconstruct a provider-backed operation without parsing its human-readable output. It deliberately contains identifiers and classifications only.

Jump to

Keyboard shortcuts

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