Documentation
¶
Overview ¶
Package coding wires the runtime pieces into a working coding agent: provider + agent loop + tools + session persistence. It is the seam the CLI modes sit on, and the precursor to P3's full orchestrator.
Index ¶
- Constants
- Variables
- func BuildRegistry(store auth.CredentialStore) (*models.Registry, []string, error)
- func FormatUsage(u ai.Usage) string
- func RefreshRadiusCatalog(ctx context.Context, store auth.CredentialStore) (*provider.RadiusCatalog, error)
- func RenderTree(ctx context.Context, s *session.Session, roots []*session.TreeNode) string
- func ResolveTrust(cwd string, override *bool) trust.Outcome
- type ExtensionLoader
- type JSONEvent
- type JSONWriter
- type LoadRequest
- type Options
- type PromptPoint
- type RPCServer
- type Session
- func (s *Session) AvailableModels() []ai.Model
- func (s *Session) Close(ctx context.Context, reason string)
- func (s *Session) Compact(ctx context.Context, instructions string) (*compaction.Result, error)
- func (s *Session) CycleModel(ctx context.Context, delta int) *ai.Model
- func (s *Session) CycleModels() []ai.Model
- func (s *Session) CycleThinkingLevel(ctx context.Context, delta int) ai.ModelThinkingLevel
- func (s *Session) Describe() string
- func (s *Session) ExportSession(ctx context.Context, path string) (string, error)
- func (s *Session) ExtensionNames() []string
- func (s *Session) ExtensionPaths() []string
- func (s *Session) Fork(ctx context.Context, entryID string) error
- func (s *Session) ImportSession(ctx context.Context, path string) (string, error)
- func (s *Session) LastAssistantText() string
- func (s *Session) ListSessions(ctx context.Context) ([]session.Metadata, error)
- func (s *Session) MaybeCompact(ctx context.Context) (bool, error)
- func (s *Session) MoveTo(ctx context.Context, entryID string, summarize bool) (*compaction.BranchResult, error)
- func (s *Session) PrepareCompaction(ctx context.Context) (*compaction.Preparation, error)
- func (s *Session) Prompt(ctx context.Context, text string) ([]ai.Message, error)
- func (s *Session) ReloadExtensions(ctx context.Context) error
- func (s *Session) ResolveModelSpec(spec string) (models.Match, error)
- func (s *Session) RestoredMessages() []ai.Message
- func (s *Session) RunCommand(ctx context.Context, line string) (slashcmd.Result, error)
- func (s *Session) SaveTrust(ctx context.Context, decision string) (string, error)
- func (s *Session) ScopedModels() string
- func (s *Session) SessionSummary() string
- func (s *Session) SetModel(ctx context.Context, spec string) (*ai.Model, error)
- func (s *Session) SetScopedModels(ctx context.Context, patterns []string) (string, error)
- func (s *Session) SetThinkingLevel(ctx context.Context, level ai.ModelThinkingLevel) ai.ModelThinkingLevel
- func (s *Session) SettingsGet(key string) (string, error)
- func (s *Session) SettingsKeys() []string
- func (s *Session) SettingsList() string
- func (s *Session) SettingsSet(ctx context.Context, key, value string) (string, error)
- func (s *Session) SettingsUnset(ctx context.Context, key string) (string, error)
- func (s *Session) ShareSession(ctx context.Context) (string, error)
- func (s *Session) Snapshot() Snapshot
- func (s *Session) StartSession(ctx context.Context) error
- func (s *Session) SwitchSession(ctx context.Context, meta session.Metadata) error
- func (s *Session) ThemePaths() []string
- func (s *Session) ThinkingLevel() ai.ModelThinkingLevel
- func (s *Session) ToolNames() []string
- func (s *Session) ToolsByName() map[string]agent.Tool
- func (s *Session) TreeNodes(ctx context.Context) ([]*session.TreeNode, error)
- func (s *Session) Usage() ai.Usage
- func (s *Session) UserPrompts(ctx context.Context) ([]PromptPoint, error)
- type Snapshot
- type SnapshotCommand
Constants ¶
const DefaultModel = "anthropic/claude-sonnet-5"
DefaultModel is the model tau picks when neither the caller nor settings name one.
It is provider-qualified deliberately. A bare id is ambiguous once the compiled catalog spans every provider — a dozen of them resell claude-sonnet-5 — and the resolver's tie-break is a sort over ids, which would silently start the session on whichever reseller happened to sort highest. A user typing a bare id still gets that behaviour, which is Pi's; tau's own default must not depend on it.
Variables ¶
var ErrNoSession = errors.New("this session is not persisted, so it has no history to work with")
ErrNoSession is returned by operations that need a persisted session.
var ErrRunning = errors.New("the agent is still working — press Esc to stop it first")
ErrRunning is returned by operations that cannot run while the agent is mid-turn.
Functions ¶
func BuildRegistry ¶ added in v0.2.1
BuildRegistry composes the compiled provider catalog with ~/.tau/models.json.
A missing or malformed models.json is not fatal: the built-ins still work, which matters because the file is hand-edited and losing every provider over one stray comma would be the worse outcome. The problem is returned as a warning rather than printed, so the caller decides where it surfaces.
func FormatUsage ¶ added in v0.2.1
FormatUsage renders a usage summary for a human.
The cache figures appear only when there are any, but when there are they matter more than the input count: on a cached turn the input number is the small remainder, and printing it alone makes a working cache look like a broken token counter.
func RefreshRadiusCatalog ¶ added in v0.10.0
func RefreshRadiusCatalog(ctx context.Context, store auth.CredentialStore) (*provider.RadiusCatalog, error)
RefreshRadiusCatalog fetches the gateway's model list and caches it.
It runs after a login rather than at startup: it is a network round trip, and making every `tau` invocation wait on a gateway would slow down sessions that have nothing to do with Radius. The moment a user signs in is when they are online, waiting, and expecting setup to happen.
func RenderTree ¶ added in v0.12.0
RenderTree draws the session tree as indented text.
Entries that carry no conversation — a leaf move, a label — are collapsed away rather than shown. They are real structure, but the question /tree answers is "where in the conversation can I go back to", and a tree where every navigation left a node would drown the answer in its own history.
func ResolveTrust ¶ added in v0.18.0
ResolveTrust answers the same question for callers outside a session — the package subcommands, which install into .tau and must not do so for a checkout the user has not trusted.
There is no prompt on this path, so an undecided project is denied and the user reaches it with --approve. A decision saved by a session is honored here, and one saved here is honored by the next session.
Types ¶
type ExtensionLoader ¶ added in v0.13.0
type ExtensionLoader interface {
// Load returns the extensions to register, plus any non-fatal problems to
// show the user. A loader that cannot start one extension reports it and
// returns the rest — a single bad file must not cost the user their
// session.
Load(ctx context.Context, req LoadRequest) ([]extension.Extension, []string)
// Invalidate marks every loaded extension's captured session state stale,
// without stopping anything.
Invalidate()
// Stop shuts the extensions down. reason is "exit", "reload", or "switch".
Stop(reason string)
// Reload stops everything and loads again, so an author can edit an
// extension and see the new code run.
Reload(ctx context.Context, req LoadRequest) ([]extension.Extension, []string)
}
ExtensionLoader discovers and launches extensions that live outside the binary.
It is an interface rather than a direct call into the subprocess host so that `coding` stays a library: an embedder can supply its own loader, or none, and the package does not drag a process supervisor in with it.
Load runs after the trust decision has been made and settings have been merged, and never before: a project's extensions must not be launched in a directory the user has not trusted, and the settings that name them are themselves project-scoped.
type JSONEvent ¶
type JSONEvent struct {
Type string `json:"type"`
// Message carries the subject message for message_* and turn_end.
Message json.RawMessage `json:"message,omitempty"`
// Delta is the incremental text or thinking for message_update, so
// consumers can render progressively without reassembling the message.
Delta string `json:"delta,omitempty"`
// DeltaKind is "text" or "thinking" when Delta is set.
DeltaKind string `json:"deltaKind,omitempty"`
ToolCallID string `json:"toolCallId,omitempty"`
ToolName string `json:"toolName,omitempty"`
Args map[string]any `json:"args,omitempty"`
Result json.RawMessage `json:"result,omitempty"`
IsError bool `json:"isError,omitempty"`
// Usage and Cost accompany the terminal event.
Usage *ai.Usage `json:"usage,omitempty"`
// Error is set on the terminal event when the run failed.
Error string `json:"error,omitempty"`
// SessionPath is emitted once at start so a caller can resume later.
SessionPath string `json:"sessionPath,omitempty"`
Model string `json:"model,omitempty"`
}
JSONEvent is one line of `tau --mode json` output. The stream is JSONL: exactly one event per line, LF-terminated, so consumers can parse incrementally without buffering the whole run.
type JSONWriter ¶
type JSONWriter struct {
// contains filtered or unexported fields
}
JSONWriter serializes agent events as JSONL.
func NewJSONWriter ¶
func NewJSONWriter(w io.Writer) *JSONWriter
NewJSONWriter builds a JSONL event writer.
func (*JSONWriter) Err ¶
func (j *JSONWriter) Err() error
Err returns the first write failure, if any.
func (*JSONWriter) Sink ¶
func (j *JSONWriter) Sink() agent.Sink
Sink returns an agent.Sink that renders the run as JSONL.
type LoadRequest ¶ added in v0.13.0
type LoadRequest struct {
// Cwd is the session's working directory.
Cwd string
// Trusted reports the project-trust decision. A loader must not read the
// project's extension directory when it is false.
Trusted bool
// SettingsPaths are the extension paths named in the merged settings.
SettingsPaths []string
// Mode is the host's UI mode, for diagnostics.
Mode extension.Mode
// Snapshot is the session state an out-of-process extension needs to be
// able to answer synchronously. Pi's ExtensionAPI getters return values,
// not promises, and an extension puts them straight into a message; a
// loader that omits this leaves every one of them empty.
Snapshot Snapshot
}
LoadRequest is what a loader needs to know to find extensions.
type Options ¶
type Options struct {
Cwd string
ModelID string
ThinkingLevel ai.ModelThinkingLevel
SystemPrompt string
// NoTools disables tool use entirely.
NoTools bool
// NoSession skips persistence (useful for one-shot runs).
NoSession bool
// AppendSystemPrompt is appended after the built system prompt.
AppendSystemPrompt string
// NoSkills disables skill discovery.
NoSkills bool
// TrustOverride forces the project-trust decision (--approve/--no-approve).
TrustOverride *bool
// Extensions are loaded before the session starts, in order.
Extensions []extension.Extension
// ExternalExtensions discovers and launches extensions that live outside
// the binary. Nil loads only the ones compiled in.
ExternalExtensions ExtensionLoader
// Mode is reported to extensions so they can degrade gracefully.
Mode extension.Mode
// Resume opens the most recent session for Cwd instead of creating one.
Resume bool
// SessionPath opens a specific session file.
SessionPath string
// UI is the host's interactive surface, handed to extensions and to the
// built-in commands that need to ask the user something. Nil is headless.
UI extension.UI
// Changelog is the release notes /changelog shows, as a Keep-a-Changelog
// document. Empty means the binary ships none, and the command says so.
// cmd/tau passes the copy embedded at the repository root.
Changelog string
// Interactive supplies the built-in commands that need dialogs. The host
// may pass a value whose session pointer is filled in after New returns —
// nothing calls it during construction.
Interactive slashcmd.Interactive
}
Options configures a coding session.
type PromptPoint ¶ added in v0.12.0
PromptPoint is a place the conversation can be forked or rewound to.
type RPCServer ¶ added in v0.13.0
type RPCServer struct {
// contains filtered or unexported fields
}
RPCServer drives a coding session from JSONL commands on a stream.
It is the third headless surface, after print and json, and the only one that is bidirectional. That is what it exists for: an editor or a supervisor can steer a running agent, answer an extension's dialog, and navigate the session tree, none of which a one-shot invocation can do.
func NewRPCServer ¶ added in v0.13.0
NewRPCServer builds a server around an existing session.
func (*RPCServer) Attach ¶ added in v0.13.0
Attach binds the session and output stream.
It exists separately from construction because of an ordering problem: the extension UI has to be handed to coding.New, and coding.New produces the session this server serves. So the server is created first, its UI is passed in, and the session is attached once it exists. An extension that opens a dialog from its factory then reaches a real client rather than a nil one.
func (*RPCServer) Dispatch ¶ added in v0.13.0
Dispatch runs one command, as though it had arrived on the input stream. A prompt given on the command line uses it, so the client sees exactly the events it would have seen had it sent the prompt itself.
func (*RPCServer) EmitExtensionLog ¶ added in v0.13.0
EmitExtensionLog surfaces a subprocess extension's diagnostic on the client's stream. Without it those lines land on tau's stderr, where a program driving tau over a pipe never sees them.
func (*RPCServer) Serve ¶ added in v0.13.0
Serve reads commands until the stream ends or ctx is cancelled.
type Session ¶
type Session struct {
Agent *agent.Agent
Env *osenv.OSEnv
Model *ai.Model
Session *session.Session
Path string
// Cwd is the directory the session is bound to.
Cwd string
// Extensions dispatches hooks; nil when no extensions are loaded.
Extensions *extension.Runner
// Trust records whether project-scoped resources were allowed to load.
Trust trust.Outcome
// Models is the composed provider catalog: built-ins plus models.json.
Models *models.Registry
// Settings is the merged global+project configuration.
Settings *settings.Resolved
// Skills are the discovered Agent Skills. They appear in the system prompt
// and, unless disabled, as /skill:<name> commands.
Skills []skills.Skill
// Prompts are the discovered prompt templates, each registered as a slash
// command that expands to its body.
Prompts []prompttemplate.Template
// Commands is the slash-command registry for this session.
Commands *slashcmd.Registry
// UI is the host's interactive surface; never nil.
UI extension.UI
// Warnings are non-fatal startup problems — a malformed models.json, say.
// The session runs regardless; the host decides whether to show them.
Warnings []string
// contains filtered or unexported fields
}
Session is a running coding agent bound to a persisted session file.
func (*Session) AvailableModels ¶
AvailableModels lists every model the registry knows, provider-qualified.
func (*Session) Close ¶
Close emits session shutdown to extensions and stops the ones running in their own processes. Skipping the second half would leak a process per session.
func (*Session) Compact ¶ added in v0.12.0
Compact summarizes the older part of the conversation and checkpoints it.
instructions is an optional focus for the summary. Returns nil when there was nothing to compact, which is not an error: /compact on a short session should say so rather than fail.
func (*Session) CycleModel ¶
CycleModel steps through the cycle set by delta, wrapping at both ends.
func (*Session) CycleModels ¶
CycleModels is the ordered set Ctrl+P cycles through: the models named by the enabledModels setting, or everything when the setting is empty.
Pi treats an unmatched pattern as a warning rather than an error, so a setting that names a model from an unconfigured provider still leaves a usable cycle set.
func (*Session) CycleThinkingLevel ¶
CycleThinkingLevel steps to the next level this model supports.
func (*Session) ExportSession ¶ added in v0.19.0
ExportSession writes the conversation to a file and returns the path.
The format follows the extension: a .jsonl path writes the current branch as a session file that tau can open again, anything else renders the self-contained HTML page. An empty path takes the default name in the working directory.
func (*Session) ExtensionNames ¶ added in v0.13.0
ExtensionNames lists the loaded extensions, for /reload and diagnostics.
func (*Session) ExtensionPaths ¶ added in v0.18.0
ExtensionPaths are the extension entry points to load: the ones named in settings first, then the ones installed packages contribute.
func (*Session) Fork ¶ added in v0.12.0
Fork copies this session up to entryID into a new session file and switches to it, leaving the original untouched.
entryID names a user message, and the copy stops just before it: the point of forking at a request is to make it differently. An empty entryID copies the whole session, which is /clone.
func (*Session) ImportSession ¶ added in v0.20.0
ImportSession adopts a session file and continues the conversation in it.
The file is copied into this directory's session folder before it is opened, which is what makes an imported transcript show up in /resume afterwards. It also means further turns are appended to tau's copy rather than to the file that was handed over — importing something out of a shared directory should not start writing to it.
This is the other half of `/export <path>.jsonl`. `tau import` is a different thing entirely: that adopts a whole Pi installation.
func (*Session) LastAssistantText ¶
LastAssistantText returns the text of the most recent assistant message.
func (*Session) ListSessions ¶
ListSessions returns this directory's sessions, most recent first.
func (*Session) MaybeCompact ¶ added in v0.12.0
MaybeCompact compacts if the context has outgrown its reserve.
Reports whether it compacted. A failure is returned rather than swallowed, but the caller is expected to keep going: a turn that cannot be compacted is still worth attempting, and the provider's own error is a clearer diagnosis than tau refusing pre-emptively.
func (*Session) MoveTo ¶ added in v0.12.0
func (s *Session) MoveTo(ctx context.Context, entryID string, summarize bool) (*compaction.BranchResult, error)
MoveTo repositions the conversation at another entry in the tree.
summarize asks for a summary of the branch being left. It costs a request, so it is the caller's decision; without one the abandoned work simply drops out of context, which is sometimes exactly what the user wants.
func (*Session) PrepareCompaction ¶ added in v0.12.0
func (s *Session) PrepareCompaction(ctx context.Context) (*compaction.Preparation, error)
PrepareCompaction reports what a compaction would replace, without spending a request. Returns nil when there is nothing to compact.
func (*Session) Prompt ¶
Prompt runs one agent loop, compacting around it if the context needs it.
The check happens twice, because there are two ways to be over the window and only one of them is visible in advance. Before the turn, the running estimate says whether the conversation has outgrown its reserve. After it, a provider that rejected the request for length says so in a way no estimate could have predicted — a cache-heavy turn, an unusually long tool result — and that rejection is recoverable exactly once.
func (*Session) ReloadExtensions ¶ added in v0.13.0
ReloadExtensions restarts the out-of-process extensions and rebuilds the dispatch runner around them.
The generation bump is the load-bearing part: every context an extension captured before this point now belongs to a session that is gone, and a handler still holding one gets ErrStale rather than a live view of state the old code was reasoning about.
Bundled extensions are re-registered too. They cannot have changed on disk, but they share the runner with the reloaded ones, and rebuilding half of it would leave the surviving half bound to a runner nothing dispatches through.
func (*Session) ResolveModelSpec ¶
ResolveModelSpec is a lookup that does not switch models, for previewing a selection.
func (*Session) RestoredMessages ¶
RestoredMessages returns the transcript the session was opened with, so a host can replay it into its display.
func (*Session) RunCommand ¶
RunCommand parses and executes a slash-command line.
It must not be called from a host's render goroutine: a command may open a dialog and block until the user answers.
func (*Session) ScopedModels ¶ added in v0.20.0
ScopedModels renders the cycle set — the models Ctrl+P moves between — and says where it was configured.
An unset enabledModels puts every model in the cycle, and printing a thousand of them helps nobody, so that case reports the count instead.
func (*Session) SessionSummary ¶
SessionSummary renders the /session report.
func (*Session) SetModel ¶
SetModel switches the model for subsequent turns, records the change in the session, and notifies extensions.
func (*Session) SetScopedModels ¶ added in v0.20.0
SetScopedModels saves patterns as the cycle set. No patterns clears the setting, which puts every model back in the cycle.
The write goes to global settings. Project scope would be refused outright in an untrusted directory, and a cycle set is a preference about the person using tau rather than about the code they are pointing it at.
func (*Session) SetThinkingLevel ¶
func (s *Session) SetThinkingLevel(ctx context.Context, level ai.ModelThinkingLevel) ai.ModelThinkingLevel
SetThinkingLevel changes the reasoning level, clamped to what the model supports, and records it in the session.
func (*Session) SettingsGet ¶ added in v0.20.0
SettingsGet renders one key. A dotted key reaches one level into a nested object, which is as far as the settings file nests.
func (*Session) SettingsKeys ¶ added in v0.20.0
SettingsKeys lists the keys tau models, for completion.
func (*Session) SettingsList ¶ added in v0.20.0
SettingsList renders every configured setting with the scope it came from.
Only what is actually set is listed. The alternative — every key tau knows about, most of them showing a default nobody chose — is the same information as the documentation, and buries the handful of lines that answer "what did I change?".
func (*Session) SettingsSet ¶ added in v0.20.0
SettingsSet writes a key to global settings and applies it to this session.
The value is read as JSON when it parses as JSON, and as a plain string when it does not: `theme dark` means "dark", `quietStartup true` means true, and `npmCommand ["pnpm","add"]` means the array. Guessing this way is what makes the command usable without quoting every string.
Writes go to the global scope. Project settings are refused outright in an untrusted directory, and choosing the scope from a one-line command would need a flag that earns its keep only for the rare project-specific value — which can be edited in the file the listing names.
func (*Session) SettingsUnset ¶ added in v0.20.0
SettingsUnset removes a key from global settings.
func (*Session) ShareSession ¶ added in v0.19.0
ShareSession uploads the exported page as a secret GitHub gist and returns the URLs to show the user.
A secret gist is unlisted, not private: anyone holding the link can read the whole transcript, including any file contents and command output in it.
func (*Session) Snapshot ¶ added in v0.13.0
Snapshot describes the session for an out-of-process extension.
It is taken at the moment it is asked for rather than cached: a reload happens mid-session, and handing the new process the state from startup would make its first answers wrong in a way nothing would report.
func (*Session) StartSession ¶
StartSession replaces the current session with a new empty one.
func (*Session) SwitchSession ¶
SwitchSession opens an existing session file and adopts its transcript.
func (*Session) ThemePaths ¶ added in v0.18.0
ThemePaths are the theme files to load, from settings and from packages.
func (*Session) ThinkingLevel ¶
func (s *Session) ThinkingLevel() ai.ModelThinkingLevel
ThinkingLevel reports the reasoning level in force.
func (*Session) ToolsByName ¶
ToolsByName exposes the full registered tool set for activation UIs.
func (*Session) TreeNodes ¶ added in v0.12.0
TreeNodes returns the session tree for a navigation UI.
func (*Session) UserPrompts ¶ added in v0.12.0
func (s *Session) UserPrompts(ctx context.Context) ([]PromptPoint, error)
UserPrompts lists the user messages on the current branch, oldest first.
This is what /fork offers to branch from: a fork point is only meaningful at a request the user made, because that is the decision being re-taken.
type Snapshot ¶ added in v0.13.0
type Snapshot struct {
SessionName string
ModelID string
ModelProvider string
ContextWindow int
MaxTokens int
ThinkingLevel string
ActiveTools []string
Commands []SnapshotCommand
}
Snapshot is the session state handed to an out-of-process extension at load.
type SnapshotCommand ¶ added in v0.13.0
SnapshotCommand is one entry in the command list Pi exposes via getCommands.