agents

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 11, 2026 License: Apache-2.0 Imports: 29 Imported by: 0

Documentation

Overview

Package agents implements the VORTEX agent runtime (build plan M10): a supervised, message-passing system of autonomous sub-agents coordinated by a single user-facing coordinator. This file defines the core types — agent state machine, configuration, inter-agent message envelope, the Agent interface, and an embeddable BaseAgent that the coordinator and spawned sub-agents build upon.

Index

Constants

View Source
const (
	TypePersistent = "persistent"
	TypeTask       = "task"
)

Agent type constants.

View Source
const (
	MsgTaskBrief = "task_brief"
	MsgResult    = "result"
	MsgError     = "error"
	MsgStatus    = "status"
)

Message type constants.

Variables

View Source
var (
	// ErrBusFull is returned when a recipient's inbox is full; sends are
	// non-blocking so a slow agent never stalls the sender.
	ErrBusFull = errors.New("agents: recipient inbox full")
	// ErrAgentNotFound is returned when routing to an unregistered agent.
	ErrAgentNotFound = errors.New("agents: agent not found")
	// ErrAlreadyRegistered is returned when registering a duplicate name.
	ErrAlreadyRegistered = errors.New("agents: agent already registered")
)

Package-level sentinel errors shared by the agent runtime and the message bus (defined here so File 1 — agent.go — compiles independently of bus.go).

View Source
var DefaultAllowedCommands = []string{
	"go", "flutter", "git", "tar", "unzip",
}

DefaultAllowedCommands is the whitelist used when none is supplied.

Interpreters and package managers (python3, npm, pip3) are deliberately EXCLUDED: they execute arbitrary code from a single flag (python3 -c, npm run, pip3 install <pkg-with-setup.py>), so name-based whitelisting gives no real containment without an OS-level sandbox. The remaining binaries still need per-argument validation (see validateArgs) because even they have code-exec flags (git core.sshCommand, tar --to-command, go -exec).

View Source
var DefaultLSPServers = map[string][]string{
	"go":         {"gopls"},
	"python":     {"pylsp"},
	"typescript": {"typescript-language-server", "--stdio"},
	"rust":       {"rust-analyzer"},
}

DefaultLSPServers maps a language to its conventional server command.

View Source
var ErrApprovalRequired = errors.New("agents: command requires human approval")

ErrApprovalRequired is returned by RunCommandTool when RequireApproval is set. It carries the full command so a human-in-the-loop approver can review it.

View Source
var ErrDangerousAction = fmt.Errorf("agents: action blocked (catastrophic system destruction)")

ErrDangerousAction is returned when an action matches a catastrophic, always-blocked pattern (e.g. rm -rf /, a fork bomb, formatting a disk, or writing into a Windows system directory). These are refused EVEN WITH user approval — they are non-recoverable system destruction, not normal edits. There is no path/working-directory confinement: the approval gate is the security control (the Claude Code model). Any other path is allowed once the user approves the action.

View Source
var ErrRuntimeStopped = errors.New("agents: runtime is stopped")

ErrRuntimeStopped is returned by Submit after the runtime has been stopped.

View Source
var ErrSSRFBlocked = errors.New("agents: SSRF target blocked")

ErrSSRFBlocked is returned when http_get is asked to reach a private, loopback, link-local, or cloud-metadata address (SSRF prevention).

View Source
var ErrSandboxEscape = fmt.Errorf("%w: path escapes sandbox boundary", ErrSandboxViolation)

ErrSandboxEscape is returned specifically when a filesystem path escapes the sandbox boundary, either lexically (../) or via a symlink pointing outside. It wraps ErrSandboxViolation so existing errors.Is(err, ErrSandboxViolation) checks continue to hold.

View Source
var ErrSandboxViolation = errors.New("agents: sandbox violation")

ErrSandboxViolation is returned when a tool's parameters would escape its permitted sandbox (path outside the sandbox dir, disallowed command, etc.).

View Source
var ErrTooManyRequests = errors.New("agents: too many concurrent submissions")

ErrTooManyRequests is returned by Submit when the concurrency cap is reached.

View Source
var ErrToolNotFound = errors.New("agents: tool not found")

ErrToolNotFound is returned when looking up an unregistered tool.

Functions

func RegisterBuiltins

func RegisterBuiltins(registry *ToolRegistry, sandboxDir string, allowedCommands []string, bus *Bus, apiBaseURL, agentName string) error

RegisterBuiltins populates registry with the built-in tools bound to the given sandbox dir, command whitelist, bus, and management API base URL. It is a convenience for wiring (used by the runtime and start.go).

func RegisterLocalTools

func RegisterLocalTools(registry *ToolRegistry, cfg LocalFSConfig) error

RegisterLocalTools registers the local filesystem + terminal tools (real machine access, approval-gated) into registry, bound to cfg. These provide list_directory/read_file (read-only) and write_file/edit_file/run_terminal/ create_project (approval-required). When mixed with RegisterBuiltins, register local tools into a separate registry to avoid read_file/write_file name collisions — the wiring (start.go) chooses one set.

Types

type AIGateway

type AIGateway interface {
	Complete(ctx context.Context, prompt string, systemPrompt string) (string, error)
}

AIGateway is the interface the coordinator uses to reach a language model. It is implemented by the messaging AI gateway (M11); for M10 a stub suffices.

type Agent

type Agent interface {
	Name() string
	State() AgentState
	Start(ctx context.Context) error
	Stop() error
	Send(msg AgentMessage) error
	Receive() <-chan AgentMessage
}

Agent is the behaviour every agent (coordinator and sub-agents) implements.

type AgentConfig

type AgentConfig struct {
	Name        string
	Type        string // "persistent" | "task"
	Description string
	MaxRetries  int           // default 3 (applied by NewBaseAgent if <= 0)
	Timeout     time.Duration // 0 = no timeout
}

AgentConfig configures a single agent.

type AgentMessage

type AgentMessage struct {
	ID        string
	FromAgent string
	ToAgent   string
	Type      string // "task_brief" | "result" | "error" | "status"
	Payload   any
	Timestamp time.Time
}

AgentMessage is the typed envelope passed between agents over the bus.

type AgentState

type AgentState string

AgentState is the lifecycle state of an agent. Agents move through these states under the supervision of the runtime; TransitionState enforces the legal edges of the state machine.

const (
	// StateIdle is the initial (and, for persistent agents, the resting) state.
	StateIdle AgentState = "idle"
	// StateRunning means the agent is actively processing work.
	StateRunning AgentState = "running"
	// StateWaiting means the agent is blocked awaiting a message or result.
	StateWaiting AgentState = "waiting"
	// StateError means the agent failed; it may retry back to Idle.
	StateError AgentState = "error"
	// StateComplete means the agent finished its task. Terminal for task
	// agents; persistent agents may return to Idle.
	StateComplete AgentState = "complete"
)

type ApprovalError

type ApprovalError struct {
	Request ApprovalRequest
}

ApprovalError wraps ErrApprovalRequired with the command details.

func (*ApprovalError) Error

func (e *ApprovalError) Error() string

Error implements error.

func (*ApprovalError) Unwrap

func (e *ApprovalError) Unwrap() error

Unwrap lets errors.Is(err, ErrApprovalRequired) succeed.

type ApprovalFunc

type ApprovalFunc func(ctx context.Context, req ApprovalRequest) bool

ApprovalFunc requests human approval for an action (e.g. a run_command). It returns true if approved, false if rejected or timed out. The messaging layer supplies the real implementation (Telegram approve/reject buttons); when nil, approval-gated actions are denied by default (fail safe).

type ApprovalRequest

type ApprovalRequest struct {
	Command string
	Args    []string

	// Richer fields for the local FS / terminal tools (M-agent local access).
	Tool        string         // e.g. "write_file", "run_terminal"
	Description string         // one-line human summary
	Preview     string         // diff / content / command preview to show
	Params      map[string]any // the parameters to re-run with on approval
}

ApprovalRequest describes an action awaiting human approval. It is the value wrapped by an *ApprovalError so callers (the coordinator/approver) can render a preview and decide. Command/Args describe a run_command; Tool/Description/ Preview describe the richer local-filesystem and terminal tools.

type AuditLogger

type AuditLogger interface {
	Append(ctx context.Context, actor, action, resource string, detail map[string]any) error
}

AuditLogger is the subset of the audit log the sandbox uses to record tool executions. It is satisfied by *audit.Log.

type BaseAgent

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

BaseAgent is an embeddable implementation of Agent. It owns the state machine and the buffered inbound message channel, and provides a supervised run wrapper that recovers from panics and drives the agent to StateError.

Embedders typically override the work performed inside Start by supplying a run function via NewBaseAgentFunc, or by embedding BaseAgent and providing their own Start that calls Supervise.

func NewBaseAgent

func NewBaseAgent(cfg AgentConfig) *BaseAgent

NewBaseAgent constructs a BaseAgent in StateIdle with a buffered inbox.

func NewBaseAgentFunc

func NewBaseAgentFunc(cfg AgentConfig, run func(ctx context.Context) error) *BaseAgent

NewBaseAgentFunc is like NewBaseAgent but attaches a unit of work run by Start under panic supervision.

func (*BaseAgent) Config

func (a *BaseAgent) Config() AgentConfig

Config returns a copy of the agent's configuration.

func (*BaseAgent) Name

func (a *BaseAgent) Name() string

Name returns the agent's configured name.

func (*BaseAgent) Receive

func (a *BaseAgent) Receive() <-chan AgentMessage

Receive returns the agent's inbound message channel.

func (*BaseAgent) Send

func (a *BaseAgent) Send(msg AgentMessage) error

Send places a message on the agent's inbox. It is non-blocking: a full inbox returns ErrBusFull rather than blocking the sender.

func (*BaseAgent) Start

func (a *BaseAgent) Start(ctx context.Context) error

Start drives the agent through its work under panic supervision. It marks the agent Running, executes the run function (if any), and transitions to Complete on success or Error on failure/panic.

func (*BaseAgent) State

func (a *BaseAgent) State() AgentState

State returns the agent's current lifecycle state.

func (*BaseAgent) Stop

func (a *BaseAgent) Stop() error

Stop transitions the agent back to Idle and is safe to call from any state.

func (*BaseAgent) Supervise

func (a *BaseAgent) Supervise(ctx context.Context) (err error)

Supervise runs the agent's work function, recovering from panics and driving the agent to StateError if one occurs. It is exported so embedders that provide a custom Start can reuse the supervision behaviour.

func (*BaseAgent) TransitionState

func (a *BaseAgent) TransitionState(from, to AgentState) error

TransitionState moves the agent from `from` to `to`, returning an error if the current state is not `from` or the edge is illegal. The Complete → Idle edge is permitted only for persistent agents (task agents treat Complete as terminal).

type BuildAppFunc

type BuildAppFunc func(ctx context.Context, userMsg, sessionID string) (string, error)

BuildAppFunc handles a BUILD_APP request, returning a user-facing reply (e.g. a job id). VORTEX Forge (M13) supplies the implementation via start.go; the coordinator stays decoupled from the forge package (which imports agents) to avoid an import cycle. When nil, BUILD_APP returns a not-implemented stub.

type Bus

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

Bus is a typed, in-process message bus that routes AgentMessages between registered agents. Routing is non-blocking: delivery to a full inbox is dropped (counted in stats) rather than blocking the sender, so one slow agent cannot stall the whole runtime.

func NewBus

func NewBus() *Bus

NewBus constructs an empty message bus.

func (*Bus) Agents

func (b *Bus) Agents() []string

Agents returns the names of all registered agents.

func (*Bus) Broadcast

func (b *Bus) Broadcast(msg AgentMessage)

Broadcast sends msg to every registered agent except the sender (msg.FromAgent). Delivery is non-blocking per recipient: a full inbox is dropped and counted, never blocking other recipients.

func (*Bus) Register

func (b *Bus) Register(agent Agent) error

Register adds an agent under its name. It returns ErrAlreadyRegistered if the name is already taken.

func (*Bus) Send

func (b *Bus) Send(msg AgentMessage) error

Send routes msg to the inbox of msg.ToAgent. It returns ErrAgentNotFound if the recipient is not registered, or ErrBusFull if its inbox is full. A successful send increments MessagesSent; a full inbox increments MessagesDropped.

func (*Bus) Stats

func (b *Bus) Stats() BusStats

Stats returns a snapshot of bus activity.

func (*Bus) Unregister

func (b *Bus) Unregister(name string)

Unregister removes an agent by name. It is a no-op if the name is unknown.

type BusStats

type BusStats struct {
	MessagesSent    int64
	MessagesDropped int64
	AgentCount      int
}

BusStats is a snapshot of bus activity.

type Coordinator

type Coordinator struct {
	*BaseAgent
	// contains filtered or unexported fields
}

Coordinator is the single user-facing agent. It classifies user messages, routes them to the appropriate mode handler, and supervises spawned sub-agents. It implements Agent via an embedded BaseAgent.

func NewCoordinator

func NewCoordinator(cfg CoordinatorConfig) (*Coordinator, error)

NewCoordinator constructs a coordinator. It requires a Bus and an AIGateway.

func (*Coordinator) ActiveAgents

func (c *Coordinator) ActiveAgents() []string

ActiveAgents returns the names of currently active sub-agents.

func (*Coordinator) ApproveAction

func (c *Coordinator) ApproveAction(session string, approved bool) (transcript string, matched bool)

ApproveAction resolves a pending TUI approval for a session and, on approval, EXECUTES the stashed action — returning a transcript of the result (the original Submit already returned the preview, so the work happens here). matched is false when no action was pending for the session.

func (*Coordinator) ClearSession

func (c *Coordinator) ClearSession(sessionID string)

ClearSession drops a session's state (called when its job completes/fails).

func (*Coordinator) ExecuteLocalTool

func (c *Coordinator) ExecuteLocalTool(ctx context.Context, session, name string, params map[string]any, emit func(string)) (any, error)

ExecuteLocalTool runs a local FS/terminal tool, streaming human-readable progress lines via emit (each becomes a chat message). Read-only tools run immediately; mutating tools that return an *ApprovalError are routed for approval — via the Approval callback if set, otherwise via a session-keyed pending request resolved by ApproveAction (the TUI [Y]/[N]). If NEITHER an approver nor a pending resolver can grant approval, the action is DENIED (fail-safe — never auto-executed).

func (*Coordinator) ExecuteLocalToolSync

func (c *Coordinator) ExecuteLocalToolSync(name string, params map[string]any) (string, error)

ExecuteLocalToolSync runs a read-only local tool and returns its transcript as a string (for non-streaming callers like the Telegram /ls command). It is only intended for tools that don't require approval.

func (*Coordinator) HandleMessage

func (c *Coordinator) HandleMessage(_ context.Context, userMsg, sessionID string) (string, error)

HandleMessage is the main entry point for a user message. It classifies the intent via the AI gateway and routes to the matching handler. For M10, the BUILD_APP/RESEARCH/DEVOPS/DATA handlers are stubs; GENERAL_QUESTION is answered directly and UNKNOWN returns a clarifying question.

func (*Coordinator) HasPendingApproval

func (c *Coordinator) HasPendingApproval(session string) bool

HasPendingApproval reports whether a session has an action awaiting approval.

func (*Coordinator) ListSessions

func (c *Coordinator) ListSessions() []SessionInfo

ListSessions returns stored conversation sessions (newest first), or nil when no memory backend is configured.

func (*Coordinator) Reap

func (c *Coordinator) Reap(name string)

Reap removes a sub-agent that has reached a terminal state from the active set and unregisters it from the bus.

func (*Coordinator) RunTool

func (c *Coordinator) RunTool(ctx context.Context, name string, params map[string]any) (any, error)

RunTool executes a named tool through the sandboxed registry, handling the human-in-the-loop approval flow: if the tool returns an *ApprovalError, the coordinator asks the configured ApprovalFunc; on approval it re-runs the action with approval granted, and on rejection (or a nil ApprovalFunc) it returns an error without executing. Tools that don't require approval run directly.

func (*Coordinator) SessionHistory

func (c *Coordinator) SessionHistory(sessionID string) []MemoryMessage

SessionHistory returns the persisted messages for a session.

func (*Coordinator) SetMemoryStore added in v0.3.0

func (c *Coordinator) SetMemoryStore(s *MemoryStore)

SetMemoryStore wires the SQLite conversation store, making it the persistence backend for this coordinator. Pass nil to use the legacy JSON store.

func (*Coordinator) SpawnAgent

func (c *Coordinator) SpawnAgent(_ context.Context, cfg AgentConfig, tools []string) (Agent, error)

SpawnAgent creates a sub-agent restricted to the named tools, registers it on the bus, and tracks it as active. It returns an error if MaxAgents would be exceeded.

func (*Coordinator) WorkingDir

func (c *Coordinator) WorkingDir() string

WorkingDir returns the directory the agent resolves relative paths against.

type CoordinatorConfig

type CoordinatorConfig struct {
	Bus         *Bus
	Tools       *SandboxedToolRegistry
	LocalTools  *ToolRegistry // local FS + terminal tools (real machine access)
	AIGateway   AIGateway
	MaxAgents   int             // concurrent sub-agent limit (default 8)
	Approval    ApprovalFunc    // human-in-the-loop approval; nil = deny gated actions
	BuildApp    BuildAppFunc    // BUILD_APP handler (VORTEX Forge); nil = stub
	Research    ResearchFunc    // RESEARCH handler (M15 research agent); nil = stub
	DevOps      DevOpsFunc      // DEVOPS handler (M16 devops agent); nil = stub
	Pipeline    PipelineFunc    // DATA_PIPELINE handler (M17 pipeline agent); nil = stub
	Orchestrate OrchestrateFunc // ORCHESTRATE handler (M18 multi-agent); nil = stub
	// SessionClarifying reports whether the most recent build for a session is
	// awaiting clarifying answers (forge JobClarify state). Optional.
	SessionClarifying func(sessionID string) bool
	// SessionPending reports whether the most recent build for a session is
	// non-terminal (queued/running/clarifying). Used so a follow-up message is
	// treated as an answer while the (async) build is still in flight — even
	// before it reaches needs_clarification. Optional.
	SessionPending func(sessionID string) bool
	// MemoryStore, when set, persists per-session conversation history under this
	// directory and passes recent context to the AI. Optional.
	MemoryStore string
	WorkingDir  string // directory relative paths resolve against
}

CoordinatorConfig configures the user-facing coordinator agent.

type CreateProjectTool

type CreateProjectTool struct {
	RequireApproval bool
	// contains filtered or unexported fields
}

CreateProjectTool scaffolds a project (approval required).

func (CreateProjectTool) Description

func (CreateProjectTool) Description() string

Description returns a human-readable summary.

func (CreateProjectTool) Execute

func (t CreateProjectTool) Execute(_ context.Context, params map[string]any) (any, error)

Execute creates the project skeleton at params["path"]/params["name"].

func (CreateProjectTool) Name

func (CreateProjectTool) Name() string

Name returns the tool name.

type DevOpsFunc added in v0.3.0

type DevOpsFunc func(ctx context.Context, msg string, progressFn func(string)) (string, error)

DevOpsFunc handles a DEVOPS request (SSH/Docker/Nginx server management), returning a user-facing reply. The M16 devops agent supplies it via start.go. When nil, DEVOPS returns a not-implemented stub.

type Diagnostic added in v0.3.0

type Diagnostic struct {
	File     string `json:"file"`
	Line     int    `json:"line"`     // 1-based
	Col      int    `json:"col"`      // 1-based
	Severity string `json:"severity"` // "error" | "warning" | "info" | "hint"
	Message  string `json:"message"`
}

Diagnostic is one error/warning reported by the language server.

type EditFileTool

type EditFileTool struct {
	RequireApproval bool
	// contains filtered or unexported fields
}

EditFileTool replaces an exact string in a real file. Requires approval.

func (EditFileTool) Description

func (EditFileTool) Description() string

Description returns a human-readable summary.

func (EditFileTool) Execute

func (t EditFileTool) Execute(_ context.Context, params map[string]any) (any, error)

Execute replaces params["old_str"] with params["new_str"] in params["path"].

func (EditFileTool) Name

func (EditFileTool) Name() string

Name returns the tool name.

type FindFilesTool

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

FindFilesTool finds files by name/glob. Read-only, no approval.

func (FindFilesTool) Description

func (FindFilesTool) Description() string

Description returns a human-readable summary.

func (FindFilesTool) Execute

func (t FindFilesTool) Execute(_ context.Context, params map[string]any) (any, error)

Execute walks params["path"] (default Root) returning files whose base name matches params["name_pattern"] (glob).

func (FindFilesTool) Name

func (FindFilesTool) Name() string

Name returns the tool name.

type GitAddTool

type GitAddTool struct {
	RequireApproval bool
	// contains filtered or unexported fields
}

GitAddTool stages files. Requires approval.

func (GitAddTool) Description

func (GitAddTool) Description() string

Description returns a human-readable summary.

func (GitAddTool) Execute

func (t GitAddTool) Execute(ctx context.Context, params map[string]any) (any, error)

Execute runs `git add files...`.

func (GitAddTool) Name

func (GitAddTool) Name() string

Name returns the tool name.

type GitCommitTool

type GitCommitTool struct {
	RequireApproval bool
	// contains filtered or unexported fields
}

GitCommitTool stages + commits. Requires approval.

func (GitCommitTool) Description

func (GitCommitTool) Description() string

Description returns a human-readable summary.

func (GitCommitTool) Execute

func (t GitCommitTool) Execute(ctx context.Context, params map[string]any) (any, error)

Execute stages params["files"] (if any) then commits with params["message"].

func (GitCommitTool) Name

func (GitCommitTool) Name() string

Name returns the tool name.

type GitDiffTool

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

GitDiffTool shows the working-tree diff. Read-only, no approval.

func (GitDiffTool) Description

func (GitDiffTool) Description() string

Description returns a human-readable summary.

func (GitDiffTool) Execute

func (t GitDiffTool) Execute(ctx context.Context, params map[string]any) (any, error)

Execute runs `git diff [file]`.

func (GitDiffTool) Name

func (GitDiffTool) Name() string

Name returns the tool name.

type GitStatusTool

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

GitStatusTool reports the repo status. Read-only, no approval.

func (GitStatusTool) Description

func (GitStatusTool) Description() string

Description returns a human-readable summary.

func (GitStatusTool) Execute

func (t GitStatusTool) Execute(ctx context.Context, _ map[string]any) (any, error)

Execute runs `git status --porcelain` and the current branch.

func (GitStatusTool) Name

func (GitStatusTool) Name() string

Name returns the tool name.

type HTTPGetTool

type HTTPGetTool struct {
	Client *http.Client
	// AllowedHosts, when non-empty, restricts requests to URLs whose hostname
	// exactly matches one of these entries (in addition to the IP checks).
	AllowedHosts []string
}

HTTPGetTool performs an HTTP(S) GET request with SSRF protection.

func (HTTPGetTool) Description

func (HTTPGetTool) Description() string

Description returns a human-readable summary.

func (HTTPGetTool) Execute

func (t HTTPGetTool) Execute(ctx context.Context, params map[string]any) (any, error)

Execute fetches the URL after SSRF validation. Only http/https schemes are permitted and internal/metadata addresses are blocked.

func (HTTPGetTool) Name

func (HTTPGetTool) Name() string

Name returns the tool name.

type Intent

type Intent string

Intent is the classification of a user message.

const (
	IntentBuildApp        Intent = "BUILD_APP"
	IntentLocalFile       Intent = "LOCAL_FILE"
	IntentResearch        Intent = "RESEARCH"
	IntentDevOpsCheck     Intent = "DEVOPS_CHECK"
	IntentDataPipeline    Intent = "DATA_PIPELINE"
	IntentOrchestrate     Intent = "ORCHESTRATE"
	IntentGeneralQuestion Intent = "GENERAL_QUESTION"
	IntentUnknown         Intent = "UNKNOWN"
)

Intent classifications produced by the coordinator.

type LSPClient added in v0.3.0

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

LSPClient is a JSON-RPC client to a language server subprocess.

func NewLSPClient added in v0.3.0

func NewLSPClient(cfg LSPConfig) (*LSPClient, error)

NewLSPClient starts the language server for cfg and performs the LSP initialize handshake. If the server binary is not on PATH it returns (nil, nil) — LSP is an optional enhancement, not a hard dependency. The caller owns Close.

func (*LSPClient) Close added in v0.3.0

func (c *LSPClient) Close() error

Close shuts down the language server.

func (*LSPClient) Definition added in v0.3.0

func (c *LSPClient) Definition(file string, line, col int) (*Location, error)

Definition returns the definition location of the symbol at (line, col).

func (*LSPClient) Diagnostics added in v0.3.0

func (c *LSPClient) Diagnostics(file string) ([]Diagnostic, error)

Diagnostics opens file in the server and returns the diagnostics it reports. It waits briefly for the server's asynchronous publishDiagnostics.

func (*LSPClient) Hover added in v0.3.0

func (c *LSPClient) Hover(file string, line, col int) (string, error)

Hover returns documentation for the symbol at (line, col) (both 1-based).

func (*LSPClient) References added in v0.3.0

func (c *LSPClient) References(file string, line, col int) ([]Location, error)

References returns all references to the symbol at (line, col).

type LSPConfig added in v0.3.0

type LSPConfig struct {
	Language  string   // "go" | "python" | "typescript" | "rust"
	ServerCmd []string // e.g. ["gopls"]; ServerCmd[0] is the binary
	WorkDir   string   // workspace root
}

LSPConfig configures an LSP client for one language/workspace.

type LSPDiagnosticsTool added in v0.3.0

type LSPDiagnosticsTool struct {
	// WorkDir is the workspace root passed to the language server.
	WorkDir string
	// contains filtered or unexported fields
}

LSPDiagnosticsTool exposes language-server diagnostics (errors/warnings) for a file as an agent tool (build plan M20). It is read-only, so it needs no approval. The tool lazily starts one LSP client per language and reuses it; when the language server is not installed it returns an empty, non-error result so the agent degrades gracefully.

func (*LSPDiagnosticsTool) Close added in v0.3.0

func (t *LSPDiagnosticsTool) Close()

Close shuts down all started LSP clients.

func (*LSPDiagnosticsTool) Description added in v0.3.0

func (*LSPDiagnosticsTool) Description() string

Description returns a human-readable summary.

func (*LSPDiagnosticsTool) Execute added in v0.3.0

func (t *LSPDiagnosticsTool) Execute(_ context.Context, params map[string]any) (any, error)

Execute runs diagnostics on params["file"]. It returns a structured result with the diagnostics list and a count.

func (*LSPDiagnosticsTool) Name added in v0.3.0

func (*LSPDiagnosticsTool) Name() string

Name returns the tool name.

type ListDirectoryTool

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

ListDirectoryTool lists a directory's entries. Read-only, no approval.

func (ListDirectoryTool) Description

func (ListDirectoryTool) Description() string

Description returns a human-readable summary.

func (ListDirectoryTool) Execute

func (t ListDirectoryTool) Execute(_ context.Context, params map[string]any) (any, error)

Execute lists params["path"] (default: working dir).

func (ListDirectoryTool) Name

func (ListDirectoryTool) Name() string

Name returns the tool name.

type LocalFSConfig

type LocalFSConfig struct {
	// Root is the base for resolving relative paths (default: os.Getwd). It does
	// NOT restrict where files may be written; absolute paths anywhere are
	// allowed once the user approves the action.
	Root string
	// RequireApproval gates mutating tools (default true via NewLocalTools).
	RequireApproval bool
}

LocalFSConfig configures the local FS/terminal tools. There is NO path confinement — the approval gate is the security model. Root is informational only: it is the base for resolving *relative* paths (defaults to the process working directory) and is shown in the TUI top bar.

type Location added in v0.3.0

type Location struct {
	File string `json:"file"`
	Line int    `json:"line"`
	Col  int    `json:"col"`
}

Location is a file position range (go-to-definition / references).

type Memory

type Memory struct {
	SessionID string          `json:"session_id"`
	Messages  []MemoryMessage `json:"messages"`
	CreatedAt time.Time       `json:"created_at"`
	UpdatedAt time.Time       `json:"updated_at"`
	// contains filtered or unexported fields
}

Memory is a per-session conversation history persisted to disk under storePath/<sessionID>.json.

func NewMemory

func NewMemory(storePath string) *Memory

NewMemory creates an in-memory conversation bound to a store directory. Call Load to populate it from disk, or Append + Save to persist.

func (*Memory) Append

func (m *Memory) Append(role, content string)

Append adds a message and bumps UpdatedAt.

func (*Memory) List

func (m *Memory) List() []SessionInfo

List returns all stored sessions (newest first), reading summaries from disk.

func (*Memory) Load

func (m *Memory) Load(sessionID string) error

Load reads a session's conversation from disk into this Memory.

func (*Memory) Recent

func (m *Memory) Recent(n int) []MemoryMessage

Recent returns the last n messages (for AI context). n<=0 returns all.

func (*Memory) Save

func (m *Memory) Save() error

Save writes the conversation to storePath/<sessionID>.json.

func (*Memory) Summary

func (m *Memory) Summary() string

Summary returns the first user message (a conversation title), or "".

type MemoryMessage

type MemoryMessage struct {
	Role      string    `json:"role"` // "user" | "agent" | "system"
	Content   string    `json:"content"`
	Timestamp time.Time `json:"timestamp"`
	ToolCalls []string  `json:"tool_calls,omitempty"`
}

MemoryMessage is one persisted turn in a conversation.

type MemoryStats added in v0.3.0

type MemoryStats struct {
	TotalSessions int     `json:"total_sessions"`
	TotalMessages int     `json:"total_messages"`
	DBSizeMB      float64 `json:"db_size_mb"`
}

MemoryStats summarises the store for the dashboard/CLI.

type MemoryStore added in v0.3.0

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

MemoryStore persists agent conversations in a single SQLite database (build plan M20), replacing the one-JSON-file-per-session layout. SQLite gives indexed queries, full-text search across all messages, and O(1) session listing instead of the O(n) directory scan the JSON store needed (production audit L2). It is safe for concurrent use — the database/sql pool serialises writes and SQLite is opened in WAL mode for concurrent reads.

func NewMemoryStore added in v0.3.0

func NewMemoryStore(dbPath string) (*MemoryStore, error)

NewMemoryStore opens (creating if needed) a SQLite-backed conversation store at dbPath, applying the schema and enabling WAL + foreign keys.

func (*MemoryStore) AppendMessage added in v0.3.0

func (m *MemoryStore) AppendMessage(sessionID, role, content string, tools []string) error

AppendMessage adds a message to a session, creating the session if needed and updating its summary (first user message) and updated_at.

func (*MemoryStore) Close added in v0.3.0

func (m *MemoryStore) Close() error

Close closes the underlying database.

func (*MemoryStore) DeleteSession added in v0.3.0

func (m *MemoryStore) DeleteSession(id string) error

DeleteSession removes a session and its messages (cascade).

func (*MemoryStore) ListSessions added in v0.3.0

func (m *MemoryStore) ListSessions() ([]SessionInfo, error)

ListSessions returns all sessions, newest-updated first.

func (*MemoryStore) MigrateJSONDir added in v0.3.0

func (m *MemoryStore) MigrateJSONDir(dir string) (int, error)

MigrateJSONDir imports legacy <sessionID>.json conversation files from dir into the store, skipping sessions that already exist. It returns the number of sessions imported. A missing/empty dir imports nothing (not an error), so it is safe to call on every startup.

func (*MemoryStore) NewSession added in v0.3.0

func (m *MemoryStore) NewSession() (string, error)

NewSession creates a session row with a generated ID and returns it.

func (*MemoryStore) Recent added in v0.3.0

func (m *MemoryStore) Recent(sessionID string, n int) ([]MemoryMessage, error)

Recent returns the last n messages for a session in chronological order. n<=0 returns all.

func (*MemoryStore) SearchMessages added in v0.3.0

func (m *MemoryStore) SearchMessages(query string) ([]SearchResult, error)

SearchMessages runs a full-text search across all message content and returns matching messages (with their session) newest-first, capped at 100.

func (*MemoryStore) Stats added in v0.3.0

func (m *MemoryStore) Stats() MemoryStats

Stats returns aggregate counts and the database file size.

type OrchestrateFunc added in v0.3.0

type OrchestrateFunc func(ctx context.Context, goal string, progressFn func(string)) (string, error)

OrchestrateFunc handles a multi-agent goal (M18): decompose into tasks and run them across specialized agents, returning a summary. Supplied via start.go. When nil, orchestration returns a not-implemented stub.

type PipelineFunc added in v0.3.0

type PipelineFunc func(ctx context.Context, msg string, progressFn func(string)) (string, error)

PipelineFunc handles a DATA_PIPELINE request (analyze data → chart → report), returning a user-facing reply. The M17 pipeline agent supplies it via start.go. When nil, DATA_PIPELINE returns a not-implemented stub.

type ReadFileTool

type ReadFileTool struct{ SandboxDir string }

ReadFileTool reads a file inside the agent's sandbox.

func (ReadFileTool) Description

func (ReadFileTool) Description() string

Description returns a human-readable summary.

func (ReadFileTool) Execute

func (t ReadFileTool) Execute(_ context.Context, params map[string]any) (any, error)

Execute reads params["path"] from under the sandbox.

func (ReadFileTool) Name

func (ReadFileTool) Name() string

Name returns the tool name.

type ReadLocalFileTool

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

ReadLocalFileTool reads a real file. Read-only, no approval.

func (ReadLocalFileTool) Description

func (ReadLocalFileTool) Description() string

Description returns a human-readable summary.

func (ReadLocalFileTool) Execute

func (t ReadLocalFileTool) Execute(_ context.Context, params map[string]any) (any, error)

Execute reads params["path"].

func (ReadLocalFileTool) Name

func (ReadLocalFileTool) Name() string

Name returns the tool name.

type ResearchFunc added in v0.3.0

type ResearchFunc func(ctx context.Context, query string, progressFn func(string)) (string, error)

ResearchFunc handles a RESEARCH request, returning a user-facing reply. The M15 research agent supplies the implementation via start.go (keeping the coordinator decoupled from the research package). progressFn streams step updates. When nil, RESEARCH returns a not-implemented stub.

type RunCommandTool

type RunCommandTool struct {
	SandboxDir      string
	AllowedCommands []string
	// RequireApproval, when true, makes Execute return an *ApprovalError
	// instead of running — the coordinator routes this to a human approver
	// (M10.7). It defaults to true via NewRunCommandTool until an OS-level
	// sandbox makes unattended execution safe.
	RequireApproval bool
}

RunCommandTool runs a whitelisted command in the sandbox directory.

func NewRunCommandTool

func NewRunCommandTool(sandboxDir string, allowed []string) RunCommandTool

NewRunCommandTool builds a RunCommandTool with RequireApproval defaulted to true (safe by default). Callers that have an OS sandbox can clear it.

func (RunCommandTool) Description

func (RunCommandTool) Description() string

Description returns a human-readable summary.

func (RunCommandTool) Execute

func (t RunCommandTool) Execute(ctx context.Context, params map[string]any) (any, error)

Execute runs params["command"] with params["args"] ([]string or []any).

func (RunCommandTool) Name

func (RunCommandTool) Name() string

Name returns the tool name.

type RunTerminalTool

type RunTerminalTool struct {
	RequireApproval bool
	// contains filtered or unexported fields
}

RunTerminalTool runs an arbitrary command (approval required, guardrailed).

func (RunTerminalTool) Description

func (RunTerminalTool) Description() string

Description returns a human-readable summary.

func (RunTerminalTool) Execute

func (t RunTerminalTool) Execute(ctx context.Context, params map[string]any) (any, error)

Execute runs params["command"] in params["cwd"] with params["timeout"] (s).

func (RunTerminalTool) Name

func (RunTerminalTool) Name() string

Name returns the tool name.

type Runtime

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

Runtime supervises the coordinator and the message bus, exposing a simple Submit API for delivering user messages and receiving streamed responses.

func NewRuntime

func NewRuntime(cfg RuntimeConfig) (*Runtime, error)

NewRuntime constructs a runtime. It requires a Bus and a Coordinator.

func (*Runtime) Approve

func (r *Runtime) Approve(sessionID string, approved bool) (string, bool)

Approve resolves a pending tool-action approval for a session, delegating to the coordinator. It returns the result transcript (executed on approval) and whether a pending action matched.

func (*Runtime) Coordinator

func (r *Runtime) Coordinator() *Coordinator

Coordinator returns the runtime's coordinator (for wiring local-tool calls).

func (*Runtime) ListSessions

func (r *Runtime) ListSessions() []SessionInfo

ListSessions returns stored conversation sessions (newest first).

func (*Runtime) SessionHistory

func (r *Runtime) SessionHistory(sessionID string) []MemoryMessage

SessionHistory returns the persisted messages for a session.

func (*Runtime) Start

func (r *Runtime) Start(_ context.Context) error

Start registers the coordinator on the bus, ensures the sandbox base exists, and marks the runtime ready. It is idempotent.

func (*Runtime) Stats

func (r *Runtime) Stats() RuntimeStats

Stats returns a snapshot of runtime activity.

func (*Runtime) Stop

func (r *Runtime) Stop(ctx context.Context) error

Stop rejects new Submits, cancels the runtime context so in-flight HandleMessage calls unwind, and waits (up to ctx's deadline) for those goroutines to drain before unregistering agents. Sub-agents are unregistered first, the coordinator last.

func (*Runtime) Submit

func (r *Runtime) Submit(ctx context.Context, userMsg, sessionID string) (<-chan string, error)

Submit delivers userMsg to the coordinator and returns a channel that receives the response (then closes). Processing is asynchronous; the call itself does not block on the coordinator.

type RuntimeConfig

type RuntimeConfig struct {
	Bus           *Bus
	Coordinator   *Coordinator
	MaxAgents     int
	MaxConcurrent int          // max simultaneous in-flight Submits (default 5)
	SandboxBase   string       // base directory for per-agent sandboxes
	Logger        *slog.Logger // optional; defaults to slog.Default()
}

RuntimeConfig configures the persistent agent runtime supervisor.

type RuntimeStats

type RuntimeStats struct {
	ActiveAgents  int
	TotalMessages int64
	QueueDepth    int
}

RuntimeStats is a snapshot of runtime activity.

type SandboxedToolRegistry

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

SandboxedToolRegistry wraps a ToolRegistry, enforcing per-tool restrictions (sandbox dir, command whitelist, bus) and recording every execution to the audit log when one is configured.

func NewSandboxedRegistry

func NewSandboxedRegistry(registry *ToolRegistry, sandboxDir string, allowedCommands []string, bus *Bus) *SandboxedToolRegistry

NewSandboxedRegistry constructs a sandboxed registry over the given base registry. The built-in stateful tools (file, command, message) are re-registered with the sandbox restrictions bound in.

func (*SandboxedToolRegistry) Execute

func (s *SandboxedToolRegistry) Execute(ctx context.Context, name string, params map[string]any) (any, error)

Execute looks up and runs a tool, recording the execution (and its outcome) to the audit log when configured. Restrictions are enforced by the tools themselves, which the registry binds to this sandbox.

func (*SandboxedToolRegistry) ExecuteApproved

func (s *SandboxedToolRegistry) ExecuteApproved(ctx context.Context, name string, params map[string]any) (any, error)

ExecuteApproved runs a tool with the human-approval gate disabled. It is called only after an approver has granted permission for an action that returned an *ApprovalError. For a RunCommandTool this re-runs the same command with RequireApproval cleared; other tools execute normally. The execution is audit-logged as an approved action.

func (*SandboxedToolRegistry) Get

func (s *SandboxedToolRegistry) Get(name string) (Tool, error)

Get returns the named tool from the underlying registry.

func (*SandboxedToolRegistry) List

func (s *SandboxedToolRegistry) List() []string

List returns the available tool names.

func (*SandboxedToolRegistry) SandboxDir

func (s *SandboxedToolRegistry) SandboxDir() string

SandboxDir returns the configured sandbox directory.

func (*SandboxedToolRegistry) WithAudit

WithAudit sets the audit logger and actor used to record executions.

type SearchFilesTool

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

SearchFilesTool searches file contents for a pattern. Read-only, no approval.

func (SearchFilesTool) Description

func (SearchFilesTool) Description() string

Description returns a human-readable summary.

func (SearchFilesTool) Execute

func (t SearchFilesTool) Execute(_ context.Context, params map[string]any) (any, error)

Execute walks params["path"] (default Root) and returns matches for params["pattern"], optionally filtered by params["extension"] and params["case_sensitive"].

func (SearchFilesTool) Name

func (SearchFilesTool) Name() string

Name returns the tool name.

type SearchResult added in v0.3.0

type SearchResult struct {
	SessionID string        `json:"session_id"`
	Message   MemoryMessage `json:"message"`
}

SearchResult is one full-text search hit.

type SendMessageTool

type SendMessageTool struct {
	Bus  *Bus
	From string
}

SendMessageTool sends a message to another agent over the bus.

func (SendMessageTool) Description

func (SendMessageTool) Description() string

Description returns a human-readable summary.

func (SendMessageTool) Execute

func (t SendMessageTool) Execute(_ context.Context, params map[string]any) (any, error)

Execute routes a message to params["to"] with type/payload.

func (SendMessageTool) Name

func (SendMessageTool) Name() string

Name returns the tool name.

type SessionInfo

type SessionInfo struct {
	SessionID string    `json:"session_id"`
	Summary   string    `json:"summary"`
	UpdatedAt time.Time `json:"updated_at"`
}

SessionInfo describes a stored session for listings.

type SessionState

type SessionState struct {
	OriginalRequest       string    // the first build message in this session
	AwaitingClarification bool      // forge asked questions; next msg is an answer
	Answers               []string  // accumulated clarification answers
	LastActivity          time.Time // for idle cleanup
}

SessionState tracks per-conversation context so a multi-turn build (with clarifying questions) continues the SAME job instead of restarting.

type StubAIGateway

type StubAIGateway struct {
	// IntentReply, if set, is returned verbatim for intent-classification
	// prompts (tests use this to drive routing).
	IntentReply string
	// AnswerReply is returned for direct-answer completions.
	AnswerReply string
}

StubAIGateway is a fixed-response AIGateway used until the real gateway is wired in (M11). It echoes a canned reply and, for intent classification, returns GENERAL_QUESTION so the coordinator answers directly.

func (StubAIGateway) Complete

func (s StubAIGateway) Complete(_ context.Context, _ string, systemPrompt string) (string, error)

Complete returns a canned response. When the system prompt asks for intent classification, it returns IntentReply (default GENERAL_QUESTION).

type Tool

type Tool interface {
	Name() string
	Description() string
	Execute(ctx context.Context, params map[string]any) (any, error)
}

Tool is a single, declared, enumerable action an agent may perform. Every agent action goes through a Tool: no tool means no action (the permission model is allow-list only).

func NewLocalTools

func NewLocalTools(cfg LocalFSConfig) []Tool

NewLocalTools returns the local FS + terminal tools bound to cfg, with approval REQUIRED on all mutating tools.

type ToolRegistry

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

ToolRegistry holds the set of tools available to agents.

func NewToolRegistry

func NewToolRegistry() *ToolRegistry

NewToolRegistry constructs an empty tool registry.

func (*ToolRegistry) Get

func (r *ToolRegistry) Get(name string) (Tool, error)

Get returns the named tool or ErrToolNotFound.

func (*ToolRegistry) List

func (r *ToolRegistry) List() []string

List returns the names of all registered tools.

func (*ToolRegistry) Register

func (r *ToolRegistry) Register(tool Tool) error

Register adds a tool. It returns an error if the name is already taken.

type UndoTool

type UndoTool struct {
	RequireApproval bool
	// contains filtered or unexported fields
}

UndoTool restores the most recent file backup for a session. Requires approval (it overwrites the current file).

func (UndoTool) Description

func (UndoTool) Description() string

Description returns a human-readable summary.

func (UndoTool) Execute

func (t UndoTool) Execute(_ context.Context, params map[string]any) (any, error)

Execute restores the most recent backup for params["session_id"].

func (UndoTool) Name

func (UndoTool) Name() string

Name returns the tool name.

type VortexAPITool

type VortexAPITool struct {
	BaseURL string // e.g. http://127.0.0.1:9090
	Client  *http.Client
}

VortexAPITool calls the VORTEX management API. Only /api/* paths are allowed, excluding the agent and control-plane paths in vortexAPIDeniedPaths.

func (VortexAPITool) Description

func (VortexAPITool) Description() string

Description returns a human-readable summary.

func (VortexAPITool) Execute

func (t VortexAPITool) Execute(ctx context.Context, params map[string]any) (any, error)

Execute issues an API request with method/path/body params.

func (VortexAPITool) Name

func (VortexAPITool) Name() string

Name returns the tool name.

type WriteFileTool

type WriteFileTool struct{ SandboxDir string }

WriteFileTool writes content to a file inside the agent's sandbox.

func (WriteFileTool) Description

func (WriteFileTool) Description() string

Description returns a human-readable summary.

func (WriteFileTool) Execute

func (t WriteFileTool) Execute(_ context.Context, params map[string]any) (any, error)

Execute writes params["content"] to params["path"] under the sandbox.

func (WriteFileTool) Name

func (WriteFileTool) Name() string

Name returns the tool name.

type WriteLocalFileTool

type WriteLocalFileTool struct {
	RequireApproval bool
	// contains filtered or unexported fields
}

WriteLocalFileTool writes a real file. Requires approval.

func (WriteLocalFileTool) Description

func (WriteLocalFileTool) Description() string

Description returns a human-readable summary.

func (WriteLocalFileTool) Execute

func (t WriteLocalFileTool) Execute(_ context.Context, params map[string]any) (any, error)

Execute writes params["path"] with params["content"], optionally creating parent dirs (params["create_dirs"]). Returns an *ApprovalError when approval is required.

func (WriteLocalFileTool) Name

func (WriteLocalFileTool) Name() string

Name returns the tool name.

Jump to

Keyboard shortcuts

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