Documentation
¶
Overview ¶
Package agent implements the LLM agent run-loop.
Package agent includes support for user-defined sub-agent profiles stored as Markdown files under .ok/agents/. Each file defines a reusable, named sub-agent with an optional model override, tool whitelist, and custom system prompt. The loader is called from boot; the resulting tools are registered alongside built-in tools so the LLM can invoke them by name.
Package agent — file-read tracker for tool-aware context compression.
The fileTracker records which messages in the session carry the content of which files (from read_file and grep results). When the same file appears in a new tool result, the previous occurrence is skeletonized in-place — keeping signatures and structural hints while dropping the body — so the model still knows the file exists and what it exports, but stops paying tokens for stale copies of the implementation.
This implements the core insight from TokenTamer (github.com/borhen68/TokenTamer): track tool_use → file mappings and skeletonize background files while keeping the most recent read intact.
Only read_file and grep results are tracked; writes (write_file, edit_file, multi_edit) are never skeletonized because they represent the authoritative state after a mutation. bash results are also skipped — their content is too varied to map to a single file.
Package agent — modelrouter.go was removed; never wired.
Package agent provides the Planner — a hierarchical task decomposition engine. It takes a high-level goal, decomposes it into sub-tasks with dependency edges, executes them in topological order, and re-plans on failure.
Package agent provides the Reasoner — OK's top-level multi-agent orchestrator that decomposes a goal into a task DAG via LLM, then executes it with Planner's DAG engine using concurrent dispatch.
Package agent — session resilience: mid-turn persistence, crash recovery, graceful context management, and reconnect support.
Package agent — dead code removed; model router was never wired.
Package agent — tool result skeletonizer for context compression.
When the same file is read multiple times in a session (by read_file or grep), older copies are skeletonized — the implementation body is replaced with a structural summary while signatures, imports, and type declarations are preserved. The model still knows what the file exports but stops paying tokens for stale copies of the implementation.
Only the most recent read of each file is kept full; every earlier read is skeletonized in-place in the session message slice.
Index ¶
- Constants
- Variables
- func FilterRegistry(parent *tool.Registry, names []string, exclude ...string) *tool.Registry
- func FormatUsageLine(u *provider.Usage, p *provider.Pricing) string
- func InstallAgent(ctx context.Context, projectRoot, name, url string) error
- func NestedSink(ctx context.Context, fallback event.Sink) event.Sink
- func NewSessionPath(dir, model string) string
- func PublishAgent(def AgentDef) string
- func RunSubAgent(ctx context.Context, prov provider.Provider, reg *tool.Registry, ...) (string, error)
- type Agent
- func (a *Agent) AggressiveCompact(ctx context.Context) error
- func (a *Agent) AuditLog() []core.AuditRecord
- func (a *Agent) CheckContextOverflow() error
- func (a *Agent) CompactNow(ctx context.Context) error
- func (a *Agent) ContextUsage() float64
- func (a *Agent) ContextWindow() int
- func (a *Agent) Hooks() ToolHooks
- func (a *Agent) LastUsage() *provider.Usage
- func (a *Agent) Run(ctx context.Context, input string) error
- func (a *Agent) Session() *Session
- func (a *Agent) SessionCache() (hit, miss int)
- func (a *Agent) SetAsker(as Asker)
- func (a *Agent) SetGate(g Gate)
- func (a *Agent) SetHooks(h ToolHooks)
- func (a *Agent) SetMsgBus(b *bus.Bus)
- func (a *Agent) SetOnTurnComplete(fn func(context.Context, string, string))
- func (a *Agent) SetPipe(p eventpipe.Sink)
- func (a *Agent) SetPlanMode(v bool)
- func (a *Agent) SetSession(s *Session)
- func (a *Agent) SetSessionPath(path string)
- type AgentDef
- type AskTool
- type Asker
- type ComputerAction
- type ComputerUse
- type Coordinator
- type Gate
- type MemMsg
- type Options
- type Plan
- type PlanTask
- type PlanTaskStatus
- type Planner
- type PlannerRunner
- type ProofRecorder
- type Reasoner
- type Renderer
- type Runner
- type Session
- func (s *Session) Add(m provider.Message)
- func (s *Session) Gen() uint64
- func (s *Session) Len() int
- func (s *Session) Replace(msgs []provider.Message)
- func (s *Session) ReplaceIfUnchanged(msgs []provider.Message, expectedGen uint64) bool
- func (s *Session) Save(path string) error
- func (s *Session) SkeletonizeAt(indices []int, toolName string)
- func (s *Session) Snapshot() []provider.Message
- type SessionInfo
- type Snapshotter
- type Specialist
- type SpecialistConfig
- type SpecialistRunner
- type StoreEntry
- type Task
- type TaskResult
- type TaskTool
- type Team
- type TeamConfig
- type TextSink
- type ToolHooks
- type ToolMsg
- type UsageTracker
Constants ¶
const DefaultPlannerPrompt = `` /* 277-byte string literal not displayed */
DefaultPlannerPrompt steers the planner toward concise plans, not execution.
const DefaultStoreURL = "https://raw.githubusercontent.com/colbymchenry/ok-agents/main/index.json"
const DefaultTaskSystemPrompt = `` /* 173-byte string literal not displayed */
DefaultTaskSystemPrompt steers a sub-agent toward focused, terse delivery. Sub-agents have the same capabilities as the main agent: they can read, write, run commands, and spawn further sub-agents. The parent's task tree keeps nesting visible.
Variables ¶
var ErrContextOverflow = fmt.Errorf("context window exhausted — send /compact to compress, or /new to start fresh")
ErrContextOverflow is returned when the context window is exhausted.
var NewComputerUse = computeruse.NewComputerUse
Functions ¶
func FilterRegistry ¶
FilterRegistry builds a sub-registry from parent: the named whitelist (empty = every parent tool), minus any excluded names. Used to scope what a spawned sub-agent — a `task` sub-agent or a subagent skill — may call.
func FormatUsageLine ¶
FormatUsageLine renders the per-turn token/cache summary — the key signal for the cache-first design — as a single line (no trailing newline), or "" when usage is unset or empty. Cache is reported as absolute "(N cached / M new)" so a turn that adds a lot of fresh content doesn't read as "cache broke" the way a falling percentage would; the cached prefix is still hitting, the denominator just grew. Reasoning tokens (a subset of completion) show the chain-of-thought cost. Shared by TextSink and the chat TUI so both frontends render the line identically.
func InstallAgent ¶
InstallAgent downloads an agent definition from URL and saves to .ok/agents/.
func NestedSink ¶
NestedSink returns a sink that forwards a sub-agent's tool activity to the parent stream, nested under the tool call carried by ctx, so a frontend shows it beneath that call (the same nesting `task` uses). Falls back to the given sink when ctx carries no call context. Used by subagent skills.
func NewSessionPath ¶
NewSessionPath returns the path to use for a fresh session, namespaced by the model so the filename hints at what the conversation was with. dir is typically config.SessionDir().
func PublishAgent ¶
PublishAgent formats an AgentDef as a shareable Markdown string.
func RunSubAgent ¶
func RunSubAgent(ctx context.Context, prov provider.Provider, reg *tool.Registry, sysPrompt, prompt string, opts Options, sink event.Sink) (string, error)
RunSubAgent runs prompt to completion in a fresh sub-agent session over reg, emitting tool activity to sink, and returns the sub-agent's final assistant answer. It is the shared core behind the `task` tool and subagent skills: a caller supplies the system prompt (the task persona or the skill body), the tool registry (already filtered), and the run Options (model budget, gate).
Types ¶
type Agent ¶
type Agent struct {
// contains filtered or unexported fields
}
func New ¶
func New(prov provider.Provider, tools tool.ToolRegistry, session *Session, opts Options, sink event.Sink) *Agent
New constructs an Agent. MaxSteps <= 0 means no cap — the run loop continues until the model gives a final answer, the context is canceled, or the provider errors (compaction keeps the context bounded). A nil sink is replaced with event.Discard so the agent can always emit unconditionally.
func (*Agent) AuditLog ¶
func (a *Agent) AuditLog() []core.AuditRecord
AuditLog returns a copy of the audit chain entries, or nil if auditing is disabled.
func (*Agent) CheckContextOverflow ¶
func (*Agent) CompactNow ¶
CompactNow runs one compaction pass immediately, regardless of the usage-ratio threshold maybeCompact normally honors. Used by the chat TUI's `/compact` command so the user can reset the prefix before it naturally fills up.
func (*Agent) ContextUsage ¶
ContextUsage returns the estimated fraction (0.0–1.0) of the context window used by the current session. Returns 0 when the window is unconfigured.
func (*Agent) ContextWindow ¶
ContextWindow returns the configured context-window size in tokens. 0 means compaction is disabled for this agent.
func (*Agent) LastUsage ¶
LastUsage returns the most recent per-turn token telemetry the provider reported (nil if no turn has run yet). The TUI uses it to show a context gauge alongside the prompt; the actual cache decisions still live inside maybeCompact.
func (*Agent) Run ¶
Run appends the user input and drives the tool loop until the model returns a final answer (no tool calls), the context is canceled, or the provider errors.
func (*Agent) Session ¶
Session returns the agent's current conversation, useful for persistence hooks that need to read the message log between turns.
func (*Agent) SessionCache ¶
SessionCache returns the cumulative cache hit/miss prompt tokens across every API call this session — the basis for the status line's aggregate hit-rate.
func (*Agent) SetAsker ¶
SetAsker installs the asker the `ask` tool uses to question the user. Interactive frontends wire one in; headless runs leave it nil.
func (*Agent) SetGate ¶
SetGate installs the per-call permission gate. Used by `ok chat` to swap the headless gate built in setup for an interactive one that prompts the user; nil disables gating. Safe to call before the run loop starts.
func (*Agent) SetMsgBus ¶
SetMsgBus wires an optional message bus for publishing execution events. nil disables publishing; all publish calls are nil-safe.
func (*Agent) SetOnTurnComplete ¶
SetOnTurnComplete registers a callback fired after each turn completes.
func (*Agent) SetPipe ¶
SetPipe installs a typed event pipeline sink. When set, the agent emits typed events directly to the pipeline instead of going through the old event.Sink. This is the migration path from old-style to typed events. Must be called before Run starts, or protected by pipeMu.
func (*Agent) SetPlanMode ¶
non-ReadOnly tool the model calls and returns a "blocked" result instead of running it. The cache-friendly bits — system prompt, tools schema, message history — are left untouched, so the toggle costs nothing in cache hits.
func (*Agent) SetSession ¶
SetSession replaces the agent's conversation wholesale. Used by `ok chat --resume` to load a saved JSONL transcript before the first turn, so the model picks up exactly where it left off.
func (*Agent) SetSessionPath ¶
SetSessionPath sets the path for mid-batch auto-save during tool chains. Called by the controller after NewSession or Resume.
type AgentDef ¶
type AgentDef struct {
Name string // derived from filename (no .md)
Description string // first H1 heading or "Sub-agent: <name>"
Model string // optional model override (empty = inherit parent)
Tools []string // tool whitelist (empty = all parent tools)
PermissionMode string // "plan" | "normal" | "yolo" | "" (inherit)
AllowedMCPServers []string // MCP servers this agent can access; empty = all
SystemPrompt string // raw Markdown body
FilePath string // source file path
}
AgentDef is a user-defined sub-agent profile loaded from .ok/agents/*.md.
func LoadAgentDefs ¶
LoadAgentDefs scans .ok/agents/ (under projectRoot) for .md files and parses each one into an AgentDef. Non-existent directory is not an error; permission or I/O errors are logged to stderr so the operator can diagnose.
func (AgentDef) MakeAgentTool ¶
func (d AgentDef) MakeAgentTool( prov provider.Provider, parentReg *tool.Registry, pricing *provider.Pricing, gate Gate, hooks ToolHooks, jm *jobs.Manager, opts Options, resolveModel func(string) (provider.Provider, *provider.Pricing, int, error), ) tool.Tool
MakeAgentTool returns a tool.Tool that executes this agent definition via RunSubAgent, using the given provider, registry, pricing, gate, hooks, jobs, and options. The caller supplies a function to resolve a model name to a provider (for model overrides) and a function to filter the registry.
type AskTool ¶
type AskTool struct{}
AskTool lets the model put a structured multiple-choice question (or a few) to the user mid-task and get the answer back — for genuine forks the model can't resolve from the request or the code (which library, which approach, …) rather than guessing or asking in prose. The frontend renders selectable options, the user picks, and the choices come back as the tool result. It reaches the user through the Asker carried on the call context (CallContext); with no asker (headless runs) it returns a "decide for yourself" result so an autonomous run never blocks.
func NewAskTool ¶
func NewAskTool() *AskTool
func (*AskTool) Description ¶
func (*AskTool) ReadOnly ¶
ReadOnly is true: asking has no host side effects, so it never needs approval and stays available in plan mode (clarifying scope while planning is fine).
func (*AskTool) Schema ¶
func (*AskTool) Schema() json.RawMessage
type ComputerAction ¶
type ComputerAction = computeruse.ComputerAction
type ComputerUse ¶
type ComputerUse = computeruse.ComputerUse
type Coordinator ¶
type Coordinator struct {
// contains filtered or unexported fields
}
Coordinator runs two models in separate sessions to keep each one's prompt prefix cache-stable: a low-frequency planner proposes an approach, then the executor (a Runner — typically a DSTRunner wrapping an Agent) carries it out. The sessions never mix, so neither model's prefix is disturbed by the other's turns.
func NewCoordinator ¶
func NewCoordinator(planner provider.Provider, plannerSession *Session, plannerPricing *provider.Pricing, executor Runner, execName string, temperature float64, sink event.Sink) *Coordinator
NewCoordinator wires a planner provider (with its own session) to an executor Runner (typically a DSTRunner wrapping an Agent). sink receives the planner's phase/text/usage events; the executor emits its own events to its own sink (the CLI wires the same sink into both). A nil sink is replaced with event.Discard.
type Options ¶
type Options struct {
MaxSteps int
Temperature float64
Pricing *provider.Pricing // optional, for per-turn cost display
// Gate is the per-call permission gate. nil disables gating.
Gate Gate
// Hooks fires PreToolUse / PostToolUse shell hooks around tool calls. nil
// disables hook firing.
Hooks ToolHooks
// Jobs is the session's background-job manager (nil disables background tools).
Jobs *jobs.Manager
// Context management. ContextWindow <= 0 disables compaction. CompactRatio
// and RecentKeep fall back to defaults when unset.
ContextWindow int
CompactRatio float64
RecentKeep int
ArchiveDir string
// AuditChain is the tamper-evident audit log for tool execution.
// nil disables auditing.
AuditChain *core.AuditChain
// OnTurnComplete, when set, is called after each complete turn (model returns
// a final answer without tool calls). It receives the user's input and the
// model's final text for episodic memory capture. The callee should not block.
OnTurnComplete func(ctx context.Context, input, answer string)
// SessionPath, when non-empty, enables mid-batch auto-save so crash recovery
// loses at most 5 tool-call rounds per long tool chain.
SessionPath string
}
Options configures an Agent.
type Plan ¶
type Plan struct {
Goal string `json:"goal"`
Tasks []PlanTask `json:"tasks"`
CreatedAt time.Time `json:"created_at"`
// contains filtered or unexported fields
}
Plan is a hierarchical task decomposition.
func (*Plan) GetReadyTasks ¶
GetReadyTasks returns tasks whose dependencies are all done and that are pending.
func (*Plan) MarkBlocked ¶
func (p *Plan) MarkBlocked()
MarkBlocked marks pending tasks with failed dependencies as blocked, and unblocks blocked tasks whose dependencies are no longer failed (e.g. after a retry resets a failed dependency to pending).
type PlanTask ¶
type PlanTask struct {
ID string `json:"id"`
Description string `json:"description"`
DependsOn []string `json:"depends_on,omitempty"`
Status PlanTaskStatus `json:"status"`
Result string `json:"result,omitempty"`
Error string `json:"error,omitempty"`
Attempts int `json:"attempts,omitempty"` // retry count
CreatedAt time.Time `json:"created_at"`
CompletedAt time.Time `json:"completed_at,omitempty"`
}
PlanTask is one atomic unit of work in a plan.
type PlanTaskStatus ¶
type PlanTaskStatus string
PlanTaskStatus tracks each sub-task's state.
const ( TaskPending PlanTaskStatus = "pending" TaskRunning PlanTaskStatus = "running" TaskDone PlanTaskStatus = "done" TaskFailed PlanTaskStatus = "failed" TaskBlocked PlanTaskStatus = "blocked" // dependency failed, won't run )
const TaskInProgress PlanTaskStatus = "in_progress"
TaskInProgress is deprecated; use TaskRunning. Kept for backward compatibility with existing serialized plans.
type Planner ¶
type Planner struct {
// contains filtered or unexported fields
}
Planner orchestrates hierarchical task execution with dependency ordering. Decomposition is handled by Reasoner.decompose() (LLM-based) or by the plan tool's explicit steps mode — Planner only manages execution and retry.
type PlannerRunner ¶
PlannerRunner executes tasks in a plan. The actual execution is delegated to a function so the tool layer can wire in the agent's run loop.
type ProofRecorder ¶
type ProofRecorder interface {
AppendWithPath(atomID, proposition, evidence, parentID, path string)
}
ProofRecorder records verification results into the proof chain.
type Reasoner ¶
type Reasoner struct {
// contains filtered or unexported fields
}
Reasoner decomposes a goal into a task DAG via an LLM planner, then executes it with Planner's topological concurrency. It satisfies the Runner interface so it slots in as a drop-in replacement for Agent or Coordinator.
The dispatch function executes individual PlanTasks — typically via RunSubAgent with the executor's provider/registry, or via a Team's orchestrator. The caller (boot) wires it.
func NewReasoner ¶
func NewReasoner( plannerProv provider.Provider, plannerSess *Session, plannerPricing *provider.Pricing, dispatch PlannerRunner, maxConcurrent int, temperature float64, sink event.Sink, ) *Reasoner
NewReasoner creates a Reasoner. plannerProv and plannerSess are the decomposition LLM (kept in its own session for cache-stable prefix). dispatch is called for each ready PlanTask; maxConcurrent caps parallel dispatches. sink receives phase/text/usage events from the decomposer.
func (*Reasoner) Reason ¶
Reason decomposes and executes like Run, but returns the aggregated result string alongside any error — see the multi-agent protocol in REASONIX.md.
type Runner ¶
Runner carries out one task turn. Both Agent (single model) and Coordinator (two-model) satisfy it, so the CLI stays agnostic to which is in use.
type Session ¶
Session holds the conversation history for one task. Uses sync.RWMutex so concurrent reads (Snapshot) don't serialize. A generation counter avoids copying the message slice on repeated Snapshot calls within the same mutation epoch — the cached snapshot is returned until the next Add or Replace.
func LoadSession ¶
LoadSession reads a JSONL file written by Save into a fresh Session value. Missing files surface as os.IsNotExist so callers can fall through to a new session.
func NewSession ¶
NewSession initializes a session with an optional system prompt.
func (*Session) Gen ¶
Gen returns the current generation counter. It increments on every Add, Replace, and ReplaceIfUnchanged call. Used for detecting concurrent changes.
func (*Session) Replace ¶
Replace atomically swaps the message history. Used by compaction. A nil input is rejected to prevent accidental data loss.
func (*Session) ReplaceIfUnchanged ¶
ReplaceIfUnchanged atomically swaps the message history only if gen still equals expectedGen. Used by compaction to detect concurrent Add calls that would otherwise be lost. Returns false when gen has changed (caller should retry or skip).
func (*Session) Save ¶
Save writes the session's messages to path in JSONL — one provider.Message per line — so a user can resume the conversation later. The file is rewritten in full on every save: chat sessions are small (kilobytes), and append-only would have to be reconciled with the compaction pass that mutates the middle of session.Messages. Safe for concurrent use.
func (*Session) SkeletonizeAt ¶
SkeletonizeAt skeletonizes tool messages at the given indices, replacing their Content with a compressed version that preserves structural info. Indices that are out of range or point to non-tool messages are silently skipped. This is called after a file re-read to compress stale copies.
type SessionInfo ¶
SessionInfo summarizes a saved session for the --resume picker: where it is on disk, when it was last touched, the first user message as a preview, and a rough turn count.
func ListSessions ¶
func ListSessions(dir string) ([]SessionInfo, error)
ListSessions returns every *.jsonl session under dir, newest first, each with a preview line so the picker can show something the user recognizes. A missing directory is not an error — it just means there's nothing to resume yet.
type Snapshotter ¶
Snapshotter captures and rolls back file state. Each call to Execute should get a fresh instance via the factory to keep layers isolated.
type Specialist ¶
type Specialist struct {
Name string
Description string
Model string
Prov provider.Provider
Pricing *provider.Pricing
ContextWindow int
Tools []string // tool names for display / filtering
Reg *tool.Registry // pre-filtered registry; nil means empty
Prompt string
}
Specialist describes one agent in a team.
type SpecialistConfig ¶
type SpecialistRunner ¶
type SpecialistRunner struct {
Specialist
// contains filtered or unexported fields
}
SpecialistRunner wraps a specialist with its own registry and session.
type StoreEntry ¶
type StoreEntry struct {
Name string `json:"name"`
Description string `json:"description"`
Author string `json:"author"`
URL string `json:"url"`
Tools string `json:"tools"`
}
StoreEntry is one agent listing in the community store index.
func ListAgents ¶
func ListAgents(ctx context.Context, storeURL string) ([]StoreEntry, error)
ListAgents fetches the agent store index.
type Task ¶
type Task = PlanTask
Task is the public alias for PlanTask — see the multi-agent protocol in REASONIX.md. See PlanTask for the full definition.
type TaskResult ¶
TaskResult is the output of a completed task — see the multi-agent protocol in REASONIX.md.
type TaskTool ¶
type TaskTool struct {
// contains filtered or unexported fields
}
func NewTaskTool ¶
func NewTaskTool(prov provider.Provider, pricing *provider.Pricing, parentReg *tool.Registry, maxSteps, contextWindow int, temperature float64, archiveDir, sysPrompt string, gate Gate, workDir string, newSnap func() Snapshotter, proofRecorder ProofRecorder, maxConcurrent int) *TaskTool
NewTaskTool is the backward-compatible 13-arg constructor (hooks/jm/lang default to nil).
func NewTaskToolFull ¶
func NewTaskToolFull(prov provider.Provider, pricing *provider.Pricing, parentReg *tool.Registry, maxSteps, contextWindow int, temperature float64, archiveDir, sysPrompt string, gate Gate, workDir string, newSnap func() Snapshotter, proofRecorder ProofRecorder, maxConcurrent int, hooks ToolHooks, jm *jobs.Manager, subPromptSuffix string) *TaskTool
NewTaskToolFull creates a TaskTool with sub-agent hooks, jobs manager, and prompt suffix.
func (*TaskTool) Description ¶
func (*TaskTool) ReadOnly ¶
ReadOnly returns true. The sub-agent spawned by task is confined to read-only tools by buildSubReg (which excludes bash, write_file, etc.), so plan mode can safely allow task calls. This also lets task parallelise with other read-only tools. An explicit p.Tools whitelist can still grant writers to the sub-agent, but that is opt-in.
func (*TaskTool) Schema ¶
func (t *TaskTool) Schema() json.RawMessage
type Team ¶
type Team struct {
Orchestrator Runner
// contains filtered or unexported fields
}
Team runs a multi-model agent team with an orchestrator + specialists.
func BuildTeam ¶
func BuildTeam( cfg TeamConfig, resolveModel func(string) (provider.Provider, *provider.Pricing, int, error), sink event.Sink, baseReg *tool.Registry, gate Gate, hooks ToolHooks, opts Options, ) (*Team, error)
BuildTeam constructs a Team from config, creating both the orchestrator Agent and all specialists. The orchestrator gets delegate_<name> tools AND a delegate_all tool for parallel dispatch.
func NewTeam ¶
func NewTeam(orchestrator Runner, specialists []Specialist, sink event.Sink) *Team
NewTeam builds a Team. The orchestrator gets a delegate tool to call specialists.
func (*Team) RunParallel ¶
func (t *Team) RunParallel(ctx context.Context, task string, names []string) (map[string]string, error)
RunParallel dispatches a task to multiple specialists concurrently and aggregates their results. All specialists receive the same task; the orchestrator receives each result labeled by specialist name.
type TeamConfig ¶
type TeamConfig struct {
Orchestrator string `toml:"orchestrator"`
Specialists []SpecialistConfig `toml:"specialists"`
}
type TextSink ¶
type TextSink struct {
// contains filtered or unexported fields
}
TextSink renders a turn's event stream to ANSI text on an io.Writer. It is the reference terminal frontend: a headless `ok run` writes to stdout, and during the cache-first migration the chat TUI is fed through it too. The output is byte-for-byte what the agent used to print directly, now driven by typed events instead of inline Fprint calls.
renderer, when non-nil, replaces the streamed raw answer text with styled markdown once the text stream completes (a Message event). termWidth is the column count used to count how many rows the raw stream occupied before the redraw moves the cursor back. A nil renderer keeps the raw stream — correct for piped output and for the chat TUI, which renders markdown itself.
func NewTextSink ¶
NewTextSink builds a TextSink writing to out. renderer/termWidth drive the post-stream markdown redraw; pass a nil renderer to keep the raw stream.
type UsageTracker ¶
type UsageTracker struct {
// contains filtered or unexported fields
}
UsageTracker records per-turn and session-aggregate token telemetry. It was extracted from Agent to keep the Agent struct focused on the run loop rather than owning every concern directly. It is safe for concurrent use: a status-bar goroutine may read LastUsage / SessionCache while the run-loop goroutine calls Record.
func NewUsageTracker ¶
func NewUsageTracker() *UsageTracker
NewUsageTracker returns an initialized UsageTracker.
func (*UsageTracker) LastUsage ¶
func (t *UsageTracker) LastUsage() *provider.Usage
LastUsage returns the most recent per-turn telemetry, or nil when no turn has completed.
func (*UsageTracker) Record ¶
func (t *UsageTracker) Record(u provider.Usage)
Record stores the latest per-turn usage and accumulates session cache tokens. Call from the run-loop goroutine on each ChunkUsage event.
func (*UsageTracker) SessionCache ¶
func (t *UsageTracker) SessionCache() (hit, miss int)
SessionCache returns the cumulative cache hit/miss prompt tokens across every API call this session, so frontends can show the aggregate hit-rate.
Source Files
¶
- agent.go
- agent_config.go
- agent_run.go
- ask.go
- compact.go
- computer.go
- coordinator.go
- defs.go
- execute.go
- filetracker.go
- interfaces.go
- modelrouter.go
- planner.go
- reasoner.go
- resilience.go
- router.go
- save.go
- session.go
- skeletonize.go
- skeletonize_nonts.go
- store.go
- stream.go
- task.go
- team.go
- textsink.go
- toolcache.go
- truncate.go
- usage.go
- width.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package agent provides the ComputerUse orchestrator — a screenshot→analyze→act→verify loop that lets the agent control the desktop GUI.
|
Package agent provides the ComputerUse orchestrator — a screenshot→analyze→act→verify loop that lets the agent control the desktop GUI. |