Documentation
¶
Index ¶
- Constants
- Variables
- func AddMCPTools(registry *tools.Registry, cfg *config.Resolved, serverIDs []string) (func(), error)
- func AdvertisedToolSpecs(base *tools.Registry, plan ToolTierPlan, agentReg *agents.AgentRegistry) ([]provider.ToolSpec, int)
- func AgentNameOf(selected *agents.ResolvedAgent) string
- func ApplyDeferredToolPrompt(sess *chat.Session, res *config.Resolved, plan ToolTierPlan, ...)
- func ApplySelectedAgentPrompt(sess *chat.Session, res *config.Resolved, selected *agents.ResolvedAgent, ...)
- func ApplySessionAgent(sess *chat.Session, res *config.Resolved, state *AgentSessionState, ...) error
- func ApplyWorkspacePromptGate(res *config.Resolved, global config.AgentsGlobal)
- func AuthorizedAgentTools(agent *agents.ResolvedAgent, registry *tools.Registry) []string
- func BuildModelBinding(sess *chat.Session, res *config.Resolved, root, providerName, model string, ...) (chat.ModelBinding, error)
- func BuildSkillCatalogue(workspaceRoot string) (map[string]agents.SkillCatalogueEntry, []string)
- func ChatBindingFactory(sess *chat.Session, res *config.Resolved, root string, ...) func(string, string) (chat.ModelBinding, error)
- func ConfigureChatWorkspace(sess *chat.Session, root string, useTools bool, res *config.Resolved, ...) (func(), error)
- func ConfiguredProfile(res *config.Resolved, providerName, model string) (config.ModelSpec, bool)
- func CoreMemoryBlockForOpts(opts SessionDispatcherOpts) string
- func CoreMemoryBlockForState(state *AgentSessionState) string
- func CurrentAgentName(state *AgentSessionState) string
- func DeclaredBinding(definition agents.ResolvedAgent) bool
- func DisabledForAgent(selected *agents.ResolvedAgent, base *tools.Registry) []string
- func EnsureMCPServerTools(registry *tools.Registry, manager *mcp.Manager) func([]string) error
- func FilterSkillRegistryForGate(skillReg *skills.Registry, allowProject bool) *skills.Registry
- func FilterSkillsForScope(reg *skills.Registry, scope AgentSkillScope) *skills.Registry
- func FormatAgentCurrent(name string, reg *agents.AgentRegistry) string
- func FormatAgentSet(name string) string
- func FormatSessionAgentStatus(state *AgentSessionState, sess *chat.Session) string
- func InstallSessionIdentity(sess *chat.Session, state *AgentSessionState)
- func LoadSessionSkills(root string, allowProject bool) (*skills.Registry, []string, error)
- func LogDiagnosticsCommandsOnce(w io.Writer, tc config.ToolsConfig, quiet bool)
- func MemoryConfigOf(state *AgentSessionState) config.MemoryConfig
- func MemoryOf(state *AgentSessionState) memory.Store
- func NewLoadToolsTool(sess *chat.Session, candidates []tools.TierCandidate) tools.Tool
- func NewProviderCompleter(res *config.Resolved, providerName, model string) (provider.Completer, error)
- func NewProviderCompleterFactory(res *config.Resolved) func(string, string) (provider.Completer, error)
- func NewSessionDispatcher(opts SessionDispatcherOpts) (*runtime.Dispatcher, error)
- func NewSurfaceWidener(sess *chat.Session, res *config.Resolved, state *AgentSessionState) chat.SurfaceWidener
- func OpenMemoryStoreWithReadOnly(root string, mc config.MemoryConfig, readOnly bool) (memory.Store, error)
- func PinAttachAdvertisedToolSpecs(sess *chat.Session, selected *agents.ResolvedAgent, plan ToolTierPlan, ...)
- func RecordSchemaMass(sess *chat.Session, state *AgentSessionState, plan ToolTierPlan, ...)
- func RefreshSummarizerAfterModelSwitch(sess *chat.Session, res *config.Resolved)
- func RegisterSessionTool(d *runtime.Dispatcher, reg *tools.Registry, tool tools.Tool) error
- func RootSystemPromptWithRoster(prompt string, registry *agents.AgentRegistry) string
- func RoutedIdentity(definition agents.ResolvedAgent, instanceID string, generation uint64) *events.Identity
- func RunAgents(args []string) error
- func RunAgentsWithIO(args []string, stdout, stderr io.Writer) error
- func SafeCatalogText(value string, max int) string
- func SameFilePath(goos, a, b string) bool
- func ScopedRootRegistry(registry *tools.Registry, selected *agents.ResolvedAgent, ...) (*tools.Registry, []string)
- func SelectableModel(catalog []config.ProviderModelGroup, providerName, model string) (config.ModelSpec, bool)
- func SessionIdentity(sess *chat.Session, state *AgentSessionState, generation uint64) *events.Identity
- func SessionMCPConfig(res *config.Resolved) config.MCPConfig
- func SetupSessionMCPTools(registry *tools.Registry, cfg *config.Resolved, selected *agents.ResolvedAgent) (*mcp.Manager, func(), error)
- func SubagentRosterSection(registry *agents.AgentRegistry) string
- func SwitchModelCommand(sess *chat.Session, res *config.Resolved, providerName, model string) (reasoning.Level, error)
- func TieredRootRegistry(base *tools.Registry, selected *agents.ResolvedAgent, extraDenylist []string, ...) *tools.Registry
- func WarnAgentLoad(warnings []string)
- func WarnDisabledAgentTools(selected *agents.ResolvedAgent, disabled []string)
- func WarnHookLoad(warnings []string)
- func WarnSkillLoad(warnings []string)
- func WireSessionMemory(opts *tools.DefaultOptions, root string, res *config.Resolved) error
- func WorkflowMCPServers(wf *definition.CompiledWorkflow, registry *agents.AgentRegistry) []string
- func WriteAgentCatalog(w io.Writer, view AgentCatalogView, diagnostics io.Writer)
- type AgentBinding
- type AgentCatalogRow
- type AgentCatalogView
- type AgentListRow
- type AgentLoadResult
- type AgentSessionContext
- type AgentSessionState
- func (s *AgentSessionState) AdoptLedgerRepo(repo ledger.LedgerRepository, owned *ledger.StorageLedgerRepository)
- func (s *AgentSessionState) CloseOwnedLedgerStore()
- func (s *AgentSessionState) Context() AgentSessionContext
- func (s *AgentSessionState) DisplayName() string
- func (s *AgentSessionState) DisplaySource() string
- func (s *AgentSessionState) Lock()
- func (s *AgentSessionState) OwnedLedgerStore() *ledger.StorageLedgerRepository
- func (s *AgentSessionState) ReleaseOwnedLedgerRepo()
- func (s *AgentSessionState) SchemaMassSnapshot() SchemaMass
- func (s *AgentSessionState) SetSkillScope(scope AgentSkillScope)
- func (s *AgentSessionState) SkillScopeSnapshot() AgentSkillScope
- func (s *AgentSessionState) Unlock()
- type AgentSkillScope
- type AgentSurface
- type ContextDispatcherWiring
- type SchemaMass
- type SessionDispatcherOpts
- type ToolTierPlan
Constants ¶
const ( // SubagentRosterMaxLines caps the roster entries; overflow collapses into // a tail line pointing at the dispatch_tasks agent enum. SubagentRosterMaxLines = 8 )
Roster bounds. The "# Subagents" section is appended to the root system prompt, so its parts are clamped to keep the assembled prompt bounded and provider prompt-cache friendly (the section changes only when the roster does).
Variables ¶
var AdvertisedSessionToolSpecsVar func(ToolTierPlan, *agents.AgentRegistry) []provider.ToolSpec
AdvertisedSessionToolSpecsVar is wired by internal/cli/cliagents_wiring.go to cli's advertisedSessionToolSpecs. Used by advertisedToolSpecs in tool_tiers.go to append the session-owned dispatcher tools to the advertised wire array. The *agents.AgentRegistry argument is the binding's immutable resolved agent snapshot, passed as data (never a global) so dispatch_tasks can advertise its real agent enum and roster at turn zero.
var BuiltInSlashTokensVar func() map[string]struct{}
BuiltInSlashTokensVar is wired by internal/cli/cliagents_wiring.go to return the set of reserved slash tokens from cli's builtInSlashCommands. Used by loadSessionSkills in model_binding.go to reject skill names that collide with built-in slash commands.
var ContextDispatcherForVar func(*chat.Session, config.SubagentConfig) ContextDispatcherWiring
ContextDispatcherForVar is wired at process start by internal/cli/cliagents_wiring.go to cli's contextDispatcherFor.
var ErrAgentWallClockExceeded = errors.New("agent wall-clock ceiling exceeded")
ErrAgentWallClockExceeded is the typed cause attached when a routed agent exhausts its own wall-clock ceiling. It distinguishes an agent-policy timeout from a caller-imposed task timeout or an operator cancel, all of which otherwise surface as context.DeadlineExceeded.
var NewSessionDispatcherVar func(SessionDispatcherOpts) (*runtime.Dispatcher, error)
NewSessionDispatcherVar is wired at process start by internal/cli/cliagents_wiring.go to cli's NewSessionDispatcher. Moving code (agent_switch.go, model_binding.go) calls this instead of importing cli directly.
var RemainderSpoolFromRegistryVar func(*tools.Registry) *remainder.Spool
RemainderSpoolFromRegistryVar is wired at process start by internal/cli/cliagents_wiring.go to cli's RemainderSpoolFromRegistry. cli's read_output.go owns the unexported readOutputTool type and cannot move, so the spool builder stays there.
var SummaryWiringVar func(*chat.Session, *config.Resolved) (*contextmgr.Summarizer, contextstate.PolicySnapshot, bool)
SummaryWiringVar is wired by internal/cli/cliagents_wiring.go to cli's summaryWiring. Used by refreshSummarizerAfterModelSwitch in model_binding.go.
var WireWorkflowToolOptionsVar func(*tools.DefaultOptions, string, *config.Resolved, func() *events.Bus, bool, ledger.LedgerRepository)
WireWorkflowToolOptionsVar is wired at process start by internal/cli/cliagents_wiring.go to cli's wireWorkflowToolOptions. chat_workspace.go (moving) calls this to wire the workflow-engine event bus without importing cli. The ledger repository is the owning session's orchestration repo (AgentSessionState.LedgerRepo); nil keeps child-run registration skipped.
Functions ¶
func AddMCPTools ¶
func AdvertisedToolSpecs ¶
func AdvertisedToolSpecs(base *tools.Registry, plan ToolTierPlan, agentReg *agents.AgentRegistry) ([]provider.ToolSpec, int)
AdvertisedToolSpecs is the exported view of advertisedToolSpecs for callers outside cliagents (tests, session catalog introspection).
func AgentNameOf ¶
func AgentNameOf(selected *agents.ResolvedAgent) string
agentNameOf is the empty-safe agent name used to key persisted admissions.
func ApplyDeferredToolPrompt ¶
func ApplyDeferredToolPrompt(sess *chat.Session, res *config.Resolved, plan ToolTierPlan, state *AgentSessionState)
applyDeferredToolPrompt appends the binding's frozen deferred-tool index to the session prompt. It runs once per binding: every later admission republishes this exact prompt, which is what keeps the cached system-prompt prefix intact while the tool array grows.
func ApplySelectedAgentPrompt ¶
func ApplySelectedAgentPrompt(sess *chat.Session, res *config.Resolved, selected *agents.ResolvedAgent, state *AgentSessionState)
applySelectedAgent applies the selected agent's prompt and turn budget to the session. max_turns: nil leaves the session default; 0 means unlimited.
Runs even when selected is nil (plan 77: found via a live smoke test that a bare `mivia chat` with no --agent never reached this far otherwise - chat_command.go's own fallback prompt resolution runs BEFORE the memory store opens and is hardcoded to no injection, so this call, right after configureChatWorkspace, is the only site that recomposes the root session's prompt with the real memory block for a no-agent session).
func ApplySessionAgent ¶
func ApplySessionAgent(sess *chat.Session, res *config.Resolved, state *AgentSessionState, name string, busy bool) error
ApplySessionAgent switches the root agent for the idle session. busy is the TUI waiting flag; active turns and switch guards are checked on sess. It reuses ToolBase for re-scope and rebuilds the dispatcher like model switch.
func ApplyWorkspacePromptGate ¶
func ApplyWorkspacePromptGate(res *config.Resolved, global config.AgentsGlobal)
applyWorkspacePromptGate strips untrusted workspace system prompts when the user gate is off. User config prompts always load.
func AuthorizedAgentTools ¶
func AuthorizedAgentTools(agent *agents.ResolvedAgent, registry *tools.Registry) []string
AuthorizedAgentTools adds discovered MCP tool names for the agent's selected servers. The server selection is the authority. An agent file does not need to repeat volatile remote tool names in its tools list.
func BuildModelBinding ¶
func BuildModelBinding(sess *chat.Session, res *config.Resolved, root, providerName, model string, state *AgentSessionState) (chat.ModelBinding, error)
buildModelBinding prepares a complete provider/model generation without mutating the session. The caller publishes it through Session.SwitchBinding.
state is the live agent session state, not a snapshot of it: a model switch rebuilds the whole surface, and the surface's authority registry, frozen tier split and skill registry exist only there. Passing a context snapshot is what made a /model switch silently narrow this session's authority. In-flight turns keep their captured binding generation.
func BuildSkillCatalogue ¶
func BuildSkillCatalogue(workspaceRoot string) (map[string]agents.SkillCatalogueEntry, []string)
buildSkillCatalogue scans user and project skill roots separately so both origins are visible for allowlist trust decisions (project cannot silently replace a user skill binding).
func ChatBindingFactory ¶
func ChatBindingFactory(sess *chat.Session, res *config.Resolved, root string, state *AgentSessionState) func(string, string) (chat.ModelBinding, error)
chatBindingFactory is the single provider/model construction path every surface rebuild goes through: the REPL and TUI model switches, and a catalog load whose saved session names a different provider or model. It closes over the live agentSessionState so each rebuild sees the current agent, tier plan and admitted set rather than a snapshot taken at startup.
func ConfigureChatWorkspace ¶
func ConfiguredProfile ¶
func CoreMemoryBlockForOpts ¶
func CoreMemoryBlockForOpts(opts SessionDispatcherOpts) string
CoreMemoryBlockForOpts is CoreMemoryBlockForState for the subagent path (plan 77, E2/E5): opts.Memory is nil for workflow/background callers, which coreMemoryBlock degrades safely to "".
func CoreMemoryBlockForState ¶
func CoreMemoryBlockForState(state *AgentSessionState) string
CoreMemoryBlockForState returns the core-memory injection block scoped to the project for the given session state. Callers hold state.mu per the LedgerRepo/Memory field convention. context.Background() is used because this is always a session-init or turn-boundary call with no request context.
func CurrentAgentName ¶
func CurrentAgentName(state *AgentSessionState) string
CurrentAgentName implements current agent name.
func DeclaredBinding ¶
func DeclaredBinding(definition agents.ResolvedAgent) bool
declared reports whether the agent named its own provider or model rather than following the session.
func DisabledForAgent ¶
func DisabledForAgent(selected *agents.ResolvedAgent, base *tools.Registry) []string
disabledForAgent lists the selected agent's tool names a registry cannot offer. /agent is an entry point, so it may report them; the surface builds it triggers stay silent because they also run mid-turn, under the TUI.
func EnsureMCPServerTools ¶
func FilterSkillRegistryForGate ¶
filterSkillRegistryForGate omits project-origin skills when the workspace gate is off. User skills remain registered.
func FilterSkillsForScope ¶
func FilterSkillsForScope(reg *skills.Registry, scope AgentSkillScope) *skills.Registry
filterSkillsForScope returns a registry containing only skills the scope may invoke (name allowlist only; tool subset is checked at invocation).
func FormatAgentCurrent ¶
func FormatAgentCurrent(name string, reg *agents.AgentRegistry) string
FormatAgentCurrent implements format agent current.
func FormatAgentSet ¶
FormatAgentSet implements format agent set.
func FormatSessionAgentStatus ¶
func FormatSessionAgentStatus(state *AgentSessionState, sess *chat.Session) string
func InstallSessionIdentity ¶
func InstallSessionIdentity(sess *chat.Session, state *AgentSessionState)
func LoadSessionSkills ¶
loadSessionSkills loads skill handlers for the session. When allowProject is false, only user skills are discovered so a workspace skill cannot shadow a user skill and then be stripped by the gate (leaving nothing).
func LogDiagnosticsCommandsOnce ¶
func LogDiagnosticsCommandsOnce(w io.Writer, tc config.ToolsConfig, quiet bool)
logDiagnosticsCommandsOnce states every configured get_diagnostics command once at startup, before any tool call: a configured command that runs programs is a disclosure, not a hidden capability (the same contract as the lifecycle-hooks armedNotice). Names are sorted so the line is deterministic across runs. quiet (--quiet) suppresses the line; the tool itself is still registered whenever the workspace declares commands.
func MemoryConfigOf ¶
func MemoryConfigOf(state *AgentSessionState) config.MemoryConfig
MemoryConfigOf returns the resolved memory config from state without requiring the caller to hold state.mu (plan 77, E2).
func MemoryOf ¶
func MemoryOf(state *AgentSessionState) memory.Store
MemoryOf returns the session-lifetime memory store from state without requiring the caller to hold state.mu (plan 77, E2).
func NewLoadToolsTool ¶
NewLoadToolsTool constructs a load_tools tool wired to sess. Pass nil, nil to build a schema-only instance for the tool catalog.
func NewProviderCompleter ¶
func NewProviderCompleter(res *config.Resolved, providerName, model string) (provider.Completer, error)
newProviderCompleter constructs a completer for one provider-qualified model. provider.NewForProvider is fail-closed: it rejects a provider with no configured runtime and one with no credential, both before any client is built, so this is the point where an agent's declared provider is really authorized (the parse-time name check is only a spelling check).
func NewProviderCompleterFactory ¶
func NewProviderCompleterFactory(res *config.Resolved) func(string, string) (provider.Completer, error)
newProviderCompleterFactory adapts newProviderCompleter to the dispatcher's factory seam. It returns nil when there is no configuration to build from, which leaves a routed agent's foreign provider failing closed rather than falling back to the session's completer.
func NewSessionDispatcher ¶
func NewSessionDispatcher(opts SessionDispatcherOpts) (*runtime.Dispatcher, error)
NewSessionDispatcher builds a runtime.Dispatcher for agent sessions. NewSessionDispatcherVar must be non-nil; wired by internal/cli/cliagents_wiring.go.
func NewSurfaceWidener ¶
func NewSurfaceWidener(sess *chat.Session, res *config.Resolved, state *AgentSessionState) chat.SurfaceWidener
newSurfaceWidener returns the host-owned publisher for staged tool admissions (plan tools/05 D7). internal/chat cannot build a session dispatcher, so the session records intent and calls back here at the turn boundary.
The candidate surface is built first and published only if every precondition still holds, checked atomically with the swap inside TryPublishAgentSurface. A refused publication closes the candidate dispatcher it never installed and leaves the stage pending.
func OpenMemoryStoreWithReadOnly ¶
func OpenMemoryStoreWithReadOnly(root string, mc config.MemoryConfig, readOnly bool) (memory.Store, error)
OpenMemoryStoreWithReadOnly resolves the memory config to a memory store. readOnly controls memory.Config.ReadOnly. Exported so internal/cli's openMemoryStore and openMemoryStoreReadOnly can delegate here without duplicating the path-resolution logic.
func PinAttachAdvertisedToolSpecs ¶
func PinAttachAdvertisedToolSpecs(sess *chat.Session, selected *agents.ResolvedAgent, plan ToolTierPlan, agentReg *agents.AgentRegistry)
pinAttachAdvertisedToolSpecs computes and pins the initial-attach binding's advertised union BEFORE sess.Tools is narrowed to its core-tier execution registry: the union must be built from the full pre-scope base (plan tools-advertising/01), same as buildSurfaceFromBase does for /agent and /model. agentReg is the session's immutable resolved registry snapshot, threaded into the advertised session-tool schemas. Must be called before sess.Tools is reassigned.
func RecordSchemaMass ¶
func RecordSchemaMass(sess *chat.Session, state *AgentSessionState, plan ToolTierPlan, admitted []string, agentName, publication string)
recordSchemaMass measures and records the session's current advertised schema mass. It takes state.mu itself; callers already holding it use recordSchemaMassLocked. admitted is passed in rather than read back off the session: the admission path records this measurement before it commits the new admitted set, so asking the session would price the surface it just replaced.
func RefreshSummarizerAfterModelSwitch ¶
RefreshSummarizerAfterModelSwitch is the exported view of refreshSummarizerAfterModelSwitch for callers outside cliagents.
func RegisterSessionTool ¶
RegisterSessionTool registers a privileged session-owned tool on both the dispatcher and the tool registry. It fails fast if the tool name is already present so registration conflicts surface at startup rather than at runtime.
func RootSystemPromptWithRoster ¶ added in v0.1.1
func RootSystemPromptWithRoster(prompt string, registry *agents.AgentRegistry) string
RootSystemPromptWithRoster appends the roster section ADDITIVELY to the root system prompt - the compiled fallback or an operator's custom chat.system_prompt alike - because the roster is environment fact, not user content. It lives at the prompt-assignment point, never inside buildAgentPrompt, so a customized prompt still gets the announcement. An empty section returns the prompt unchanged byte-for-byte.
func RoutedIdentity ¶
func RoutedIdentity(definition agents.ResolvedAgent, instanceID string, generation uint64) *events.Identity
RoutedIdentity builds an events.Identity for a routed agent invocation.
func RunAgentsWithIO ¶
RunAgentsWithIO is the exported view of runAgentsWithIO for callers outside cliagents (tests, integration harnesses).
func SafeCatalogText ¶
func SameFilePath ¶ added in v0.1.1
SameFilePath reports whether two path spellings name the same file: both are normalized (backslashes go to slashes, dot-dot and double-slash segments resolve away), then compared - case-folded on Windows, whose filesystems match case-insensitively, and byte-exact elsewhere. goos is a parameter, not runtime.GOOS, so the Windows branch stays testable from every OS. Normalization is done by hand because filepath.Clean is host-dependent (it treats backslashes as plain bytes on Unix), which a GOOS-parameterized comparison cannot lean on. Accepted limits, each benign in direction (a miss only skips the chmod of the file the store is opening anyway, never hardens a wrong file): a literal backslash inside a Unix filename reads as a separator, and a symlink or 8.3 short-name alias of the temp path compares unequal - both require deliberately spelling out our hash-named TempStorePath, which the default-filled path never does. Resolving them needs live-filesystem calls, which would give back the host-dependence this pure seam exists to remove. This is deliberately NOT config.sameFilePath (internal/config/agents_io.go), which resolves symlinks on the live filesystem; this one is pure, so a path that does not exist yet still compares. Empty paths never match. SameFilePath is the shared gate helper for ad-hoc store hardening: the clichat and cliworkflow orchestration-ledger gates call this exported form so all three packages compare paths by one contract.
func ScopedRootRegistry ¶
func ScopedRootRegistry(registry *tools.Registry, selected *agents.ResolvedAgent, extraDenylist []string) (*tools.Registry, []string)
scopedRootRegistry intersects a registry with the selected agent's effective tools using ScopeRoot (privileged/delegation tools kept). It returns the scoped registry and the agent's tool names this build could not honour.
It reports rather than prints: this runs on EVERY surface build, including the ones a tool admission performs mid-turn, and a raw stderr write while the TUI owns the terminal corrupts the rendered frame. Only the attach and /agent entry points turn the report into a diagnostic, via warnDisabledAgentTools.
func SelectableModel ¶
func SelectableModel(catalog []config.ProviderModelGroup, providerName, model string) (config.ModelSpec, bool)
SelectableModel returns the catalog profile for one provider-qualified model. Unlike the previous modelInCatalog helper it reports the profile, so the caller can bind the routed model's own context window instead of inheriting the session model's.
func SessionIdentity ¶
func SessionIdentity(sess *chat.Session, state *AgentSessionState, generation uint64) *events.Identity
SessionIdentity resolves the current agent identity (name and source) for a session generation. Shared with internal/legacytui's TUI event handling.
func SetupSessionMCPTools ¶
func SubagentRosterSection ¶ added in v0.1.1
func SubagentRosterSection(registry *agents.AgentRegistry) string
SubagentRosterSection renders the "# Subagents" prompt section: one line per agent in registry order (file-backed agents first, then compiled built-ins), capped at SubagentRosterMaxLines with an overflow tail. Empty when there is nothing to announce. A pure function of the immutable registry snapshot.
func SwitchModelCommand ¶
func SwitchModelCommand(sess *chat.Session, res *config.Resolved, providerName, model string) (reasoning.Level, error)
SwitchModelCommand publishes a model generation and reports the /effort choice the switch took away, if any. Three surfaces run this switch and each words its own confirmation; deciding here what was lost is what stops them from disagreeing about whether anything was.
Only a CHOICE counts as a loss. An untouched dial reads the outgoing model's default, and the incoming model declaring a different one is that model describing itself, not a preference being dropped. Whether a choice exists is the session's fact, not something the levels can be subtracted to reveal: a user may deliberately pick the level their model already defaults to.
The before/after reading straddles the publication because only the session knows whether the new generation kept the override, and it is also what keeps a dropped choice the incoming model happens to default to quiet - nothing the user can observe changed there.
func TieredRootRegistry ¶
func TieredRootRegistry(base *tools.Registry, selected *agents.ResolvedAgent, extraDenylist []string, plan ToolTierPlan, admitted []string) *tools.Registry
tieredRootRegistry materializes the core tier in base order and appends the admitted tools as a tail (plan tools/05 D8). An inert plan falls through to the ordinary root scope so a zero-config session is byte-identical to a build without deferred loading.
func WarnAgentLoad ¶
func WarnAgentLoad(warnings []string)
func WarnDisabledAgentTools ¶
func WarnDisabledAgentTools(selected *agents.ResolvedAgent, disabled []string)
warnDisabledAgentTools reports the selected agent's tool names the live registry cannot offer. Call it only from a session entry point the operator initiated (attach, /agent), never from a surface rebuild.
func WarnHookLoad ¶
func WarnHookLoad(warnings []string)
warnHookLoad surfaces lifecycle-hook diagnostics at startup, not in debug output. A silently ignored hook is how someone concludes hooks are broken.
func WarnSkillLoad ¶
func WarnSkillLoad(warnings []string)
func WireSessionMemory ¶
WireSessionMemory wires the memory store into the session tool options so memory_save and memory_search register (plan 68). A nil res or a disabled memory section leaves opts.Memory unchanged.
func WorkflowMCPServers ¶
func WorkflowMCPServers(wf *definition.CompiledWorkflow, registry *agents.AgentRegistry) []string
WorkflowMCPServers returns the MCP server IDs referenced by workflow steps, in registry order. Only agents actually used in a step are included. See cli/workflow_run_build.go for the caller.
func WriteAgentCatalog ¶
func WriteAgentCatalog(w io.Writer, view AgentCatalogView, diagnostics io.Writer)
Types ¶
type AgentBinding ¶
type AgentBinding struct {
ProviderName string
Model string
Completer provider.Completer
// maxTokens caps one provider response. It is the tighter of the agent's
// own ceiling and the operator's session cap, so an agent file can lower
// the ceiling but never raise it above what the operator allowed.
MaxTokens int
// reasoning is the routed MODEL's dial, not the session's. An agent
// pinned to another model must think at the depth that model declares;
// inheriting the session's would send one model's wire fields to another.
Reasoning reasoning.Setting
// contains filtered or unexported fields
}
AgentBinding is one routed agent's immutable execution target. It is resolved once, at dispatcher construction, and never mutated afterwards - concurrent Invokes on the shared handler only read it.
func ResolveAgentBinding ¶
func ResolveAgentBinding(definition agents.ResolvedAgent, opts SessionDispatcherOpts) (AgentBinding, error)
ResolveAgentBinding resolves and validates one agent's execution target.
It is deliberately eager: registerAgentHandlers calls it at dispatcher construction so a mistyped provider or model surfaces at startup rather than twenty minutes into a run. A failure is stored on the handler and returned on invoke, so one bad definition cannot take down an otherwise usable session.
func ResolvePinnedAgentBinding ¶
func ResolvePinnedAgentBinding(definition agents.ResolvedAgent, opts SessionDispatcherOpts, providerName, model string) (AgentBinding, error)
ResolvePinnedAgentBinding re-authorizes a provider/model pair restored from a ledger row. The pair is descriptive metadata, never a handler selector: the current catalog and provider factory must authorize it again.
func (AgentBinding) ContextBudget ¶
func (b AgentBinding) ContextBudget() int
ContextBudget is the prompt budget this agent may actually use.
func (AgentBinding) EffectiveReasoning ¶
func (b AgentBinding) EffectiveReasoning() reasoning.Setting
EffectiveReasoning is the dial this agent's requests carry.
func (AgentBinding) WithWallClock ¶
func (b AgentBinding) WithWallClock(ctx context.Context, agentName string) (context.Context, context.CancelFunc, error)
WithWallClock applies the agent's wall-clock ceiling as a parent of whatever bound the caller already imposed. Layering it rather than replacing the caller's timeout matches the handler contract: MultiStepHandler and OneShotHandler clamp a handler-level TotalTimeout against the per-task timeout and keep the tighter of the two, so this parent context composes with the handler bound instead of fighting it - the tightest deadline always wins.
The cause is a fresh per-invocation error value, not the shared sentinel, so ownership is unambiguous: an ancestor that breached ITS ceiling propagates its own cause down, and comparing by identity keeps this agent from reporting a breach it never had. It still wraps ErrAgentWallClockExceeded so callers can match the class with errors.Is.
type AgentCatalogRow ¶
type AgentCatalogView ¶
type AgentCatalogView struct {
Report agents.InspectionReport
Rows []AgentCatalogRow
}
func LoadAgentCatalog ¶
func LoadAgentCatalog(workspaceRoot string) (AgentCatalogView, error)
func (AgentCatalogView) ReportCollection ¶
func (v AgentCatalogView) ReportCollection() string
func (AgentCatalogView) ReportCollectionState ¶
func (v AgentCatalogView) ReportCollectionState() config.AgentCollectionState
type AgentListRow ¶
AgentListRow is one selectable entry for the /agent dialog and listings.
type AgentLoadResult ¶
type AgentLoadResult struct {
Registry *agents.AgentRegistry
Global config.AgentsGlobal
Selected *agents.ResolvedAgent // nil when no agent selected
Warnings []string
}
AgentLoadResult is Layer-B output: resolved definitions and the user gate.
func LoadAgentDefinitions ¶
func LoadAgentDefinitions(workspaceRoot, agentFlag string, skillReg *skills.Registry) (AgentLoadResult, error)
LoadAgentDefinitions discovers and resolves file-backed agents. skillReg may be nil (no skill collision check). When non-nil, agent names that collide with skills fail closed.
When agentFlag is empty and a definition named config.DefaultAgentName ("mivia") exists, that definition is selected as the root session agent. That replaces the former .mivia/agent-prompt.md load path. A flag equal to config.RootAgentName restores the compiled root surface (no selection).
type AgentSessionContext ¶
type AgentSessionContext struct {
Global config.AgentsGlobal
Selected *agents.ResolvedAgent
Registry *agents.AgentRegistry
// AllowProjectSkills is true when workspace skill handlers may register.
AllowProjectSkills bool
}
AgentSessionContext is a value snapshot for dispatcher construction (startup and model switch). Mutable session state lives in agentSessionState.
type AgentSessionState ¶
type AgentSessionState struct {
Global config.AgentsGlobal
Selected *agents.ResolvedAgent
AllowProjectSkills bool
Registry *agents.AgentRegistry
WorkspaceRoot string
// ToolBase is the post-dispatcher, pre-scope registry for re-scoping.
// Nil when tools are off.
ToolBase *tools.Registry
// MCPManager owns the session-wide MCP clients. Agent switches borrow it to
// discover newly selected server tools without starting another client.
MCPManager *mcp.Manager
// SkillScope is the immutable per-instance skill policy for the selected
// root agent, including the final live tool registry snapshot (plan 43).
// Set at dispatcher attach and agent switch; read by the TUI slash path.
SkillScope AgentSkillScope
// TierPlan is the frozen core/deferred tool split for the current agent
// binding (plan tools/05 D8). Computed once per binding; never recomputed
// while it lives, so the prompt index it feeds stays byte-stable.
TierPlan ToolTierPlan
// SkillRegFull is the current binding's unfiltered skill registry. Surface
// widening reuses it so admitting a tool performs no skill disk I/O.
SkillRegFull *skills.Registry
// LedgerRepo is the session-lifetime ledger repository every surface rebuild
// passes to NewSessionDispatcherVar. It exists so no dispatcher ever OWNS a
// ledger store: a republished surface carries the live remainder spool, the
// spool captured its ContentStore at construction, and publication closes
// the dispatcher it replaced. A per-dispatcher store would therefore be
// closed out from under the spool by the first tool admission. Nil means the
// caller supplied a shared store (the dispatcher borrows it) or tools are off.
LedgerRepo ledger.LedgerRepository
// LastSchemaMass is the most recent advertised schema-mass measurement for
// this session's surface (plan tools/05 D5 telemetry). It is written by the
// three publications that can change the split or the admitted tail: attach,
// /agent switch and tool admission. A /model rebuild republishes the same
// frozen tiers with the same admitted tail, so it deliberately leaves this
// measurement alone rather than re-emitting an identical one.
LastSchemaMass SchemaMass
BaselinePrompt string
BaselineMaxSteps int
BaselineCaptured bool
// Memory is the session-lifetime memory store, opened once by
// configureChatWorkspace and never closed here - the same store
// tools.DefaultOptions.Memory wires into memory_save/memory_search (plan
// 77, E1). Nil when memory is disabled or tools are off. Callers hold
// state.mu (applySessionAgent does), so the field is read directly,
// matching the LedgerRepo convention above.
Memory memory.Store
// MemoryConfig is the resolved [memory] section, read alongside Memory
// to build the core-tier injection block (coreMemoryBlock).
MemoryConfig config.MemoryConfig
// contains filtered or unexported fields
}
AgentSessionState is the mid-session mutable agent context. Startup and /agent switch share this so model-switch rebuilds keep the selected agent.
var ClassicAgentState *AgentSessionState
ClassicAgentState is the root agent context for the classic REPL/one-shot chat path. The TUI stores the same pointer on TUIModel.agentState.
func (*AgentSessionState) AdoptLedgerRepo ¶
func (s *AgentSessionState) AdoptLedgerRepo(repo ledger.LedgerRepository, owned *ledger.StorageLedgerRepository)
AdoptLedgerRepo sets the session-lifetime ledger repository and owned store. Used by cli.adoptSessionLedgerRepo so the field stays package-private here.
func (*AgentSessionState) CloseOwnedLedgerStore ¶
func (s *AgentSessionState) CloseOwnedLedgerStore()
CloseOwnedLedgerStore closes the session's durable ledger store. Called by sessionSurfaceCleanup after the dispatcher is torn down.
func (*AgentSessionState) Context ¶
func (s *AgentSessionState) Context() AgentSessionContext
Context returns a snapshot of the agent session context. Thread-safe.
func (*AgentSessionState) DisplayName ¶
func (s *AgentSessionState) DisplayName() string
DisplayName is the status dialog's "agent" row: the locked, nil-safe read of the currently selected agent's name. Exported for internal/legacytui's dialog rendering, which cannot lock the unexported mu field directly.
func (*AgentSessionState) DisplaySource ¶
func (s *AgentSessionState) DisplaySource() string
DisplaySource is the status dialog's "source" row: the locked, nil-safe read of the currently selected agent's provenance source. Exported for internal/legacytui's dialog rendering, which cannot lock the unexported mu field directly.
func (*AgentSessionState) Lock ¶
func (s *AgentSessionState) Lock()
Lock acquires the session state mutex. Use with Unlock for cross-package atomic reads/writes (tests, legacytui). Production paths hold mu directly.
func (*AgentSessionState) OwnedLedgerStore ¶
func (s *AgentSessionState) OwnedLedgerStore() *ledger.StorageLedgerRepository
OwnedLedgerStore returns the session-owned durable ledger store or nil. Used by tests outside this package that cannot read the unexported field.
func (*AgentSessionState) ReleaseOwnedLedgerRepo ¶
func (s *AgentSessionState) ReleaseOwnedLedgerRepo()
ReleaseOwnedLedgerRepo closes and forgets the store adoptSessionLedgerRepo opened. Used by cli.releaseSessionLedgerRepo on the error path.
func (*AgentSessionState) SchemaMassSnapshot ¶
func (s *AgentSessionState) SchemaMassSnapshot() SchemaMass
SchemaMassSnapshot returns the last recorded measurement for display.
func (*AgentSessionState) SetSkillScope ¶
func (s *AgentSessionState) SetSkillScope(scope AgentSkillScope)
SetSkillScope stores the selected root agent's skill policy. Writers that already hold s.mu (applySessionAgent) assign the field directly.
func (*AgentSessionState) SkillScopeSnapshot ¶
func (s *AgentSessionState) SkillScopeSnapshot() AgentSkillScope
SkillScopeSnapshot returns a copy of the current root skill policy for the TUI slash path. A nil state or unset scope yields the open zero value.
func (*AgentSessionState) Unlock ¶
func (s *AgentSessionState) Unlock()
Unlock releases the session state mutex acquired by Lock.
type AgentSkillScope ¶
type AgentSkillScope struct {
// contains filtered or unexported fields
}
AgentSkillScope is an immutable per-instance skill policy snapshot for the selected root agent. Built once at dispatcher construction; never shared across concurrent agents or model switches as a mutable registry.
Zero value is unrestricted (backward compatible for dispatchers built without an agent). Explicit empty allowlists always set restricted=true with a non-nil allowed map.
v1 scope is root fan-out only: nested multi_step agents do not receive privileged dispatch_tasks/spawn_agent, so they cannot synthesize skill tasks. Resume/retry re-enters skill handlers which re-check this scope.
func SkillScopeFromAgent ¶
func SkillScopeFromAgent(selected *agents.ResolvedAgent) AgentSkillScope
skillScopeFromAgent snapshots the selected agent's skill allowlist and tools. A nil agent means the compiled default root (all skills, no tool subset gate).
func SkillScopeFromAgentAndRegistry ¶
func SkillScopeFromAgentAndRegistry(selected *agents.ResolvedAgent, reg *tools.Registry) AgentSkillScope
skillScopeFromAgentAndRegistry is skillScopeFromAgent plus the final live tool registry snapshot (after disable/deny filtering). A nil agent stays unrestricted (compiled default root owns the full catalogue); a nil registry leaves the live check disabled. SkillScopeFromAgentAndRegistry builds a scope from an agent and its registry.
func (AgentSkillScope) CheckSkillDefinition ¶
func (s AgentSkillScope) CheckSkillDefinition(def skills.Definition) error
CheckSkillDefinition enforces the full plan 43 policy for one skill definition: allowlist, declared-tool subset of the agent's effective tools and the live registry, and origin fail-closed (a runtime definition whose origin differs from the allowlist-bound origin for the same name is an authorization event).
type AgentSurface ¶
type AgentSurface struct {
// Dispatcher is the built tool dispatcher. The caller must close it when
// it is no longer needed or will not be published to a session.
Dispatcher *runtime.Dispatcher
}
AgentSurface is the exported view of a widened agent surface. It exposes the built dispatcher so callers outside cliagents can close it or probe it.
func BuildWidenedWith ¶
func BuildWidenedWith(sess *chat.Session, res *config.Resolved, state *AgentSessionState, admitted []string) (*AgentSurface, error)
BuildWidenedWith derives the same binding's surface with admitted appended as a tail and returns it for the caller to inspect or publish. See buildWidenedWith.
type ContextDispatcherWiring ¶
type ContextDispatcherWiring struct {
Preparation contextmgr.PreparationManager
PreparationInput contextmgr.PrepareInput
}
ContextDispatcherWiring carries the context-preparation state from the session setup into the agent surface builders. The function that assembles it lives in internal/cli (contextDispatcherFor) and is injected here via ContextDispatcherForVar so the import direction stays inward. See internal/cli/cliagents_wiring.go for the wiring init.
type SchemaMass ¶
type SchemaMass struct {
Advertised int
Tokens int
Locked int
LockedTokens int
AgentName string
Publication string
}
SchemaMass is the advertised tool-schema cost of one agent surface: the number every request pays before a single message is added.
Advertised/Tokens price the pinned wire snapshot (plan tools-advertising/01): core tier PLUS every deferred candidate, since admission now changes execution authority only, never what is advertised. Locked/LockedTokens are the subset of that snapshot which is authorized and visible but not yet admitted for execution - "deferred" no longer means "withheld", it means "locked until loaded with load_tools". LockedTokens prices the same shortened (one-line) description advertisedToolSpecs actually ships for a locked tool, not its full Description(), so it stays consistent with Tokens.
func (SchemaMass) String ¶
func (m SchemaMass) String() string
String renders the operator-facing one-liner used by /tools and diagnostics.
type SessionDispatcherOpts ¶
type SessionDispatcherOpts struct {
// Registry is the advertised surface: what the root model is shown and what
// the root loop may invoke. Under a deferred tool tier this is only the core
// block plus whatever has been admitted.
Registry *tools.Registry
// AuthorityRegistry is the root-scoped FULL authorized tool set, deferred
// tier included. Delegation authority is not an advertising decision: a
// routed agent, a skill and a nested multi-step loop are scoped from this,
// so narrowing what the root model sees never narrows what it may delegate.
// Nil defaults to Registry, which is the correct answer whenever nothing is
// deferred.
AuthorityRegistry *tools.Registry
Completer provider.Completer
Model string
ProviderName string
// AllowWorkspaceAgentProviders is the user-owned opt-in for static workflow
// panel provider routing.
AllowWorkspaceAgentProviders bool
ModelGeneration uint64
// ModelGenerationFunc is evaluated when a routed task starts. Candidate
// dispatchers are built before a binding is published, so a fixed
// generation here can be stale after a concurrent switch.
ModelGenerationFunc func() uint64
ModelCatalog []config.ProviderModelGroup
// CompleterFactory builds a completer bound to one provider. It is required
// before a routed agent may execute on a provider other than the session's;
// when it is absent such an agent fails closed rather than silently
// downgrading onto the session completer. Completers are provider-scoped
// (the model travels per request), so the model argument is advisory.
CompleterFactory func(providerName, model string) (provider.Completer, error)
Config config.SubagentConfig
MCP config.MCPConfig
// EnsureMCPTools lazily adds wrappers for an authorized routed agent.
// The session owns the manager and registry that this callback uses.
EnsureMCPTools func([]string) error
ToolResultCapBytes int
// ToolRunTimeout is the [tools] tool_run_timeout_seconds knob applied to
// every nested sub-agent loop's SDK tool registry: the registry-wide run
// backstop for tools with no declared Capability.Timeout. <= 0 = no
// registry-wide cap (the SDK's TimeoutNone).
ToolRunTimeout time.Duration
// BatchResultBudgetBytes is the [tools] batch_result_budget_bytes knob,
// applied to every nested sub-agent loop the same way it applies to the
// session loop. 0 = off.
BatchResultBudgetBytes int
// RefOnlyTools is the [tools] ref_only_tools knob for every nested sub-agent loop; empty = off.
RefOnlyTools []string
// WorkspaceRoot is the directory lifecycle hooks execute in. Empty means
// no hooks are wired, which is what every non-chat caller wants.
WorkspaceRoot string
// Memory is the session's memory store (plan 77, E2), the same instance
// agentSessionState.Memory holds - not a second Open. Nil for every
// non-chat caller (workflow/background paths); CoreMemoryBlockForState
// already treats a nil store as "", so subagent prompt composition
// degrades safely with no caller-side nil check required.
Memory memory.Store
// MemoryConfig is the resolved [memory] section read alongside Memory.
MemoryConfig config.MemoryConfig
// Repo, if set, is used as-is and its lifetime is caller-owned.
// If nil, the constructor opens a store from Config (with the
// memory-backend fallback) and owns its Close via dispatcher.OnClose.
Repo ledger.LedgerRepository
// MaxContextTokens / MaxTokens configure the nested subagent handlers.
// Zero values mean "unset" (handler defaults apply).
MaxContextTokens int
MaxTokens *int
// WorkLimits are session limits. Each task combines these limits with its
// agent, model, task, and parent-panel limits.
WorkLimits runtime.WorkLimits
// Budget, if non-nil, is the live session budget provider read by nested
// handlers when invoked (so /budget applies without rebuilding).
Budget func() int
// Reasoning, if non-nil, is the live session dial read by nested handlers
// when invoked (so /effort applies without rebuilding). It supersedes the
// dial resolved from ModelCatalog for every path that follows the session.
Reasoning func() reasoning.Setting
// adapter borrows it and the dispatcher never closes it.
SharedSQLite *storage.SQLite
// ContextPreparationManager is a preparation-only capability for nested
// loops. The dispatcher never receives a checkpoint publisher or store.
ContextPreparationManager contextmgr.PreparationManager
ContextPreparationInput contextmgr.PrepareInput
// SkillReg, if non-nil, registers each skill as a Subagent handler.
SkillReg *skills.Registry
// WorkflowSkillSnapshots pins workflow skill content for every workflow
// invocation. A nil map means this is not a workflow dispatcher.
WorkflowSkillSnapshots map[string]workflowledger.RefSnapshot
// SkillScope is the immutable per-instance skill policy for the selected
// root agent (plan 06). Zero value allows all skills (no agent selected).
SkillScope AgentSkillScope
// AgentRegistry is the caller-authorized immutable catalogue whose names
// are the only task routing targets.
AgentRegistry *agents.AgentRegistry
// DeferredTools is this agent binding's frozen deferred set (plan
// tools/05). Non-empty registers load_tools as a privileged session tool;
// empty leaves the surface byte-identical to a build without the feature.
DeferredTools []tools.TierCandidate
// Session is the session whose tool surface load_tools stages against.
// Required whenever DeferredTools is non-empty.
Session *chat.Session
// RemainderSpool is the live spool of an EXISTING session whose surface is
// being rebuilt. Visibility grants for truncated output live in the spool
// instance while the bytes live in a shared store, so minting a new spool
// for a republished surface would turn every earlier ref into "denied" for
// the session that produced it. Nil mints one, which is what a genuinely
// new session wants.
RemainderSpool *remainder.Spool
// Sink, when set, receives one runtime.Event per invocation lifecycle
// step (started, retrying, completed) with bounded audit metadata. Nil
// disables sink delivery and keeps every other caller unchanged. The sink
// runs on the invoking goroutine, so it must be cheap and safe for
// concurrent calls.
Sink func(runtime.Event)
}
SessionDispatcherOpts carries every input the session dispatcher needs. Repo and Budget are optional; their absence selects the legacy defaults (open a SQLite store from Config, no live budget provider). Moved here from internal/cli/dispatcher.go so agent_binding.go and other cliagents code can reference the type without importing cli. internal/cli/dispatcher.go re-exports it via a type alias.
func (SessionDispatcherOpts) Authority ¶
func (o SessionDispatcherOpts) Authority() *tools.Registry
Authority resolves the full authorized set nested principals are scoped from. AuthorityRegistry takes precedence; Registry is the fallback when nothing is deferred.
type ToolTierPlan ¶
type ToolTierPlan struct {
Tiers tools.Tiers
// Candidates are the deferred tools with their one-line descriptions, in
// live-registry order. Empty means the plan is inert.
Candidates []tools.TierCandidate
// Digest fingerprints the tier split a persisted admitted set was made
// against, so a resumed session can drop a stale set fail-closed.
Digest string
}
ToolTierPlan is one agent binding's frozen deferred-tool decision (plan tools/05 D8). It is computed once per binding, before any admission, and never recomputed while that binding lives: the prompt index it feeds must stay byte-stable across admissions, so it is stale by design afterwards.
func PlanToolTiers ¶
func PlanToolTiers(base *tools.Registry, selected *agents.ResolvedAgent, res *config.Resolved) ToolTierPlan
planToolTiers splits the authorized tool set of the live pre-scope registry into core and deferred tiers. Authority is unchanged: the split only decides which authorized schemas ship on every request and which wait for load_tools.
func (ToolTierPlan) Deferred ¶
func (p ToolTierPlan) Deferred() bool
Deferred reports whether this binding defers anything at all. A plan that defers nothing must behave byte-identically to a build without the feature: no load_tools tool, no prompt index, no tail ordering.
Source Files
¶
- agent_binding.go
- agent_catalog.go
- agent_definitions.go
- agent_handlers.go
- agent_skill_policy.go
- agent_switch.go
- agents_command.go
- chat_workspace.go
- context_dispatcher.go
- dispatcher_wiring.go
- handler_names.go
- identity.go
- load_tools_tool.go
- mcp_scope.go
- mcp_session.go
- memory_support.go
- model_binding.go
- session_dispatcher_opts.go
- subagent_roster.go
- tool_admission.go
- tool_schema_mass.go
- tool_tiers.go