RFC-003: Agent Configuration Layer #233

Merged
xiaomo merged 2 commits from rfc/003-agent-config-layer into main 2026-04-29 04:29:47 +00:00
+170
View File
@@ -0,0 +1,170 @@
# RFC-003: Agent Configuration Layer
**Author:** 小橘 🍊(NEKO Team)
**Status:** Draft
**Created:** 2026-04-29
## Summary
Introduce a top-level `agents` and `extract` configuration in `nerve.yaml`, separating agent infrastructure from workflow business logic. Workflows define Roles (prompt + schema) that reference named Agents by domain expertise, not by implementation detail.
## Motivation
Currently, Role definitions in workflows are tightly coupled with agent implementation details (type, model, timeout). This leads to:
- **Duplication** — multiple workflows using the same agent config repeat it everywhere
- **Fragility** — switching from `cursor` to `codex` requires touching every workflow
- **Leaky abstraction** — workflow authors need to know agent internals
## Key Concepts
### Agent vs Role
| | Agent | Role |
|---|---|---|
| **What** | Professional domain capability | Scenario-specific persona |
| **Granularity** | Few (2–4) | Many (per workflow step) |
| **Examples** | `developer`, `ops`, `writer` | `architect`, `coder`, `reviewer`, `deployer` |
| **Defines** | Tool, model, timeout defaults | Prompt, meta schema, timeout override |
| **Layer** | Infrastructure (`nerve.yaml`) | Business logic (TypeScript) |
A `developer` agent becomes an architect, coder, or reviewer depending on the prompt it receives. The agent defines *what it's good at*; the role defines *what it does right now*.
### Agent Protocol
All agent types implement a single unified interface:
```ts
type AgentFn = (prompt: string, context: WorkflowContext) => Promise<string>
```
- **Input**: prompt (assembled by Role) + context (start frame + prior messages)
- **Output**: raw string — structured data is extracted separately
- **Internals**: adapter handles tool-specific details (cursor CLI, hermes subagent, codex API, etc.)
Workflow runtime never interacts with agent internals.
### Extract Layer
A separate concern that parses agent output (raw string) into typed meta:
```ts
type ExtractFn<T> = (raw: string, schema: Schema<T>) => Promise<T>
```
Configured globally in `nerve.yaml`, overridable per role.
## Design
### Configuration (`nerve.yaml`)
```yaml
agents:
developer:
type: cursor # adapter: cursor | hermes | codex | ...
model: auto
timeout: 300s
ops:
type: hermes
model: auto
timeout: 600s
extract:
provider: dashscope
model: qwen-plus
```
### Workflow Definition (TypeScript)
```ts
const workflow: WorkflowSpec<MyMeta> = {
name: "develop-workflow",
roles: {
architect: { agent: "developer", prompt: architectPrompt, meta: architectSchema },
coder: { agent: "developer", prompt: coderPrompt, meta: coderSchema },
reviewer: { agent: "developer", prompt: reviewPrompt, meta: reviewSchema, timeout: "60s" },
deployer: { agent: "ops", prompt: deployPrompt, meta: deploySchema },
},
moderator,
};
```
### Runtime Assembly
```
nerve.yaml → AgentRegistry → adapter(cursor/hermes/codex/...)
WorkflowSpec → Role(agent + prompt) → AgentFn(prompt, ctx) → string
nerve.yaml#extract → ExtractFn(string, schema) → T (typed meta)
```
`AgentRegistry` reads config, instantiates adapters, and returns `AgentFn` by name. Role assembly is handled by the runtime — users never call Role factories directly.
### Timeout Resolution
Two-layer with role override:
1. Agent config provides the default timeout
2. Role definition can override for specific scenarios
```yaml
# Agent default
agents:
developer:
timeout: 300s
```
```ts
// Role override — review is faster
reviewer: { agent: "developer", ..., timeout: "60s" }
// coder uses agent default (300s)
coder: { agent: "developer", ... }
```
### No Runtime Fallback
- **`nerve init`** — detects agent availability (CLI exists? service reachable?), reports errors immediately
- **Runtime** — if an agent is unavailable, the workflow fails with a clear error. No silent degradation.
Rationale: silent fallback hides quality differences (cursor → hermes subagent produces very different output) and makes debugging harder.
## Compatibility with Current Types
The existing `Role<Meta>` signature:
```ts
type Role<Meta> = (start: StartStep, messages: WorkflowMessage[]) => Promise<RoleResult<Meta>>
```
remains the runtime interface. The new config layer is syntactic sugar — the runtime assembles `Role<Meta>` functions from `(agent config + prompt + schema)` instead of users writing them by hand. `WorkflowDefinition` stays the same at the engine level; `WorkflowSpec` is the new user-facing authoring format that compiles down to it.
## Knowledge Layer
Project knowledge is **not a nerve feature**. It is managed by [Alysaril](https://git.shazhou.work/uncaged/alysaril) — an independent project knowledge base tool (Zettelkasten cards + semantic search).
Nerve's relationship to project knowledge:
- **Nerve does not hardcode knowledge paths** — no `.nerve/knowledge/` convention in runtime code
- **Knowledge loading is a prompt concern** — role prompts tell agents to read relevant cards
- **Agent long-term memory** — domain expertise accumulated across runs (e.g. "this repo uses pnpm"), stored per agent, separate from project knowledge
- **Workflow context** (`start` + `messages`) serves as the only in-run state — no separate "short-term memory" layer needed
```
Project knowledge (Alysaril) Shared, git managed, any agent reads via prompt
Agent long-term memory Per agent, domain expertise, cross-run
Workflow context (start + msgs) Per run, moderator-controlled history
```
## Open Questions
1. **Agent naming convention** — should we enforce a fixed set (`developer`, `ops`, `writer`) or allow arbitrary names?
2. **Extract override granularity** — global only, or also per-agent and per-role?
3. **Context threading** — should `WorkflowContext` expose `workdir` and `signal` alongside the existing `start` + `messages`?
4. **Agent long-term memory** — storage format and mechanism for persisting domain expertise across runs
## References
- [RFC-002: Workflow Engine](./rfc-002-workflow-engine.md)
- Current `Role` / `Moderator` types: `packages/core/src/workflow.ts`
- [Alysaril](https://git.shazhou.work/uncaged/alysaril) — project knowledge base (independent tool)