394 lines
15 KiB
Markdown
394 lines
15 KiB
Markdown
# Agents
|
|
|
|
[← Docs index](./README.md)
|
|
|
|
Fusion uses multiple agent roles for triage, execution, review, and merge workflows.
|
|
|
|
## Agent Field Parity Matrix
|
|
|
|
Every first-class editable agent field has a defined create/edit/import/template behavior. This ensures consistent round-tripping across all surfaces.
|
|
|
|
### Agent Model Fields
|
|
|
|
| Field | Create | Edit | Import | Notes |
|
|
|-------|--------|------|--------|-------|
|
|
| `name` | ✓ | ✓ | ✓ (from manifest) | Unique identifier |
|
|
| `role` | ✓ | ✓ | ✓ (mapped from manifest) | Agent capability |
|
|
| `metadata` | ✓ | ✓ | ✓ | Arbitrary key-value data |
|
|
| `title` | ✓ | ✓ | ✓ (from manifest) | Job title/description |
|
|
| `icon` | ✓ | ✓ | ✓ (from manifest) | Emoji or icon identifier |
|
|
| `reportsTo` | ✓ | ✓ | ✓ (from manifest) | Parent agent ID |
|
|
| `runtimeConfig` | ✓ | ✓ | ✗ | Heartbeat/budget config |
|
|
| `permissions` | ✓ | ✓ | ✗ | Capability flags |
|
|
| `instructionsPath` | ✓ | ✓ | ✗ | File-backed instructions path |
|
|
| `instructionsText` | ✓ | ✓ | ✓ (from manifest `instructionBody`) | Inline instructions |
|
|
| `soul` | ✓ | ✓ | ✗ | Personality/identity description |
|
|
| `memory` | ✓ | ✓ | ✗ | Per-agent accumulated knowledge |
|
|
| `bundleConfig` | ✓ | ✓ | ✗ | Structured instruction bundle |
|
|
|
|
### Agent Companies Manifest Fields
|
|
|
|
| Manifest Field | First-Class Agent Field | Fallback |
|
|
|---------------|------------------------|----------|
|
|
| `name` | `name` | — (required) |
|
|
| `title` | `title` | — |
|
|
| `icon` | `icon` | — |
|
|
| `role` | `role` (mapped to AgentCapability) | `custom` |
|
|
| `reportsTo` | `reportsTo` | — |
|
|
| `instructionBody` | `instructionsText` | — |
|
|
| `skills` | `metadata.skills` | — |
|
|
|
|
### System-Managed Fields (Not User-Editable)
|
|
|
|
These fields are managed by the engine and cannot be directly edited:
|
|
|
|
- `id` — Auto-generated unique identifier
|
|
- `state` — Agent lifecycle state (managed by engine)
|
|
- `taskId` — Current working task (managed by scheduler)
|
|
- `totalInputTokens` / `totalOutputTokens` — Token usage totals (managed by engine)
|
|
- `createdAt` / `updatedAt` / `lastHeartbeatAt` — Timestamps (managed by system)
|
|
- `lastError` — Last error message (managed by engine)
|
|
|
|
## Agents View (Dashboard)
|
|
|
|
The agents surface provides:
|
|
|
|
- Agent list and status
|
|
- Detail/config panels
|
|
- Runtime metrics
|
|
- Run history
|
|
- Task assignment context
|
|
|
|

|
|
|
|
## Built-In Agent Prompt Templates
|
|
|
|
Fusion includes built-in templates for role prompts:
|
|
|
|
- `default-executor`
|
|
- `default-triage`
|
|
- `default-reviewer`
|
|
- `default-merger`
|
|
- `senior-engineer`
|
|
- `strict-reviewer`
|
|
- `concise-triage`
|
|
|
|
These can be assigned per role using `agentPrompts.roleAssignments`.
|
|
|
|
## Per-Agent Configuration
|
|
|
|
Agents can be configured with:
|
|
|
|
- Custom instructions
|
|
- Heartbeat interval/timeout limits
|
|
- Max concurrent heartbeat runs
|
|
|
|
Heartbeat values are validated and minimum-clamped.
|
|
|
|
## Agent Instructions (Dashboard)
|
|
|
|
The Agent Detail view includes a dedicated **Instructions** tab for editing agent custom instructions. This replaces the previous embedded instructions editor in the Settings tab, providing a more discoverable and user-friendly experience.
|
|
|
|
### Inline vs File-Backed Instructions
|
|
|
|
There are two ways to provide custom instructions:
|
|
|
|
1. **Inline Instructions**: Direct text entry in the dashboard textarea. Good for simple, short instructions.
|
|
|
|
2. **File-Backed Instructions**: A path to a `.md` file in the project that contains the instructions. Good for:
|
|
- Longer, more complex instructions
|
|
- Version control of instruction changes
|
|
- Sharing instruction files across teams
|
|
|
|
### Using the Instructions Tab
|
|
|
|
1. Open an agent from the Agents view
|
|
2. Click the **Instructions** tab
|
|
3. Enter inline instructions in the **Inline Instructions** textarea
|
|
4. Or set a path in **Instructions File Path** (e.g., `.fusion/agents/my-agent.md`)
|
|
5. When a path is set, a **File Content** editor appears for direct file editing
|
|
6. Save instructions using the **Save Instructions** button
|
|
7. Save file content separately using the **Save File** button
|
|
|
|
### File Editor Behavior
|
|
|
|
- File content loads automatically when an instructions path is set
|
|
- Missing files (ENOENT) are treated as new files with empty content
|
|
- Non-ENOENT errors (e.g., permission denied) show an error toast
|
|
- The editor has an **Unsaved changes** indicator when file content is modified
|
|
- File saves are independent from instruction metadata saves
|
|
|
|
## New Agent Presets (Dashboard UI)
|
|
|
|
The New Agent dialog in the dashboard provides quick-start presets for common agent roles. Each preset includes:
|
|
|
|
- **Name and icon** - Display identification
|
|
- **Professional title** - Descriptive role title
|
|
- **Soul** - Personality and operating principles defining how the agent thinks and communicates
|
|
- **Instructions** - Actionable behavioral guidelines
|
|
|
|
### Preset Library Location
|
|
|
|
Preset definitions live in `packages/dashboard/app/components/agent-presets/`:
|
|
|
|
```
|
|
agent-presets/
|
|
├── index.ts # Exports AGENT_PRESETS and helper functions
|
|
├── ceo/soul.md # Chief Executive Officer soul
|
|
├── cto/soul.md # Chief Technology Officer soul
|
|
├── cmo/soul.md # Chief Marketing Officer soul
|
|
├── cfo/soul.md # Chief Financial Officer soul
|
|
├── engineer/soul.md # Software Engineer soul
|
|
├── backend-engineer/soul.md
|
|
├── frontend-engineer/soul.md
|
|
├── fullstack-engineer/soul.md
|
|
├── qa-engineer/soul.md
|
|
├── devops-engineer/soul.md
|
|
├── ci-engineer/soul.md
|
|
├── security-engineer/soul.md
|
|
├── data-engineer/soul.md
|
|
├── ml-engineer/soul.md
|
|
├── product-manager/soul.md
|
|
├── designer/soul.md
|
|
├── marketing-manager/soul.md
|
|
├── technical-writer/soul.md
|
|
├── triage/soul.md
|
|
└── reviewer/soul.md
|
|
```
|
|
|
|
### Soul File Format
|
|
|
|
Each `soul.md` file is a Markdown document containing:
|
|
|
|
```markdown
|
|
# Soul: [Role Name]
|
|
|
|
[First-person identity statement]
|
|
|
|
## Operating Principles
|
|
|
|
[Bullet points describing key behaviors]
|
|
|
|
## Communication Style
|
|
|
|
[How the agent communicates]
|
|
```
|
|
|
|
Soul content should be:
|
|
|
|
- **First-person** - Written from the agent's perspective ("I am...")
|
|
- **Role-specific** - Defines the unique character of this role
|
|
- **Actionable** - Describes concrete behaviors, not abstract qualities
|
|
- **Paperclip-inspired** - Clear ownership, decision discipline, communication standards
|
|
|
|
### Adding or Modifying Presets
|
|
|
|
1. Create or edit the `soul.md` file in the appropriate directory
|
|
2. Update `index.ts` if adding a new preset (export the imported soul and add to `AGENT_PRESETS` array)
|
|
3. Run tests to verify: `pnpm --filter @fusion/dashboard exec vitest run app/components/__tests__/agent-presets.test.ts`
|
|
|
|
### Preset vs Engine Templates
|
|
|
|
**Dashboard presets** are a UI-only concept that populates the New Agent dialog fields (name, icon, role, soul, instructionsText). They don't map to engine types.
|
|
|
|
**Engine role prompts** (in `agentPrompts` settings) define the actual agent behavior when executing tasks. These are separate from dashboard presets and live in project settings.
|
|
|
|
This separation means:
|
|
- Presets provide starting point personality and instructions for new agents
|
|
- Engine templates control actual task execution behavior
|
|
- An agent created from a preset can have its engine role prompt customized independently
|
|
|
|
## Configurable Agent Prompts (`agentPrompts`)
|
|
|
|
`agentPrompts` project setting supports:
|
|
|
|
- `templates[]`: custom prompt templates by role
|
|
- `roleAssignments`: map role → template ID
|
|
|
|
When no assignment is configured, Fusion falls back to built-in defaults.
|
|
|
|
## Fine-Grained Prompt Overrides (`promptOverrides`)
|
|
|
|
The **Prompts** section in the Settings modal provides a user-friendly interface for customizing specific segments of agent prompts. Unlike `agentPrompts` which replaces entire role templates, `promptOverrides` allows surgical customization of individual prompt sections.
|
|
|
|
### Supported Override Keys
|
|
|
|
| Key | Agent Role | Description |
|
|
|-----|-----------|-------------|
|
|
| `executor-welcome` | executor | Introductory section for the executor agent |
|
|
| `executor-guardrails` | executor | Behavioral guardrails and constraints |
|
|
| `executor-spawning` | executor | Instructions for spawning child agents |
|
|
| `executor-completion` | executor | Completion criteria and signaling |
|
|
| `triage-welcome` | triage | Introductory section for the triage/specification agent |
|
|
| `triage-context` | triage | Context-gathering instructions |
|
|
| `reviewer-verdict` | reviewer | Verdict criteria and format |
|
|
| `merger-conflicts` | merger | Merge conflict resolution instructions |
|
|
| `agent-generation-system` | — | System prompt for AI-assisted agent specification generation |
|
|
| `workflow-step-refine` | — | System prompt for refining workflow step descriptions |
|
|
|
|
### How It Works
|
|
|
|
1. Navigate to **Settings → Prompts** in the dashboard
|
|
2. Each prompt shows its name, key, description, and current value
|
|
3. Edit the textarea to create a custom override
|
|
4. Click **Reset** to restore the built-in default
|
|
|
|
### Clearing Overrides
|
|
|
|
To clear a specific override, click the **Reset** button in the UI. This sends `null` for that prompt key, deleting the override from settings and reverting to the built-in default.
|
|
|
|
### Relationship with `agentPrompts`
|
|
|
|
- `agentPrompts` replaces entire role templates
|
|
- `promptOverrides` customizes individual segments within any template
|
|
- Both can be used together — `promptOverrides` applies to the segment even within a custom role template
|
|
|
|
## Inter-Agent Messaging
|
|
|
|
Messaging is available in dashboard mailbox UI and CLI.
|
|
|
|
```bash
|
|
fn message inbox
|
|
fn message outbox
|
|
fn message send AGENT-001 "Please prioritize FN-420"
|
|
fn message read MSG-123
|
|
fn message delete MSG-123
|
|
fn agent mailbox AGENT-001
|
|
```
|
|
|
|
## Agent Spawning
|
|
|
|
Executor sessions can spawn child agents through `spawn_agent`.
|
|
|
|
Behavior:
|
|
|
|
- Child agents run in separate worktrees
|
|
- Parent/child relationship is tracked
|
|
- Limits enforced:
|
|
- `maxSpawnedAgentsPerParent` (default 5)
|
|
- `maxSpawnedAgentsGlobal` (default 20)
|
|
- Child sessions terminate when parent task ends
|
|
|
|
## Heartbeat Monitoring and Trigger Scheduling
|
|
|
|
Fusion's `HeartbeatTriggerScheduler` supports three trigger types:
|
|
|
|
- `timer` — periodic wake based on heartbeat interval
|
|
- `assignment` — wake when task is assigned to agent
|
|
- `on_demand` — manual run trigger (`POST /api/agents/:id/runs`)
|
|
|
|
All triggers respect per-agent `maxConcurrentRuns` and produce structured wake context metadata.
|
|
|
|
### Control-Plane Lane (No Task Concurrency Gating)
|
|
|
|
Heartbeat runs from the Agents panel run on a **separate control-plane lane** that is independent of task execution concurrency limits. This ensures agent responsiveness is preserved even when task pipelines are saturated.
|
|
|
|
**Key behaviors:**
|
|
|
|
- Heartbeat runs (via `POST /api/agents/:id/runs`) execute without gating on `maxConcurrent` or in-progress task count
|
|
- The `HeartbeatTriggerScheduler` and `HeartbeatMonitor` components do not receive the task-lane semaphore
|
|
- Trigger scheduling remains responsive regardless of how busy the task pipeline is
|
|
- Active-run 409 conflict semantics still apply — a new heartbeat run is rejected if the agent already has an active run
|
|
|
|
**Architectural boundary:**
|
|
|
|
| Component | Path | Concurrency |
|
|
|-----------|------|------------|
|
|
| TriageProcessor | Task lane | Semaphore-gated |
|
|
| TaskExecutor | Task lane | Semaphore-gated |
|
|
| Scheduler | Task lane | Semaphore-gated |
|
|
| onMerge | Task lane | Semaphore-gated |
|
|
| HeartbeatMonitor | Utility/control plane | **NOT** semaphore-gated |
|
|
| HeartbeatTriggerScheduler | Utility/control plane | **NOT** semaphore-gated |
|
|
| CronRunner | Utility/control plane | **NOT** semaphore-gated |
|
|
|
|
## Dashboard Health Status
|
|
|
|
The dashboard displays agent health status in AgentsView, AgentListModal, and AgentDetailView using a centralized health evaluation utility (`packages/dashboard/app/utils/agentHealth.ts`).
|
|
|
|
### Health Labels (Priority Order)
|
|
|
|
| Label | Condition |
|
|
|-------|-----------|
|
|
| **Terminated** | Agent state is "terminated" |
|
|
| **Error** | Agent state is "error" (uses lastError if available) |
|
|
| **Paused** | Agent state is "paused" (uses pauseReason if available) |
|
|
| **Running** | Agent state is "running" |
|
|
| **Disabled** | `runtimeConfig.enabled === false` |
|
|
| **Starting...** | State is "active" with no lastHeartbeatAt |
|
|
| **Idle** | Non-active state with no lastHeartbeatAt |
|
|
| **Healthy** | Heartbeat is fresh within configured timeout |
|
|
| **Unresponsive** | Heartbeat exceeded configured timeout |
|
|
|
|
### Timeout Configuration
|
|
|
|
Health status uses a timeout-based evaluation:
|
|
|
|
1. If `runtimeConfig.heartbeatTimeoutMs` is set on the agent, use that value
|
|
2. Otherwise, use the default 60-second (60000ms) timeout
|
|
|
|
### Key Behaviors
|
|
|
|
- **Monitoring disabled**: Agents with `runtimeConfig.enabled === false` display "Disabled" — they are NOT falsely labeled as "Unresponsive"
|
|
- **Consistent across views**: All dashboard surfaces use the same centralized utility, ensuring consistent health labels everywhere
|
|
- **Auto-refresh**: Health status is refreshed every 30 seconds while views are open to keep status current
|
|
- **State-first evaluation**: Terminal states (terminated, error, paused, running) take priority over timeout-based evaluation
|
|
|
|
## Heartbeat Run Lifecycle
|
|
|
|
Agent runs have a defined lifecycle managed by `AgentStore`:
|
|
|
|
### Run States
|
|
|
|
A heartbeat run can be in one of these states:
|
|
|
|
- `active` — Run is currently executing
|
|
- `completed` — Run finished successfully (via `endHeartbeatRun(runId, "completed")`)
|
|
- `terminated` — Run was stopped (via `endHeartbeatRun(runId, "terminated")`)
|
|
- `failed` — Run encountered an error
|
|
|
|
### Run Lifecycle API
|
|
|
|
- `startHeartbeatRun(agentId)` — Creates a new run and persists it to structured storage
|
|
- `endHeartbeatRun(runId, status)` — Ends a run with terminal status, updates persisted state
|
|
- `getActiveHeartbeatRun(agentId)` — Returns the current active run (or null)
|
|
- `getCompletedHeartbeatRuns(agentId)` — Returns all terminal runs (newest first)
|
|
- `saveRun(run)` — Persists run to structured storage
|
|
- `getRunDetail(agentId, runId)` — Gets a specific run by ID
|
|
|
|
### Active-Run Conflict Semantics
|
|
|
|
When an agent already has an active run, attempts to start a new run return **409 Conflict**:
|
|
|
|
```
|
|
POST /api/agents/:id/runs → 409 { error: "Agent already has an active run", details: { runId } }
|
|
```
|
|
|
|
After a run is completed (or terminated), a new run can be started successfully:
|
|
|
|
```
|
|
POST /api/agents/:id/runs → 201 { id: "run-xxx", status: "active", ... }
|
|
```
|
|
|
|
### Storage Architecture
|
|
|
|
Run records are stored in structured JSON files at `.fusion/agents/{agentId}-runs/{runId}.json`.
|
|
|
|
Heartbeat events are also appended to `.fusion/agents/{agentId}-heartbeats.jsonl` for legacy compatibility. The structured storage is the source of truth; heartbeat events provide a fallback for older run data.
|
|
|
|
### Stopping Runs
|
|
|
|
Use `POST /api/agents/:id/runs/stop` to terminate an active run:
|
|
|
|
```
|
|
POST /api/agents/:id/runs/stop → 200 { ok: true, runId: "run-xxx" }
|
|
```
|
|
|
|
If there's no active run, returns `{ ok: true, message: "No active run" }`.
|
|
|
|
## Related Docs
|
|
|
|
- [Workflow Steps](./workflow-steps.md)
|
|
- [Settings Reference](./settings-reference.md)
|
|
- [Architecture](./architecture.md)
|