Documentation
¶
Overview ¶
Package agent implements the core agent loop that drives the LLM ↔ Tool execution cycle and exposes a stream of events for the TUI.
Index ¶
- Constants
- Variables
- func AdvancePastID(id string)
- func IsContextLengthExceededPendingCompaction(err error) bool
- func NextInstanceID(agentType string) string
- func RebuildTouchedPathsFromMessages(msgs []message.Message) []string
- type ActivityObserver
- type ActivityType
- type AgentActivityEvent
- type AgentContextUsage
- type AgentDoneEvent
- type AgentEvent
- type AgentForTUI
- type AgentResult
- type AgentStatusEvent
- type ArtifactRef
- type AssistantMessageEvent
- type CompactionController
- type CompactionStatusEvent
- type CompletionEnvelope
- type ConfirmFunc
- type ConfirmRequestEvent
- type ConfirmResponse
- type ConfirmRuleIntent
- type ContextUsageUpdateEvent
- type DurableTaskRecord
- type EnvStatusUpdateEvent
- type ErrorEvent
- type Event
- type ForkSessionEvent
- type HandoffEvent
- type HandoffResult
- type IdleEvent
- type InfoEvent
- type KeyHealthReporter
- type KeyPoolChangedEvent
- type LLMResponsePayload
- type LSPServerDisplay
- type LSPStateProvider
- type LoopAssessment
- type LoopAssessmentAction
- type LoopContinuationNote
- type LoopController
- type LoopNoticeEvent
- type LoopState
- type LoopStateChangedEvent
- type MCPControlAction
- type MCPControlRequest
- type MCPControlResult
- type MCPSelectEvent
- type MCPServerDisplay
- type MCPStateProvider
- type MainAgent
- func (a *MainAgent) AddedOverlayRules() []permission.AddedRule
- func (a *MainAgent) AgentOverridePoolName(agentName string) (string, bool)
- func (a *MainAgent) AppendContextMessage(msg message.Message)
- func (a *MainAgent) ApplyInitialModel(providerModel string) error
- func (a *MainAgent) AskQuestions(ctx context.Context, questions []tools.QuestionItem, timeout time.Duration) ([]tools.QuestionAnswer, error)
- func (a *MainAgent) AvailableAgents() []string
- func (a *MainAgent) AvailableRoles() []string
- func (a *MainAgent) AvailableSubAgents() []tools.AgentInfo
- func (a *MainAgent) AwaitConfirm(ctx context.Context, toolName, argsJSON string, timeout time.Duration, ...) (ConfirmResponse, error)
- func (a *MainAgent) CancelCompaction() bool
- func (a *MainAgent) CancelCurrentTurn() bool
- func (a *MainAgent) CancelSubAgent(ctx context.Context, taskID, reason string) (tools.TaskHandle, error)
- func (a *MainAgent) ClearPendingInteractions()
- func (a *MainAgent) ContinueFromContext()
- func (a *MainAgent) CreateSubAgent(ctx context.Context, description, agentType string, ...) (tools.TaskHandle, error)
- func (a *MainAgent) CurrentLoopIteration() int
- func (a *MainAgent) CurrentLoopMaxIterations() int
- func (a *MainAgent) CurrentLoopState() LoopState
- func (a *MainAgent) CurrentLoopTarget() string
- func (a *MainAgent) CurrentPoolName() string
- func (a *MainAgent) CurrentRateLimitSnapshot() *ratelimit.KeyRateLimitSnapshot
- func (a *MainAgent) CurrentRole() string
- func (a *MainAgent) CurrentRoleConfig() *config.AgentConfig
- func (a *MainAgent) CurrentRoleModelRefs() []string
- func (a *MainAgent) DeleteSession(sessionID string) error
- func (a *MainAgent) DisableLoopMode()
- func (a *MainAgent) EnableLoopMode(target string)
- func (a *MainAgent) Events() <-chan AgentEvent
- func (a *MainAgent) ExecutePlan(planPath, agentName string)
- func (a *MainAgent) ExportSession(format, path string)
- func (a *MainAgent) FocusedAgentID() string
- func (a *MainAgent) FocusedAgentName() string
- func (a *MainAgent) ForkSession(msgIndex int)
- func (a *MainAgent) GetAllAgentsContextUsage() []AgentContextUsage
- func (a *MainAgent) GetContextMessageCount() int
- func (a *MainAgent) GetContextStats() (current, limit int)
- func (a *MainAgent) GetMessages() []message.Message
- func (a *MainAgent) GetSessionSummary() *SessionSummary
- func (a *MainAgent) GetSidebarUsageStats() analytics.SessionStats
- func (a *MainAgent) GetSubAgents() []SubAgentInfo
- func (a *MainAgent) GetTodos() []tools.TodoItem
- func (a *MainAgent) GetTokenUsage() message.TokenUsage
- func (a *MainAgent) GetUsageStats() analytics.SessionStats
- func (a *MainAgent) HasAvailableSubAgents() bool
- func (a *MainAgent) InvokedSkills() []*skill.Meta
- func (a *MainAgent) IsCompactionRunning() bool
- func (a *MainAgent) KeyPoolNextTransition() time.Duration
- func (a *MainAgent) KeyStats() (confirmed, total int)
- func (a *MainAgent) LSPServerList() []LSPServerDisplay
- func (a *MainAgent) ListSessionSummaries() ([]SessionSummary, error)
- func (a *MainAgent) ListSkills() []*skill.Meta
- func (a *MainAgent) LoadSkill(name string) (*skill.Skill, error)
- func (a *MainAgent) LoopKeepsMainBusy() bool
- func (a *MainAgent) MCPServerList() []MCPServerDisplay
- func (a *MainAgent) MainModelPoolName() string
- func (a *MainAgent) MainModelPoolNames() []string
- func (a *MainAgent) MarkSkillInvoked(meta *skill.Meta)
- func (a *MainAgent) MarkSkillInvokedByName(name string)
- func (a *MainAgent) MarkSkillsReady()
- func (a *MainAgent) ModelName() string
- func (a *MainAgent) ModelPoolPolicy() *RuntimeModelPoolPolicy
- func (a *MainAgent) ModelsStatusText() string
- func (a *MainAgent) NewSession()
- func (a *MainAgent) NotifyEnvStatusUpdated()
- func (a *MainAgent) NotifySubAgent(ctx context.Context, taskID, message, kind string) (tools.TaskHandle, error)
- func (a *MainAgent) Overlay() *permission.Overlay
- func (a *MainAgent) PendingUserMessageCount() int
- func (a *MainAgent) PoolNames() []string
- func (a *MainAgent) PrewarmModelPolicy() error
- func (a *MainAgent) ProjectRoot() string
- func (a *MainAgent) ProviderModelRef() string
- func (a *MainAgent) ProxyInUseForRef(ref string) bool
- func (a *MainAgent) QueuePendingUserDraft(draftID string, parts []message.ContentPart) bool
- func (a *MainAgent) RegisterMainMCPServers(serverNames []string)
- func (a *MainAgent) ReloadAgentsMD() bool
- func (a *MainAgent) RemoveLastMessage()
- func (a *MainAgent) RemoveOverlayAddedRule(index int) error
- func (a *MainAgent) RemovePendingUserDraft(draftID string) bool
- func (a *MainAgent) ResetMCPReady()
- func (a *MainAgent) ResolveConfirm(action, finalArgsJSON, editSummary, denyReason, requestID string)
- func (a *MainAgent) ResolveConfirmWithRuleIntent(action, finalArgsJSON, editSummary, denyReason, requestID string, ...)
- func (a *MainAgent) ResolveQuestion(answers []string, cancelled bool, requestID string)
- func (a *MainAgent) RestoreSessionAtStartup() error
- func (a *MainAgent) ResumeSession()
- func (a *MainAgent) ResumeSessionID(sessionID string)
- func (a *MainAgent) Run(ctx context.Context) error
- func (a *MainAgent) RunningModelRef() string
- func (a *MainAgent) RunningVariant() string
- func (a *MainAgent) SendAgentEvent(eventType, sourceID string, payload any)
- func (a *MainAgent) SendUserMessage(content string)
- func (a *MainAgent) SendUserMessageWithParts(parts []message.ContentPart)
- func (a *MainAgent) SessionID() string
- func (a *MainAgent) SetActivityObserver(obs ActivityObserver)
- func (a *MainAgent) SetAgentConfigs(configs map[string]*config.AgentConfig)
- func (a *MainAgent) SetAgentModelPool(agentName, pool string) error
- func (a *MainAgent) SetConfirmFunc(fn ConfirmFunc)
- func (a *MainAgent) SetCurrentModelPool(pool string) error
- func (a *MainAgent) SetCustomCommands(defs []*command.Definition)
- func (a *MainAgent) SetLLMFactory(fn func(systemPrompt string, agentModels []string, variant string) *llm.Client)
- func (a *MainAgent) SetLSPSessionFuncs(reset func(), load func([]message.Message))
- func (a *MainAgent) SetLSPStatusFunc(serverList func() []LSPServerDisplay)
- func (a *MainAgent) SetMCPControlFunc(fn func(context.Context, MCPControlRequest) (MCPControlResult, error))
- func (a *MainAgent) SetMCPServerEnabled(server string, enabled bool) error
- func (a *MainAgent) SetMCPServersPromptBlock(block string)
- func (a *MainAgent) SetMCPStatusFunc(serverList func() []MCPServerDisplay)
- func (a *MainAgent) SetModelPoolPolicy(policy *RuntimeModelPoolPolicy, statePath string)
- func (a *MainAgent) SetModelSwitchFactory(fn func(providerModel string) (*llm.Client, string, int, error))
- func (a *MainAgent) SetPendingMCPDiscovery(mcpTools []tools.Tool, block string)
- func (a *MainAgent) SetProviderModelRef(ref string)
- func (a *MainAgent) SetSessionArtifactsDirFunc(fn func() string)
- func (a *MainAgent) SetSessionLock(lock *recovery.SessionLock)
- func (a *MainAgent) SetSessionTargetChangedFunc(fn func(string))
- func (a *MainAgent) SetSkills(skills []*skill.Meta)
- func (a *MainAgent) SetUsageEventSink(fn func(event analytics.UsageEvent))
- func (a *MainAgent) Shutdown(timeout time.Duration) error
- func (a *MainAgent) StartupResumeStatus() (pending bool, sessionID string)
- func (a *MainAgent) SwapLLMClient(newClient *llm.Client, modelName string, contextLimit int)
- func (a *MainAgent) SwitchFocus(agentID string)
- func (a *MainAgent) SwitchModel(providerModel string) error
- func (a *MainAgent) SwitchRole(role string)
- func (a *MainAgent) UpdatePendingUserDraft(draftID string, parts []message.ContentPart) bool
- func (a *MainAgent) UpdateTodos(todos []tools.TodoItem) error
- func (a *MainAgent) WakeCodexRateLimitPolling()
- type MessageSender
- type ModelOption
- type ModelPoolSelectorTarget
- type ModelPoolSelectorTargetKind
- type ModelSelectEvent
- type ModelSelector
- type PendingDraftConsumedEvent
- type PendingToolCall
- type PlanExecutor
- type PromptResolver
- type QuestionRequestEvent
- type QuestionResponse
- type RateLimitUpdatedEvent
- type RequestCycleStartedEvent
- type RequestProgressEvent
- type RoleChangedEvent
- type RoleController
- type RunningModelChangedEvent
- type RuntimeModelPoolPolicy
- func (p *RuntimeModelPoolPolicy) AgentOverride(agentName string) (string, bool)
- func (p *RuntimeModelPoolPolicy) ClearAgentOverride(agentName string)
- func (p *RuntimeModelPoolPolicy) CurrentModelPool() string
- func (p *RuntimeModelPoolPolicy) EffectiveModels(agentName string, cfg *config.AgentConfig) []string
- func (p *RuntimeModelPoolPolicy) EffectivePool(agentName string, cfg *config.AgentConfig) string
- func (p *RuntimeModelPoolPolicy) LastPicked(roleName, poolName string) (string, bool)
- func (p *RuntimeModelPoolPolicy) Overrides() map[string]string
- func (p *RuntimeModelPoolPolicy) ReplaceSelections(currentModelPool string, overrides map[string]string)
- func (p *RuntimeModelPoolPolicy) ReplaceSelectionsForSessionRestore(currentModelPool string, overrides map[string]string)
- func (p *RuntimeModelPoolPolicy) ResolveInitialModelRef(agentName string, cfg *config.AgentConfig) string
- func (p *RuntimeModelPoolPolicy) SetAgentOverride(agentName, pool string)
- func (p *RuntimeModelPoolPolicy) SetCurrentModelPool(pool string)
- func (p *RuntimeModelPoolPolicy) SetLastPicked(roleName, poolName, modelRef string)
- type SessionController
- type SessionRestoredEvent
- type SessionSelectEvent
- type SessionSummary
- type SessionSwitchStartedEvent
- type SkillsStateProvider
- type SpawnFinishedEvent
- type StreamRollbackEvent
- type StreamTextEvent
- type StreamThinkingDeltaEvent
- type StreamThinkingEvent
- type StreamingToolDiscardInfo
- type StreamingToolExecutor
- func (e *StreamingToolExecutor) AcquireExecutionSlot(ctx context.Context) func()
- func (e *StreamingToolExecutor) DiscardAll(reason string) []PendingToolCall
- func (e *StreamingToolExecutor) DiscardCall(callID, reason string) (StreamingToolDiscardInfo, bool)
- func (e *StreamingToolExecutor) DiscardExcept(valid map[string]struct{}, reason string) []PendingToolCall
- func (e *StreamingToolExecutor) DiscardExceptInfo(valid map[string]struct{}, reason string) []StreamingToolDiscardInfo
- func (e *StreamingToolExecutor) Promote(call message.ToolCall) (*ToolResultPayload, bool, bool)
- func (e *StreamingToolExecutor) SetTraceCallbacks(onStart func(callID, toolName string, at time.Time), ...)
- func (e *StreamingToolExecutor) Start(call message.ToolCall) bool
- type SubAgent
- func (s *SubAgent) CancelCurrentTurn() bool
- func (s *SubAgent) ContinueFromContext()
- func (s *SubAgent) Depth() int
- func (s *SubAgent) GetContextMessageCount() int
- func (s *SubAgent) GetContextStats() (current, limit int)
- func (s *SubAgent) GetMessages() []message.Message
- func (s *SubAgent) InjectUserMessage(content string)
- func (s *SubAgent) InjectUserMessageWithMailboxAck(content, mailboxAckID string)
- func (s *SubAgent) InjectUserMessageWithParts(parts []message.ContentPart)
- func (s *SubAgent) InvokedSkills() []*skill.Meta
- func (s *SubAgent) LastArtifact() tools.ArtifactRef
- func (s *SubAgent) LastMailboxID() string
- func (s *SubAgent) LastReplyThread() (replyMessageID, replyToMailboxID, replyKind, replySummary string)
- func (s *SubAgent) LastSummary() string
- func (s *SubAgent) ListSkills() []*skill.Meta
- func (s *SubAgent) LoadSkill(name string) (*skill.Skill, error)
- func (s *SubAgent) MarkSkillInvoked(meta *skill.Meta)
- func (s *SubAgent) OwnerAgentID() string
- func (s *SubAgent) OwnerTaskID() string
- func (s *SubAgent) PendingCompleteIntent() *AgentResult
- func (s *SubAgent) RemoveLastMessage()
- func (s *SubAgent) RestoreMessages(msgs []message.Message)
- func (s *SubAgent) State() SubAgentState
- func (s *SubAgent) StateChangedAt() time.Time
- func (s *SubAgent) TryEnqueueContextAppend(msg message.Message) bool
- type SubAgentCloseRequestedPayload
- type SubAgentConfig
- type SubAgentInfo
- type SubAgentInspector
- type SubAgentMailboxAckRecord
- type SubAgentMailboxKind
- type SubAgentMailboxMessage
- type SubAgentMailboxPriority
- type SubAgentProgressUpdatedPayload
- type SubAgentSendMessagePayload
- type SubAgentState
- type SubAgentStateChangedPayload
- type SubAgentStopPayload
- type ThinkingStartedEvent
- type ToastEvent
- type TodosUpdatedEvent
- type ToolCallExecutionEvent
- type ToolCallExecutionState
- type ToolCallStartEvent
- type ToolCallUpdateEvent
- type ToolExecutionResult
- type ToolProgressEvent
- type ToolProgressSnapshot
- type ToolResultEvent
- type ToolResultPayload
- type ToolResultStatus
- type Turn
- type TurnCancelledPayload
- type UsageReporter
- type UsageUpdatedEvent
Constants ¶
const ( EventUserMessage = "user_message" EventAppendContext = "append_context" // append user message to ctx without calling LLM (e.g. !shell output) EventLLMResponse = "llm_response" EventToolResult = "tool_result" EventTurnCancelled = "turn_cancelled" EventAgentError = "agent_error" EventExecutePlan = "execute_plan" // Internal: execute a plan file after user selects target agent (payload: *executePlanPayload) EventSessionControl = "session_control" EventModelPoolSwitch = "model_pool_switch" EventMCPControl = "mcp_control" EventMCPControlDone = "mcp_control_done" EventPendingDraftUpsert = "pending_draft_upsert" EventPendingDraftRemove = "pending_draft_remove" // Multi-agent orchestration event types. EventAgentDone = "agent_done" // SubAgent completed its task EventAgentIdle = "agent_idle" // SubAgent idle timeout (no tool calls, no Complete) EventAgentNotify = "agent_notify" // SubAgent non-blocking notify update EventEscalate = "escalate" // SubAgent requests owner/MainAgent intervention EventSubAgentMailbox = "subagent_mailbox" // structured mailbox message from or about a SubAgent EventSubAgentStateChanged = "subagent_state_changed" EventSubAgentCloseRequested = "subagent_close_requested" EventSubAgentProgressUpdated = "subagent_progress_updated" EventSubAgentSendMessage = "subagent_send_message" EventSubAgentStop = "subagent_stop" EventAgentLog = "agent_log" // Informational log from SubAgent (e.g. buffer overflow warning) EventResetNudge = "reset_nudge" // SubAgent activity detected; reset idle nudge counter EventSpawnFinished = "background_object_finished" // Spawned background process finished; runtime-only notification EventContinue = "continue" // re-run LLM with existing context (no new user message) EventLoopAssessment = "loop_assessment" // internal loop-controller decision point after a completed assistant round // Durable compaction (async worker); payloads are *compactionDraft / error. EventCompactionReady = "compaction_ready" EventCompactionFailed = "compaction_failed" EventCompactionOversizeSuspend = "compaction_oversize_suspend" // LLM call suspended due to oversize while compaction running )
Internal event types used by the MainAgent event loop.
const DefaultIdleTimeout = 120 * time.Second
DefaultIdleTimeout is the default duration before a SubAgent is considered idle after receiving a pure-text LLM response.
Variables ¶
var ErrAgentShutdown = fmt.Errorf("agent is shutting down")
ErrAgentShutdown is returned when the agent is shutting down and can no longer process interactive requests.
Functions ¶
func AdvancePastID ¶
func AdvancePastID(id string)
AdvancePastID parses the numeric suffix from an instance ID (e.g. "builder-3") and advances the global agentSeq so that future calls to NextInstanceID never collide with restored IDs.
func IsContextLengthExceededPendingCompaction ¶
IsContextLengthExceededPendingCompaction reports whether err is a context-length-exceeded error that should be suspended pending compaction.
func NextInstanceID ¶
NextInstanceID returns a unique identifier for an agent instance. The name is derived from the agent type (e.g. "builder-1", "explorer-2"). It is safe to call from any goroutine.
func RebuildTouchedPathsFromMessages ¶
RebuildTouchedPathsFromMessages reconstructs the session-scoped touched-file set from persisted tool history. Successful Write/Edit add files; successful Delete removes files. Read-only tools are ignored.
Types ¶
type ActivityObserver ¶
type ActivityObserver interface {
// OnAgentActivity is called when an agent's activity type changes.
// agentID is "main" for the main agent, or the instance ID for subagents.
OnAgentActivity(agentID string, activity ActivityType)
}
ActivityObserver receives notifications when agent activity changes. The observer is called synchronously from the event emission path, so implementations should be non-blocking or spawn their own goroutines.
type ActivityType ¶
type ActivityType string
ActivityType represents the specific technical state of an agent's LLM or tool loop.
const ( ActivityIdle ActivityType = "idle" ActivityConnecting ActivityType = "connecting" ActivityWaitingHeaders ActivityType = "waiting_headers" ActivityWaitingToken ActivityType = "waiting_token" ActivityStreaming ActivityType = "streaming" ActivityExecuting ActivityType = "executing" ActivityCompacting ActivityType = "compacting" ActivityRetrying ActivityType = "retrying" ActivityRetryingKey ActivityType = "retrying_key" ActivityCooling ActivityType = "cooling" ActivityVerifying ActivityType = "verifying" )
type AgentActivityEvent ¶
type AgentActivityEvent struct {
AgentID string
Type ActivityType
Detail string // e.g. "3 tools", "retry 2/6", "cooldown 5s"
}
AgentActivityEvent is emitted to the TUI to show real-time progress.
type AgentContextUsage ¶
type AgentContextUsage struct {
AgentID string
ContextCurrent int
ContextLimit int
ContextMessageCount int
}
AgentContextUsage holds context stats for one agent (main or sub) for sidebar display.
type AgentDoneEvent ¶
type AgentDoneEvent struct {
AgentID string // instance ID (e.g. "agent-1")
TaskID string // plan task ID (e.g. "3") or ad-hoc ID (e.g. "adhoc-1")
Summary string // completion summary from Complete tool
}
AgentDoneEvent signals that a SubAgent has completed its task. Emitted to TUI so it can update the sidebar and optionally switch focus.
type AgentEvent ¶
type AgentEvent interface {
// contains filtered or unexported methods
}
AgentEvent is the sealed interface for events emitted to the TUI layer.
type AgentForTUI ¶
type AgentForTUI interface {
Events() <-chan AgentEvent
GetMessages() []message.Message
StartupResumeStatus() (pending bool, sessionID string)
// ProjectRoot returns the runtime project root directory.
ProjectRoot() string
// InvokedSkills returns skills explicitly loaded via the Skill tool in the current session.
InvokedSkills() []*skill.Meta
// GetTodos returns the current todo list for sidebar display.
GetTodos() []tools.TodoItem
MessageSender
PromptResolver
ModelSelector
SessionController
SubAgentInspector
LoopController
RoleController
UsageReporter
KeyHealthReporter
CompactionController
PlanExecutor
}
AgentForTUI is the full interface required by the TUI. It is implemented by the local MainAgent and by remote client adapters used in C/S mode. New code that consumes only a slice of this surface should target the smaller sub-interfaces (MessageSender, ModelSelector, …) instead.
type AgentResult ¶
type AgentResult struct {
Summary string
Envelope *CompletionEnvelope
Error error
}
AgentResult is the completion payload sent via EventAgentDone when a SubAgent finishes its task (or fails).
type AgentStatusEvent ¶
type AgentStatusEvent struct {
AgentID string // instance ID (e.g. "agent-1")
Status string // e.g. "running", "idle", "error", "done"
Message string // human-readable detail
}
AgentStatusEvent carries a SubAgent status update for the TUI sidebar. Used to reflect agent lifecycle changes (running, idle, error, etc.).
type ArtifactRef ¶ added in v0.2.0
type ArtifactRef = tools.ArtifactRef
type AssistantMessageEvent ¶
type AssistantMessageEvent struct {
AgentID string // originating agent ("" = main agent)
Text string // assistant text content (may be empty if only tool calls)
ToolCalls int // number of tool calls in this response
}
AssistantMessageEvent is emitted when a finalized assistant message has been appended to the conversation context. This is the stable, post-streaming representation — no rollback or retry will change it.
Consumers that need "what the assistant just said" should use this event rather than watching StreamTextEvent deltas or waiting for IdleEvent.
type CompactionController ¶ added in v0.2.0
type CompactionController interface {
// IsCompactionRunning reports whether a compaction goroutine is in flight.
IsCompactionRunning() bool
// CancelCompaction cancels an in-flight compaction. Returns true if there
// was a running compaction to cancel.
CancelCompaction() bool
}
CompactionController exposes durable compaction state for the status bar.
type CompactionStatusEvent ¶
CompactionStatusEvent drives the TUI background compaction slot precisely. Status is one of: "started", "succeeded", "failed", "cancelled". Bytes/Events are optional and currently reserved for future dedicated compaction-progress wiring.
type CompletionEnvelope ¶
type CompletionEnvelope struct {
Summary string `json:"summary,omitempty"`
FilesChanged []string `json:"files_changed,omitempty"`
VerificationRun []string `json:"verification_run,omitempty"`
RemainingLimitations []string `json:"remaining_limitations,omitempty"`
KnownRisks []string `json:"known_risks,omitempty"`
FollowUpRecommended []string `json:"follow_up_recommended,omitempty"`
Artifacts []tools.ArtifactRef `json:"artifacts,omitempty"`
}
type ConfirmFunc ¶
type ConfirmFunc func(ctx context.Context, toolName string, args string, needsApproval []string, alreadyAllowed []string) (ConfirmResponse, error)
ConfirmFunc is the callback the agent invokes when a tool call requires user confirmation (permission action "ask"). The TUI (or test harness) supplies the implementation.
- ctx: context for cancellation (e.g. turn cancelled while waiting)
- toolName: the name of the tool being invoked (e.g. "Shell")
- args: the raw JSON arguments string
- needsApproval: explicit paths covered by this approval prompt (Delete only)
- alreadyAllowed: explicit paths already allowed by rules in the same batch (Delete only)
- ConfirmResponse: approved decision plus the final args JSON chosen by the user
- err: non-nil if the confirmation flow itself fails
type ConfirmRequestEvent ¶
type ConfirmRequestEvent struct {
ToolName string
ArgsJSON string
RequestID string
Timeout time.Duration
NeedsApproval []string
AlreadyAllowed []string
}
ConfirmRequestEvent is sent to the TUI when a tool invocation requires user confirmation. The TUI shows the dialog and then calls ResolveConfirm on the agent with the user's choice.
type ConfirmResponse ¶
type ConfirmResponse struct {
Approved bool
FinalArgsJSON string
EditSummary string
DenyReason string
RuleIntent *ConfirmRuleIntent // nil = no new rule
}
ConfirmResponse carries the user's response to a ConfirmRequestEvent.
type ConfirmRuleIntent ¶
type ConfirmRuleIntent struct {
Pattern string
Scope int // 0=session, 1=project, 2=userGlobal (matches permission.RuleScope)
}
ConfirmRuleIntent captures the user's intent to add a permission rule.
type ContextUsageUpdateEvent ¶
type ContextUsageUpdateEvent struct{}
ContextUsageUpdateEvent is emitted by the remote client when it receives a context_usage envelope from the server. It does not carry data; the TUI should re-read GetContextStats/GetUsageStats to refresh the sidebar. Used only in C/S mode so the sidebar updates after Idle.
type DurableTaskRecord ¶
type DurableTaskRecord struct {
TaskID string `json:"task_id"`
AgentDefName string `json:"agent_def_name,omitempty"`
TaskDesc string `json:"task_desc,omitempty"`
PlanTaskRef string `json:"plan_task_ref,omitempty"`
SemanticTaskKey string `json:"semantic_task_key,omitempty"`
ExpectedWriteScope tools.WriteScope `json:"expected_write_scope,omitempty"`
OwnerAgentID string `json:"owner_agent_id,omitempty"`
OwnerTaskID string `json:"owner_task_id,omitempty"`
Depth int `json:"depth,omitempty"`
JoinToOwner bool `json:"join_to_owner,omitempty"`
State string `json:"state,omitempty"`
ResumePolicy string `json:"resume_policy,omitempty"`
LatestInstanceID string `json:"latest_instance_id,omitempty"`
InstanceHistory []string `json:"instance_history,omitempty"`
LastSummary string `json:"last_summary,omitempty"`
LastMailboxID string `json:"last_mailbox_id,omitempty"`
LastReplyMessageID string `json:"last_reply_message_id,omitempty"`
LastReplyToMailboxID string `json:"last_reply_to_mailbox_id,omitempty"`
LastReplyKind string `json:"last_reply_kind,omitempty"`
LastReplySummary string `json:"last_reply_summary,omitempty"`
LastArtifactRefs []tools.ArtifactRef `json:"last_artifact_refs,omitempty"`
LastCompletion *CompletionEnvelope `json:"last_completion,omitempty"`
SuspectedStallReason string `json:"suspected_stall_reason,omitempty"`
CreatedTurn uint64 `json:"created_turn,omitempty"`
LastUpdatedTurn uint64 `json:"last_updated_turn,omitempty"`
CreatedAt time.Time `json:"created_at,omitempty"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
ClosedReason string `json:"closed_reason,omitempty"`
}
type EnvStatusUpdateEvent ¶
type EnvStatusUpdateEvent struct{}
EnvStatusUpdateEvent signals that background environment state changed (currently MCP connectivity), so the TUI should re-read state providers.
type ErrorEvent ¶
ErrorEvent carries an error that occurred during the agent loop.
type Event ¶
type Event struct {
Type string
TurnID uint64
Payload any
Seq uint64
SourceID string // identifies which agent sent the event (e.g. "main", "agent-1")
}
Event is an internal event in the MainAgent event loop.
type ForkSessionEvent ¶
type ForkSessionEvent struct {
Parts []message.ContentPart
}
ForkSessionEvent is emitted after a fork (ee chord) operation completes. Parts holds the content of the forked message so the TUI can load it into the composer for editing.
type HandoffEvent ¶
type HandoffEvent struct {
PlanPath string
}
HandoffEvent signals that plan generation has finished. The TUI prompts the user to select a target agent for execution (default: builder).
type HandoffResult ¶
type HandoffResult struct {
PlanPath string
}
HandoffResult wraps the data from a Handoff tool invocation.
type IdleEvent ¶
type IdleEvent struct{}
IdleEvent signals that the agent has finished processing and is waiting for new user input.
type InfoEvent ¶
InfoEvent carries an informational message for display in the TUI. Used for non-error status messages (e.g. export/resume success).
type KeyHealthReporter ¶ added in v0.2.0
type KeyHealthReporter interface {
// KeyStats returns (available, total) API keys for the focused agent's provider.
KeyStats() (available, total int)
// CurrentRateLimitSnapshot returns the latest rate-limit snapshot for the active key, or nil.
CurrentRateLimitSnapshot() *ratelimit.KeyRateLimitSnapshot
ProxyInUseForRef(ref string) bool
}
KeyHealthReporter exposes provider key/rate-limit/proxy state for the right info panel.
type KeyPoolChangedEvent ¶
type KeyPoolChangedEvent struct{}
KeyPoolChangedEvent signals that API key availability (cooldown / selection) changed; the TUI should re-read KeyStats and schedule key-pool ticks.
type LLMResponsePayload ¶
type LLMResponsePayload struct {
Content string
ThinkingBlocks []message.ThinkingBlock
ToolCalls []message.ToolCall
StopReason string
ThinkingToolcallMarkerHit bool
ReasoningContent string // full reasoning text when marker hit
Usage *message.TokenUsage // token usage for this round; nil when the provider did not return usage; persisted with the assistant message for session resume
}
LLMResponsePayload wraps an LLM response for the internal event bus.
type LSPServerDisplay ¶
type LSPServerDisplay struct {
Name string
OK bool
Pending bool // not connected yet (lazy start)
Err string
Errors int
Warnings int
}
LSPServerDisplay is one row in the ENVIRONMENT / LSP sidebar block.
type LSPStateProvider ¶
type LSPStateProvider interface {
// LSPServerList returns configured language servers; nil/empty hides the LSP block.
LSPServerList() []LSPServerDisplay
}
LSPStateProvider is an optional interface for agents that can expose per-file last-review LSP diagnostics (Write/Edit target file only, excluding related files) to the TUI info panel.
type LoopAssessment ¶
type LoopAssessment struct {
Action LoopAssessmentAction
Message string
Reasons []string
}
type LoopAssessmentAction ¶
type LoopAssessmentAction string
const ( LoopAssessmentActionNone LoopAssessmentAction = "none" LoopAssessmentActionContinue LoopAssessmentAction = "continue_from_context" LoopAssessmentActionVerify LoopAssessmentAction = "verify" LoopAssessmentActionCompleted LoopAssessmentAction = "completed" LoopAssessmentActionBlocked LoopAssessmentAction = "blocked" LoopAssessmentActionBudgetExhausted LoopAssessmentAction = "budget_exhausted" )
type LoopContinuationNote ¶
type LoopController ¶ added in v0.2.0
type LoopController interface {
// LoopKeepsMainBusy reports whether the local MainAgent remains in a
// non-terminal loop state even if no turn is currently active.
LoopKeepsMainBusy() bool
// CurrentLoopState returns the current loop-controller state for the main
// agent, or empty string when loop mode is disabled / unsupported.
CurrentLoopState() LoopState
CurrentLoopTarget() string
CurrentLoopIteration() int
CurrentLoopMaxIterations() int
EnableLoopMode(target string)
DisableLoopMode()
}
LoopController exposes the post-assistant loop-mode runtime state.
type LoopNoticeEvent ¶
LoopNoticeEvent displays the loop continuation/control note that is also sent to the model for the next continued request.
type LoopState ¶
type LoopState string
const ( LoopStateIdle LoopState = "idle" LoopStateExecuting LoopState = "executing" LoopStateVerifying LoopState = "verifying" LoopStateAssessing LoopState = "assessing" LoopStateCompleted LoopState = "completed" LoopStateBlocked LoopState = "blocked" LoopStateBudgetExhausted LoopState = "budget_exhausted" )
type LoopStateChangedEvent ¶
type LoopStateChangedEvent struct{}
LoopStateChangedEvent notifies the TUI that loop-controller state changed and any loop-dependent pills/activity text should refresh immediately.
type MCPControlAction ¶ added in v0.5.1
type MCPControlAction string
const ( MCPControlEnable MCPControlAction = "enable" MCPControlDisable MCPControlAction = "disable" )
type MCPControlRequest ¶ added in v0.5.1
type MCPControlRequest struct {
Action MCPControlAction
Servers []string
}
MCPControlRequest describes a runtime MCP enable/disable operation. Servers may contain one or more server names. If Servers is empty, the operation applies to all configured servers.
type MCPControlResult ¶ added in v0.5.1
MCPControlResult carries the post-operation MCP tool set and the prompt block describing connected servers.
type MCPSelectEvent ¶ added in v0.5.1
type MCPSelectEvent struct{}
MCPSelectEvent signals the TUI to open the MCP server selector overlay. Emitted in response to /mcp with no arguments.
type MCPServerDisplay ¶
type MCPServerDisplay struct {
Name string
OK bool
Pending bool // not connected yet (async startup)
Disabled bool // explicitly disabled (manual /mcp disable)
Manual bool // configured as manual/on-demand; only manual servers can be changed with /mcp
Retrying bool // transient failure, retry still in progress
Attempt int
MaxAttempts int
Err string
}
MCPServerDisplay is one row in the TUI MCP sidebar.
type MCPStateProvider ¶
type MCPStateProvider interface {
// MCPServerList returns every configured MCP with connection outcome.
MCPServerList() []MCPServerDisplay
}
MCPStateProvider is implemented by agents that can expose MCP server status.
type MainAgent ¶
type MainAgent struct {
// contains filtered or unexported fields
}
MainAgent orchestrates the LLM ↔ Tool loop. It owns an internal event bus (eventCh) for sequencing work and an output channel (outputCh) that the TUI consumes.
func NewMainAgent ¶
func NewMainAgent( ctx context.Context, llmClient *llm.Client, ctxMgr *ctxmgr.Manager, toolRegistry *tools.Registry, hookEngine hook.Manager, sessionDir string, modelName string, projectRoot string, globalCfg *config.Config, projectCfg *config.Config, mcpClientInfo mcp.ClientInfo, ) *MainAgent
NewMainAgent creates a fully-initialised MainAgent. The caller must invoke Run in a separate goroutine to start the event loop.
projectRoot is the root directory of the project (typically cwd) and is used to load AGENTS.md and determine git repository status for the system prompt.
globalCfg is the user-level config (~/.config/chord/config.yaml). projectCfg is the project-level config (.chord/config.yaml); either may be nil.
func (*MainAgent) AddedOverlayRules ¶
func (a *MainAgent) AddedOverlayRules() []permission.AddedRule
AddedOverlayRules returns rules added from the confirm rule picker in this session.
func (*MainAgent) AgentOverridePoolName ¶ added in v0.3.0
func (*MainAgent) AppendContextMessage ¶
AppendContextMessage appends a user-role message to the focused agent's conversation context without invoking the LLM (e.g. TUI !shell output).
func (*MainAgent) ApplyInitialModel ¶
ApplyInitialModel applies the given model (e.g. from config or recovery) without showing a "Switched model" toast. Used at startup.
func (*MainAgent) AskQuestions ¶
func (a *MainAgent) AskQuestions(ctx context.Context, questions []tools.QuestionItem, timeout time.Duration) ([]tools.QuestionAnswer, error)
AskQuestions emits question request events one at a time, waits for each answer, and returns the collected responses in tool-compatible form.
func (*MainAgent) AvailableAgents ¶
AvailableAgents returns the names of agent roles available for Handoff selection. Only main-mode agents are eligible, and the current active role is excluded so planner cannot hand off to itself. builder remains the default when available so the selector always offers an execution agent. Non-builder roles are sorted alphabetically for deterministic selection order.
func (*MainAgent) AvailableRoles ¶
AvailableRoles returns the ordered list of roles the user can cycle through. Only main-mode agents are included; subagent-only configs are excluded. builder is always first; planner second (if present); custom roles after that are sorted alphabetically for deterministic Tab cycling.
func (*MainAgent) AvailableSubAgents ¶
func (*MainAgent) AwaitConfirm ¶
func (a *MainAgent) AwaitConfirm(ctx context.Context, toolName, argsJSON string, timeout time.Duration, needsApproval []string, alreadyAllowed []string) (ConfirmResponse, error)
AwaitConfirm emits a confirmation request event, waits for the user's reply, and returns the resolved response. Only one confirm flow may be active at a time because the TUI supports a single modal dialog.
func (*MainAgent) CancelCompaction ¶
CancelCompaction cancels the in-flight compaction goroutine. Returns true if there was a running compaction to cancel.
func (*MainAgent) CancelCurrentTurn ¶
CancelCurrentTurn cancels the agent's active turn (if any), aborting any in-flight LLM call or tool execution. It is safe to call from any goroutine (typically the TUI's Ctrl+C handler). Returns true if a turn was active and cancelled, false if the agent was already idle.
If the turn had pending tool calls, synthetic terminal tool-result messages are appended when the cancellation event is handled so the conversation and persisted session keep a matching output for each tool call.
func (*MainAgent) CancelSubAgent ¶
func (*MainAgent) ClearPendingInteractions ¶
func (a *MainAgent) ClearPendingInteractions()
ClearPendingInteractions removes requestID mappings for any in-flight confirm/question requests. It does not close the per-request channels; any waiters are expected to exit via ctx cancellation or stoppingCh during shutdown.
func (*MainAgent) ContinueFromContext ¶
func (a *MainAgent) ContinueFromContext()
ContinueFromContext re-runs the LLM with the existing context without appending a new user message. Routes to the focused SubAgent if active.
func (*MainAgent) CreateSubAgent ¶
func (a *MainAgent) CreateSubAgent(ctx context.Context, description, agentType string, planTaskRef, semanticTaskKey string, expectedWriteScope tools.WriteScope) (tools.TaskHandle, error)
func (*MainAgent) CurrentLoopIteration ¶
func (*MainAgent) CurrentLoopMaxIterations ¶
func (*MainAgent) CurrentLoopState ¶
func (*MainAgent) CurrentLoopTarget ¶
func (*MainAgent) CurrentPoolName ¶ added in v0.3.0
CurrentPoolName returns the effective pool name for the agent currently shown in the TUI (focused SubAgent if any, else current main role), or "" if no pool policy is configured.
func (*MainAgent) CurrentRateLimitSnapshot ¶
func (a *MainAgent) CurrentRateLimitSnapshot() *ratelimit.KeyRateLimitSnapshot
CurrentRateLimitSnapshot returns the latest rate-limit snapshot for the active provider when that provider uses preset: codex. Otherwise it returns nil. Display precedence is:
- current provider-scoped inline snapshot cache (cleared on key switch)
- client-selected key inline snapshot
- provider/account-scoped polled usage snapshot
func (*MainAgent) CurrentRole ¶
CurrentRole returns the active role name. Goroutine-safe.
func (*MainAgent) CurrentRoleConfig ¶
func (a *MainAgent) CurrentRoleConfig() *config.AgentConfig
CurrentRoleConfig returns the active role configuration. The returned config must be treated as read-only by callers.
func (*MainAgent) CurrentRoleModelRefs ¶
CurrentRoleModelRefs returns the configured model chain for the active role. Entries preserve the original AgentConfig.Models strings, including any inline @variant suffixes. A nil/empty slice means "use global default model only". CurrentRoleModelRefs returns the effective model chain for the active role, resolved through the model pool policy. A nil/empty slice means "use global default model only" (auto mode).
func (*MainAgent) DeleteSession ¶
func (*MainAgent) DisableLoopMode ¶
func (a *MainAgent) DisableLoopMode()
func (*MainAgent) EnableLoopMode ¶
func (*MainAgent) Events ¶
func (a *MainAgent) Events() <-chan AgentEvent
Events returns a read-only channel of AgentEvents for the TUI to consume.
func (*MainAgent) ExecutePlan ¶
func (*MainAgent) ExportSession ¶
func (*MainAgent) FocusedAgentID ¶
FocusedAgentID returns the instance ID of the currently focused SubAgent, or "" if the main agent is focused.
func (*MainAgent) FocusedAgentName ¶ added in v0.3.0
FocusedAgentName returns the agent definition name of the currently focused SubAgent, or "" if the main agent is focused.
func (*MainAgent) ForkSession ¶
ForkSession queues a fork of the current session at msgIndex. The fork creates a new session seeded with messages[:msgIndex] as history; the message at msgIndex is returned via ForkSessionEvent so the TUI can load it into the composer.
func (*MainAgent) GetAllAgentsContextUsage ¶
func (a *MainAgent) GetAllAgentsContextUsage() []AgentContextUsage
func (*MainAgent) GetContextMessageCount ¶
GetContextMessageCount returns the number of messages in the focused agent's context (for sidebar).
func (*MainAgent) GetContextStats ¶
GetContextStats returns current context usage and limit for the focused agent. Current = input + output + cache + reasoning from last API response (all count toward context).
func (*MainAgent) GetMessages ¶
GetMessages returns a thread-safe snapshot of the focused agent's conversation history. Routes to the focused SubAgent if one is active.
func (*MainAgent) GetSessionSummary ¶
func (a *MainAgent) GetSessionSummary() *SessionSummary
func (*MainAgent) GetSidebarUsageStats ¶
func (a *MainAgent) GetSidebarUsageStats() analytics.SessionStats
GetSidebarUsageStats returns usage for the TUI-focused agent only (main or SubAgent), matching GetContextStats / GetTokenUsage routing.
func (*MainAgent) GetSubAgents ¶
func (a *MainAgent) GetSubAgents() []SubAgentInfo
GetSubAgents returns information about all active SubAgents for TUI sidebar display. Safe to call from any goroutine.
func (*MainAgent) GetTodos ¶
GetTodos returns a copy of the current todo list. It implements the tools.TodoStore interface.
func (*MainAgent) GetTokenUsage ¶
func (a *MainAgent) GetTokenUsage() message.TokenUsage
GetTokenUsage returns cumulative token usage statistics.
func (*MainAgent) GetUsageStats ¶
func (a *MainAgent) GetUsageStats() analytics.SessionStats
GetUsageStats returns session-wide usage statistics (all agents in the session).
func (*MainAgent) HasAvailableSubAgents ¶
func (*MainAgent) InvokedSkills ¶
func (*MainAgent) IsCompactionRunning ¶
IsCompactionRunning reports whether a compaction goroutine is currently in flight, or a draft is waiting to be applied at the continuation barrier. This is the public API for TUI to query compaction state.
func (*MainAgent) KeyPoolNextTransition ¶
KeyPoolNextTransition returns how soon the key pool sidebar line may need a refresh (cooldown expiry or Codex rate-limit window reset). Zero means no scheduled transition or single-key pool. Uses the same agent as KeyStats.
func (*MainAgent) KeyStats ¶
KeyStats returns (healthy, total) API keys for the focused agent's provider (SubAgent when focused, else MainAgent), aligned with RunningModelRef. healthy = selectable AND not recovering (re-proven healthy since last failure/reset).
func (*MainAgent) LSPServerList ¶
func (a *MainAgent) LSPServerList() []LSPServerDisplay
func (*MainAgent) ListSessionSummaries ¶
func (a *MainAgent) ListSessionSummaries() ([]SessionSummary, error)
func (*MainAgent) ListSkills ¶
func (*MainAgent) LoopKeepsMainBusy ¶
func (*MainAgent) MCPServerList ¶
func (a *MainAgent) MCPServerList() []MCPServerDisplay
func (*MainAgent) MainModelPoolName ¶ added in v0.5.1
func (*MainAgent) MainModelPoolNames ¶ added in v0.5.1
func (*MainAgent) MarkSkillInvoked ¶
func (*MainAgent) MarkSkillInvokedByName ¶
func (*MainAgent) MarkSkillsReady ¶
func (a *MainAgent) MarkSkillsReady()
func (*MainAgent) ModelPoolPolicy ¶ added in v0.3.0
func (a *MainAgent) ModelPoolPolicy() *RuntimeModelPoolPolicy
ModelPoolPolicy returns the current runtime model pool policy (read-only).
func (*MainAgent) ModelsStatusText ¶ added in v0.3.0
func (*MainAgent) NewSession ¶
func (a *MainAgent) NewSession()
func (*MainAgent) NotifyEnvStatusUpdated ¶
func (a *MainAgent) NotifyEnvStatusUpdated()
func (*MainAgent) NotifySubAgent ¶
func (*MainAgent) Overlay ¶
func (a *MainAgent) Overlay() *permission.Overlay
Overlay returns the overlay for external access (e.g., from TUI).
func (*MainAgent) PendingUserMessageCount ¶
PendingUserMessageCount returns the number of queued user messages waiting to be drained after the current turn ends.
func (*MainAgent) PrewarmModelPolicy ¶
PrewarmModelPolicy prepares the current main-agent model policy in the background so the first real LLM request doesn't pay the setup cost.
func (*MainAgent) ProjectRoot ¶
func (*MainAgent) ProviderModelRef ¶
ProviderModelRef returns the selected model reference string for unique identification. It may include an inline @variant suffix when the selected model was configured that way, which lets the TUI distinguish model presets that share the same base provider/model.
func (*MainAgent) ProxyInUseForRef ¶
ProxyInUseForRef reports whether the given provider/model ref uses a proxy. ref is "providerName/modelID"; if empty, the main agent's ProviderModelRef is used. Used by the TUI status bar to show a proxy indicator for the current (or focused) agent.
func (*MainAgent) QueuePendingUserDraft ¶
func (a *MainAgent) QueuePendingUserDraft(draftID string, parts []message.ContentPart) bool
QueuePendingUserDraft mirrors a busy local TUI draft into the agent's pending queue so it can be consumed in-turn or at the next idle drain.
func (*MainAgent) RegisterMainMCPServers ¶
RegisterMainMCPServers registers the main-agent's MCP server names as sentinels in mcpServerCache so that SubAgents never reconnect them. Called after the main-agent MCP servers are connected.
func (*MainAgent) ReloadAgentsMD ¶
ReloadAgentsMD reloads project AGENTS.md from disk and marks the startup gate (agentsMDReady) so ensureSessionBuilt can proceed. The content is consumed the next time ensureSessionBuilt rebuilds the session-context reminder (on session-head events). Mid-session edits to AGENTS.md are not picked up until the next /new, /resume, or equivalent reset; AGENTS.md is treated as a session-scope snapshot.
func (*MainAgent) RemoveLastMessage ¶
func (a *MainAgent) RemoveLastMessage()
RemoveLastMessage removes the last message from context and rewrites the persistence log. Routes to the focused SubAgent if active. Only valid when the agent is idle.
func (*MainAgent) RemoveOverlayAddedRule ¶
RemoveOverlayAddedRule removes one picker-added rule and refreshes merged ruleset.
func (*MainAgent) RemovePendingUserDraft ¶
RemovePendingUserDraft removes a queued draft before it is consumed.
func (*MainAgent) ResetMCPReady ¶ added in v0.5.1
func (a *MainAgent) ResetMCPReady()
ResetMCPReady creates a new MCP readiness channel. It is used when MCP startup or runtime control begins so the next request blocks until the new tool surface is ready.
func (*MainAgent) ResolveConfirm ¶
func (a *MainAgent) ResolveConfirm(action, finalArgsJSON, editSummary, denyReason, requestID string)
ResolveConfirm sends the user's confirmation response back to the waiting ConfirmFunc goroutine via the requestID→channel map. Only acquires confirmMapMu (never confirmFlowMu) to avoid deadlock.
func (*MainAgent) ResolveConfirmWithRuleIntent ¶
func (a *MainAgent) ResolveConfirmWithRuleIntent(action, finalArgsJSON, editSummary, denyReason, requestID string, ruleIntent *ConfirmRuleIntent)
ResolveConfirmWithRuleIntent sends the confirmation response with an optional rule intent for adding a permission overlay rule.
func (*MainAgent) ResolveQuestion ¶
ResolveQuestion sends the user's question response back to the waiting QuestionFunc goroutine via the requestID→channel map. Only acquires questionMapMu (never questionFlowMu) to avoid deadlock.
func (*MainAgent) RestoreSessionAtStartup ¶
RestoreSessionAtStartup preloads the current session directory before the event loop starts, so the first on_session_start hook and all new writes target the resumed session directly.
func (*MainAgent) ResumeSession ¶
func (a *MainAgent) ResumeSession()
func (*MainAgent) ResumeSessionID ¶
func (*MainAgent) Run ¶
Run starts the blocking event loop. It returns when ctx is cancelled, the agent's parent context is cancelled, or an unrecoverable error occurs. The caller should run this in a dedicated goroutine:
go agent.Run(ctx)
func (*MainAgent) RunningModelRef ¶
RunningModelRef returns the effective provider/model for the TUI sidebar (focused SubAgent if any, else MainAgent). It may differ from ProviderModelRef() while fallback is in effect on that agent's client.
func (*MainAgent) RunningVariant ¶
RunningVariant returns the active variant name for the running model (focused SubAgent if any, else MainAgent), or empty string if none.
func (*MainAgent) SendAgentEvent ¶
SendAgentEvent maps tool event type strings to internal event constants and forwards the event through the event bus. It implements the tools.EventSender interface.
func (*MainAgent) SendUserMessage ¶
SendUserMessage enqueues a user message for processing. It is safe to call from any goroutine (typically the TUI input handler).
If a SubAgent is currently focused (via Tab), the message is routed directly to that SubAgent instead of the MainAgent's event loop. Local-only slash commands (/export, /models) bypass SubAgent routing because they belong to the main agent — they're sent to the main event loop unchanged.
func (*MainAgent) SendUserMessageWithParts ¶
func (a *MainAgent) SendUserMessageWithParts(parts []message.ContentPart)
SendUserMessageWithParts enqueues a multi-part user message (text + images).
func (*MainAgent) SessionID ¶
SessionID returns the unique session identifier for this agent instance. Used by the C/S server to scope event subscriptions. Goroutine-safe.
func (*MainAgent) SetActivityObserver ¶
func (a *MainAgent) SetActivityObserver(obs ActivityObserver)
SetActivityObserver registers an observer for activity events. Only one observer can be registered at a time; setting a new one replaces the previous. Pass nil to remove the observer.
func (*MainAgent) SetAgentConfigs ¶
func (a *MainAgent) SetAgentConfigs(configs map[string]*config.AgentConfig)
SetAgentConfigs stores the pre-resolved agent configurations (built-in → global → project merged). If the current active role is present in configs, it is preserved; otherwise the active role defaults to "builder". The permission ruleset is rebuilt accordingly.
Call this after NewMainAgent and before Run.
func (*MainAgent) SetAgentModelPool ¶ added in v0.3.0
func (*MainAgent) SetConfirmFunc ¶
func (a *MainAgent) SetConfirmFunc(fn ConfirmFunc)
SetConfirmFunc sets the callback used when a tool invocation requires user confirmation (permission action "ask"). This must be called before Run when the active ruleset can yield ActionAsk.
func (*MainAgent) SetCurrentModelPool ¶ added in v0.5.1
func (*MainAgent) SetCustomCommands ¶
func (a *MainAgent) SetCustomCommands(defs []*command.Definition)
func (*MainAgent) SetLLMFactory ¶
func (*MainAgent) SetLSPSessionFuncs ¶
func (*MainAgent) SetLSPStatusFunc ¶
func (a *MainAgent) SetLSPStatusFunc(serverList func() []LSPServerDisplay)
func (*MainAgent) SetMCPControlFunc ¶ added in v0.5.1
func (a *MainAgent) SetMCPControlFunc(fn func(context.Context, MCPControlRequest) (MCPControlResult, error))
SetMCPControlFunc installs the runtime callback used to connect/disconnect MCP servers. The callback runs in a background goroutine; results are applied on the agent event loop.
func (*MainAgent) SetMCPServerEnabled ¶ added in v0.5.1
SetMCPServerEnabled requests enabling/disabling an MCP server. It is safe to call from any goroutine.
func (*MainAgent) SetMCPServersPromptBlock ¶
SetMCPServersPromptBlock sets the MCP section appended to the system prompt and refreshes the installed system prompt on the LLM client and context manager.
func (*MainAgent) SetMCPStatusFunc ¶
func (a *MainAgent) SetMCPStatusFunc(serverList func() []MCPServerDisplay)
func (*MainAgent) SetModelPoolPolicy ¶ added in v0.3.0
func (a *MainAgent) SetModelPoolPolicy(policy *RuntimeModelPoolPolicy, statePath string)
SetModelPoolPolicy installs the runtime model pool policy. Must be called before Run. statePath is the per-project file for persisting pool selections.
func (*MainAgent) SetModelSwitchFactory ¶
func (a *MainAgent) SetModelSwitchFactory(fn func(providerModel string) (*llm.Client, string, int, error))
SetModelSwitchFactory sets the factory used by SwitchModel to create a new LLM client from a "provider/model" reference string. Must be called before Run. The factory returns (client, displayModelName, contextLimit, error).
func (*MainAgent) SetPendingMCPDiscovery ¶
func (*MainAgent) SetProviderModelRef ¶
SetProviderModelRef sets the initial selected model reference for the agent. The ref is usually "provider/model" and may optionally include an inline @variant suffix. Called from startup/model-switch wiring after construction.
func (*MainAgent) SetSessionArtifactsDirFunc ¶
SetSessionArtifactsDirFunc installs a callback that returns the active session artifacts directory. When unset, exports fall back to the historical project-level path.
func (*MainAgent) SetSessionLock ¶
func (a *MainAgent) SetSessionLock(lock *recovery.SessionLock)
SetSessionLock installs the ownership lock handle for the currently active session.
func (*MainAgent) SetSessionTargetChangedFunc ¶
SetSessionTargetChangedFunc installs a callback invoked after the active session directory changes.
func (*MainAgent) SetUsageEventSink ¶
func (a *MainAgent) SetUsageEventSink(fn func(event analytics.UsageEvent))
func (*MainAgent) Shutdown ¶
Shutdown cancels any in-flight work and waits for the event loop to exit (up to the given timeout). The caller should cancel the context passed to Run as well.
func (*MainAgent) StartupResumeStatus ¶
func (*MainAgent) SwapLLMClient ¶
SwapLLMClient atomically replaces the MainAgent's LLM client, model name, and context manager token budget. Thread-safe: called from the TUI goroutine while the event loop may be reading llmClient.
func (*MainAgent) SwitchFocus ¶
func (*MainAgent) SwitchModel ¶
SwitchModel switches the MainAgent to a different model at runtime. It is kept for internal tests and pool-driven client rebuilds; user-facing commands should switch pools via /models rather than choosing provider/model refs directly.
func (*MainAgent) SwitchRole ¶
SwitchRole switches the MainAgent to the named role and emits RoleChangedEvent. Goroutine-safe (posts to eventCh).
func (*MainAgent) UpdatePendingUserDraft ¶
func (a *MainAgent) UpdatePendingUserDraft(draftID string, parts []message.ContentPart) bool
UpdatePendingUserDraft replaces a queued draft before it is consumed.
func (*MainAgent) UpdateTodos ¶
UpdateTodos replaces the todo list and saves a snapshot via the recovery manager. It implements the tools.TodoStore interface.
func (*MainAgent) WakeCodexRateLimitPolling ¶ added in v0.3.0
func (a *MainAgent) WakeCodexRateLimitPolling()
WakeCodexRateLimitPolling triggers an on-demand /wham/usage poll for the currently focused agent's provider, when configured with preset: codex. It is a best-effort hint used by the TUI when a reset timestamp is reached.
type MessageSender ¶ added in v0.2.0
type MessageSender interface {
SendUserMessage(content string)
// SendUserMessageWithParts sends a user message that may include images.
SendUserMessageWithParts(parts []message.ContentPart)
// AppendContextMessage appends a user message to the model context without
// invoking the LLM. Content may differ from Parts when persistence needs a
// machine-readable form but the live context should stay human-readable.
AppendContextMessage(msg message.Message)
CancelCurrentTurn() bool
// QueuePendingUserDraft mirrors a busy local draft into the agent's pending
// queue so it can be consumed later without showing in the transcript early.
QueuePendingUserDraft(draftID string, parts []message.ContentPart) bool
// UpdatePendingUserDraft replaces a queued draft before it is consumed.
UpdatePendingUserDraft(draftID string, parts []message.ContentPart) bool
// RemovePendingUserDraft removes a queued draft before it is consumed.
RemovePendingUserDraft(draftID string) bool
// ContinueFromContext re-runs the LLM using the existing context without
// appending a new user message. Routes to focused SubAgent if one is active.
ContinueFromContext()
// RemoveLastMessage removes the last message from context and rewrites
// persistence. Used before ContinueFromContext when last message is a
// thinking-only assistant block that was interrupted.
RemoveLastMessage()
}
MessageSender covers user-message submission, queued drafts, and turn continuation. Implemented by MainAgent and remote-client adapters.
type ModelOption ¶
type ModelOption struct {
ProviderModel string // e.g. "anthropic-main/claude-opus-4.7" or "anthropic-main/claude-opus-4.7@high"
ProviderName string // e.g. "anthropic-main"
ModelID string // e.g. "claude-opus-4.7"
ContextLimit int
OutputLimit int
}
ModelOption describes a model available for runtime switching.
type ModelPoolSelectorTarget ¶ added in v0.3.0
type ModelPoolSelectorTarget struct {
Kind ModelPoolSelectorTargetKind `json:"kind"`
AgentName string `json:"agent_name,omitempty"`
}
ModelPoolSelectorTarget describes the explicit target edited by the model-pool selector. Current-view selection follows the active TUI focus (main role or focused SubAgent). Main role selection changes the current project-scoped model pool. Agent override selection changes the named agent's explicit fixed pool and may also offer a restore-default action.
type ModelPoolSelectorTargetKind ¶ added in v0.3.0
type ModelPoolSelectorTargetKind string
ModelPoolSelectorTargetKind identifies which runtime model-pool setting the TUI selector should edit.
const ( ModelPoolSelectorTargetCurrentView ModelPoolSelectorTargetKind = "current_view" ModelPoolSelectorTargetMainRole ModelPoolSelectorTargetKind = "main_role" ModelPoolSelectorTargetAgentOverride ModelPoolSelectorTargetKind = "agent_override" )
type ModelSelectEvent ¶
type ModelSelectEvent struct {
Target ModelPoolSelectorTarget
}
ModelSelectEvent signals the TUI to open the model pool selector overlay. Emitted in response to /models for the current view.
type ModelSelector ¶ added in v0.2.0
type ModelSelector interface {
ProviderModelRef() string
RunningModelRef() string
RunningVariant() string
// CurrentPoolName returns the effective pool name for the agent currently shown
// in the TUI (focused SubAgent if any, else current main role), or "" if no pool
// policy is configured.
CurrentPoolName() string
// PoolNames returns the pool names for the agent currently shown in the TUI.
PoolNames() []string
// MainModelPoolName returns the effective pool name for the current main
// role regardless of focused SubAgent state.
MainModelPoolName() string
// MainModelPoolNames returns the pool names for the current main role regardless
// of focused SubAgent state.
MainModelPoolNames() []string
// AgentOverridePoolName returns the explicit override for the named agent, if any.
AgentOverridePoolName(agentName string) (string, bool)
// SetCurrentModelPool sets the current main model pool.
SetCurrentModelPool(pool string) error
// SetAgentModelPool sets the named agent's pool.
SetAgentModelPool(agentName, pool string) error
}
ModelSelector exposes model identity for the status bar and model pool controls.
type PendingDraftConsumedEvent ¶
type PendingDraftConsumedEvent struct {
DraftID string
Parts []message.ContentPart
AgentID string // "" = main agent
}
PendingDraftConsumedEvent signals that a queued draft was actually appended to the conversation context and is now part of the transcript.
type PendingToolCall ¶
type PendingToolCall struct {
CallID string
Name string
ArgsJSON string
AgentID string
Audit *message.ToolArgsAudit
}
PendingToolCall records the minimal metadata needed to close a pending tool card when a turn is cancelled before a normal ToolResultEvent arrives.
type PlanExecutor ¶ added in v0.2.0
type PlanExecutor interface {
// ExecutePlan triggers execution of a plan with the specified target agent.
// agentName may be empty (defaults to "builder").
ExecutePlan(planPath, agentName string)
}
PlanExecutor triggers plan-execution workflows.
type PromptResolver ¶ added in v0.2.0
type PromptResolver interface {
// ResolveConfirm sends the user's confirmation response back to the pending
// confirm flow.
ResolveConfirm(action, finalArgsJSON, editSummary, denyReason, requestID string)
// ResolveQuestion sends the user's question response back to the pending
// question flow.
ResolveQuestion(answers []string, cancelled bool, requestID string)
}
PromptResolver delivers user responses for confirm/question dialogs back to the agent's pending interaction flow.
type QuestionRequestEvent ¶
type QuestionRequestEvent struct {
ToolName string
Header string
Question string
Options []string
OptionDetails []string
DefaultAnswer string
Multiple bool
RequestID string
Timeout time.Duration
}
QuestionRequestEvent is sent to the TUI when the agent asks a structured question. The TUI shows the dialog and then calls ResolveQuestion.
type QuestionResponse ¶
QuestionResponse carries the user's response to a QuestionRequestEvent.
type RateLimitUpdatedEvent ¶
type RateLimitUpdatedEvent struct {
Snapshot *ratelimit.KeyRateLimitSnapshot
}
RateLimitUpdatedEvent is emitted when a new rate-limit snapshot is available for the current API key. The TUI should re-read CurrentRateLimitSnapshot.
type RequestCycleStartedEvent ¶
RequestCycleStartedEvent signals that the runtime has started a new main request cycle. TUI should reset request-scoped display progress immediately; subsequent transport progress belongs to the new cycle.
type RequestProgressEvent ¶
RequestProgressEvent reports cumulative visible response progress for the currently active request of an agent. Bytes are cumulative received bytes for visible response payload/status metadata tracked by the agent; Events counts visible stream/status events received so far. Zero values mean "no known visible progress yet".
type RoleChangedEvent ¶
type RoleChangedEvent struct {
Role string // new active role name (e.g. "planner", "builder")
}
RoleChangedEvent signals that the MainAgent's active role has changed. The TUI uses this to update the role pill in the status bar.
type RoleController ¶ added in v0.2.0
type RoleController interface {
// SwitchRole requests the agent to switch its active role.
// In embedded mode this calls switchRole directly; in C/S mode it sends
// TypeSwitchRole to the server. The new role is broadcast as RoleChangedEvent.
SwitchRole(role string)
// AvailableRoles returns the ordered list of role names the user can cycle
// through with the Tab key in the main agent view.
AvailableRoles() []string
CurrentRole() string
// AvailableAgents returns the names of agent roles available for Handoff.
AvailableAgents() []string
}
RoleController exposes role/handoff lifecycle for the active agent.
type RunningModelChangedEvent ¶
type RunningModelChangedEvent struct {
AgentID string // "" = main agent, non-empty = sub-agent instance ID
ProviderModelRef string // selected model (user's choice)
RunningModelRef string // actually running model (may differ during fallback)
}
RunningModelChangedEvent signals that the active running model has changed. Emitted after a manual model switch or fallback switch so the TUI can update the sidebar without waiting for the next idle snapshot.
type RuntimeModelPoolPolicy ¶ added in v0.3.0
type RuntimeModelPoolPolicy struct {
// contains filtered or unexported fields
}
func NewRuntimeModelPoolPolicy ¶ added in v0.3.0
func NewRuntimeModelPoolPolicy() *RuntimeModelPoolPolicy
func (*RuntimeModelPoolPolicy) AgentOverride ¶ added in v0.3.0
func (p *RuntimeModelPoolPolicy) AgentOverride(agentName string) (string, bool)
func (*RuntimeModelPoolPolicy) ClearAgentOverride ¶ added in v0.3.0
func (p *RuntimeModelPoolPolicy) ClearAgentOverride(agentName string)
func (*RuntimeModelPoolPolicy) CurrentModelPool ¶ added in v0.5.1
func (p *RuntimeModelPoolPolicy) CurrentModelPool() string
func (*RuntimeModelPoolPolicy) EffectiveModels ¶ added in v0.3.0
func (p *RuntimeModelPoolPolicy) EffectiveModels(agentName string, cfg *config.AgentConfig) []string
func (*RuntimeModelPoolPolicy) EffectivePool ¶ added in v0.3.0
func (p *RuntimeModelPoolPolicy) EffectivePool(agentName string, cfg *config.AgentConfig) string
func (*RuntimeModelPoolPolicy) LastPicked ¶ added in v0.3.0
func (p *RuntimeModelPoolPolicy) LastPicked(roleName, poolName string) (string, bool)
func (*RuntimeModelPoolPolicy) Overrides ¶ added in v0.3.0
func (p *RuntimeModelPoolPolicy) Overrides() map[string]string
func (*RuntimeModelPoolPolicy) ReplaceSelections ¶ added in v0.5.0
func (p *RuntimeModelPoolPolicy) ReplaceSelections(currentModelPool string, overrides map[string]string)
func (*RuntimeModelPoolPolicy) ReplaceSelectionsForSessionRestore ¶ added in v0.5.0
func (p *RuntimeModelPoolPolicy) ReplaceSelectionsForSessionRestore(currentModelPool string, overrides map[string]string)
func (*RuntimeModelPoolPolicy) ResolveInitialModelRef ¶ added in v0.3.0
func (p *RuntimeModelPoolPolicy) ResolveInitialModelRef(agentName string, cfg *config.AgentConfig) string
func (*RuntimeModelPoolPolicy) SetAgentOverride ¶ added in v0.3.0
func (p *RuntimeModelPoolPolicy) SetAgentOverride(agentName, pool string)
func (*RuntimeModelPoolPolicy) SetCurrentModelPool ¶ added in v0.5.1
func (p *RuntimeModelPoolPolicy) SetCurrentModelPool(pool string)
func (*RuntimeModelPoolPolicy) SetLastPicked ¶ added in v0.3.0
func (p *RuntimeModelPoolPolicy) SetLastPicked(roleName, poolName, modelRef string)
type SessionController ¶ added in v0.2.0
type SessionController interface {
ListSessionSummaries() ([]SessionSummary, error)
GetSessionSummary() *SessionSummary
DeleteSession(sessionID string) error
ExportSession(format, path string)
ResumeSession()
ResumeSessionID(sessionID string)
NewSession()
// ForkSession creates a new session branching from the message at msgIndex.
// The message at msgIndex becomes the draft loaded into the composer.
ForkSession(msgIndex int)
}
SessionController exposes session lifecycle controls (resume, fork, delete, export). In remote mode some methods may be unavailable until a dedicated protocol/API is defined.
type SessionRestoredEvent ¶
type SessionRestoredEvent struct{}
SessionRestoredEvent signals that the conversation was restored from a persisted session (e.g. after /resume <id>). The TUI should rebuild the viewport from the current messages so the restored history is visible.
type SessionSelectEvent ¶
type SessionSelectEvent struct {
Sessions []SessionSummary // optional: pre-fetched list from server
}
SessionSelectEvent signals the TUI to open the session picker overlay. Emitted when the user runs /resume with no arguments; the user then chooses a session from the list to restore. Sessions, when non-nil, is the list from the server (C/S mode); the TUI uses it instead of calling ListSessionSummaries() so remote clients get the list.
type SessionSummary ¶
type SessionSummary struct {
ID string
LastModTime time.Time
FirstUserMessage string
FirstUserMessageIsCompactionSummary bool
OriginalFirstUserMessage string // preserved across compaction
OriginalFirstUserMessageIsCompactionSummary bool // legacy-only: see recovery.SessionInfo
ForkedFrom string
Locked bool
}
SessionSummary holds display info for one session (current or list entry).
type SessionSwitchStartedEvent ¶
type SessionSwitchStartedEvent struct {
Kind string
SessionID string // optional target session ID (for /resume)
}
SessionSwitchStartedEvent signals that a local session-control operation has started and the TUI should show transient loading feedback until the switch either completes (SessionRestoredEvent) or fails (ErrorEvent/IdleEvent). Kind is one of: "resume", "new", "fork".
type SkillsStateProvider ¶
type SkillsStateProvider interface {
// ListSkills returns currently discoverable skills visible to the runtime.
ListSkills() []*skill.Meta
}
SkillsStateProvider is implemented by agents that can expose currently available skill metadata to the TUI info panel.
type SpawnFinishedEvent ¶
type SpawnFinishedEvent struct {
BackgroundID string
AgentID string // originating agent ("" = main agent)
Kind string
Status string
Command string
Description string
MaxRuntimeSec int
Message string
}
SpawnFinishedEvent is emitted when a background process started by Spawn completes. It is a lightweight runtime notification; stdout/stderr remain in the returned log_file.
func (SpawnFinishedEvent) EffectiveID ¶
func (e SpawnFinishedEvent) EffectiveID() string
type StreamRollbackEvent ¶
StreamRollbackEvent asks the UI to discard the currently streaming assistant output for an agent (used when a provider-side incremental attempt must be rolled back and retried with full input).
type StreamTextEvent ¶
StreamTextEvent carries an incremental text chunk from the LLM.
type StreamThinkingDeltaEvent ¶
type StreamThinkingDeltaEvent struct {
Text string // incremental thinking content since last delta
AgentID string // originating agent ("" = main agent)
}
StreamThinkingDeltaEvent carries an incremental thinking chunk for streaming display. Emitted every ~150ms while thinking is in progress, so users see thinking as it evolves. The final complete thinking block is still sent via StreamThinkingEvent on thinking_end.
type StreamThinkingEvent ¶
type StreamThinkingEvent struct {
Text string // full thinking content for this block
AgentID string // originating agent ("" = main agent)
}
StreamThinkingEvent carries a complete thinking block from the LLM. It is emitted once per thinking block (after the block is fully assembled), not incrementally — this avoids flooding the output channel during extended thinking sessions that may produce thousands of small deltas.
type StreamingToolDiscardInfo ¶ added in v0.5.0
type StreamingToolExecutor ¶ added in v0.5.0
type StreamingToolExecutor struct {
// contains filtered or unexported fields
}
func NewStreamingToolExecutor ¶ added in v0.5.0
func NewStreamingToolExecutor(turnID uint64, ctx context.Context, emit func(AgentEvent), execute func(context.Context, message.ToolCall) (ToolExecutionResult, error)) *StreamingToolExecutor
func (*StreamingToolExecutor) AcquireExecutionSlot ¶ added in v0.5.0
func (e *StreamingToolExecutor) AcquireExecutionSlot(ctx context.Context) func()
AcquireExecutionSlot blocks until a shared tool execution slot is available or ctx is canceled. The returned release function must be called exactly once.
func (*StreamingToolExecutor) DiscardAll ¶ added in v0.5.0
func (e *StreamingToolExecutor) DiscardAll(reason string) []PendingToolCall
func (*StreamingToolExecutor) DiscardCall ¶ added in v0.5.0
func (e *StreamingToolExecutor) DiscardCall(callID, reason string) (StreamingToolDiscardInfo, bool)
func (*StreamingToolExecutor) DiscardExcept ¶ added in v0.5.0
func (e *StreamingToolExecutor) DiscardExcept(valid map[string]struct{}, reason string) []PendingToolCall
func (*StreamingToolExecutor) DiscardExceptInfo ¶ added in v0.5.0
func (e *StreamingToolExecutor) DiscardExceptInfo(valid map[string]struct{}, reason string) []StreamingToolDiscardInfo
func (*StreamingToolExecutor) Promote ¶ added in v0.5.0
func (e *StreamingToolExecutor) Promote(call message.ToolCall) (*ToolResultPayload, bool, bool)
func (*StreamingToolExecutor) SetTraceCallbacks ¶ added in v0.5.0
func (e *StreamingToolExecutor) SetTraceCallbacks(onStart func(callID, toolName string, at time.Time), onFirstVisible func(callID, toolName string, at time.Time), onDiscard func(info StreamingToolDiscardInfo))
type SubAgent ¶
type SubAgent struct {
// contains filtered or unexported fields
}
SubAgent runs an independent event loop that executes a single task delegated by the MainAgent. It has its own LLM client, context manager, and tool registry, but shares the recovery manager and hook engine with its parent MainAgent.
All mutable state is confined to the runLoop goroutine (single-writer); external user input is enqueued via InjectUserMessage / InjectUserMessageWithParts.
func NewSubAgent ¶
func NewSubAgent(cfg SubAgentConfig) *SubAgent
NewSubAgent creates a fully-initialised SubAgent. The caller must invoke runLoop in a separate goroutine to start the event loop.
func (*SubAgent) CancelCurrentTurn ¶
CancelCurrentTurn cancels the SubAgent's active turn and persists synthetic terminal tool results for any pending calls so session restore shows them as cancelled instead of pending forever.
func (*SubAgent) ContinueFromContext ¶
func (s *SubAgent) ContinueFromContext()
ContinueFromContext signals the SubAgent to re-run the LLM with its existing context without appending a new user message. Non-blocking.
func (*SubAgent) GetContextMessageCount ¶
GetContextMessageCount returns the number of messages in this agent's context (for sidebar).
func (*SubAgent) GetContextStats ¶
GetContextStats returns current context usage and limit for this SubAgent. Current = input + output + cache + reasoning from last API response.
func (*SubAgent) GetMessages ¶
GetMessages returns a thread-safe snapshot of the SubAgent's conversation history (for TUI display when the user tabs to this agent).
func (*SubAgent) InjectUserMessage ¶
InjectUserMessage receives user messages directly (non-blocking enqueue). Overflow is preserved in-memory so older messages are not silently dropped. This is safe to call from any goroutine (typically MainAgent's event loop).
func (*SubAgent) InjectUserMessageWithMailboxAck ¶
func (*SubAgent) InjectUserMessageWithParts ¶
func (s *SubAgent) InjectUserMessageWithParts(parts []message.ContentPart)
InjectUserMessageWithParts enqueues a multi-part user message for the SubAgent.
func (*SubAgent) InvokedSkills ¶
func (*SubAgent) LastArtifact ¶
func (s *SubAgent) LastArtifact() tools.ArtifactRef
func (*SubAgent) LastMailboxID ¶
func (*SubAgent) LastReplyThread ¶
func (*SubAgent) LastSummary ¶
func (*SubAgent) ListSkills ¶
func (*SubAgent) MarkSkillInvoked ¶
func (*SubAgent) OwnerAgentID ¶
func (*SubAgent) OwnerTaskID ¶
func (*SubAgent) PendingCompleteIntent ¶
func (s *SubAgent) PendingCompleteIntent() *AgentResult
func (*SubAgent) RemoveLastMessage ¶
func (s *SubAgent) RemoveLastMessage()
RemoveLastMessage removes the last message from the SubAgent's context and rewrites the persistence log. Only safe when idle (turn == nil), but since this is called from the TUI goroutine and the actual mutation happens on the runLoop goroutine via handleContinue, we use DropLastMessage which is mutex-protected. The persistence rewrite is best-effort.
func (*SubAgent) RestoreMessages ¶
RestoreMessages loads a previously persisted message history into the SubAgent's context manager. Used during session restore to rebuild a SubAgent's conversation without replaying LLM calls.
func (*SubAgent) State ¶
func (s *SubAgent) State() SubAgentState
func (*SubAgent) StateChangedAt ¶
type SubAgentCloseRequestedPayload ¶
type SubAgentCloseRequestedPayload struct {
Reason string
ClosedReason string
FinalState SubAgentState
}
type SubAgentConfig ¶
type SubAgentConfig struct {
InstanceID string
TaskID string
AgentDefName string
TaskDesc string
PlanTaskRef string
SemanticKey string
WriteScope tools.WriteScope
OwnerAgentID string
OwnerTaskID string
Depth int
JoinToOwner bool
Delegation config.DelegationConfig
Color string
SystemPrompt string // custom role instructions from agent YAML body; empty = use built-in
LLMClient *llm.Client
Recovery *recovery.RecoveryManager
Parent *MainAgent
ParentCtx context.Context
Cancel context.CancelFunc
BaseTools *tools.Registry // shared base tool registry (Read, Write, Edit, Shell, Grep, Glob, etc.)
ExtraMCPTools []tools.Tool // agent-specific MCP tools
Ruleset permission.Ruleset
WorkDir string
VenvPath string // absolute path to detected Python virtual environment, or ""
SessionDir string
AgentsMD string
Skills []*skill.Meta
ModelName string
IdleTimeout time.Duration // 0 → DefaultIdleTimeout
}
SubAgentConfig holds the parameters for creating a new SubAgent.
type SubAgentInfo ¶
type SubAgentInfo struct {
InstanceID string
TaskID string
AgentDefName string
TaskDesc string
ModelName string
SelectedRef string
RunningRef string
State string
Color string // optional ANSI color code from agent config
LastSummary string
UrgentInboxCount int
LastArtifact tools.ArtifactRef
}
SubAgentInfo carries read-only information about a running SubAgent for TUI display (sidebar listing). The fields are snapshot values safe to read from any goroutine.
type SubAgentInspector ¶ added in v0.2.0
type SubAgentInspector interface {
GetSubAgents() []SubAgentInfo
SwitchFocus(agentID string)
// FocusedAgentID returns the instance ID of the focused SubAgent, or "" when
// the main agent is focused.
FocusedAgentID() string
// FocusedAgentName returns the agent definition name of the focused SubAgent,
// or "" when the main agent is focused.
FocusedAgentName() string
}
SubAgentInspector lets the TUI list, focus, and follow subagents.
type SubAgentMailboxAckRecord ¶
type SubAgentMailboxAckRecord struct {
MessageID string `json:"message_id"`
Outcome string `json:"outcome"`
TurnID uint64 `json:"turn_id,omitempty"`
InReplyTo string `json:"in_reply_to,omitempty"`
ReplyMessageID string `json:"reply_message_id,omitempty"`
ReplyToMailboxID string `json:"reply_to_mailbox_id,omitempty"`
ReplySummary string `json:"reply_summary,omitempty"`
ReplyKind string `json:"reply_kind,omitempty"`
ArtifactID string `json:"artifact_id,omitempty"`
ArtifactRelPath string `json:"artifact_rel_path,omitempty"`
ArtifactType string `json:"artifact_type,omitempty"`
AckedAt time.Time `json:"acked_at"`
}
type SubAgentMailboxKind ¶
type SubAgentMailboxKind string
const ( SubAgentMailboxKindProgress SubAgentMailboxKind = "progress" SubAgentMailboxKindCompleted SubAgentMailboxKind = "completed" SubAgentMailboxKindBlocked SubAgentMailboxKind = "blocked" SubAgentMailboxKindDecisionRequired SubAgentMailboxKind = "decision_required" SubAgentMailboxKindRiskAlert SubAgentMailboxKind = "risk_alert" SubAgentMailboxKindDirectionChange SubAgentMailboxKind = "direction_change_request" )
type SubAgentMailboxMessage ¶
type SubAgentMailboxMessage struct {
MessageID string `json:"message_id"`
AgentID string `json:"agent_id"`
TaskID string `json:"task_id"`
OwnerAgentID string `json:"owner_agent_id,omitempty"`
OwnerTaskID string `json:"owner_task_id,omitempty"`
InReplyTo string `json:"in_reply_to,omitempty"`
Kind SubAgentMailboxKind `json:"kind"`
Priority SubAgentMailboxPriority `json:"priority"`
Summary string `json:"summary"`
Payload string `json:"payload,omitempty"`
Completion *CompletionEnvelope `json:"completion,omitempty"`
RequiresAck bool `json:"requires_ack,omitempty"`
Consumed bool `json:"consumed,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
type SubAgentMailboxPriority ¶
type SubAgentMailboxPriority string
const ( SubAgentMailboxPriorityNotify SubAgentMailboxPriority = "notify" SubAgentMailboxPriorityUrgent SubAgentMailboxPriority = "urgent" SubAgentMailboxPriorityInterrupt SubAgentMailboxPriority = "interrupt" )
type SubAgentProgressUpdatedPayload ¶
type SubAgentProgressUpdatedPayload struct {
Summary string
}
type SubAgentState ¶
type SubAgentState string
const ( SubAgentStateRunning SubAgentState = "running" SubAgentStateWaitingMain SubAgentState = "waiting_main" SubAgentStateWaitingDescendant SubAgentState = "waiting_descendant" SubAgentStateCompleted SubAgentState = "completed" SubAgentStateFailed SubAgentState = "failed" SubAgentStateCancelled SubAgentState = "cancelled" SubAgentStateIdle SubAgentState = "idle" )
type SubAgentStateChangedPayload ¶
type SubAgentStateChangedPayload struct {
State SubAgentState
Summary string
}
type SubAgentStopPayload ¶
type ThinkingStartedEvent ¶
type ThinkingStartedEvent struct{}
ThinkingStartedEvent is emitted when the first thinking delta is received in a block, so the TUI can start the "thought duration" timer.
type ToastEvent ¶
type ToastEvent struct {
Message string
Level string
AgentID string // originating agent ("" = main agent)
}
ToastEvent carries a transient notification message. Level is one of: "info", "warn", "error".
type TodosUpdatedEvent ¶
TodosUpdatedEvent is emitted when the todo list changes via TodoWrite.
type ToolCallExecutionEvent ¶
type ToolCallExecutionEvent struct {
ID string
Name string
ArgsJSON string
State ToolCallExecutionState
AgentID string // originating agent ("" = main agent)
}
ToolCallExecutionEvent updates the live execution phase for an already-visible tool card after finalize. It distinguishes truly queued work from actively running work so the TUI does not animate tools that are only waiting on a later batch.
type ToolCallExecutionState ¶
type ToolCallExecutionState string
ToolCallExecutionState is the live execution phase of a visible tool card.
const ( ToolCallExecutionStateQueued ToolCallExecutionState = "queued" ToolCallExecutionStateRunning ToolCallExecutionState = "running" )
type ToolCallStartEvent ¶
type ToolCallStartEvent struct {
ID string
Name string
ArgsJSON string
AgentID string // originating agent ("" = main agent)
}
ToolCallStartEvent is emitted when the LLM begins a tool invocation.
type ToolCallUpdateEvent ¶
type ToolCallUpdateEvent struct {
ID string
Name string
ArgsJSON string
ArgsStreamingDone bool
AgentID string // originating agent ("" = main agent)
}
ToolCallUpdateEvent refreshes the visible arguments for an already-started tool call. Used for streaming providers that deliver tool arguments incrementally. When ArgsStreamingDone is true, ArgsJSON is the final accumulated argument JSON for this speculative card and the temporary "chars received" indicator should be cleared immediately even before execution-state/result events arrive.
type ToolExecutionResult ¶
type ToolProgressEvent ¶
type ToolProgressEvent struct {
CallID string
Name string
AgentID string // originating agent ("" = main agent)
Progress ToolProgressSnapshot
}
ToolProgressEvent updates the visible progress for an already-started tool call. It never replaces start/end lifecycle events.
type ToolProgressSnapshot ¶
ToolProgressSnapshot is a best-effort structured progress snapshot for a visible running tool card. Zero values mean "no known progress".
type ToolResultEvent ¶
type ToolResultEvent struct {
CallID string
Name string
ArgsJSON string // full tool arguments (available after streaming completes)
Audit *message.ToolArgsAudit
Result string
Status ToolResultStatus
AgentID string // originating agent ("" = main agent)
Diff string // unified diff for Write/Edit tools (not sent to LLM)
DiffAdded int // full added-line count before any diff truncation
DiffRemoved int // full removed-line count before any diff truncation
FileCreated bool // true when Write created a file that did not previously exist
}
ToolResultEvent is emitted after a tool execution completes.
type ToolResultPayload ¶
type ToolResultPayload struct {
CallID string
Name string
ArgsJSON string
Audit *message.ToolArgsAudit
Result string
Error error
TurnID uint64
Duration time.Duration
Diff string // unified diff for Write/Edit tools; not sent to LLM
DiffAdded int // full added-line count before any diff truncation
DiffRemoved int // full removed-line count before any diff truncation
FileCreated bool // true when Write created a file that did not previously exist
LSPReviews []message.LSPReview // last-review snapshot for the directly edited file only
FileState *message.ToolFileState
// contains filtered or unexported fields
}
ToolResultPayload wraps a tool execution result for the internal event bus.
type ToolResultStatus ¶
type ToolResultStatus string
ToolResultStatus is the terminal state of a tool call for UI/protocol purposes.
const ( ToolResultStatusSuccess ToolResultStatus = "success" ToolResultStatusError ToolResultStatus = "error" ToolResultStatusCancelled ToolResultStatus = "cancelled" )
type Turn ¶
type Turn struct {
ID uint64
Epoch uint64
Ctx context.Context
Cancel context.CancelFunc
// PendingToolCalls and TotalToolCalls are accessed from both the event-loop
// goroutine (writes) and external goroutines like CancelCurrentTurn (reads),
// so they must be accessed atomically.
PendingToolCalls atomic.Int32 // number of tool results not yet received
TotalToolCalls atomic.Int32 // total tool calls in this turn (set when dispatching)
PendingToolMeta map[string]PendingToolCall
// MalformedCount tracks consecutive LLM rounds where tool calls had
// abnormal arguments — either the malformed sentinel (invalid JSON) or
// empty "{}" for tools with required parameters (output truncation).
// When this reaches maxMalformedToolCalls the turn is aborted.
MalformedCount int
LengthRecoveryCount int
InLengthRecovery bool
LastTruncatedToolName string
LengthRecoveryAutoCompactAttempted bool
OversizeRecoveryCount int
CompletedToolCalls []any
ChangedFiles []any
// contains filtered or unexported fields
}
Turn represents a single user-initiated interaction cycle. Each user message starts a new turn; starting a new turn cancels any in-flight work from the previous one.
type TurnCancelledPayload ¶
type TurnCancelledPayload struct {
TurnID uint64
Calls []PendingToolCall
// MarkToolCallsFailed turns synthetic terminal tool results for already
// declared calls into error results instead of cancelled results.
MarkToolCallsFailed bool
// KeepPendingUserMessagesQueued suppresses the usual idle-time pending-input
// drain so cancellation does not immediately auto-run any remaining queued
// work on the IdleEvent it just produced.
KeepPendingUserMessagesQueued bool
// CommitPendingUserMessagesWithoutTurn appends queued user messages to the
// durable context/transcript but does not start a follow-up LLM turn.
CommitPendingUserMessagesWithoutTurn bool
}
TurnCancelledPayload carries the pending tool calls that must be explicitly closed in the UI when a turn is cancelled. The main agent also persists synthetic terminal tool-result messages for these calls so session restore can show them as cancelled instead of pending forever.
type UsageReporter ¶ added in v0.2.0
type UsageReporter interface {
GetTokenUsage() message.TokenUsage
// GetUsageStats returns session-wide totals (e.g. $ /stats Session overview and per-agent table).
GetUsageStats() analytics.SessionStats
// GetSidebarUsageStats returns token/cost totals for the focused agent only, aligned with
// GetContextStats and GetTokenUsage for the right info panel and footer pills.
GetSidebarUsageStats() analytics.SessionStats
// GetContextStats returns current context usage and limit for the focused agent.
// current is the last input token count (approximate context window usage); limit is the model context limit (0 if unknown).
GetContextStats() (current, limit int)
// GetContextMessageCount returns the number of messages in the focused agent's context (for sidebar). -1 if unknown.
GetContextMessageCount() int
}
UsageReporter aggregates token usage and context-window stats for status, sidebar, and stats overlay rendering.
type UsageUpdatedEvent ¶
type UsageUpdatedEvent struct{}
UsageUpdatedEvent signals that session usage (input/output tokens, cost) was just updated after an LLM round. In C/S mode the server uses this to push context_usage to clients so the sidebar updates during tool-call loops, not only after the turn ends (IdleEvent).
Source Files
¶
- activity_observer.go
- compaction.go
- compaction_backend.go
- compaction_checkpoint.go
- compaction_failure_policy.go
- compaction_file_context.go
- compaction_persistence.go
- compaction_policy.go
- compaction_profile.go
- compaction_resume_mode.go
- compaction_resume_state.go
- compaction_runner.go
- completion_envelope.go
- completion_envelope_json.go
- coordination_snapshot.go
- delete_runtime.go
- edit_preconditions.go
- event.go
- file_read_restore.go
- file_state_metadata.go
- hooks.go
- id.go
- interaction.go
- loop_state.go
- lsp_touched_restore.go
- main.go
- main_commands.go
- main_context_api.go
- main_env_status.go
- main_export.go
- main_handlers_llm.go
- main_handlers_tools.go
- main_interaction_api.go
- main_length_recovery.go
- main_length_recovery_compaction.go
- main_llm.go
- main_llm_gate.go
- main_loop.go
- main_loop_assessment.go
- main_mcp.go
- main_mcp_control.go
- main_model.go
- main_model_pool.go
- main_persist.go
- main_prompt.go
- main_rate_limit.go
- main_role_loop_api.go
- main_session_restore.go
- main_session_summary.go
- main_skills.go
- main_subagent.go
- main_subagent_control.go
- main_subagent_events.go
- main_subagent_inbox.go
- main_subagent_lifecycle.go
- main_tool_exec.go
- main_tool_helpers.go
- main_tui_api.go
- main_turn.go
- main_turn_tool_bookkeeping.go
- main_usage.go
- modelref_notification.go
- overlay_helpers.go
- prompt_blocks.go
- prompt_bugtriage.go
- prompt_capabilities.go
- prompt_coordination.go
- provenance.go
- recovery_snapshot.go
- restore_normalize.go
- rule_intent.go
- session_context.go
- session_switch.go
- streaming_tool_exec.go
- streaming_tool_finalize.go
- streaming_tool_policy.go
- streaming_tool_rollback.go
- sub.go
- sub_continue_msg.go
- sub_event.go
- sub_event_llm.go
- sub_event_tools.go
- sub_event_user.go
- sub_lifecycle.go
- sub_mailbox.go
- sub_skills.go
- sub_state.go
- sub_streaming_tool_finalize.go
- sub_turn_cancel.go
- subagent_artifact.go
- subagent_meta.go
- subagent_state.go
- task_registry.go
- task_registry_mailbox.go
- thinking_toolcall_compat.go
- todo_snapshot.go
- tool_exec_context.go
- tool_permission.go
- tool_permission_shell.go
- tool_validation.go
- tool_visibility.go
- tui_agent.go
- turn_overlays.go
- turn_pending_snapshot.go
- user_interrupt.go