agent

package
v1.2.8 Latest Latest
Warning

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

Go to latest
Published: Oct 2, 2026 License: MIT Imports: 58 Imported by: 0

Documentation

Index

Constants

View Source
const (
	GoalStatusRunning   = "running"
	GoalStatusCompleted = "completed"
	GoalStatusFailed    = "failed"
	GoalStatusCancelled = "cancelled"
	GoalStatusBlocked   = "blocked"
	GoalStatusTimeout   = "timeout"
	GoalStatusStalled   = "stalled"
)

Goal status constants

View Source
const (
	RoutingKindRouted            = "routed"
	RoutingKindNoMatch           = "no_match"
	RoutingKindRouterUnavailable = "router_unavailable"
	RoutingKindRouteUnusable     = "route_unusable"
	RoutingKindFailover          = "failover"
)

Routing notice kinds (RoutingInfo.Kind).

View Source
const (
	PersonaSourceDecision = "decision"
	PersonaSourceLLM      = "llm"
	PersonaSourceSticky   = "sticky"
	PersonaSourceDefault  = "default"
)

Persona routing sources (PersonaRoutingInfo.Source).

View Source
const (
	ResumePriorityFallback = 0
	ResumePriorityOwner    = 100
)

Handler priorities. Handlers are consulted from the highest priority to the lowest; handlers of equal priority in registration order. A surface that only owns the sessions it opened itself (e.g. an ACP client session) registers at ResumePriorityOwner and returns taken == false for any other session; a surface that can show any session (the WebUI API) registers at ResumePriorityFallback and takes everything that no specific owner claimed.

View Source
const (
	AgentToolName = "agent"
)
View Source
const DraftSessionID = "draft:new-session"

DraftSessionID keys the model selection made before a session exists (the TUI model dialog on an empty chat). It is never a real session: the selection is moved onto the session created by the first prompt with AdoptDraftSessionOverrides.

View Source
const ReasonRouteUnusable = "route_unusable"

ReasonRouteUnusable is the routing reason used when the decision matched a route but none of its models can serve the turn (unknown, disabled, cooling down, no attachment support, context too small). The turn runs on the coder.

Variables

View Source
var (
	ErrRequestCancelled = errors.New("request cancelled by user")
	ErrSessionBusy      = errors.New("session is currently processing another request")
	// ErrSessionNotBusy is returned by Steer when the session has no active run to
	// steer. Callers should fall back to a normal Run in that case.
	ErrSessionNotBusy = errors.New("session is not currently processing a request")
)

Common errors

View Source
var (
	ErrGoalMaxIterationsReached = errors.New("goal reached max iterations")
	ErrGoalMaxDurationExceeded  = errors.New("goal exceeded max duration")
)
View Source
var ErrLearningNotActive = errors.New("learning mode is not active for this session")

ErrLearningNotActive is returned when a Learning-only operation (the closing turn) is requested for a session that never enabled the mode.

View Source
var ErrNoModel = fmt.Errorf("no model configured, please select a model")

ErrNoModel is returned when the agent has no model configured.

View Source
var ErrSuperpowersNotActive = errors.New("superpowers mode is not active for this session")

ErrSuperpowersNotActive is returned when a Superpowers-only operation (the closing turn) is requested for a session that never enabled the mode.

Functions

func AdoptDraftSessionOverrides added in v1.2.7

func AdoptDraftSessionOverrides(sessionID string)

AdoptDraftSessionOverrides moves the model selection stored under DraftSessionID onto sessionID and clears the draft. It is a no-op when no draft selection exists.

func AppliedAutoPersona added in v1.2.7

func AppliedAutoPersona(sessionID string) (name, source string)

AppliedAutoPersona returns the persona the auto-selection applied to the session on its last user turn and where the choice came from (a PersonaSource* value; "llm" when the decision model option is off). The name is empty when nothing was applied yet.

func ApplyToolDiscovery added in v0.416.3

func ApplyToolDiscovery(allTools []tools.BaseTool, gateway *mcpgateway.Gateway) []tools.BaseTool

ApplyToolDiscovery applies the unified tool selection policy to allTools. When discovery is enabled it:

  1. Adds extension-contributed tools and applies extension tool middleware (see internal/extensions.ApplyTools). This happens even when discovery is disabled.
  2. Syncs all live tools into the shared registry (upsert by name).
  3. When gateway is non-nil, syncs the full MCP catalog as catalog-only entries and wires the gateway as the remote executor so any MCP tool — favorite or not — is searchable and executable through tool_search.
  4. Creates the unified tool_search tool (search + call) backed by the registry.
  5. Returns only the visible subset (core tools + tool_search + session-discovered).

When discovery is disabled the tool set is returned as-is after step 0.

func AttachSessionMCPServers added in v1.0.4

func AttachSessionMCPServers(ctx context.Context, sessionID string, servers map[string]config.MCPServer, permissions permission.Service) error

AttachSessionMCPServers connects to every server in servers, initializes it and lists its tools, then exposes those tools to the session's agent runs only. It replaces whatever was attached to the session before (a session/load re-attaches). A server that fails is skipped: the successful ones stay attached and the failures come back joined in the error.

Connections are owned by the registry, not by ctx: ctx only bounds the discovery, so a stdio server keeps running after the ACP request that asked for it has returned. DetachSessionMCPServers releases them.

func BuildGoalContinuationPrompt added in v0.324.0

func BuildGoalContinuationPrompt(objective string, iteration int, maxIterations int, progress string, nextStep string) string

func BuildGoalInitialPrompt added in v0.324.0

func BuildGoalInitialPrompt(objective string, additionalInstructions string) string

func CachedMcpToolNames added in v0.720.2

func CachedMcpToolNames() []string

CachedMcpToolNames returns the "<server>_<tool>" names of the MCP tools already discovered in this process, without connecting to anything and without constructing a permission service. It returns nil when discovery has not run yet: a name list for a prompt is not a reason to open MCP connections, and it is certainly not a reason to populate the shared cache (PANDO-US-0031, defect 2).

func CavemanMode added in v0.621.0

func CavemanMode(sessionID string) caveman.Mode

CavemanMode returns the effective caveman mode for a session: the session's explicit choice when set, otherwise the configured default (off when none).

func CoderAgentTools

func CoderAgentTools(
	permissions permission.Service,
	history history.Service,
	lspProvider tools.LSPProvider,
	userInput userinput.Service,
	sessions session.Service,
) []tools.BaseTool

func CoderAgentToolsWithMesnada

func CoderAgentToolsWithMesnada(
	mesnadaOrchestrator *orchestrator.Orchestrator,
	remembrances *rag.RemembrancesService,
	gateway *mcpgateway.Gateway,
	permissions permission.Service,
	history history.Service,
	lspProvider tools.LSPProvider,
	userInput userinput.Service,
	sessions session.Service,
) []tools.BaseTool

func ContextEnricherAgentTools added in v0.646.4

func ContextEnricherAgentTools(remembrances *rag.RemembrancesService, lspProvider tools.LSPProvider) []tools.BaseTool

ContextEnricherAgentTools returns the read-only retrieval tool set used by the context-enrichment agent loop: knowledge base, memories, past events and the code index, plus plain file inspection. No tool in this set can modify state, so the loop can never touch the workspace while it gathers context for the main agent.

func CreateAgentProvider added in v0.403.0

func CreateAgentProvider(ctx context.Context, agentName config.AgentName) (provider.Provider, error)

CreateAgentProvider creates a provider for the given agent name. It is exported for use in app-layer code that needs a provider outside of the agent itself (e.g. the context-enricher LLM planner adapter).

func DesignTools added in v0.700.0

func DesignTools(permissions permission.Service) []tools.BaseTool

DesignTools returns the full Design Studio tool set. The Design Studio is always active; MCP server mode decides separately whether to expose these tools to external clients.

func DetachSessionMCPServers added in v1.0.4

func DetachSessionMCPServers(sessionID string)

DetachSessionMCPServers closes every connection attached to the session and removes its tools. It is a no-op for a session with nothing attached.

func ExtensionManager added in v0.700.0

func ExtensionManager() *extension.Manager

ExtensionManager returns the wired manager, or nil when the build has none.

func ForgetSessionPersona added in v1.2.7

func ForgetSessionPersona(sessionID string)

ForgetSessionPersona drops the remembered persona and the persona warning state of a session.

func GetActivePersona added in v0.200.0

func GetActivePersona() string

GetActivePersona returns the currently active persona name. An empty string means no persona is active (auto-select or none).

func GetMcpFavoriteTools added in v0.646.4

func GetMcpFavoriteTools(ctx context.Context, permissions permission.Service, gw *mcpgateway.Gateway) []tools.BaseTool

GetMcpFavoriteTools returns the gateway's favorite MCP tools as direct wrappers so the LLM can call them without going through a proxy (lower latency, richer schema visibility). The rest of the MCP catalog stays reachable through the unified tool_search tool.

func GetMcpTools

func GetMcpTools(ctx context.Context, permissions permission.Service) []tools.BaseTool

GetMcpTools returns the MCP catalog as tools bound to the permission service the CALLER passed. The discovery result is cached and shared (one connection per server per process, as before); only the permission binding is per call.

func GetMcpToolsWithGateway added in v0.8.0

func GetMcpToolsWithGateway(ctx context.Context, permissions permission.Service, gw *mcpgateway.Gateway) []tools.BaseTool

GetMcpToolsWithGateway returns MCP-backed tools for the LLM agent. When gw is non-nil (gateway mode), it exposes two proxy tools plus any favorite tools as direct wrappers. When gw is nil it falls back to the standard per-server tool list.

NOTE: this is the legacy gateway exposure path, kept for the ToolDiscovery-disabled configuration and for the pando mcp-server mode. The unified discovery path uses GetMcpFavoriteTools plus the tool_search tool wired in ApplyToolDiscovery.

func GetPersonaManager added in v0.200.0

func GetPersonaManager() *persona.Manager

GetPersonaManager returns the global persona manager, or nil if not initialised.

func LastRoutedModel added in v1.2.7

func LastRoutedModel(sessionID string) (models.ModelID, bool)

LastRoutedModel returns the model the last Auto turn of the session ran on.

func LearningMode added in v0.622.0

func LearningMode(sessionID string) bool

LearningMode reports whether the Learning policy is active for a session.

func ListAvailablePersonas added in v0.200.0

func ListAvailablePersonas() []string

ListAvailablePersonas returns the names of all loaded personas. Uses the global persona manager when available; falls back to the selector's manager.

func NewAgentTool

func NewAgentTool(
	Sessions session.Service,
	Messages message.Service,
	lspProvider tools.LSPProvider,
	skillManager *skills.SkillManager,
) tools.BaseTool

func NewMcpTool

func NewMcpTool(name string, tool mcp.Tool, permissions permission.Service, mcpConfig config.MCPServer) tools.BaseTool

func NewSetupBridge added in v0.629.4

func NewSetupBridge(sessions session.Service) tools.SetupBridge

NewSetupBridge wires the pando_setup tool to the session store and the session-mode registry. A nil session service is tolerated: usage reporting then fails with a clear message instead of panicking.

func PonytailMode added in v0.605.1

func PonytailMode(sessionID string) ponytail.Mode

PonytailMode returns the effective ponytail mode for a session: the session's explicit choice when set, otherwise the configured default (off when none).

func ResetMcpToolsCache added in v0.310.3

func ResetMcpToolsCache()

ResetMcpToolsCache drops the discovered catalog. Its meaning is unchanged: the next GetMcpTools re-runs discovery.

func ResetSharedDiscoveryRegistry added in v0.646.4

func ResetSharedDiscoveryRegistry()

ResetSharedDiscoveryRegistry drops the shared registry (tests, config reloads).

func RunLearningFinish added in v0.622.0

func RunLearningFinish(ctx context.Context, svc Service, sessionID string) (<-chan AgentEvent, error)

RunLearningFinish runs the closing turn for /learning-finish as a normal agent turn (so it streams, persists and is cancellable like any other), consolidating what was learned into KB/memory, then disables the mode only once that turn reaches a successful terminal response. A cancelled or failed run keeps the mode on, so the workflow is never silently abandoned.

Keeping the success-only rule here — rather than in each of the ACP, Web UI and TUI command handlers — is what guarantees all three surfaces behave identically. The returned channel must be drained by the caller, exactly like Service.Run's.

func RunSuperpowersFinish added in v0.609.1

func RunSuperpowersFinish(ctx context.Context, svc Service, sessionID string) (<-chan AgentEvent, error)

RunSuperpowersFinish runs the closing turn for /superpowers-finish as a normal agent turn (so it streams, persists and is cancellable like any other), and disables the mode only once that turn reaches a successful terminal response. A cancelled or failed run keeps the mode on, so the workflow is never silently abandoned.

Keeping the success-only rule here — rather than in each of the ACP, Web UI and TUI command handlers — is what guarantees all three surfaces behave identically. The returned channel must be drained by the caller, exactly like Service.Run's.

func SessionAutoMode added in v1.2.7

func SessionAutoMode(sessionID string) bool

SessionAutoMode reports whether the session runs in Auto mode: the explicit per-session flag when set, otherwise the global selection. It is always false when modelAutoMode.enabled is off.

func SessionModelID added in v0.643.1

func SessionModelID(sessionID string) models.ModelID

SessionModelID returns the model a session actually runs on: its runtime override when one is set, otherwise the coder agent's configured model. Surfaces (TUI status bar, ACP model picker) must use this instead of reading the configured agent model, which does not know about per-session switches.

func SessionModelOverrideID added in v0.643.1

func SessionModelOverrideID(sessionID string) models.ModelID

SessionModelOverrideID returns only the runtime override of a session, empty when the session still runs on the configured model. Callers that keep their own notion of the selected model (the ACP session state) use this to tell "the agent switched model" apart from "the global default differs from what this session picked", which must not be overwritten.

func SessionTools added in v1.0.4

func SessionTools(sessionID string) []tools.BaseTool

SessionTools returns the tools attached to the session, or nil.

func SetActivePersona added in v0.200.0

func SetActivePersona(name string) error

SetActivePersona sets the active persona by name. Pass an empty string to clear the active persona (revert to auto-select or none). Returns an error if the named persona does not exist (and name is non-empty).

func SetAndPersistActivePersona added in v1.2.5

func SetAndPersistActivePersona(name string) error

SetAndPersistActivePersona activates the persona like SetActivePersona and then saves the choice to the config (project file when present, else global) so it survives a restart. Persistence failures are returned after the in-memory switch has already taken effect.

func SetCavemanMode added in v0.621.0

func SetCavemanMode(sessionID string, mode caveman.Mode)

SetCavemanMode sets the caveman mode for a session. It is safe for concurrent use and is the single mutation point used by every surface that exposes the /caveman command (ACP, Web UI, TUI). Turning it off clears the override unless a non-off default is configured, in which case an explicit "off" is recorded so the session stays disabled despite the default.

func SetContextEnricher added in v0.236.1

func SetContextEnricher(e ContextEnricher)

SetContextEnricher sets the context enricher used to prepend KB/code context to user messages. Pass nil to disable context enrichment.

func SetContextTrimmer added in v0.407.0

func SetContextTrimmer(ct ContextTrimmer)

SetContextTrimmer sets the context trimmer used to filter the tool list for new sessions. Pass nil to disable context trimming (all tools will always be included).

func SetExtensionManager added in v0.700.0

func SetExtensionManager(mgr *extension.Manager)

SetExtensionManager wires the process-wide extension manager into the agent's tool-set builder. Called once from internal/app after extensions are loaded. Passing nil detaches it (tests, teardown).

func SetLearningMode added in v0.622.0

func SetLearningMode(sessionID string, enabled bool)

SetLearningMode enables or disables the Learning learner/documentarian policy for a session. It is the entry point used by every surface that exposes the /learning commands (ACP, Web UI, TUI), mirroring SetSuperpowersMode. The state itself lives in internal/learning so tools can read it without importing this package.

func SetLuaManager added in v0.8.0

func SetLuaManager(fm *luaengine.FilterManager)

SetLuaManager sets the global Lua filter manager used for MCP tool input/output filtering.

func SetMemoryInjector added in v0.416.3

func SetMemoryInjector(m MemoryInjector)

SetMemoryInjector wires the memory injector used to prepend a <memories> block to the system prompt. Pass nil to disable memory injection.

func SetNonInteractiveMode added in v0.291.0

func SetNonInteractiveMode(enabled bool)

SetNonInteractiveMode configures all agents to run autonomously without waiting for user input. Call this before running a session when a prompt is provided via the -p flag or stdin pipe.

func SetPersonaManager added in v0.200.0

func SetPersonaManager(mgr *persona.Manager)

SetPersonaManager sets the global persona manager used for persona listing and manual persona selection. This should be called during app initialisation.

func SetPersonaManagerRefresher added in v1.2.7

func SetPersonaManagerRefresher(fn func())

SetPersonaManagerRefresher installs a hook the agent calls before every auto-selection so the app can reload the persona manager when the persona path changed. It must be cheap when nothing changed.

func SetPersonaSelector added in v0.41.0

func SetPersonaSelector(ps *PersonaSelector)

SetPersonaSelector sets the global persona selector used in the main conversation agent.

func SetPonytailMode added in v0.605.1

func SetPonytailMode(sessionID string, mode ponytail.Mode)

SetPonytailMode sets the ponytail mode for a session. It is safe for concurrent use and is the single mutation point used by every surface that exposes the /ponytail command (ACP, Web UI, TUI). Turning it off clears the override unless a non-off default is configured, in which case an explicit "off" is recorded so the session stays disabled despite the default.

func SetProjectServiceForTools added in v0.647.5

func SetProjectServiceForTools(svc project.Service)

SetProjectServiceForTools wires the project registry used by pando_setup's "projects" command. Called once at startup from app.go; a nil service is tolerated and leaves the command reporting "unavailable".

func SetSessionAutoMode added in v1.2.7

func SetSessionAutoMode(sessionID string, auto bool)

SetSessionAutoMode sets the explicit per-session Auto flag. Turning it on also drops any manual model override so the next turn routes; turning it off keeps the session on the configured coder model (or whatever model the caller selects next).

func SetSessionLLMOverrides added in v0.407.0

func SetSessionLLMOverrides(sessionID string, overrides SessionLLMOverrides)

func SetSessionModelOverride added in v0.643.1

func SetSessionModelOverride(sessionID string, model models.ModelID)

SetSessionModelOverride replaces only the model of a session's overrides, keeping persona and inference settings intact. Writing the whole struct here would silently drop the persona ACP or the Web UI installed for the session. An empty model clears just the model override.

Selecting a concrete (non-empty) model also switches Auto mode off for the session: picking a model by hand is an explicit "stop routing". Auto's own turn-scoped application uses setAutoTurnModelOverride, which leaves the flag alone.

func SetSuperpowersMode added in v0.609.1

func SetSuperpowersMode(sessionID string, enabled bool)

SetSuperpowersMode enables or disables the Superpowers workflow policy for a session. It is the entry point used by every surface that exposes the /superpowers commands (ACP, Web UI, TUI), mirroring SetPonytailMode. The state itself lives in internal/superpowers so tools can read it without importing this package.

func SharedDiscoveryRegistry added in v0.646.4

func SharedDiscoveryRegistry() *tooldiscovery.Registry

SharedDiscoveryRegistry returns the process-wide tool discovery registry, creating it on first use.

func SuperpowersMode added in v0.609.1

func SuperpowersMode(sessionID string) bool

SuperpowersMode reports whether the Superpowers policy is active for a session.

func TaskAgentTools

func TaskAgentTools(lspProvider tools.LSPProvider) []tools.BaseTool

Types

type AgentEvent

type AgentEvent struct {
	Type       AgentEventType
	Message    message.Message
	Error      error
	Delta      string
	ToolCall   *message.ToolCall
	ToolResult *message.ToolResult

	// MessageID identifies the assistant message this event belongs to. It is
	// populated on ThinkingDelta/ContentDelta/ToolCall events with the ID of the
	// in-flight assistant message (assistantMsg.ID) so ACP-side streaming can
	// group live chunks under the same messageId used by session/load replay,
	// from the very first delta rather than only after AgentEventTypeResponse.
	MessageID string

	// When summarizing
	SessionID string
	Progress  string
	Done      bool

	// Todos is populated when Type == AgentEventTypeTodosUpdated.
	Todos []tools.TodoItem

	// SystemMessage is populated when Type == AgentEventTypeSystemMessage.
	// It carries a human-readable status message (context compaction, retries, etc.)
	// that should be shown to the user regardless of the transport (TUI, ACP, web).
	SystemMessage string

	// TokenUsage is populated when Type == AgentEventTypeTokenUsage.
	TokenUsage *TokenUsageInfo

	// Routing is set on the AgentEventTypeSystemMessage event that announces an
	// Auto model mode decision or failover (SystemMessage carries the same
	// notice text, e.g. "Auto: implementation → gpt-x (p=0.93, 38 ms via
	// ollama/tev1:0.8b)"). Nil on every other event.
	Routing *RoutingInfo

	// ContextFilter is set on the AgentEventTypeSystemMessage event that
	// announces the decision model dropped part of the injected context
	// (SystemMessage carries the same text, e.g. "Context filter: kept 4/9
	// (38 ms) — code 1/3, kb 2/4, events 1/2"). Nil on every other event.
	ContextFilter *ContextFilterInfo
}

type AgentEventType

type AgentEventType string
const (
	AgentEventTypeError         AgentEventType = "error"
	AgentEventTypeResponse      AgentEventType = "response"
	AgentEventTypeSummarize     AgentEventType = "summarize"
	AgentEventTypeContentDelta  AgentEventType = "content_delta"
	AgentEventTypeThinkingDelta AgentEventType = "thinking_delta"
	AgentEventTypeToolCall      AgentEventType = "tool_call"
	AgentEventTypeToolResult    AgentEventType = "tool_result"
	// AgentEventTypeTodosUpdated is emitted when the TodoWrite tool runs successfully.
	// It carries the current todo list for non-ACP consumers (TUI, WebUI).
	AgentEventTypeTodosUpdated AgentEventType = "todos_updated"
	// AgentEventTypeSystemMessage carries internal status messages (context compaction,
	// retries, etc.) that should be displayed to the user but are not part of the
	// LLM response. Unlike ContentDelta these are sent with a blocking channel write
	// so they are never silently dropped.
	AgentEventTypeSystemMessage AgentEventType = "system_message"
	// AgentEventTypeTokenUsage carries a live context-window token update so the
	// TUI/WebUI can show consumption as it grows during the agent loop (e.g. while
	// tools execute or a file is produced), not only when the LLM response finishes.
	// When TokenUsage.Estimated is true the value is a heuristic estimate that the
	// next confirmed usage (EventComplete) will reconcile.
	AgentEventTypeTokenUsage AgentEventType = "token_usage"
	// AgentEventTypeSteeringQueued is emitted when the user submits a steering
	// message (mid-run feedback) that is queued for injection at the next safe
	// boundary of the agent loop. SystemMessage carries a human-readable note.
	AgentEventTypeSteeringQueued AgentEventType = "steering_queued"
	// AgentEventTypeSteeringInjected is emitted when one or more queued steering
	// messages have been injected into the conversation and the loop will continue
	// taking them into account. SystemMessage carries a human-readable note.
	AgentEventTypeSteeringInjected AgentEventType = "steering_injected"
	// AgentEventTypeConclusionQueued is emitted when a delegated-task conclusion
	// is queued (via InjectConclusion) for injection into a still-running parent
	// loop at the next safe boundary. SystemMessage carries a human-readable note.
	AgentEventTypeConclusionQueued AgentEventType = "conclusion_queued"
	// AgentEventTypeConclusionInjected is emitted when one or more queued delegated
	// conclusions have been injected into the conversation so the parent loop can
	// react to the subagent's result. SystemMessage carries a human-readable note.
	AgentEventTypeConclusionInjected AgentEventType = "conclusion_injected"
	// AgentEventTypeResurrected is emitted at the start of a system-initiated run
	// that resumes an idle parent session because one or more delegated tasks
	// finished (Case B of the delegation protocol). It lets the UI frame the turn
	// as "resuming because a delegated task reported its result" rather than as a
	// user message. SystemMessage carries a human-readable note.
	AgentEventTypeResurrected AgentEventType = "resurrected"
)

type AgentParams

type AgentParams struct {
	Prompt string `json:"prompt"`
}

type AutoModeController added in v1.2.7

type AutoModeController interface {
	SetSessionAutoMode(sessionID string, auto bool)
	SessionAutoMode(sessionID string) bool
	LastRoutedModel(sessionID string) (models.ModelID, bool)
	LastRouting(sessionID string) (RoutingInfo, bool)
}

AutoModeController is implemented by the coder agent. It is kept out of Service so test doubles of Service do not have to implement it; callers type-assert (or use the package-level functions, which are session keyed).

type ContextEnricher added in v0.236.1

type ContextEnricher interface {
	EnrichContext(ctx context.Context, query string) string
}

ContextEnricher is the interface used by the agent to enrich the user's prompt with context retrieved from the KB and code index before sending it to the LLM. A local interface is used to avoid import cycles between agent and rag packages.

type ContextFilterCounts added in v1.2.7

type ContextFilterCounts struct {
	Kept    int `json:"kept"`
	Dropped int `json:"dropped"`
}

ContextFilterCounts is the kept/dropped count of one source.

type ContextFilterInfo added in v1.2.7

type ContextFilterInfo struct {
	Kept    int `json:"kept"`
	Dropped int `json:"dropped"`
	// BySource maps "code", "kb", "events" and "memory" to {kept, dropped};
	// only sources with at least one candidate are present.
	BySource       map[string]ContextFilterCounts `json:"bySource"`
	Threshold      float64                        `json:"threshold"`
	LatencyMs      int64                          `json:"latencyMs"`
	RouterProvider string                         `json:"routerProvider,omitempty"`
	RouterModel    string                         `json:"routerModel,omitempty"`
	// Reason is empty on full success, otherwise "partial:<class>".
	Reason string `json:"reason,omitempty"`
	// Notice is the human readable line (same text as the system message).
	Notice string `json:"notice"`
}

ContextFilterInfo summarises the relevance filtering of one turn. It is the payload of the context filter notice (AgentEvent.ContextFilter). It never carries prompt or snippet text.

type ContextTrimmer added in v0.407.0

type ContextTrimmer interface {
	// ProfileTask returns the recommended tool names for the task.
	// Returns nil/empty to indicate "use all tools" (e.g., on error or low confidence).
	ProfileTask(ctx context.Context, firstMessage string, availableTools []ToolDescription) ([]string, error)
}

ContextTrimmer analyzes the user's first message and recommends a minimal tool set to reduce context window usage by filtering irrelevant tools from the initial API call. It is wired from app.go via SetContextTrimmer.

type EvaluationResult added in v0.324.0

type EvaluationResult struct {
	Complete      bool
	Blocked       bool
	Stalled       bool
	Reason        string
	Progress      string
	NextStep      string
	Confidence    float64
	ProgressMade  bool
	Signature     string
	TodoSignature string
}

type FilteredContextEnricher added in v1.2.7

type FilteredContextEnricher interface {
	EnrichContextWithResult(ctx context.Context, query string) (string, rag.FilterResult)
}

FilteredContextEnricher is an optional extension of ContextEnricher for enrichers that report what the relevance filter did.

type FilteredMemoryInjector added in v1.2.7

type FilteredMemoryInjector interface {
	BuildMemoryBlockWithResult(ctx context.Context, query string) (string, rag.FilterResult)
}

FilteredMemoryInjector is an optional extension of MemoryInjector that reports what the relevance filter did.

type FilteredSessionContextEnricher added in v1.2.7

type FilteredSessionContextEnricher interface {
	EnrichContextForSessionWithResult(ctx context.Context, sessionID, query string) (string, rag.FilterResult)
}

FilteredSessionContextEnricher is the session-aware counterpart of FilteredContextEnricher.

type GoalEvaluator added in v0.324.0

type GoalEvaluator interface {
	Evaluate(ctx context.Context, goal *GoalState, lastMessage string, todos []llmtools.TodoItem) (EvaluationResult, error)
}

type GoalEvent added in v0.324.0

type GoalEvent struct {
	Type      GoalEventType
	GoalState *GoalState
	Message   string
}

GoalEvent represents a state change event for a goal.

type GoalEventType added in v0.324.0

type GoalEventType string

GoalEventType represents the type of goal event.

const (
	GoalEventStart     GoalEventType = "goal_start"
	GoalEventIteration GoalEventType = "goal_iteration"
	GoalEventComplete  GoalEventType = "goal_complete"
	GoalEventFailed    GoalEventType = "goal_failed"
	GoalEventCancelled GoalEventType = "goal_cancelled"
	GoalEventBlocked   GoalEventType = "goal_blocked"
	GoalEventTimeout   GoalEventType = "goal_timeout"
	GoalEventStalled   GoalEventType = "goal_stalled"
)

type GoalOptions added in v0.324.0

type GoalOptions struct {
	MaxIterations   int64
	MaxDuration     time.Duration
	StallIterations int
	InitialPrompt   string
}

type GoalRunner added in v0.324.0

type GoalRunner struct {
	// contains filtered or unexported fields
}

func NewGoalRunner added in v0.324.0

func NewGoalRunner(agent Service, goalStore GoalStore) *GoalRunner

func (*GoalRunner) Run added in v0.324.0

func (gr *GoalRunner) Run(ctx context.Context, sessionID string, objective string, opts GoalOptions) (<-chan AgentEvent, error)

type GoalState added in v0.324.0

type GoalState struct {
	ID                      string
	SessionID               string
	Objective               string
	StatusValue             string
	Iteration               int
	MaxIterations           int
	MaxDurationSecs         int
	StartedAt               time.Time
	CompletedAt             *time.Time
	LastProgress            string
	NextStep                string
	BlockedReason           string
	CreatedAt               time.Time
	InitialTodoSignature    string
	LastTodoSignature       string
	LastEvaluationSignature string
	ConsecutiveNoProgress   int
	// contains filtered or unexported fields
}

GoalState represents the current state of a goal.

func NewGoalState added in v0.324.0

func NewGoalState(id, sessionID, objective string, maxIter, maxDurSecs int) *GoalState

func (*GoalState) Advance added in v0.324.0

func (g *GoalState) Advance(progress string, nextStep string)

func (*GoalState) CanTransitionTo added in v0.324.0

func (g *GoalState) CanTransitionTo(next string) bool

func (*GoalState) Cancel added in v0.324.0

func (g *GoalState) Cancel()

Cancel signals the goal to stop.

func (*GoalState) Elapsed added in v0.324.0

func (g *GoalState) Elapsed() time.Duration

Elapsed returns the time elapsed since the goal started.

func (*GoalState) IsCancelled added in v0.324.0

func (g *GoalState) IsCancelled() bool

IsCancelled returns true if the goal has been cancelled.

func (*GoalState) IsRunning added in v0.324.0

func (g *GoalState) IsRunning() bool

IsRunning returns true if the goal is currently active.

func (*GoalState) IsTerminal added in v0.324.0

func (g *GoalState) IsTerminal() bool

IsTerminal returns true if the status is a terminal state.

func (*GoalState) RecordIteration added in v0.324.0

func (g *GoalState) RecordIteration(progress string, nextStep string, todoSignature string, evaluationSignature string, progressMade bool)

func (*GoalState) RemainingDuration added in v0.324.0

func (g *GoalState) RemainingDuration() time.Duration

RemainingDuration returns the remaining time before max duration.

func (*GoalState) SetStatus added in v0.324.0

func (g *GoalState) SetStatus(s string)

SetStatus updates the status and marks done if terminal.

func (*GoalState) Status added in v0.324.0

func (g *GoalState) Status() string

Status returns the current status for serialization.

func (*GoalState) Transition added in v0.324.0

func (g *GoalState) Transition(next string, now time.Time) error

type GoalStore added in v0.324.0

type GoalStore interface {
	CreateGoal(ctx context.Context, arg db.CreateGoalParams) (db.SessionGoal, error)
	UpdateGoalStatus(ctx context.Context, arg db.UpdateGoalStatusParams) (db.SessionGoal, error)
}

type HeuristicGoalEvaluator added in v0.324.0

type HeuristicGoalEvaluator struct {
	// contains filtered or unexported fields
}

func NewHeuristicGoalEvaluator added in v0.324.0

func NewHeuristicGoalEvaluator() *HeuristicGoalEvaluator

func NewHeuristicGoalEvaluatorWithThreshold added in v0.324.0

func NewHeuristicGoalEvaluatorWithThreshold(stallThreshold int) *HeuristicGoalEvaluator

func (*HeuristicGoalEvaluator) Evaluate added in v0.324.0

func (e *HeuristicGoalEvaluator) Evaluate(_ context.Context, goal *GoalState, lastMessage string, todos []llmtools.TodoItem) (EvaluationResult, error)

type MCPClient

type MCPClient interface {
	Initialize(
		ctx context.Context,
		request mcp.InitializeRequest,
	) (*mcp.InitializeResult, error)
	ListTools(ctx context.Context, request mcp.ListToolsRequest) (*mcp.ListToolsResult, error)
	CallTool(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error)
	Close() error
}

type MemoryInjector added in v0.416.3

type MemoryInjector interface {
	BuildMemoryBlock(ctx context.Context, query string) string
}

MemoryInjector builds the <memories> block prepended to the system prompt. The agent builds it once per session and freezes it (see sessionMemoryBlock). It is a separate interface from ContextEnricher so memory enrichment can be enabled independently of the main context-enrichment pipeline.

type PersonaRoutingInfo added in v1.2.7

type PersonaRoutingInfo struct {
	// Persona is the applied persona, empty when none.
	Persona string
	// Source: "decision" (router matched), "llm" (fallback model chose),
	// "sticky" (previous persona kept) or "default" (assistant / none).
	Source string
	// Reason is the decision outcome: matched, no_match, low_probability,
	// no_personas, router_error or no_router.
	Reason      string
	Probability float64
	LatencyMs   int64
	CostUSD     *float64
	// ErrClass is the typed router error when the decision model was unavailable.
	ErrClass string
	// Changed reports that Persona differs from the previous turn's persona.
	Changed bool
}

PersonaRoutingInfo summarises the last auto-selection of a session. It never carries the prompt text.

func LastPersonaRouting added in v1.2.7

func LastPersonaRouting(sessionID string) (PersonaRoutingInfo, bool)

LastPersonaRouting returns the last auto-selection of the session.

type PersonaSelector added in v0.41.0

type PersonaSelector struct {
	// contains filtered or unexported fields
}

PersonaSelector is the LLM based persona classifier. It uses a lite LLM provider (configured via agents["persona-selector"]) to pick the best matching persona from the personas directory. It is the selection path when the decision model option is off, and the fallback when the decision model cannot answer.

func NewLazyPersonaSelector added in v1.2.7

func NewLazyPersonaSelector() *PersonaSelector

NewLazyPersonaSelector creates a selector that can always be installed: it is only active while personaAutoSelect.enabled is on, resolves personas from the global persona manager and builds its LLM provider on first use from the current persona-selector agent configuration (rebuilt when that changes).

func NewPersonaSelector added in v0.41.0

func NewPersonaSelector(personaPath string) (*PersonaSelector, error)

NewPersonaSelector creates a PersonaSelector that loads personas from personaPath and uses the model configured under agents["persona-selector"] to perform selection. Returns an error if the persona-selector agent is not configured or the model is unavailable.

func (*PersonaSelector) SelectAndApply added in v0.41.0

func (ps *PersonaSelector) SelectAndApply(ctx context.Context, userPrompt string) string

SelectAndApply selects the best persona for userPrompt and returns the prompt with the persona content prepended. Kept for backward compatibility; prefer SelectPersonaContent when the content will be injected into the system prompt.

func (*PersonaSelector) SelectPersonaContent added in v0.265.0

func (ps *PersonaSelector) SelectPersonaContent(ctx context.Context, userPrompt string) string

SelectPersonaContent selects the best persona for userPrompt and returns its raw content (the persona instructions). Returns an empty string if no persona matches, the selector is disabled, or an error occurs. The content is intended to be injected into the system prompt rather than prepended to the user message.

func (*PersonaSelector) SelectPersonaName added in v1.2.7

func (ps *PersonaSelector) SelectPersonaName(ctx context.Context, userPrompt string) (string, error)

SelectPersonaName asks the persona-selector LLM which persona fits userPrompt. It returns "" with a nil error when the model answered "none" or an unknown name, and a non-nil error when the model could not be consulted (no usable model, provider creation failed, the call failed).

type ResumeHandler added in v1.2.7

type ResumeHandler func(sessionID string, start ResumeStart) (taken bool, err error)

ResumeHandler is offered every run the delegation supervisor resumes for an idle session (Case B). It decides whether its surface owns the session:

  • taken == false: not mine, start was NOT called; the next handler is tried.
  • taken == true: the handler owns the run. It has called start (and is responsible for consuming the events) or failed trying, in which case err is returned. ErrSessionBusy makes the supervisor fall back to live injection.

type ResumeRegistry added in v1.2.7

type ResumeRegistry struct {
	// contains filtered or unexported fields
}

ResumeRegistry holds the surfaces that may own a resumed run. The zero value is not usable; build it with NewResumeRegistry. A nil *ResumeRegistry is safe: Offer reports nothing taken, so callers without any surface (TUI, CLI) need no special case and fall back to Resume (drain only).

func NewResumeRegistry added in v1.2.7

func NewResumeRegistry() *ResumeRegistry

NewResumeRegistry creates an empty registry.

func (*ResumeRegistry) Offer added in v1.2.7

func (r *ResumeRegistry) Offer(sessionID string, start ResumeStart) (taken bool, err error)

Offer presents a resumed run to the registered handlers, highest priority first. It returns taken == true as soon as one handler takes it (err is that handler's result); taken == false means nobody owns the session and the caller must run it itself (Resume).

func (*ResumeRegistry) Register added in v1.2.7

func (r *ResumeRegistry) Register(priority int, h ResumeHandler) (unregister func())

Register adds a handler and returns a function that removes it again (safe to call more than once). A surface registers when it starts serving and unregisters when it stops.

type ResumeStart added in v1.2.7

type ResumeStart func(ctx context.Context) (<-chan AgentEvent, error)

ResumeStart starts the system-initiated run of a resumed session and returns its event channel (it is a closure over agent.ResumeRun). The context bounds the run: cancelling it cancels the run. A handler that takes a run MUST call it at most once and read the returned channel until it is closed.

type RoutingInfo added in v1.2.7

type RoutingInfo struct {
	// RouteID is the matched route, empty when nothing matched.
	RouteID string `json:"routeId,omitempty"`
	// Model is the model that is (or last was) answering the turn. It changes
	// when the turn fails over.
	Model models.ModelID `json:"model"`
	// Matched reports that a route matched with enough probability.
	Matched     bool    `json:"matched"`
	Probability float64 `json:"probability"`
	Confidence  float64 `json:"confidence"`
	// Reason: matched, no_match, low_probability, low_confidence, router_error,
	// no_routes, route_unusable, failover.
	Reason string `json:"reason"`
	// FallbackUsed is true when Model is a failover candidate rather than the
	// first choice.
	FallbackUsed bool `json:"fallbackUsed"`
	// ErrorClass is the typed router error (unreachable, unauthorized, ...)
	// when the router was unavailable.
	ErrorClass      string           `json:"errorClass,omitempty"`
	RouterProvider  string           `json:"routerProvider,omitempty"`
	RouterModel     string           `json:"routerModel,omitempty"`
	RouterLatencyMs int64            `json:"routerLatencyMs"`
	RouterCostUSD   *float64         `json:"routerCostUsd,omitempty"`
	Candidates      []models.ModelID `json:"candidates,omitempty"`
	// Kind classifies the notice: "routed", "no_match", "router_unavailable",
	// "route_unusable" or "failover".
	Kind string `json:"kind"`
	// Notice is the human readable line (same text as the system message).
	Notice string `json:"notice"`
}

RoutingInfo summarises the last Auto routing decision of a session. It is also the payload of the routing notice (AgentEvent.Routing).

func LastRouting added in v1.2.7

func LastRouting(sessionID string) (RoutingInfo, bool)

LastRouting returns the summary of the last Auto routing decision.

type Service

type Service interface {
	pubsub.Suscriber[AgentEvent]
	Model() models.Model
	Run(ctx context.Context, sessionID string, content string, attachments ...message.Attachment) (<-chan AgentEvent, error)
	LastRunSystemMessages(sessionID string) []string
	Cancel(sessionID string)
	// Steer queues a mid-run feedback message for the given session. It is injected
	// into the conversation at the next safe boundary of the agent loop (after the
	// current iteration's tool results, or at the end of the current turn) without
	// cancelling the run. Returns ErrSessionNotBusy if there is no active run.
	Steer(sessionID string, content string, attachments ...message.Attachment) error
	// PendingSteering reports how many steering messages are queued for the session.
	PendingSteering(sessionID string) int
	// InjectConclusion queues a delegated-task conclusion for injection into a
	// still-running parent loop at the next safe boundary (Case A of the delegation
	// protocol). The content must already be the fully formatted text the parent
	// will see — the agent does not re-frame it. Behaviour mirrors Steer but the
	// message is typed as a conclusion (distinct UI framing) and it carries no
	// attachments. Returns ErrSessionNotBusy when the session is idle; the
	// supervisor uses that signal to fall back to resurrection (a later phase).
	InjectConclusion(sessionID string, content string) error
	// Resume starts a NEW system-initiated run for an IDLE session (Case B of the
	// delegation protocol). The content is the pre-framed resurrection text the
	// supervisor built. It is distinct from Run (user-initiated) and from
	// InjectConclusion (live-loop steering): events still reach UIs via the pubsub
	// broker, but the returned run channel is drained internally so the caller does
	// not have to. Returns ErrSessionBusy if a run is already active. Each Resume
	// increments the session's resurrection counter (see ResurrectionCount); a
	// user-initiated Run resets it.
	Resume(ctx context.Context, sessionID string, content string) error
	// ResumeRun is Resume for a surface that owns the run: it returns the run's
	// event channel instead of draining it, with AgentEventTypeResurrected as the
	// first event on it. The caller must read the channel until it is closed;
	// cancelling ctx cancels the run. Same busy/counter semantics as Resume. See
	// ResumeRegistry for how a surface claims the runs the supervisor resumes.
	ResumeRun(ctx context.Context, sessionID string, content string) (<-chan AgentEvent, error)
	// ResurrectionCount reports how many times the session has been resurrected via
	// Resume since the last user-initiated Run. The supervisor reads it to enforce
	// the MaxResurrections cap; the count auto-resets whenever the user sends a new
	// manual message (Run) and is cleared on Cancel.
	ResurrectionCount(sessionID string) int
	IsSessionBusy(sessionID string) bool
	IsBusy() bool
	Update(agentName config.AgentName, modelID models.ModelID) (models.Model, error)
	Summarize(ctx context.Context, sessionID string) error
	// SummarizeStream performs a manual summary and returns a channel of progress
	// events that is closed when the summary finishes (or fails). Callers that need
	// to know when the (asynchronous) summary is actually done must use this instead
	// of Summarize, which returns immediately and only broadcasts via pubsub.
	SummarizeStream(ctx context.Context, sessionID string) (<-chan AgentEvent, error)
	SetLuaManager(fm *luaengine.FilterManager)
	// GetTools returns the tools available to this agent instance.
	GetTools() []tools.BaseTool
}

func NewAgent

func NewAgent(
	agentName config.AgentName,
	sessions session.Service,
	messages message.Service,
	agentTools []tools.BaseTool,
	skillManager *skills.SkillManager,
) (Service, error)

type SessionContextEnricher added in v0.646.4

type SessionContextEnricher interface {
	ContextEnricher
	EnrichContextForSession(ctx context.Context, sessionID, query string) string
	// SessionStartOnly reports whether enrichment must run only for the first message
	// of a session instead of every turn.
	SessionStartOnly() bool
	// Announce reports whether the run should be announced in the chat with start and
	// end status messages (same treatment as context compaction).
	Announce() bool
}

SessionContextEnricher is an optional extension of ContextEnricher for enrichers that need the active chat session — the agent-loop enricher attaches its run to that session as a child session so the user can inspect it from the UI.

type SessionLLMOverrides added in v0.407.0

type SessionLLMOverrides struct {
	// Model, when non-empty, replaces the agent's configured model for this
	// session only (request-scoped; does not touch global config).
	Model models.ModelID
	// ReasoningEffort / ThinkingMode override inference settings per session.
	ReasoningEffort string
	ThinkingMode    config.ThinkingMode
	// Persona, when non-empty, selects a specific persona for this session.
	// It is only honored when PersonaScoped is true.
	Persona string
	// PersonaScoped marks the session as managing its own persona
	// authoritatively: when true, the per-session Persona (or, if empty,
	// auto-selection) takes precedence over the package-global active persona.
	// This is what lets concurrent sessions use different personas safely.
	PersonaScoped bool
	// Prompt is extra system-prompt text appended for this session only, on
	// top of whatever persona content PersonaScoped resolves (see
	// getPersonaContent in persona_selector.go). It is only honored when
	// PersonaScoped is true, exactly like Persona above: this is the AG-UI
	// per-profile Prompt override (PANDO-US-0014) reusing the existing
	// per-session mechanism instead of adding a second one.
	Prompt string
	// AutoMode is the explicit per-session Auto model mode choice: nil means
	// "follow the global selection" (config modelAutoMode), true/false force it
	// on/off for this session (see SessionAutoMode in model_auto.go).
	AutoMode *bool
}

SessionLLMOverrides holds per-session runtime overrides that should take precedence over agent config when building a request-scoped provider.

These overrides are the mechanism that makes a single process safe to run several agent loops in parallel (e.g. an ACP server serving multiple concurrent sessions, or a warm delegation instance): instead of mutating shared/global agent state per prompt, each session threads its model, persona and inference settings through the request context so two concurrent runs never clobber each other.

func SessionLLMOverridesFor added in v0.643.1

func SessionLLMOverridesFor(sessionID string) SessionLLMOverrides

SessionLLMOverridesFor returns the overrides stored for a session, or the zero value when none are set. Unlike sessionLLMOverridesForContext it does not need a request context, so callers outside the agent loop (the pando_setup bridge) can read the session's effective model.

type TokenUsageInfo added in v0.418.12

type TokenUsageInfo struct {
	PromptTokens     int64
	CompletionTokens int64
	ContextWindow    int64
	Estimated        bool

	// CacheReadTokens, CacheCreationTokens, ReasoningTokens and Cost are only
	// populated on confirmed updates (Estimated == false); estimated updates
	// during tool execution have no breakdown/cost data available.
	CacheReadTokens     int64
	CacheCreationTokens int64
	ReasoningTokens     int64
	Cost                float64
}

TokenUsageInfo carries a live token-usage snapshot for AgentEventTypeTokenUsage. PromptTokens/CompletionTokens are cumulative for the session (same semantics as session.Session), ContextWindow is the effective window for the active model, and Estimated marks the value as provisional (not yet confirmed by the provider).

type ToolDescription added in v0.407.0

type ToolDescription struct {
	Name        string
	Description string
}

ToolDescription carries the minimal information the ContextTrimmer needs about each tool.

type ToolsSetter added in v0.643.1

type ToolsSetter interface {
	SetTools(newTools []tools.BaseTool)
}

ToolsSetter is implemented by agents whose tool set can be swapped while the process runs. It is deliberately kept out of the Service interface so test doubles do not have to implement it; callers type-assert on it.

Jump to

Keyboard shortcuts

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