event

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jun 21, 2026 License: Apache-2.0 Imports: 2 Imported by: 0

Documentation

Overview

Package event defines the typed event stream the agent emits as it runs a turn, and the Sink it emits to. It decouples "what happened" (the model produced reasoning, a tool was dispatched, a turn used N tokens) from "how to show it" (ANSI scrollback in a terminal, a card in a webview).

The agent depends only on Sink; each frontend implements one. The chat TUI renders events to its scrollback; a headless run renders them to plain ANSI on stdout; a future GUI/serve transport forwards them to a webview or websocket. This replaces the old io.Writer contract, where the agent wrote pre-formatted ANSI and the consumer had to re-derive structure by matching line prefixes — fragile, and lossy for any frontend richer than a terminal.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Approval

type Approval struct {
	ID      string
	Tool    string
	Subject string
}

Approval identifies a pending tool-call approval for an ApprovalRequest event. ID correlates the request with the controller's Approve(ID, …) reply.

type Ask

type Ask struct {
	ID        string
	Questions []AskQuestion
}

Ask carries an AskRequest: a batch of questions and the ID that correlates the controller's AnswerQuestion(ID, …) reply.

type AskAnswer

type AskAnswer struct {
	QuestionID string
	Selected   []string
}

AskAnswer is the user's reply to one AskQuestion: the chosen option label(s) (a free-typed answer is carried as a single Selected entry).

type AskOption

type AskOption struct {
	Label       string
	Description string // optional one-line explanation shown under the label
}

AskOption is one choice the user can pick for an AskQuestion.

type AskQuestion

type AskQuestion struct {
	ID      string // stable per-question id, so answers correlate back
	Header  string // short label (the tab title)
	Prompt  string // the question text
	Options []AskOption
	Multi   bool // allow selecting more than one option
}

AskQuestion is one structured question the `ask` tool puts to the user.

type Event

type Event struct {
	Kind      Kind
	Text      string            // Reasoning / Text / Message / Notice / Phase
	Reasoning string            // Message: the full reasoning chain
	Tool      Tool              // ToolDispatch / ToolResult
	Usage     *provider.Usage   // Usage
	Pricing   *provider.Pricing // Usage: for cost display (nil = omit cost)
	// SessionHit/SessionMiss carry cumulative cache tokens across the whole
	// session (Usage events only), so a frontend can show the aggregate hit-rate
	// — which doesn't crater on a short turn or after compaction — alongside
	// Usage's single-turn numbers.
	SessionHit  int      // Usage: cumulative cache-hit prompt tokens this session
	SessionMiss int      // Usage: cumulative cache-miss prompt tokens this session
	Level       Level    // Notice
	Approval    Approval // ApprovalRequest
	Ask         Ask      // AskRequest
	Err         error    // TurnDone / TurnAborted: non-nil on failure or refusal reason
	Covenant    string   // TurnAborted: principle ID that was violated, e.g. "p2"
}

Event is one increment in a turn's event stream. Read the field(s) documented for Kind; the others are zero.

type FuncSink

type FuncSink func(*Event)

FuncSink adapts a plain function to a Sink.

func (FuncSink) Emit

func (f FuncSink) Emit(e *Event)

Emit calls the wrapped function.

type Kind

type Kind int

Kind tags an Event. Read the field(s) documented for that kind.

const (
	// TurnStarted marks the start of one top-level Run (one user turn). Sinks
	// reset any per-turn rendering state on it. Carries no payload.
	TurnStarted Kind = iota
	// Reasoning is a thinking-mode reasoning delta (Text). Streamed before the
	// visible answer; sinks typically render it muted under a "thinking" header.
	Reasoning
	// Text is an answer-text delta (Text).
	Text
	// Message marks the assistant turn's text as complete: Text holds the full
	// answer and Reasoning the full chain-of-thought (both already streamed via
	// the deltas above). A sink may use it to re-render the streamed raw text as
	// styled markdown; a plain sink can ignore it.
	Message
	// ToolDispatch announces a tool call is about to run (Tool: ID/Name/Args/ReadOnly).
	ToolDispatch
	// ToolResult reports a finished tool call (Tool: Output/Err/Truncated set).
	ToolResult
	// Usage carries per-turn token telemetry (Usage; Pricing optional, for cost).
	Usage
	// Notice is an out-of-band message — a warning, truncation, block, or
	// compaction notice (Level + Text).
	Notice
	// Phase marks a coordinator boundary, e.g. planner→executor handoff (Text =
	// label such as "deepseek · planning").
	Phase
	// ApprovalRequest asks the frontend to approve a pending tool call
	// (Approval: ID/Tool/Subject). The run blocks until the controller's
	// Approve(ID, …) resolves it; a frontend shows a prompt and answers.
	ApprovalRequest
	// AskRequest asks the frontend to put one or more structured multiple-choice
	// questions to the user (Ask: ID + Questions). The run blocks until the
	// controller's AnswerQuestion(ID, …) resolves it. Powers the `ask` tool.
	AskRequest
	// TurnDone marks the end of one top-level Run (Err non-nil on failure;
	// nil also for a user cancellation, which is not an error). Always the
	// last event of a turn.
	TurnDone
	// TurnAborted marks that the agent refused to continue due to a core
	// covenant violation. This is not an error — it is a deliberate refusal.
	// Err carries the principle ID and reason. Always the last event of a turn.
	TurnAborted
)

type Level

type Level int

Level classifies a Notice so sinks can style or filter it.

const (
	LevelInfo Level = iota
	LevelWarn
)

type Sink

type Sink interface {
	Emit(*Event)
}

Sink consumes a turn's events. The agent calls Emit serially from its run loop (tool execution may fan out across goroutines, but emission does not), so an implementation need not be safe for concurrent Emit. Emit must not block indefinitely — a channel-backed sink should be buffered or drained by a live reader.

var Discard Sink = FuncSink(func(*Event) {})

Discard is a Sink that drops every event. Useful in tests and for runs that only care about the final session state.

func Sync

func Sync(s Sink) Sink

Sync wraps a Sink so concurrent Emit calls are serialized. The base Sink contract assumes serial emission — the agent's run loop emits one event at a time. Background jobs (internal/jobs) emit from their own goroutines, which can overlap a running turn's emission; wrapping the session sink once in Sync keeps the serial-Emit invariant every sink relies on (an SSE writer, a webview EventsEmit, a TUI channel) without each having to lock. A nil sink yields Discard.

type Tool

type Tool struct {
	ID        string
	Name      string
	Args      string
	Output    string // ToolResult: the result text fed to the model
	Err       string // ToolResult: non-empty when the call failed or was blocked
	ReadOnly  bool
	Truncated bool // ToolResult: Output was head+tailed before display/model
	// Partial marks an early ToolDispatch emitted when a call begins (ID/Name set,
	// Args still streaming) so a frontend can show the card immediately; a second,
	// full ToolDispatch (Partial false, Args set) follows when the call completes.
	Partial bool
	// ParentID, when set, is the ID of the tool call that spawned this one — a
	// sub-agent's calls carry the parent `task` call's ID so a frontend can nest
	// them under it. Empty for top-level calls.
	ParentID string
}

Tool describes a tool call for ToolDispatch / ToolResult events. On dispatch only ID/Name/Args/ReadOnly are set; on result Output/Err/Truncated are filled in. Args is the raw JSON arguments — a sink compacts it for display.

Jump to

Keyboard shortcuts

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