code

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: May 31, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Overview

Package code defines the Agent interface implemented by the in-process wingman backend (sub-package wingman) and the external ACP subprocess backend (sub-package acp). Higher layers (server, TUI) hold one active Agent and swap it on user selection.

The interface is session-id-explicit: every per-conversation operation takes a session id allocated via [Agent.NewSession]. Backends own the session catalog (wingman: on-disk; acp: the external server). Switching the active agent closes the prior one.

Index

Constants

View Source
const BuiltinAgentName = "wingman"

BuiltinAgentName identifies the in-process wingman backend. It's reserved — user-defined AgentDef entries cannot share this name.

Variables

View Source
var AvailableModels = []Model{
	{ID: "claude-sonnet-4-6", Name: "Claude Sonnet 4.6"},
	{ID: "claude-sonnet-4-5", Name: "Claude Sonnet 4.5"},

	{ID: "gpt-5.5", Name: "GPT 5.5"},
	{ID: "gpt-5.4", Name: "GPT 5.4"},

	{ID: "gpt-5.3-codex", Name: "GPT 5.3 Codex"},
	{ID: "gpt-5.2-codex", Name: "GPT 5.2 Codex"},

	{ID: "claude-opus-4-8", Name: "Claude Opus 4.8"},
	{ID: "claude-opus-4-7", Name: "Claude Opus 4.7"},
	{ID: "claude-opus-4-6", Name: "Claude Opus 4.6"},
	{ID: "claude-opus-4-5", Name: "Claude Opus 4.5"},
}

AvailableModels lives here (not pkg/agent) so the agent runtime stays provider-agnostic.

Functions

func ModelName

func ModelName(id string) string

func SaveAgents added in v0.7.0

func SaveAgents(defs []AgentDef) error

SaveAgents writes the agents config. Used by the desktop app's settings page. Creating the parent directory is handled here so callers don't have to.

func SessionIDFromContext added in v0.7.0

func SessionIDFromContext(ctx context.Context) string

SessionIDFromContext returns the session id set by WithSessionID, or "" when none is present.

func SessionsDir added in v0.6.9

func SessionsDir(workingDir string) string

func WithSessionID added in v0.7.0

func WithSessionID(ctx context.Context, sid string) context.Context

WithSessionID stamps sid onto ctx so downstream tool calls can recover it via SessionIDFromContext. The coder agent does this in Send so elicitation UIs can route prompts back to the right session.

Types

type Agent

type Agent interface {
	// Name returns a stable identifier for this backend. For wingman
	// it's [BuiltinAgentName]; for ACP backends it's the [AgentDef.Name]
	// that constructed them.
	Name() string

	// Workspace returns the shared workspace the agent is rooted at.
	// Same instance regardless of which backend is active — its
	// Rewind / LSP / MCP subsystems are wingman-only side-effects but
	// the workspace itself (RootPath, Skills, MemoryPath) is shared.
	Workspace() *Workspace

	// Models reports the available model catalog and the currently
	// selected id. Cached read — no RPC. Empty list = the backend
	// doesn't expose a model selector.
	Models() (available []Model, current string)

	// SetModel switches the active model. Returns [errors.ErrUnsupported]
	// when the backend has no model selector.
	SetModel(ctx context.Context, id string) error

	// Effort reports the current effort id and the available values.
	// Empty options = effort selector not supported.
	Effort() (current string, options []string)

	SetEffort(ctx context.Context, value string) error

	// Modes reports the operating modes the backend exposes for the given
	// session and the currently active mode id. An empty list means the
	// backend has no mode selector (the UI hides the picker). Cached read —
	// no RPC.
	Modes(sessionID string) (available []Mode, current string)

	// SetMode switches the session's active operating mode. Returns
	// [errors.ErrUnsupported] when the backend has no mode selector, or an
	// error when modeID is not one of the advertised modes.
	SetMode(ctx context.Context, sessionID, modeID string) error

	// ListSessions returns the backend's saved session catalog scoped
	// to the workspace.
	ListSessions(ctx context.Context) ([]SessionInfo, error)

	// NewSession allocates a fresh session and returns its id. For
	// wingman this is a locally minted UUID; for ACP it's the id
	// returned by the ACP server's session/new.
	NewSession(ctx context.Context) (string, error)

	// LoadSession restores an existing session into memory so
	// [Messages] / [Usage] reflect its transcript and subsequent
	// [Send] calls continue it.
	LoadSession(ctx context.Context, id string) error

	// DeleteSession removes a session from the catalog. Returns
	// [errors.ErrUnsupported] when the backend can't delete (ACP).
	DeleteSession(ctx context.Context, id string) error

	// Messages returns the transcript for a session id. Returns nil
	// for sessions the backend hasn't loaded.
	Messages(sessionID string) []agent.Message

	Usage(sessionID string) agent.Usage

	// Send drives a turn. Returns nil when a turn is already running
	// for this session id. The iterator yields per-update chunks; the
	// implementation commits the assembled message(s) into the
	// session's transcript by end-of-turn.
	Send(ctx context.Context, sessionID string, input []agent.Content) iter.Seq2[agent.Message, error]

	// Cancel aborts an in-flight Send for the session id. No-op when
	// no turn is in flight or the id is unknown.
	Cancel(sessionID string)

	// Close releases all resources (subprocess, IO, file handles).
	// Idempotent.
	Close() error
}

Agent is the swappable backend that drives chat turns and owns its own session catalog + transcript storage. The two concrete implementations live in sub-packages wingman and acp.

All methods are safe for concurrent use across distinct session ids. Concurrent calls on the SAME session id are NOT supported — callers must ensure only one Send is in flight per session at a time.

type AgentDef added in v0.7.0

type AgentDef struct {
	// Name is the user-facing label and the key used by [*Agent.SetAgent].
	Name string `json:"name"`

	// Command is the absolute path (or PATH-lookup name) of the ACP
	// server binary to spawn.
	Command string `json:"command"`

	// Args are extra arguments passed to the subprocess.
	Args []string `json:"args,omitempty"`

	// Env adds/overrides environment variables for the subprocess. The
	// parent process's environment is inherited.
	Env map[string]string `json:"env,omitempty"`
}

AgentDef describes an external ACP-server backend. The selected backend is launched as a subprocess; its stdio carries the ACP JSON-RPC stream. Wingman talks to it as a client (analogous to Zed / other ACP hosts).

Defs are loaded from ~/.wingman/agents.json by LoadAgents; the built-in wingman backend (name = BuiltinAgentName) is always available and doesn't need a config entry.

func LoadAgents added in v0.7.0

func LoadAgents() []AgentDef

LoadAgents reads ~/.wingman/agents.json and returns the configured external coder backends. A missing or unreadable file means "only the built-in wingman backend is available." Entries without a Name or Command are dropped silently so a malformed line doesn't break the selection list.

type Mode added in v0.8.0

type Mode struct {
	ID          string
	Name        string
	Description string
}

Mode is one operating mode a backend can run a session in — typically an approval/sandbox or planning level. It mirrors ACP's SessionMode, and is what the UI's mode picker is populated from.

type Model

type Model struct {
	ID   string
	Name string
}

type SessionInfo added in v0.7.0

type SessionInfo struct {
	ID        string
	Title     string
	UpdatedAt time.Time
}

SessionInfo is one row in the backend's session catalog (wingman's on-disk list or the ACP server's ListSessions response).

type UI

type UI interface {
	Ask(ctx context.Context, message string) (string, error)
	Confirm(ctx context.Context, message string) (bool, error)
}

UI is the elicitation hook a frontend provides for tool ask/confirm prompts. Pass nil to NewAgent for safe defaults (Confirm → true, Ask → ""). The session id that triggered the prompt is on ctx via SessionIDFromContext for UIs that route prompts per session.

type Workspace added in v0.6.9

type Workspace struct {
	Root        *os.Root
	RootPath    string
	MemoryPath  string
	ScratchPath string

	Skills []skill.Skill

	MCP *mcp.Manager
	// LSP and Rewind are set by WarmUp; nil for unsupported workspaces.
	LSP    *lsp.Manager
	Rewind *rewind.Manager
	// contains filtered or unexported fields
}

func NewWorkspace added in v0.6.9

func NewWorkspace(workDir string) (*Workspace, error)

func (*Workspace) Checkpoints added in v0.6.9

func (w *Workspace) Checkpoints() ([]rewind.Checkpoint, error)

func (*Workspace) Close added in v0.6.9

func (w *Workspace) Close()

func (*Workspace) Commit added in v0.6.9

func (w *Workspace) Commit(msg string) error

func (*Workspace) Diagnostics added in v0.6.9

func (w *Workspace) Diagnostics(ctx context.Context) map[string][]lsp.Diagnostic

func (*Workspace) Diffs added in v0.6.9

func (w *Workspace) Diffs() ([]rewind.FileDiff, error)

func (*Workspace) InitMCP added in v0.6.9

func (w *Workspace) InitMCP(ctx context.Context) error

func (*Workspace) IsGitRepo added in v0.6.9

func (w *Workspace) IsGitRepo() bool

IsGitRepo is re-evaluated each call so callers can react to mid-session `git init` / `rm -rf .git`.

func (*Workspace) ManagedTools added in v0.7.0

func (w *Workspace) ManagedTools() (mcpTools, lspTools []tool.Tool)

ManagedTools snapshots MCP + LSP tools under the workspace mutex so a concurrent WarmUp / InitMCP can't race the per-turn tool() callback. Exported for use by the wingman sub-package, which builds each session's tool set from baseTools + ManagedTools().

func (*Workspace) MemoryContent added in v0.6.9

func (w *Workspace) MemoryContent() string

MemoryContent renders an index of the memory dir for injection into the system prompt: one line per `*.md` file with a short hook. The hook is the file's frontmatter `description`, falling back to the first non-empty line of the body (heading markers stripped). Cached by per-file mtime so repeat turns don't re-read.

func (*Workspace) Restore added in v0.6.9

func (w *Workspace) Restore(hash string) error

func (*Workspace) SyncProjectMode added in v0.6.9

func (w *Workspace) SyncProjectMode()

SyncProjectMode rebuilds LSP when the working dir's git status flips. No-op on unsupported workspaces.

func (*Workspace) WarmUp added in v0.6.9

func (w *Workspace) WarmUp()

WarmUp probes the workspace and initializes Rewind/LSP. Idempotent. Resulting modes:

  • supported git repo → Rewind set, LSP set, lspTools set
  • supported scratch → Rewind set, LSP nil, lspTools nil
  • unsupported (huge) → Rewind nil, LSP nil

Directories

Path Synopsis
Package acp is the ACP-subprocess code.Agent implementation.
Package acp is the ACP-subprocess code.Agent implementation.
Package agent is the in-process code.Agent implementation.
Package agent is the in-process code.Agent implementation.

Jump to

Keyboard shortcuts

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