app

package
v1.12.21 Latest Latest
Warning

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

Go to latest
Published: Jul 17, 2026 License: MIT Imports: 27 Imported by: 0

Documentation

Overview

Package app defines the provider-vendor registry and protocol mapping.

A "provider" here is a business-level vendor (kimi, deepseek, openai, anthropic, …), not a wire protocol. Each vendor carries:

  • the wire protocol it speaks (anthropic-messages or openai-completions)
  • its default endpoint, default model, and API-key env var

CLI, server, and Web UI all resolve through this single registry so a new vendor only needs one line here.

Package app is the single place that constructs provider clients and wires them into an agent. CLI, HTTP server, and IM bridge all bootstrap through here, so the provider wire packages are imported in exactly one spot and the one-directional dependency graph (provider → agent) stays intact.

This file owns provider-client construction and the provider.Provider → agent.Sender adapter. Higher-level session assembly (executor, gate, MCP, sub-agents) lands in bootstrap.go as the migration proceeds.

Index

Constants

View Source
const (
	ProviderAnthropic = "anthropic"
	ProviderOpenAI    = "openai"
)

Provider name constants (legacy). New code should use vendor IDs directly.

View Source
const ProviderCustom = "custom"

ProviderCustom is the catch-all vendor for self-hosted / third-party endpoints. It is the only vendor that accepts a free-form base URL (CustomEndpoint) and the only one whose wire protocol is chosen per config entry rather than pinned in the registry — a base URL and a protocol are both required to build its client.

Variables

View Source
var Registry = []Vendor{
	{
		ID:             "openai",
		DisplayName:    "OpenAI",
		Protocol:       "openai",
		API:            "openai-completions",
		DefaultBaseURL: "https://api.openai.com",
		DefaultModel:   "gpt-5.4",
		Models: []VendorModel{
			{ID: "gpt-5.6-sol", Vision: true},
			{ID: "gpt-5.6-terra", Vision: true},
			{ID: "gpt-5.6-luna", Vision: true},
			{ID: "gpt-5.5", Vision: true},
			{ID: "gpt-5.4", Vision: true},
			{ID: "gpt-5.4-mini", Vision: true},
			{ID: "gpt-5.4-nano", Vision: true},
			{ID: "gpt-4.1", Vision: true},
			{ID: "gpt-4.1-mini", Vision: true},
			{ID: "gpt-4.1-nano", Vision: true},
			{ID: "o3", Vision: true},
			{ID: "o3-mini", Vision: false},
			{ID: "o4-mini", Vision: true},
		},
		LiteModel:    "gpt-5.4-mini",
		APIKeyEnvVar: "OPENAI_API_KEY",
		WebsiteURL:   "https://platform.openai.com/api-keys",
	},
	{
		ID:             "anthropic",
		DisplayName:    "Anthropic",
		Protocol:       "anthropic",
		API:            "anthropic-messages",
		DefaultBaseURL: "https://api.anthropic.com",
		DefaultModel:   "claude-sonnet-4-6",
		Models: []VendorModel{
			{ID: "claude-fable-5", Vision: true},
			{ID: "claude-opus-4-8", Vision: true},
			{ID: "claude-opus-4-7", Vision: true},
			{ID: "claude-opus-4-6", Vision: true},
			{ID: "claude-sonnet-5", Vision: true},
			{ID: "claude-sonnet-4-6", Vision: true},
			{ID: "claude-sonnet-4-5", Vision: true},
			{ID: "claude-haiku-4-5", Vision: true},
		},
		LiteModel:    "claude-haiku-4-5",
		APIKeyEnvVar: "ANTHROPIC_API_KEY",
		WebsiteURL:   "https://console.anthropic.com/settings/keys",
	},
	{
		ID:             "openrouter",
		DisplayName:    "OpenRouter",
		Protocol:       "openai",
		API:            "openai-completions",
		DefaultBaseURL: "https://openrouter.ai/api",
		DefaultModel:   "anthropic/claude-sonnet-4-6",

		Models: []VendorModel{
			{ID: "anthropic/claude-sonnet-5", Vision: true},
			{ID: "anthropic/claude-sonnet-4-6", Vision: true},
			{ID: "anthropic/claude-opus-4-8", Vision: true},
			{ID: "anthropic/claude-opus-4-7", Vision: true},
			{ID: "anthropic/claude-opus-4-6", Vision: true},
			{ID: "anthropic/claude-haiku-4-5", Vision: true},
			{ID: "openai/gpt-5.5", Vision: true},
			{ID: "openai/gpt-5.4", Vision: true},
			{ID: "openai/gpt-5.4-mini", Vision: true},
			{ID: "google/gemini-3-flash-preview", Vision: true},
			{ID: "google/gemini-2.5-pro", Vision: true},
			{ID: "google/gemini-2.5-flash", Vision: true},
			{ID: "meta-llama/llama-3.3-70b-instruct", Vision: false},
			{ID: "x-ai/grok-4.5", Vision: true},
			{ID: "x-ai/grok-4.3", Vision: true},
			{ID: "tencent/hy3", Vision: false},
			{ID: "xiaomi/mimo-v2.5", Vision: true},
			{ID: "deepseek/deepseek-v4-flash", Vision: false},
			{ID: "deepseek/deepseek-v4-pro", Vision: false},
			{ID: "z-ai/glm-5.2", Vision: false},
			{ID: "minimax/minimax-m3", Vision: true},
			{ID: "nvidia/nemotron-3-ultra-550b-a55b", Vision: false},
		},
		APIKeyEnvVar: "OPENROUTER_API_KEY",
		WebsiteURL:   "https://openrouter.ai/keys",
	},
	{
		ID:             "deepseek",
		DisplayName:    "DeepSeek",
		Protocol:       "openai",
		API:            "openai-completions",
		DefaultBaseURL: "https://api.deepseek.com",
		DefaultModel:   "deepseek-v4-pro",

		Models: []VendorModel{
			{ID: "deepseek-v4-flash", Vision: false},
			{ID: "deepseek-v4-pro", Vision: false},
		},
		LiteModel:    "deepseek-v4-flash",
		APIKeyEnvVar: "DEEPSEEK_API_KEY",
		WebsiteURL:   "https://platform.deepseek.com/api_keys",
	},
	{
		ID:             "minimax",
		DisplayName:    "Minimax",
		Protocol:       "openai",
		API:            "openai-completions",
		DefaultBaseURL: "https://api.minimaxi.com",
		DefaultModel:   "MiniMax-M3",
		Models: []VendorModel{
			{ID: "MiniMax-M2.5", Vision: false},
			{ID: "MiniMax-M2.7", Vision: false},
			{ID: "MiniMax-M3", Vision: true},
		},
		APIKeyEnvVar: "MINIMAX_API_KEY",
		WebsiteURL:   "https://www.minimaxi.com/user-center/basic-information/interface-key",
		EndpointVariants: []EndpointVariant{
			{Label: "Mainland China", LabelKey: "settings.models.baseurl.variant.mainland_cn", BaseURL: "https://api.minimaxi.com", Region: "cn"},
			{Label: "International", LabelKey: "settings.models.baseurl.variant.international", BaseURL: "https://api.minimax.io", Region: "intl"},
		},
	},
	{
		ID:             "kimi",
		DisplayName:    "Kimi (Moonshot)",
		Protocol:       "openai",
		API:            "openai-completions",
		DefaultBaseURL: "https://api.moonshot.cn",
		DefaultModel:   "kimi-k2.6",

		Models: []VendorModel{
			{ID: "k3", Vision: true},
			{ID: "kimi-k2.6", Vision: true},
			{ID: "kimi-k2.7-code", Vision: true},
		},
		APIKeyEnvVar: "MOONSHOT_API_KEY",
		WebsiteURL:   "https://platform.moonshot.cn/console/api-keys",
		EndpointVariants: []EndpointVariant{
			{Label: "Mainland China", LabelKey: "settings.models.baseurl.variant.mainland_cn", BaseURL: "https://api.moonshot.cn", Region: "cn"},
			{Label: "International", LabelKey: "settings.models.baseurl.variant.international", BaseURL: "https://api.moonshot.ai", Region: "intl"},
		},
	},
	{
		ID:             "kimi-coding-plan",
		DisplayName:    "Kimi Coding Plan",
		Protocol:       "anthropic",
		API:            "anthropic-messages",
		DefaultBaseURL: "https://api.kimi.com/coding",
		DefaultModel:   "kimi-for-coding",
		Models: []VendorModel{
			{ID: "kimi-for-coding", Vision: true},
			{ID: "kimi-for-coding-highspeed", Vision: true},
			{ID: "k3", Vision: true},
			{ID: "kimi-k2.6", Vision: true},
			{ID: "kimi-k2.7-code", Vision: true},
		},
		APIKeyEnvVar: "MOONSHOT_API_KEY",
		WebsiteURL:   "https://platform.moonshot.cn/console/api-keys",
	},
	{
		ID:             "glm",
		DisplayName:    "GLM (Zhipu)",
		Protocol:       "openai",
		API:            "openai-completions",
		DefaultBaseURL: "https://open.bigmodel.cn/api/paas/v4",
		DefaultModel:   "glm-4.5",

		Models: []VendorModel{
			{ID: "glm-5.2", Vision: false},
			{ID: "glm-4.5", Vision: false},
			{ID: "glm-4.5-air", Vision: false},
			{ID: "glm-4.5-flash", Vision: false},
		},
		LiteModel:    "glm-4.5-flash",
		APIKeyEnvVar: "ZHIPU_API_KEY",
		WebsiteURL:   "https://open.bigmodel.cn/usercenter/apikey",
		EndpointVariants: []EndpointVariant{
			{Label: "Mainland China", LabelKey: "settings.models.baseurl.variant.mainland_cn", BaseURL: "https://open.bigmodel.cn/api/paas/v4", Region: "cn"},
			{Label: "International", LabelKey: "settings.models.baseurl.variant.international", BaseURL: "https://api.z.ai", Region: "intl"},
		},
	},
	{
		ID:             "bailian",
		DisplayName:    "Bailian (Alibaba)",
		Protocol:       "openai",
		API:            "openai-completions",
		DefaultBaseURL: "https://dashscope.aliyuncs.com/compatible-mode",
		DefaultModel:   "qwen3.7-plus",

		Models: []VendorModel{
			{ID: "qwen3.7-max", Vision: false},
			{ID: "qwen3.7-plus", Vision: true},
			{ID: "qwen3.6-flash", Vision: true},
			{ID: "qwen3.5-flash", Vision: true},
			{ID: "qwen-plus", Vision: false},
		},
		LiteModel:    "qwen3.5-flash",
		APIKeyEnvVar: "DASHSCOPE_API_KEY",
		WebsiteURL:   "https://bailian.console.aliyun.com",
		EndpointVariants: []EndpointVariant{
			{Label: "Mainland China", LabelKey: "settings.models.baseurl.variant.mainland_cn", BaseURL: "https://dashscope.aliyuncs.com/compatible-mode", Region: "cn"},
			{Label: "International", LabelKey: "settings.models.baseurl.variant.international", BaseURL: "https://dashscope-us.aliyuncs.com/compatible-mode", Region: "intl"},
		},
	},
	{
		ID:             "mimo",
		DisplayName:    "MiMo (Xiaomi)",
		Protocol:       "openai",
		API:            "openai-completions",
		DefaultBaseURL: "https://api.xiaomimimo.com",
		DefaultModel:   "mimo-v2.5-pro",

		Models: []VendorModel{
			{ID: "mimo-v2.5-pro", Vision: true},
			{ID: "mimo-v2.5-flash", Vision: true},
		},
		APIKeyEnvVar: "MIMO_API_KEY",
		WebsiteURL:   "https://platform.xiaomimimo.com/#/console/api-keys",
	},
	{
		ID:             "longcat",
		DisplayName:    "LongCat (Meituan)",
		Protocol:       "openai",
		API:            "openai-completions",
		DefaultBaseURL: "https://api.longcat.chat/openai",
		DefaultModel:   "LongCat-2.0",

		Models: []VendorModel{
			{ID: "LongCat-2.0", Vision: false},
		},
		APIKeyEnvVar: "LONGCAT_API_KEY",
		WebsiteURL:   "https://longcat.chat/platform/api_keys",
	},
	{
		ID:          ProviderCustom,
		DisplayName: "Custom",

		Protocol:       "",
		API:            "",
		APIKeyEnvVar:   "CUSTOM_API_KEY",
		CustomEndpoint: true,
	},
}

Registry is the ordered list of supported vendors. The order is the display order in the Web UI onboarding dropdown.

Functions

func AnthropicThinkingBudget

func AnthropicThinkingBudget(effort string) int

AnthropicThinkingBudget maps a unified reasoning-effort level to an Anthropic thinking-token figure. "" (off) yields 0, which disables thinking. On modern Claude models (adaptive thinking + output_config.effort) the provider uses this only as a max_tokens floor; on older Claude / Kimi-for-coding it is the literal thinking.budget_tokens. The provider bumps max_tokens to fit a value larger than it, so the higher levels can outrun the default cap safely.

func ConnectMCP

func ConnectMCP(ctx context.Context, cwd string, warn io.Writer) (func(), error)

ConnectMCP loads the MCP server config under cwd, connects every server non-interactively, and registers the resulting surface so DefaultToolsFor / the tool executor pick it up. It is the server/IM counterpart to the CLI's own (interactive, OAuth-prompting) connect path — here authPromptFor is nil, so servers needing fresh authorization are skipped (a nil prompt makes authorize() fail fast with ErrReauthRequired) while stdio, header-auth, and cached-OAuth servers connect.

Returns a cleanup that unregisters and closes the registry; it is always non-nil (a no-op when no servers connected), so callers can defer it unconditionally. warn receives per-server skip diagnostics.

func ConnectMCPServer

func ConnectMCPServer(ctx context.Context, name string, entry mcp.ServerEntry, childStderr io.Writer) error

ConnectMCPServer connects (or reconnects) a single named server into the active registry, installing an empty registry first if none is active — the incremental path the web management API uses so adding one server doesn't restart every other connection. The connect error (if any) is recorded on the registry and returned.

func ConnectMCPServerAuth

func ConnectMCPServerAuth(ctx context.Context, name string, entry mcp.ServerEntry, prompt mcp.OAuthPrompt, childStderr io.Writer) error

ConnectMCPServerAuth is ConnectMCPServer with an interactive OAuth prompt. A non-nil prompt on an oauth entry widens the connect window to fit an interactive browser authorization.

func DefaultBaseURL deprecated

func DefaultBaseURL(providerName string) string

DefaultBaseURL returns the vendor's built-in API endpoint for the given provider ID, or "" for an unknown one. Exposed so callers can show the effective endpoint without importing the vendor packages themselves.

Deprecated: prefer VendorBaseURL(id) from provider.go.

func DisconnectMCPServer

func DisconnectMCPServer(name string)

DisconnectMCPServer drops one server's live connection (and recorded connect error) from the active registry, if any.

func ImplicitLiteModel

func ImplicitLiteModel(provider, model, baseURL string) string

ImplicitLiteModel returns the lite model a session should compact on when the user configured none explicitly: the vendor's registry LiteModel, served over the SAME sender as the primary model — same endpoint, key, and prompt-cache routing. It returns "" (no implicit lite) when:

  • the vendor is unknown or has no LiteModel,
  • the primary model already IS the lite model, or
  • baseURL points off the vendor's own endpoints — a custom endpoint is a different backend wearing a compatible protocol, and its catalogue won't include the vendor's lite model.

func IsAnthropicProtocol

func IsAnthropicProtocol(id string) bool

IsAnthropicProtocol reports whether the vendor speaks the Anthropic protocol.

func IsKnownVendor

func IsKnownVendor(id string) bool

IsKnownVendor reports whether id is a registered vendor ID.

func MakeBrowserHealer

func MakeBrowserHealer(sender agent.Sender, model string) browser.Healer

MakeBrowserHealer builds the LLM-backed step healer used by the browser tool's run_skill. When a recorded step fails (e.g. a drifted selector), it shows the model the page's current interactive elements (a text digest — model-agnostic, no vision needed when the DOM/AX is reachable) and asks for the corrected selector, which it writes into the step for retry + write-back.

Returns nil when no sender is configured, so run_skill stays deterministic.

func MakeSkillGenerator

func MakeSkillGenerator(sender agent.Sender, model string) browser.SkillGenerator

MakeSkillGenerator builds the LLM-backed skill distiller for record_stop. It refines the deterministic baseline into a clean optimal-path skill, grounded in the captured selectors (the engine enforces the selector constraint). Returns nil when no sender is configured, so generation stays deterministic.

func NewPermissionGate

func NewPermissionGate(engine *permission.Engine, ask PermissionAsk) agent.PermissionGate

NewPermissionGate builds the single agent.PermissionGate every transport uses. The engine resolves allow/deny/ask policy. Pass a non-nil ask for an interactive transport (the CLI prompts the user on ask-class verdicts); pass nil for a non-interactive one (HTTP server, IM bridge), where ask resolves to deny — the same posture the old per-transport gates had.

func NewSender

func NewSender(opts SenderOptions) (agent.Sender, error)

NewSender builds the provider client for opts and wraps it as an agent.Sender. It is the single entry point through which every transport obtains a sender.

func NewSessionToolEnv added in v1.8.6

func NewSessionToolEnv(
	ctx context.Context,
	a *agent.Agent,
	sessionID string,
	executor agent.ToolExecutor,
	callbacks ToolEnvCallbacks,
) (context.Context, agent.ToolExecutor, *tools.SubAgentManager, func())

NewSessionToolEnv builds a session-scoped, concurrency-safe tool environment for one turn. It returns a context stamped with the per-session managers, a fresh *tools.DefaultRegistry, and the SubAgentManager that was wired into the context.

Contracts:

  • It does NOT read or write Agent.Gate. Callers set a.Gate before or after this call.
  • It does NOT call config.Load() or permission.New(). It performs no local file I/O.
  • It does NOT handle process-global browser state (SetBrowserVision etc.) or workflow-discovery-cwd state. See dev-docs/octoagent-pkg-design.md.
  • It does NOT register or use an MCP registry.

The returned cleanup function is currently a no-op but is reserved for future resource release. It does NOT destroy the session-scoped managers (sub-agent, background, workflow), because those are cached by sessionID and reused across turns. Callers manage session lifecycle resources themselves.

func RefreshMemoryBackend added in v1.10.4

func RefreshMemoryBackend()

RefreshMemoryBackend re-reads memory_backend from config and re-installs it via tools.SetMemoryBackend/SetMemoryBackendAutoRecall. WireTools calls this once for the CLI's whole process lifetime; internal/server calls it fresh on every turn (serve never calls WireTools) since it has no equivalent one-time startup hook — see its callers for why it must run before tools.MemoryBackendGuidance()/tools.RegisterMemoryBackendHooks. A bad Type/BaseURL just leaves the backend unconfigured rather than erroring; cheap to call repeatedly (a lightweight REST client, not a persistent connection). Uses LoadCached so a config.yml that's mid-edit and momentarily invalid doesn't tear down a live serve session's memory backend on the next turn — it keeps the last config that parsed.

func SetMCPChildStderr

func SetMCPChildStderr(w io.Writer)

SetMCPChildStderr sets the destination for stdio MCP subprocess stderr across every app-level connect path (ConnectMCP, SwapMCP, ConnectMCPServer*). Pass nil to restore the os.Stderr default. Set it before connecting.

func ShutdownMCP

func ShutdownMCP()

ShutdownMCP clears the active registry and closes it. The counterpart of SwapMCP for process shutdown.

func SwapMCP

func SwapMCP(ctx context.Context, cwd string, warn io.Writer) error

SwapMCP reloads the MCP config under cwd, connects a fresh registry, and atomically replaces the active one (closing the old registry after the swap so in-flight readers holding it can finish dialing). Unlike ConnectMCP it installs the registry even when zero servers connected — the per-server connect errors it records are what a management UI displays. With zero servers configured the active registry is cleared. On config error the active registry is left untouched.

Callers that expose this concurrently (the web server) must serialise calls themselves; two overlapping swaps would race on which registry survives.

func TestConnection

func TestConnection(ctx context.Context, providerName, apiKey, baseURL, model, protocol string) error

TestConnection pings the provider with a minimal request to verify that the API key, base URL, and model all work. It returns a descriptive error on failure (auth, model not found, network, etc.).

func ToolSearchConfigFrom

func ToolSearchConfigFrom(c config.ToolSearchConfig) tools.ToolSearchConfig

ToolSearchConfigFrom maps the persisted tools.tool_search config block onto the tools-package config. Unknown/empty "enabled" defaults to auto; numeric zero values are left for SetToolSearchConfig to backfill with its documented defaults. Shared by every entry point so Tool Search behaves identically.

func VendorAPIKeyEnvVar

func VendorAPIKeyEnvVar(id string) string

VendorAPIKeyEnvVar returns the environment-variable name for a vendor's API key.

func VendorBaseURL

func VendorBaseURL(id string) string

VendorBaseURL returns the default base URL for a vendor ID, or "" if unknown.

func VendorByBaseURL

func VendorByBaseURL(baseURL string) string

VendorByBaseURL returns the vendor whose default endpoint or one of whose regional variants equals baseURL (ignoring a trailing slash), or "". The settings panel saves entries without naming a vendor, so the server infers it from the endpoint the user picked.

func VendorCustomEndpoint

func VendorCustomEndpoint(id string) bool

VendorCustomEndpoint reports whether the vendor has no fixed endpoint and requires a user-supplied base URL.

func VendorDefaultModel

func VendorDefaultModel(id string) string

VendorDefaultModel returns the built-in default model for a vendor ID.

func VendorDisplayName

func VendorDisplayName(id string) string

VendorDisplayName returns the human-readable label for a vendor ID.

func VendorModelVision

func VendorModelVision(vendorID, modelID string) (vision, known bool)

VendorModelVision reports a predefined model's image-input capability. known is false when the vendor or model isn't in the catalogue (e.g. the Custom vendor, or a model id the user typed by hand) — callers then fall back to the heuristic (config.ModelSupportsVision) or ask the user.

func VendorModelVisionMap

func VendorModelVisionMap(id string) map[string]bool

VendorModelVisionMap returns model-id → vision for a vendor's catalogue, for the web form to pre-fill the toggle when a predefined model is picked. Nil for unknown vendors or vendors with no predefined models (e.g. Custom).

func VendorModels

func VendorModels(id string) []string

VendorModels returns the catalogue of model IDs offered for a vendor (for a UI dropdown), or nil if the vendor is unknown.

func VendorNeedsProtocol

func VendorNeedsProtocol(id string) bool

VendorNeedsProtocol reports whether the vendor has no fixed wire protocol, so the caller must supply one ("anthropic" or "openai") from the model entry. Only the Custom catch-all needs this; every named vendor pins its protocol.

func VendorProtocol

func VendorProtocol(id string) string

VendorProtocol returns "anthropic" or "openai" for a vendor ID, or "" if unknown.

func VendorWebsiteURL

func VendorWebsiteURL(id string) string

VendorWebsiteURL returns the key-management page URL for a vendor ID.

Types

type EndpointVariant

type EndpointVariant struct {
	Label    string `json:"label"`
	LabelKey string `json:"label_key,omitempty"`
	BaseURL  string `json:"base_url"`
	Region   string `json:"region,omitempty"`
}

EndpointVariant is a regional endpoint alternative for a vendor.

func VendorEndpointVariants

func VendorEndpointVariants(id string) []EndpointVariant

VendorEndpointVariants returns the regional endpoint alternatives for a vendor, or nil if it has none / is unknown.

type PermissionAsk

type PermissionAsk func(ctx context.Context, toolName string, toolInput map[string]any) (allow, remember bool, err error)

PermissionAsk prompts the user to approve one tool call (already unwrapped to its real tool name). It returns whether to allow the call and whether to remember that decision for the rest of the session. A nil PermissionAsk makes the gate non-interactive: ask-class verdicts resolve straight to deny.

type SenderOptions

type SenderOptions struct {
	Provider string // vendor ID, e.g. "kimi", "deepseek", "anthropic", "openai"
	APIKey   string
	BaseURL  string // optional endpoint override; empty uses the vendor default
	// Protocol ("anthropic" | "openai") is required only for the Custom vendor,
	// which has no registry-pinned wire format; named vendors ignore it.
	Protocol string

	// CacheKey is forwarded as the provider's prompt-cache key, stable across a
	// conversation's turns so the backend routes them to the same cache.
	CacheKey string
	// ThinkingBudget > 0 enables Anthropic extended thinking with this trace
	// budget; ignored by OpenAI-protocol vendors.
	ThinkingBudget int
	// ReasoningEffort ("low"|"medium"|"high"|"xhigh"|"max") is forwarded to OpenAI-protocol
	// vendors as reasoning_effort; ignored by Anthropic-protocol vendors
	// (which use ThinkingBudget).
	ReasoningEffort string
	// ShowReasoning gates whether the reasoning/thinking trace is surfaced to
	// the agent event stream.
	ShowReasoning bool
}

SenderOptions is everything needed to build an agent.Sender for a vendor. Key resolution and any user-facing help text stay with the caller (a CLI prints setup hints; a server returns an error) — this layer only constructs.

type Spawner

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

Spawner implements tools.Spawner by building a child agent on each sub_agent call. The child shares the parent's Sender (one provider connection) and System (same harness identity), but runs in isolation: fresh History, no visibility into the parent's conversation, its own loop budget. The final child reply text is returned to the parent as the sub_agent tool_result; the child's token usage is rolled into the parent's session totals so they report one consolidated number.

toolsFn is a deferred lookup of the LLM-facing tool catalog (DefaultTools), given the ctx the child is being spawned under — so a server/cron caller can pass tools.DefaultToolsForCtx and have the child's own tool list reflect that turn's ctx-scoped sub-agent manager instead of depending on process-global state (#1133). Resolving it on each Spawn — rather than capturing a slice at construction — also lets cmd/octo set up the spawner before computing the tool list, since SetSpawner has to run first for sub_agent to appear in DefaultTools().

func NewSpawner

func NewSpawner(parent *agent.Agent, executor agent.ToolExecutor, toolsFn func(ctx context.Context) []agent.ToolDefinition) *Spawner

func (*Spawner) Continue

func (s *Spawner) Continue(ctx context.Context, agentID, message string) (tools.SpawnResult, error)

Continue implements tools.Spawner. It re-runs a still-alive child with a new message. An unknown / evicted id returns an error whose text steers the model to start a fresh sub-agent.

func (*Spawner) Spawn

Spawn implements tools.Spawner. It builds an isolated child, registers it so a later Continue can resume it, runs the first prompt, and returns the child's id alongside its reply.

type ToolEnv

type ToolEnv struct {
	Executor    tools.DefaultRegistry
	SubAgentMgr *tools.SubAgentManager
	ToolsFor    func(ctx context.Context) []agent.ToolDefinition
}

ToolEnv is the wired tool environment for a session: the executor the agent loop dispatches tool calls through, the manager that tracks async sub-agents (sub_agent), and a model-aware tool-list function. Call ToolsFor again after MCP connects so the list (or its Tool Search bridge) picks up the new surface. ToolsFor takes a ctx (server/cron callers pass the turn's ctx so tools.DefaultToolsForCtx can see that turn's ctx-scoped sub-agent manager, #1133); the CLI/TUI's single-session path can pass any ctx since it has no ctx-scoped manager and always resolves through the process-global slots this function also registers.

func WireTools

func WireTools(a *agent.Agent, enableTasks bool) (ToolEnv, func())

WireTools sets up the tool environment every full-loop entry point shares — the CLI today, the HTTP server and IM bridge as they migrate. It builds a read-before-write executor, registers the sub-agent spawner globally (so sub_agent appears in the catalog, which is why SetSpawner must run before any DefaultTools call), creates the async sub-agent manager, and — when enableTasks — installs the session task store.

It returns the wired environment and a cleanup that resets the process-global registrations (spawner, task store); defer it for the session's lifetime. The caller still owns the agent's Sender, System prompt, knobs, gate, asker, and MCP connection strategy — those legitimately differ per entry point.

type ToolEnvCallbacks added in v1.8.6

type ToolEnvCallbacks struct {
	SubAgentOnEvent func(tools.SubAgentEvent)
	SubAgentOnExit  func(tools.SubAgentNotification)
	WorkflowOnEvent func(tools.WorkflowEvent)
	WorkflowOnDone  func(tools.WorkflowNotification)
}

ToolEnvCallbacks carries optional hooks for sub-agent and workflow lifecycle events. All fields may be nil.

type Vendor

type Vendor struct {
	ID               string            // canonical identifier, e.g. "kimi"
	DisplayName      string            // human label, e.g. "Kimi (Moonshot)"
	Protocol         string            // "anthropic" or "openai"
	API              string            // "anthropic-messages" or "openai-completions"
	DefaultBaseURL   string            // vendor's official endpoint (host only; the client appends the protocol path)
	DefaultModel     string            // cheapest/reasoning-capable default
	Models           []VendorModel     // available models (for UI dropdown), each with its vision capability
	LiteModel        string            // lightweight/cheaper model variant
	APIKeyEnvVar     string            // environment variable name for the key
	WebsiteURL       string            // link to the key-management page
	EndpointVariants []EndpointVariant // regional endpoint alternatives
	// CustomEndpoint marks a vendor with no fixed endpoint: the user must
	// supply a base URL. Vendors without it are pinned to DefaultBaseURL
	// (plus EndpointVariants) — they don't take arbitrary URLs.
	CustomEndpoint bool
}

Vendor is everything needed to bootstrap a provider client and render it in

type VendorModel

type VendorModel struct {
	ID     string
	Vision bool
}

VendorModel is one catalogue entry: the model id plus whether it accepts image input. Vision is authoritative for predefined vendors — the value is copied onto the model entry when the user picks it, so the capability is recorded rather than re-guessed from the id at runtime.

Jump to

Keyboard shortcuts

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