-
Notifications
You must be signed in to change notification settings - Fork 0
Agent Framework
Relevant source files
The following files were used as context for generating this wiki page:
- cmd/axis/agent_slash_test.go
- internal/agent/agent.go
- internal/agent/agent_test.go
- internal/agent/async_tasks.go
- internal/agent/async_tasks_test.go
- internal/agent/autonomy.go
- internal/agent/autonomy_test.go
- internal/agent/cloud_backend.go
- internal/agent/cloud_backend_test.go
- internal/agent/compaction.go
- internal/agent/confirm.go
- internal/agent/p0_editing_test.go
- internal/agent/p0_test.go
- internal/agent/p1_test.go
- internal/agent/routing.go
- internal/agent/routing_test.go
- internal/agent/session_branch.go
- internal/agent/session_branch_test.go
- internal/agent/subagent.go
- internal/agent/subagent_test.go
- internal/agent/summarize.go
- internal/agent/tools.go
- internal/agent/tools_cluster.go
- internal/agent/tools_git_test.go
- internal/chat/message.go
- internal/chat/persist.go
- internal/chat/persist_test.go
- internal/ui/diff_test.go
The Agent Framework constitutes Layer 5 (Advisory Plane) of the AXIS architecture. It provides a structured, multi-turn LLM loop capable of observing cluster state and executing actions through a strictly guarded tool-calling interface. The Agent struct is a consumer of the fact plane; it can propose changes but never represents the underlying cluster "truth" directly internal/agent/agent.go:44-46.
The Agent operates by maintaining a chat.Conversation and iterating through a loop of reasoning and tool execution. Each turn involves sending the conversation history to a ChatBackend (typically Ollama or a cloud provider) and processing the resulting text or tool calls internal/agent/agent.go:44-80.
To stay within LLM context limits, the Conversation struct tracks an approximate token budget (calculated as characters / 4). When the budget is exceeded, the framework performs Context Compaction internal/chat/message.go:37-56:
- Protected Window: The system prompt and the most recent 4 messages are never compacted internal/chat/message.go:105-106.
-
Tool Payload Truncation: Older
RoleToolmessages with payloads > 200 characters are truncated to 180 characters plus a summary marker internal/chat/message.go:125-146. -
Rollback Support: The
RestoreAllmethod allows the conversation to be rewound to a prior state, supporting session branching internal/chat/message.go:80-82.
The following diagram illustrates the flow from a user request through the reasoning loop to code-space entities.
Agent Execution Pipeline
graph TD
User["User Request"] --> AgentLoop["Agent.Run Loop"]
AgentLoop --> LLM["LLM (ChatBackend)"]
LLM --> Decision{"Tool Call?"}
Decision -- "Yes" --> Safety["Safety Evaluation (internal/safety)"]
Safety --> Confirm{"ConfirmFunc"}
Confirm -- "Approved" --> Registry["ToolRegistry.Execute"]
Registry --> ToolExec["Specific ToolExecutor"]
ToolExec --> FS["Filesystem (internal/agent/tools.go)"]
ToolExec --> Cluster["Cluster State (internal/state)"]
ToolExec --> Execution["Task Execution (internal/execution)"]
ToolExec --> Result["Tool Result String"]
Result --> AgentLoop
Decision -- "No (Text)" --> User
Sources: internal/agent/agent.go:44-80, internal/agent/tools.go:152-158, internal/agent/confirm.go:23-26
The ToolRegistry serves as the bridge between natural language intent and the AXIS subsystem APIs. It maps string identifiers to ToolExecutor functions internal/agent/tools.go:31-43.
| Category | Key Tools | Implementation Detail |
|---|---|---|
| Cluster Inspection |
axis_status, axis_facts
|
Consumes models.ClusterSnapshot internal/agent/tools.go:188-218
|
| File I/O |
read_file, edit_file, multi_edit
|
Uses checkpointer for session-level undo internal/agent/tools.go:120-123
|
| Execution |
run_shell, run_on_node, axis_run_task
|
CLI wires ShellRunner/NodeShellRunner/TaskRunner to Layer-4 guarded execution cmd/axis/agent.go
|
| Git Operations |
git_status, git_diff, git_log
|
Invokes internal/git helpers internal/agent/tools.go:127
|
| Session Control |
branch_session, rollback_session
|
Manages Agent.branchStack internal/agent/session_branch.go:12-18
|
Tools do not access global state. Instead, they receive a ToolContext which provides an atomic RuntimeView containing the current Config, Snapshot, State, and Ledger internal/agent/tools.go:45-59. This ensures that even during concurrent agent turns, tools operate on a consistent point-in-time view of the cluster.
AXIS implements a multi-tiered safety gate for tool execution.
-
Read-Only Auto-Approval: Tools like
axis_statusorread_fileare classified as read-only and bypass interactive confirmation internal/agent/confirm.go:97-110. -
Safety Scoring: Mutating commands (like
run_shell) are passed to theinternal/safetyevaluator. Commands with a safety score below a configurable threshold (default: 70) may be auto-approved in "full" autonomy mode internal/agent/confirm.go:78-94. -
Interactive Confirmation: High-risk commands trigger a
ConfirmFunc(usuallyStdinConfirm), presenting the operator with the tool name, details, and a color-coded risk assessment internal/agent/confirm.go:29-56.
The framework supports different levels of autonomy internal/agent/agent.go:90:
- Default: Prompts for all mutating actions.
- Edit: Auto-approves file modifications but prompts for shell/cluster tasks.
- Full: Auto-approves low-risk shell commands and file edits.
The Agent can "branch" its conversation state using branch_session. This creates a deep copy of the chat.Message list, including ToolCalls and their arguments internal/agent/session_branch.go:23-49. If a risky path fails, rollback_session restores the conversation to the snapshot, effectively letting the LLM "undo" its reasoning turns internal/agent/session_branch.go:62-91.
The run_background tool allows the agent to spawn long-running shell or cluster tasks without blocking the main reasoning loop internal/agent/async_tasks.go:107-122.
-
Tracking: Tasks are stored in a
backgroundTaskStorewith unique IDs (e.g.,bg-1) internal/agent/async_tasks.go:47-51. -
Polling: The agent can use
check_taskto retrieve partial output and completion status internal/agent/async_tasks.go:165-205.
Agents can spawn child agents via spawn_subagent to delegate sub-tasks. To prevent infinite loops, the framework tracks subAgentDepth and enforces a hard recursion limit internal/agent/agent.go:71-73.
The RoutingBackend optimizes cost and performance by directing turns to different models based on complexity internal/agent/routing.go:23-29:
- Cheap Model: Used for status reads, summaries, and short lookups internal/agent/routing.go:73-77.
- Strong Model: Triggered by "hard keywords" (e.g., implement, refactor, debug) or if the previous turn involved a mutating tool internal/agent/routing.go:96-134.
Routing Decision Logic
graph LR
subgraph "Natural Language Space"
Prompt["'Fix the bug in main.go'"]
Keywords["'implement', 'refactor'"]
end
subgraph "Code Entity Space"
Classifier["DefaultRouterClassifier (internal/agent/routing.go)"]
Primary["Primary Backend (e.g. GPT-4)"]
Cheap["Cheap Backend (e.g. Llama-3-8B)"]
end
Prompt --> Classifier
Keywords --> Classifier
Classifier -- "Hard Keyword Detected" --> Primary
Classifier -- "Simple Status Request" --> Cheap
Sources: internal/agent/routing.go:78-124, internal/agent/routing.go:127-134
| Type | File | Purpose |
|---|---|---|
Agent |
internal/agent/agent.go:46 | Main orchestrator of the advisory reasoning loop. |
ToolRegistry |
internal/agent/tools.go:31 | Map of string names to Go function executors. |
Conversation |
internal/chat/message.go:38 | Buffer of messages with token-aware compaction logic. |
RoutingBackend |
internal/agent/routing.go:23 | Wrapper that switches between models based on turn complexity. |
ToolContext |
internal/agent/tools.go:56 | Provides tools with thread-safe access to cluster snapshots. |
Sources: internal/agent/agent.go:1-80, internal/agent/tools.go:1-150, internal/chat/message.go:1-110, internal/agent/routing.go:1-135, internal/agent/async_tasks.go:1-153, internal/agent/session_branch.go:1-100