Documentation
¶
Overview ¶
Package agentruntime is the shared session-construction layer behind `yottacode run` (internal/oneshot), the TUI (internal/tui), and the ACP server (internal/acp). All three build the same "world" — registry, permissions, adapter, router, LSP manager, skills, subagents, MCP, compaction — and previously did so via two independently-drifting ~370/~850 line inline blocks. Builder.Build is the single place that construction happens now; callers layer their own presentation-specific state (Bubbletea Model, stdout streaming, checkpoints, recall) on top of the returned Runtime.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var EffortLevels = []string{"", "low", "medium", "high"}
EffortLevels is the closed set RebuildAdapterForEffort accepts, mirroring internal/tui/effort_picker.go's effortEntries — "" means provider default (no reasoning override injected).
Functions ¶
func IsValidEffortLevel ¶
IsValidEffortLevel reports whether level is one of EffortLevels.
func RebuildAdapterForEffort ¶
RebuildAdapterForEffort updates rt.ChatOptions.ReasoningEffort and reconstructs every adapter that bakes reasoning effort in at construction time — rt.Adapter and, when a router pair is configured for this session, rt.RouterAdapters — using exactly Build's own adapter-selection logic (RoutingEnabled → the freshly-rebuilt advisor adapter; otherwise a plain adapter.NewWithConfig), so a mid-session effort change can never silently knock a routed session off its advisor model the way an independent "just call NewWithConfig" rebuild could. Session-only: nothing is persisted to config.toml. No preflight re-probe — matches internal/tui/effort_picker.go's commitEffortChoice, which also skips it (the provider connection already worked at session start).
func RecomposeSystemPrompt ¶
RecomposeSystemPrompt rewrites the session's system message. headBytes marks the stable cache prefix (the static base prompt ahead of the memory tail) — see adapter.Message.CacheHeadBytes. Exported because callers with a live prompt at construction time (oneshot) re-score memory against it after Build returns and need to overwrite what Build injected with the prompt-unaware memory.SystemPrompt.
func SetAdvisorRouting ¶
SetAdvisorRouting toggles whether subagent dispatch and summarization route through rt.RouterAdapters' implementer/advisor pair. Mirrors internal/tui/cmd_router.go's applyRoutingOn/applyRoutingOff exactly — session-only (nothing persisted to config.toml), and deliberately does NOT touch rt.Adapter/rt.Cfg.Adapter: which model serves the main conversation is decided once, at Build time, by fileCfg.Router.RoutingEnabled() (see RebuildAdapterForEffort), not by this toggle. Returns an error when enabling is requested but no advisor/implementer pair is configured for this session — mirrors the TUI's own "/advisor on" guidance to configure one first.
Types ¶
type Builder ¶
type Builder struct{}
Builder constructs a Runtime from a SessionSpec. Stateless — safe to share across concurrent Build calls (each call only touches its own local state and the spec/session it's given).
func NewBuilder ¶
func NewBuilder() *Builder
NewBuilder returns a Builder. A constructor exists (rather than a bare struct literal at call sites) so adding builder-level config later (e.g. injected clocks for tests) doesn't churn every caller.
func (*Builder) Build ¶
Build constructs the full session world: session, memory, adapter, router, permissions, registry + tools, MCP, subagents, and the LoopConfig ready to hand to agent.Turn. It never calls os.Getwd()/os.Chdir() — every constructor here takes spec.Cwd explicitly, which is what makes this safe to call concurrently for N different sessions with different working directories (see SessionSpec.Cwd's doc comment).
type Runtime ¶
type Runtime struct {
Session *session.Session
Fresh bool
Cfg agent.LoopConfig
Registry *agent.Registry
Permissions *permissions.Permissions
AgentTool *agent.AgentTool
SubagentTasks *subagents.Registry
MCPManager *mcppkg.Manager
Skills []skills.Skill
SkillTool *agent.SkillTool
LSPManager *lsp.Manager
CodeMapProvider codemap.Provider
Adapter adapter.Client
RouterAdapters *cli.RouterAdapters
// ChatOptions is the live, as-constructed options snapshot Adapter
// (and RouterAdapters) were built from — mirrors internal/tui's own
// m.opts. Build seeds it (including any advisor-model override
// applied to spec.ChatOptions.Model below); RebuildAdapterForEffort
// mutates ChatOptions.ReasoningEffort and reconstructs every adapter
// that bakes reasoning effort in at construction time. Session-only —
// never written back to config.toml.
ChatOptions cli.ChatOptions
// RoutingAuto is the session-live mirror of fileCfg.Router.RoutingAuto()
// at construction — whether subagent dispatch/summarization currently
// route through RouterAdapters' implementer/advisor pair. Distinct from
// FileCfg.Router.Mode (the on-disk setting Build read once): this field
// is what SetAdvisorRouting toggles, session-only, matching
// internal/tui/cmd_router.go's own m.routerMode/RouterModeAuto split
// between "what's persisted" and "what's live."
RoutingAuto bool
// GHClient is the typed GitHub client backing the pr_*/issue_*/
// git_push composite tools (see Build). Lazy and side-effect-free
// to construct — the real auth/network cost is paid on first tool
// call, not here — so every caller gets it unconditionally, same as
// MCPManager. Exposed on Runtime because TUI's status bar also
// reads it directly (resolveCurrentPRCmd) for a display-only
// current-PR lookup that has no ACP equivalent.
GHClient githubapi.Interface
// RecallIndex backs the model-callable session_recall tool (see
// Build) — a full-text/semantic index over every saved session at
// ~/.yottacode/index.sqlite, shared across every caller (it's one
// file on disk, not per-session state; SQLite's WAL mode is what
// makes concurrent handles from oneshot/tui/acp safe at once). Nil
// when recall.Open fails (non-fatal — see rt.Warnings); callers
// must Close it themselves when the session ends (TUI's own
// teardown does this already; CloseSession/Shutdown do it for ACP).
// Backfilling the corpus (session.List + re-index) stays a
// TUI-only background job — see internal/tui/run.go — since it's a
// startup-time catch-up most valuable for the interactive,
// long-running case; oneshot/ACP sessions still search whatever a
// prior TUI/backfill run already indexed, they just don't trigger
// a fresh corpus-wide catch-up themselves.
RecallIndex *recall.Index
// Model is the effective model name after Build's own resolution —
// specifically, when advisor routing is enabled and overrides the
// requested model, this is the *overridden* name. spec.Model (i.e.
// spec.ChatOptions.Model) stays whatever the caller originally
// passed in; callers that display or persist the active model (the
// TUI's status bar, session bookkeeping) must read this field, not
// spec.Model, or they'll show a stale name under routing.
Model string
PlanMode *agent.PlanModeState
AutoMode *agent.AutoModeState
YoloMode *agent.YoloModeState
LoopControl *agent.LoopControlState
PlanStore *agent.PlanStore
CwdRef *agent.CwdRef
// CmdSandbox is the optional session-scoped command sandbox backing
// run_bash and worktree/dispatch sandbox inheritance. Nil preserves
// HostSandbox behavior.
CmdSandbox agent.Sandbox
FileCfg config.Config
ExperimentalSet *experimental.Set
Mem memory.Loaded
EmbedClient *memory.EmbedClient
// BaseSystemPrompt is the pre-memory composed prompt (profile framing
// + skills section, before memory injection). Callers that know the
// live user prompt at construction time (oneshot) can re-score memory
// against it and overwrite the session's system message via
// RecomposeSystemPrompt; callers that don't (TUI, ACP — the prompt
// arrives later, via session/prompt) just keep what Build already
// injected with the prompt-unaware memory.SystemPrompt.
BaseSystemPrompt string
// RawSystemPrompt is the base system prompt *before*
// composeSystemPrompt/appendSkillsSection are applied — opts.
// SystemPrompt (or defaultSystemPrompt) plus the dispatch addendum,
// nothing else. TUI needs this raw form, not BaseSystemPrompt: its
// own per-turn/reload paths (rebuildSystemPromptForTurn,
// reloadMemoryNow, recomposeSystemPromptWithSkills) call
// composeSystemPrompt/appendSkillsSection themselves, so handing them
// the already-composed BaseSystemPrompt would double the profile
// framing and skills section on every turn.
RawSystemPrompt string
// Warnings collects non-fatal construction issues (router degrade,
// embedding model unreachable, MCP server start failures, unknown
// experimental flags, skills/subagents load warnings) as pre-formatted
// lines. The caller decides how to surface them — TUI startup
// notices, oneshot stderr, an ACP diagnostic message.
Warnings []string
}
Runtime is everything Builder.Build constructs for one session. Callers layer their own presentation-specific state on top: the Bubbletea Model/Config (TUI), stdout streaming (oneshot), or ACP protocol plumbing (internal/acp). Deliberately excluded (stay caller-specific): checkpoints, recall/FTS index, workspace trust, sensitivity posture, and the GitHub PR/Issue tool suite — all TUI-interactive or ghClient-coupled concerns with no ACP v1 equivalent yet.
func (*Runtime) Close ¶
Close releases every process/goroutine resource owned by this Runtime. It is intentionally safe to call more than once: callers use it from both normal session-close paths and error/defer cleanup paths. Persistence stays caller-owned because TUI, oneshot, and ACP each have different save gates.
type SessionSpec ¶
type SessionSpec struct {
cli.ChatOptions
// Cwd is the session's working directory. ChatOptions carries no cwd
// field — oneshot/tui both derive it from os.Getwd() today. ACP must
// derive it from session/new's cwd parameter instead, and Build must
// never call os.Getwd()/os.Chdir() itself: it hosts N concurrent
// sessions with potentially different cwds in one process.
Cwd string
// MCPServers is session-scoped and additive on top of the global
// fileCfg.MCPServers Build loads from config.toml. Empty for
// oneshot/tui (they only ever use the global set); ACP's session/new
// carries this from the client's mcpServers param. On name collision
// a session-scoped entry overrides the global one of the same name.
MCPServers []config.MCPServer
// DisableWorktreeTools excludes EnterWorktreeTool/ExitWorktreeTool
// from the registry. Both tools call process-global os.Chdir() in
// addition to updating the session's CwdRef (see
// EnterWorktreeTool.swapCwd) — safe when one process hosts one
// session at a time (oneshot, TUI), unsafe when one process hosts N
// concurrent sessions with different cwds (ACP). oneshot/tui pass
// false; acp passes true.
DisableWorktreeTools bool
// SupportsBackgroundDispatch controls AgentTool.AllowBackground and
// DispatchTool.SupportsBackground. oneshot passes false (no
// long-lived session to host async completions — its own rationale,
// documented at the oneshot call site historically). tui and acp
// both pass true: both are long-lived processes that can host
// detached background work and surface its completion later.
SupportsBackgroundDispatch bool
// PreCompact is the optional pre-compaction snapshot hook threaded
// into LoopConfig.Compaction.PreCompact. tui supplies its snapshot
// writer (writePreSummarySnapshot); oneshot and acp leave this nil,
// which agent.CompactionConfig treats as "no snapshot taken."
PreCompact func(history []adapter.Message) (string, error)
// DeferMCPStart skips starting the MCP manager and registering its
// tools inside Build. Build still constructs Runtime.MCPManager (via
// mcp.NewManager) so the caller has something to Start() later — it
// just doesn't block Build on it. TUI sets this: it deliberately
// starts MCP servers asynchronously via its own Bubbletea tea.Cmd
// (internal/tui/cmd_mcp.go) so slow/hanging npx-based servers don't
// delay first paint, and that existing machinery already knows how
// to Start() the manager and register tools once it has a
// *mcp.Manager and *agent.Registry to work with — nothing new is
// needed there. oneshot and acp both leave this false: neither has a
// progressive-UI concept, so Build's synchronous start-and-register
// is exactly what they want (acp's session/new must return only
// once the session is actually ready).
DeferMCPStart bool
}
SessionSpec is the input to Builder.Build. It wraps cli.ChatOptions (the struct both current callers already resolve from flags/env/config via cli.Resolve) rather than re-deriving a hand-picked subset, plus the handful of fields ChatOptions has no room for.