agent

package
v0.8.1 Latest Latest
Warning

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

Go to latest
Published: Aug 22, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package agent watches the JSONL transcripts that Codex and Claude Code write while their TUI runs, and projects those files as normalized events. The PTY byte stream stays the source of truth; this is a side channel for clients (notably Web) that want a structured view of the same process.

Index

Constants

View Source
const (
	// BindEnvSession marks the Warren session owning the CLI process. Hooks
	// and tool subprocesses see it, but only the managed hook uses it.
	BindEnvSession = "WARREN_SESSION_ID"
	// BindEnvFile points the managed hook at the file it must write with the
	// CLI session ID and transcript path.
	BindEnvFile = "WARREN_BIND_FILE"
	// BindEnvKind names the agent kind (codex or claude) for the hook.
	BindEnvKind = "WARREN_AGENT_KIND"
	// BindEnvState points the managed hook at the file it must update when the
	// CLI session changes lifecycle, so the daemon can update the status overlay.
	BindEnvState = "WARREN_STATE_FILE"
	// CodexSessionID and CodexThreadID are launcher-provided identity hints.
	// An interactive shell can inherit them from its parent Codex process; an
	// independently-created Warren session must not reuse that conversation.
	BindEnvCodexSessionID = "CODEX_SESSION_ID"
	BindEnvCodexThreadID  = "CODEX_THREAD_ID"
)
View Source
const (
	// DefaultReadRecent bounds a command result so an external agent does not
	// accidentally ingest an entire long-running conversation.
	DefaultReadRecent = 20
	// DefaultReadContentLimit is measured in Unicode code points, not bytes.
	DefaultReadContentLimit = 2000
	// MaxReadActivities bounds an unbounded (--all) read. Callers that need a
	// smaller response should set Recent explicitly.
	MaxReadActivities = 100000
)

Variables

This section is empty.

Functions

func BindDir

func BindDir() string

BindDir is the directory holding per-session bindings.

func BindEnvironment

func BindEnvironment(warrenSessionID, kind string) []string

BindEnvironment returns the runtime environment entries a session needs so the managed hook can report an agent CLI's own session ID to Warren.

func BindPath

func BindPath(warrenSessionID string) string

BindPath is the per-session file the managed hook writes.

func ClaudeConfigDir

func ClaudeConfigDir() string

ClaudeConfigDir returns the directory Claude reads settings from, honoring CLAUDE_CONFIG_DIR just like the CLI itself.

func ClaudeProjectsRoot

func ClaudeProjectsRoot() string

ClaudeProjectsRoot returns the directory Claude writes transcripts into, honoring CLAUDE_CONFIG_DIR just like the CLI itself.

func ClaudeTranscriptPath

func ClaudeTranscriptPath(claudeRoot, workspacePath, sessionID string) string

ClaudeTranscriptPath computes the transcript file Claude writes for a given session ID in a given working directory.

func CodexHome

func CodexHome() string

CodexHome returns the Codex configuration directory the daemon's children inherit, honoring CODEX_HOME just like the CLI itself.

func EnsureClaudeBindHook

func EnsureClaudeBindHook(claudeConfigDir string) (changed bool, err error)

EnsureClaudeBindHook installs the same two hooks into Claude's user settings file, preserving every existing entry.

func EnsureCodexBindHook

func EnsureCodexBindHook(codexHome string) (changed bool, err error)

EnsureCodexBindHook installs the Warren SessionStart and SessionEnd hooks into Codex's user hooks file, preserving every existing entry.

func InjectClaudeSessionID

func InjectClaudeSessionID(command, warrenSessionID string) string

InjectClaudeSessionID makes Claude's transcript path deterministic for a Warren session. Existing resume/session flags are left untouched so a user who explicitly resumes an older conversation keeps their intent.

func ProjectEvents

func ProjectEvents(events []api.AgentEvent, options ReadOptions) ([]api.AgentEvent, error)

ProjectEvents applies the same filtering and content limits as ReadTranscript to events already retained by a live Host watcher. This is used by remote session readers, where the transcript file lives on the Host rather than on the CLI machine.

func ReadAgentStatus

func ReadAgentStatus(path string) (api.AgentStatus, error)

ReadAgentStatus returns the status recorded by the managed hook, or a zero status when the file is missing or malformed.

func ReadTranscript

func ReadTranscript(ctx context.Context, provider, path string, options ReadOptions) ([]api.AgentEvent, error)

ReadTranscript parses one Codex or Claude JSONL transcript into the same normalized events used by Warren's live agent view. The file is consumed line by line, so the reader never loads the whole transcript into memory.

func RemoveBinding

func RemoveBinding(warrenSessionID string)

RemoveBinding cleans up the per-session file when the session is deleted.

func StatePath

func StatePath(warrenSessionID string) string

StatePath is the per-session file the managed hook uses to report lifecycle changes to the daemon.

func WriteAgentStatus

func WriteAgentStatus(path string, status api.AgentStatus) error

WriteAgentStatus persists a status reported by a hook. The write is atomic so the daemon never reads a half-written status file.

func WriteBinding

func WriteBinding(path string, binding Binding) error

WriteBinding persists the binding reported by a hook. It is safe for the hook and the daemon to race: both write the same structured JSON and the daemon only starts a watcher for a path that exists on disk.

Types

type ActivityTracker

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

ActivityTracker folds normalized transcript events into an AgentStatus. It owns lifecycle and liveness state; provider-specific attention observations can be applied through MarkAttention without teaching the tracker provider event names.

func NewActivityTracker

func NewActivityTracker() *ActivityTracker

NewActivityTracker starts an agent in the ready state: open and idle.

func (*ActivityTracker) Activity

func (t *ActivityTracker) Activity() api.AgentActivity

Activity returns the lifecycle portion of Status.

func (*ActivityTracker) ClearAttention

func (t *ActivityTracker) ClearAttention()

ClearAttention removes a pending human-facing condition without changing the current lifecycle state.

func (*ActivityTracker) DrainTurns

func (t *ActivityTracker) DrainTurns() []api.AgentTurn

DrainTurns returns lifecycle transitions observed since the previous call.

func (*ActivityTracker) Exited

func (t *ActivityTracker) Exited()

Exited marks the agent process as gone.

func (*ActivityTracker) MarkAttention

func (t *ActivityTracker) MarkAttention(kind api.AgentAttentionKind, reason, requestID string, since time.Time)

MarkAttention applies a provider-neutral human-facing observation. The reducer owns the resulting activity so callers cannot accidentally create a yellow state without the corresponding blocked/warning lifecycle state.

func (*ActivityTracker) Observe

func (t *ActivityTracker) Observe(event api.AgentEvent)

Observe advances the tracker from one normalized transcript event.

func (*ActivityTracker) Status

func (t *ActivityTracker) Status() api.AgentStatus

Status returns the current complete presentation state.

func (*ActivityTracker) Tick

func (t *ActivityTracker) Tick(now time.Time)

Tick notices a tool call that has made no progress for the liveness grace period. It intentionally produces a stalled warning, never an input or approval request.

func (*ActivityTracker) Turn

func (t *ActivityTracker) Turn() uint64

Turn returns the current turn number. It remains stable after completion so events emitted at the boundary can still be associated with that turn.

func (*ActivityTracker) TurnAborted

func (t *ActivityTracker) TurnAborted()

TurnAborted marks a turn the user interrupted. An intentional interruption is a normal return to idle, not an outstanding request for attention.

func (*ActivityTracker) TurnComplete

func (t *ActivityTracker) TurnComplete()

TurnComplete marks a finished turn. The agent is idle and ready for the next instruction.

func (*ActivityTracker) TurnFailed

func (t *ActivityTracker) TurnFailed()

TurnFailed marks a turn that ended with an error.

func (*ActivityTracker) TurnStarted

func (t *ActivityTracker) TurnStarted()

TurnStarted marks the beginning of a new turn and clears attention from a request that the new user turn supersedes.

type Binding

type Binding struct {
	Provider       string    `json:"provider"`
	SessionID      string    `json:"sessionId"`
	TranscriptPath string    `json:"transcriptPath"`
	Cwd            string    `json:"cwd,omitempty"`
	UpdatedAt      time.Time `json:"updatedAt"`
}

Binding records which Codex/Claude conversation belongs to one Warren session. It is written by the Warren-managed SessionStart hook (Codex) or derived from the deterministic `--session-id` flag (Claude), and read by the daemon so transcript discovery is keyed by the CLI's own session ID instead of guessing by cwd and mtime.

func ReadBinding

func ReadBinding(path string) (*Binding, error)

ReadBinding returns nil when the file does not exist or is malformed; a malformed file is transient while a hook is mid-write, so callers retry.

type DefaultFinder

type DefaultFinder struct {
	// CodexRoot is the Codex sessions directory (default ~/.codex/sessions).
	CodexRoot string
	// ClaudeRoot is the Claude Code projects directory (default ~/.claude/projects).
	ClaudeRoot string
}

DefaultFinder implements Finder for the stock Codex and Claude Code layouts.

func (DefaultFinder) Find

func (f DefaultFinder) Find(ctx context.Context, kind, workspacePath string, after time.Time) (string, error)

type Finder

type Finder interface {
	Find(ctx context.Context, kind, workspacePath string, after time.Time) (string, error)
}

Finder locates the transcript file for a running Codex or Claude session. A missing file is not an error: the CLI may not be installed, may not have written a transcript yet, or may be running a version with a different layout. Callers retry until the file appears.

type ReadOptions

type ReadOptions struct {
	Recent       int
	ContentLimit int
	Full         bool
	IncludeTypes []string
	ExcludeTypes []string
}

ReadOptions controls how a transcript is projected for an external caller. A zero Recent means that every matching event is returned. ContentLimit is ignored when Full is true; a zero ContentLimit uses the default limit.

type Watcher

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

Watcher tails one transcript file and emits normalized events. The first poll replays existing history; later polls only deliver newly appended lines. A truncated file restarts from byte zero without re-emitting the already-served prefix, which is acceptable for a best-effort side channel.

func Start

func Start(
	sessionID, provider, path string,
	onEvents func([]api.AgentEvent, api.AgentStatus),
	onStatus func(api.AgentStatus),
	onTurns func([]api.AgentTurn, bool),
) *Watcher

Start begins tailing path immediately in a background goroutine.

func (*Watcher) Close

func (w *Watcher) Close()

Close stops the poll loop and waits for it to finish.

func (*Watcher) Path

func (w *Watcher) Path() string

Path returns the transcript file being watched.

func (*Watcher) Snapshot

func (w *Watcher) Snapshot() []api.AgentEvent

Snapshot returns the retained event history.

func (*Watcher) WaitReady

func (w *Watcher) WaitReady(ctx context.Context) error

WaitReady waits until the initial transcript replay has established the current status and turn cursor.

Jump to

Keyboard shortcuts

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