@dreb/coding-agent 2.45.4 → 2.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -4
- package/dist/core/agent-session.d.ts +10 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +94 -23
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/context-buffer.d.ts +2 -0
- package/dist/core/context-buffer.d.ts.map +1 -1
- package/dist/core/context-buffer.js +8 -0
- package/dist/core/context-buffer.js.map +1 -1
- package/dist/core/dispatch-arbiter.d.ts +94 -0
- package/dist/core/dispatch-arbiter.d.ts.map +1 -0
- package/dist/core/dispatch-arbiter.js +316 -0
- package/dist/core/dispatch-arbiter.js.map +1 -0
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +7 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +10 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +35 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/git-repo-state.d.ts +2 -0
- package/dist/core/git-repo-state.d.ts.map +1 -1
- package/dist/core/git-repo-state.js +19 -0
- package/dist/core/git-repo-state.js.map +1 -1
- package/dist/core/model-routing-guide.d.ts +15 -0
- package/dist/core/model-routing-guide.d.ts.map +1 -0
- package/dist/core/model-routing-guide.js +186 -0
- package/dist/core/model-routing-guide.js.map +1 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +38 -2
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +18 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +33 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/thinking.d.ts +14 -0
- package/dist/core/thinking.d.ts.map +1 -1
- package/dist/core/thinking.js +35 -2
- package/dist/core/thinking.js.map +1 -1
- package/dist/core/tools/ask-user.d.ts +45 -0
- package/dist/core/tools/ask-user.d.ts.map +1 -0
- package/dist/core/tools/ask-user.js +210 -0
- package/dist/core/tools/ask-user.js.map +1 -0
- package/dist/core/tools/index.d.ts +18 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +8 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/subagent.d.ts +53 -6
- package/dist/core/tools/subagent.d.ts.map +1 -1
- package/dist/core/tools/subagent.js +343 -53
- package/dist/core/tools/subagent.js.map +1 -1
- package/dist/modes/interactive/components/ask-user.d.ts +59 -0
- package/dist/modes/interactive/components/ask-user.d.ts.map +1 -0
- package/dist/modes/interactive/components/ask-user.js +240 -0
- package/dist/modes/interactive/components/ask-user.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +4 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +99 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +13 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +167 -6
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +18 -3
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +177 -59
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +32 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/agent-models.md +33 -1
- package/docs/dashboard.md +9 -3
- package/docs/extensions.md +33 -3
- package/docs/json.md +31 -5
- package/docs/rpc.md +105 -15
- package/docs/session.md +8 -2
- package/docs/settings.md +33 -1
- package/docs/skills.md +38 -0
- package/package.json +1 -1
- package/skills/model-routing-guide/SKILL.md +182 -0
package/docs/extensions.md
CHANGED
|
@@ -9,7 +9,7 @@ Extensions are TypeScript modules that extend dreb's behavior. They can subscrib
|
|
|
9
9
|
**Key capabilities:**
|
|
10
10
|
- **Custom tools** - Register tools the LLM can call via `dreb.registerTool()`
|
|
11
11
|
- **Event interception** - Block or modify tool calls, inject context, customize compaction
|
|
12
|
-
- **User interaction** - Prompt users via `ctx.ui` (select, confirm, input, notify)
|
|
12
|
+
- **User interaction** - Prompt users via `ctx.ui` (select, confirm, input, ask, notify)
|
|
13
13
|
- **Custom UI components** - Full TUI components with keyboard input via `ctx.ui.custom()` for complex interactions
|
|
14
14
|
- **Custom commands** - Register commands like `/mycommand` via `dreb.registerCommand()`
|
|
15
15
|
- **Session persistence** - Store state that survives restarts via `dreb.appendEntry()`
|
|
@@ -161,6 +161,26 @@ export default function (dreb: ExtensionAPI) {
|
|
|
161
161
|
ctx.ui.notify("Done!", "success");
|
|
162
162
|
ctx.ui.setStatus("my-ext", "Processing..."); // Footer status
|
|
163
163
|
ctx.ui.setWidget("my-ext", ["Line 1", "Line 2"]); // Widget above editor (default)
|
|
164
|
+
|
|
165
|
+
// ctx.ui.ask — a rich clarifying question with options + free text,
|
|
166
|
+
// rendered natively in the TUI and Dashboard (and over RPC). Resolves to
|
|
167
|
+
// { selected: string[], customText?: string }. Dismissing or timing out an
|
|
168
|
+
// ask stops the current agent turn and resolves undefined. This is the same
|
|
169
|
+
// primitive that powers the built-in `ask_user` tool.
|
|
170
|
+
const answer = await ctx.ui.ask(
|
|
171
|
+
{
|
|
172
|
+
title: "Choose a database",
|
|
173
|
+
question: "Which persistence strategy should I use?",
|
|
174
|
+
options: ["SQLite", "PostgreSQL", "Keep the JSON file"],
|
|
175
|
+
allowFreeText: true, // default; offers a "type your own answer" field
|
|
176
|
+
multiSelect: false, // true → checkboxes, combined with any free text
|
|
177
|
+
multiline: false, // true → multi-line free-text area
|
|
178
|
+
},
|
|
179
|
+
{ signal, timeout: 60000 }, // both optional; absent user never deadlocks
|
|
180
|
+
);
|
|
181
|
+
if (!answer) {
|
|
182
|
+
// The ask was dismissed or timed out; the current agent turn is stopping.
|
|
183
|
+
}
|
|
164
184
|
});
|
|
165
185
|
|
|
166
186
|
// Register tools, commands, shortcuts, flags
|
|
@@ -593,7 +613,7 @@ In the default parallel tool execution mode, sibling tool calls from the same as
|
|
|
593
613
|
import { isToolCallEventType } from "@dreb/coding-agent";
|
|
594
614
|
|
|
595
615
|
dreb.on("tool_call", async (event, ctx) => {
|
|
596
|
-
// event.toolName - "bash", "read", "write", "edit", "grep", "find", "ls", "web_search", "web_fetch", "subagent", "wait", "search", "skill", "tasks_update", "suggest_next", or custom tool names
|
|
616
|
+
// event.toolName - "bash", "read", "write", "edit", "grep", "find", "ls", "web_search", "web_fetch", "subagent", "wait", "search", "ask_user", "skill", "tasks_update", "suggest_next", or custom tool names
|
|
597
617
|
// event.toolCallId
|
|
598
618
|
// event.input - tool parameters
|
|
599
619
|
|
|
@@ -1498,7 +1518,7 @@ async execute(toolCallId, params) {
|
|
|
1498
1518
|
|
|
1499
1519
|
### Overriding Built-in Tools
|
|
1500
1520
|
|
|
1501
|
-
Extensions can override built-in tools (`read`, `bash`, `edit`, `write`, `grep`, `find`, `ls`, `web_search`, `web_fetch`, `subagent`, `wait`, `search`) by registering a tool with the same name. Interactive mode displays a warning when this happens. The factory-only tools (`skill`, `tasks_update`, `suggest_next`) can also be overridden.
|
|
1521
|
+
Extensions can override built-in tools (`read`, `bash`, `edit`, `write`, `grep`, `find`, `ls`, `web_search`, `web_fetch`, `subagent`, `wait`, `search`, `ask_user`) by registering a tool with the same name. Interactive mode displays a warning when this happens. The factory-only tools (`skill`, `tasks_update`, `suggest_next`) can also be overridden.
|
|
1502
1522
|
|
|
1503
1523
|
```bash
|
|
1504
1524
|
# Extension's read tool replaces built-in read
|
|
@@ -1782,6 +1802,15 @@ const ok = await ctx.ui.confirm("Delete?", "This cannot be undone");
|
|
|
1782
1802
|
// Text input
|
|
1783
1803
|
const name = await ctx.ui.input("Name:", "placeholder");
|
|
1784
1804
|
|
|
1805
|
+
// Rich question: question text supports Markdown and options can be combined
|
|
1806
|
+
// with free text. Dismissal stops the current agent turn and returns undefined.
|
|
1807
|
+
const answer = await ctx.ui.ask({
|
|
1808
|
+
title: "Choose a database",
|
|
1809
|
+
question: "Which persistence strategy should I use?",
|
|
1810
|
+
options: ["SQLite", "PostgreSQL"],
|
|
1811
|
+
allowFreeText: true,
|
|
1812
|
+
});
|
|
1813
|
+
|
|
1785
1814
|
// Multi-line editor
|
|
1786
1815
|
const text = await ctx.ui.editor("Edit:", "prefilled text");
|
|
1787
1816
|
|
|
@@ -1812,6 +1841,7 @@ if (confirmed) {
|
|
|
1812
1841
|
- `select()` returns `undefined`
|
|
1813
1842
|
- `confirm()` returns `false`
|
|
1814
1843
|
- `input()` returns `undefined`
|
|
1844
|
+
- `ask()` returns `undefined` and stops the current agent turn
|
|
1815
1845
|
|
|
1816
1846
|
#### Manual Dismissal with AbortSignal
|
|
1817
1847
|
|
package/docs/json.md
CHANGED
|
@@ -17,8 +17,12 @@ type AgentSessionEvent =
|
|
|
17
17
|
| { type: "auto_compaction_end"; result: CompactionResult | undefined; aborted: boolean; willRetry: boolean; errorMessage?: string }
|
|
18
18
|
| { type: "auto_retry_start"; attempt: number; maxAttempts: number; delayMs: number; errorMessage: string }
|
|
19
19
|
| { type: "auto_retry_end"; success: boolean; attempt: number; finalError?: string }
|
|
20
|
-
| { type: "background_agent_start"; agentId: string; agentType: string; taskSummary: string }
|
|
21
|
-
| { type: "
|
|
20
|
+
| { type: "background_agent_start"; agentId: string; agentType: string; taskSummary: string; sessionDir?: string }
|
|
21
|
+
| { type: "subagent_arbitration"; agentId: string; status: "success" | "failure"; proposed: DispatchRoute; final: DispatchRoute | null; changed: ("agent" | "model" | "thinking")[]; step?: number; errorCode?: string; errorMessage?: string }
|
|
22
|
+
| { type: "background_agent_end"; agentId: string; agentType: string; success: boolean; model?: string; thinking?: ThinkingLevel; steps?: SubagentStepMetadata[]; sessionFile?: string }
|
|
23
|
+
| { type: "background_agent_event"; agentId: string; event: Record<string, unknown> }
|
|
24
|
+
| { type: "parent_paused_for_background_agents"; runningAgentCount: number; turnsUsed: number; turnLimit: number }
|
|
25
|
+
| { type: "session_name_changed"; name: string }
|
|
22
26
|
| { type: "tasks_update"; tasks: readonly SessionTask[] }
|
|
23
27
|
| { type: "suggest_next"; command: string };
|
|
24
28
|
|
|
@@ -28,6 +32,20 @@ interface SessionTask {
|
|
|
28
32
|
title: string;
|
|
29
33
|
status: "pending" | "in_progress" | "completed";
|
|
30
34
|
}
|
|
35
|
+
|
|
36
|
+
interface SubagentStepMetadata {
|
|
37
|
+
step: number;
|
|
38
|
+
agent: string;
|
|
39
|
+
success: boolean;
|
|
40
|
+
model?: string; // canonical provider/model
|
|
41
|
+
thinking?: ThinkingLevel;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface DispatchRoute {
|
|
45
|
+
agent: string;
|
|
46
|
+
model: string; // canonical provider/model
|
|
47
|
+
thinking: ThinkingLevel;
|
|
48
|
+
}
|
|
31
49
|
```
|
|
32
50
|
|
|
33
51
|
Base events from [`AgentEvent`](https://github.com/aebrer/dreb/blob/master/packages/agent/src/types.ts):
|
|
@@ -35,7 +53,7 @@ Base events from [`AgentEvent`](https://github.com/aebrer/dreb/blob/master/packa
|
|
|
35
53
|
```typescript
|
|
36
54
|
type AgentEvent =
|
|
37
55
|
// Agent lifecycle
|
|
38
|
-
| { type: "agent_start"; model?: { provider: string; id: string } }
|
|
56
|
+
| { type: "agent_start"; model?: { provider: string; id: string }; thinkingLevel?: ThinkingLevel }
|
|
39
57
|
| { type: "agent_end"; messages: AgentMessage[] }
|
|
40
58
|
// Turn lifecycle
|
|
41
59
|
| { type: "turn_start" }
|
|
@@ -75,7 +93,7 @@ Each line is a JSON object. The first line is the session header (`version` is t
|
|
|
75
93
|
Followed by events as they occur:
|
|
76
94
|
|
|
77
95
|
```json
|
|
78
|
-
{"type":"agent_start","model":{"provider":"anthropic","id":"claude-sonnet-4-20250514"}}
|
|
96
|
+
{"type":"agent_start","model":{"provider":"anthropic","id":"claude-sonnet-4-20250514"},"thinkingLevel":"high"}
|
|
79
97
|
{"type":"turn_start"}
|
|
80
98
|
{"type":"message_start","message":{"role":"assistant","content":[],...}}
|
|
81
99
|
{"type":"message_update","message":{...},"assistantMessageEvent":{"type":"text_delta","delta":"Hello",...}}
|
|
@@ -84,6 +102,14 @@ Followed by events as they occur:
|
|
|
84
102
|
{"type":"agent_end","messages":[...]}
|
|
85
103
|
```
|
|
86
104
|
|
|
105
|
+
With global Dispatch Arbiter enabled, each background start is followed before child events/spawn by one safe structured decision. Unchanged decisions use an empty `changed`; failed decisions use `final: null`, prevent spawn, and carry only host-generated errors. Chain decisions also include `step`.
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{"type":"subagent_arbitration","agentId":"a1b2c3","status":"success","proposed":{"agent":"Explore","model":"provider/frontier","thinking":"high"},"final":{"agent":"feature-dev","model":"provider/worker","thinking":"medium"},"changed":["agent","model","thinking"]}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The event never contains the arbiter prompt, response, reasoning, guide, task, or conversation excerpt. The matching parent session persists the same safe fields as a non-context custom JSONL entry.
|
|
112
|
+
|
|
87
113
|
## Error handling
|
|
88
114
|
|
|
89
115
|
Errors surface as events, not as broken JSON or exit codes:
|
|
@@ -104,7 +130,7 @@ Events are emitted in a predictable sequence:
|
|
|
104
130
|
|
|
105
131
|
`message_update` events stream as chunks arrive — expect many per message. `tool_execution_update` events are optional (only emitted for tools that report progress).
|
|
106
132
|
|
|
107
|
-
Auto-compaction and auto-retry events can appear between turns.
|
|
133
|
+
Auto-compaction and auto-retry events can appear between turns. Background lifecycle events are asynchronous: `background_agent_start` is emitted immediately, then an enabled `subagent_arbitration` record appears before that child's first `background_agent_event`; a failed arbitration is followed by `background_agent_end` without any child event.
|
|
108
134
|
|
|
109
135
|
## Example
|
|
110
136
|
|
package/docs/rpc.md
CHANGED
|
@@ -224,17 +224,17 @@ The `model` field is a full [Model](#model) object or `null`. `scopedModels` is
|
|
|
224
224
|
|
|
225
225
|
#### get_dashboard_snapshot
|
|
226
226
|
|
|
227
|
-
Capture the dashboard-visible parent-session state, full parent transcript,
|
|
227
|
+
Capture the dashboard-visible parent-session state, full parent transcript, background-agent registry, and blocking extension UI requests at one RPC command boundary. This is for authoritative recovery, not ordinary incremental refreshes.
|
|
228
228
|
|
|
229
229
|
```json
|
|
230
230
|
{"id": "snapshot-7", "type": "get_dashboard_snapshot"}
|
|
231
231
|
```
|
|
232
232
|
|
|
233
|
-
The `RpcDashboardSnapshot` result is a `snapshotId`, a complete `RpcSessionState` (including `tasks`), `messages`, and `
|
|
233
|
+
The `RpcDashboardSnapshot` result is a `snapshotId`, a complete `RpcSessionState` (including `tasks`), `messages`, `backgroundAgents`, and `pendingExtensionUiRequests`. The last field contains every blocking `select`, `confirm`, `input`, `editor`, or `ask` request still awaiting a host response, so a recovering Dashboard can restore the answer UI instead of leaving the runtime blocked. The RPC child writes a `RpcDashboardSnapshotBarrierEvent` to stdout **immediately before** the matching response line:
|
|
234
234
|
|
|
235
235
|
```json
|
|
236
236
|
{"type":"dashboard_snapshot_barrier","snapshotId":"snapshot-7"}
|
|
237
|
-
{"id":"snapshot-7","type":"response","command":"get_dashboard_snapshot","success":true,"data":{"snapshotId":"snapshot-7","state":{...},"messages":[...],"backgroundAgents":[...]}}
|
|
237
|
+
{"id":"snapshot-7","type":"response","command":"get_dashboard_snapshot","success":true,"data":{"snapshotId":"snapshot-7","state":{...},"messages":[...],"backgroundAgents":[...],"pendingExtensionUiRequests":[...]}}
|
|
238
238
|
```
|
|
239
239
|
|
|
240
240
|
Stdout JSONL ordering is the contract: a relay records its current event-stream sequence when the marker arrives, before resolving the response, and pairs the snapshot only with that exact marker. The dashboard returns that captured sequence as `/api/resync.barrierSeq`; consumers discard queued events through it and replay only later events. The marker itself is not broadcast as another browser event, so one recovering client does not interrupt healthy clients. Do not infer ordering from request/response timing; see [dashboard recovery](dashboard.md#live-connection-and-recovery).
|
|
@@ -1243,17 +1243,18 @@ Note: with `summarize: true` the command is LLM-bound and can take a while. `Rpc
|
|
|
1243
1243
|
|
|
1244
1244
|
### Settings
|
|
1245
1245
|
|
|
1246
|
-
Persistent settings, backed by the settings file (see [settings.md](settings.md)). They are normally distinct from live session state, with
|
|
1246
|
+
Persistent settings, backed by the settings file (see [settings.md](settings.md)). They are normally distinct from live session state, with global-only control/security-policy exceptions:
|
|
1247
1247
|
|
|
1248
1248
|
- **Persistent defaults** (`get_settings` / `set_settings`): provider/model, thinking level, queue modes, compaction/retry/image/skill/thinking-display/transport toggles, and per-agent model fallback lists seed fresh runtimes. Writing these ordinary defaults does **not** change a running session.
|
|
1249
1249
|
- **Global nested-context trust policy** (`autoLoadNestedContext`, `trustedContextFolders`, `effectiveTrustedContextRoots`, and the trust commands below): this is read from `~/.dreb/agent/settings.json` only, never project settings. Active main/subagent processes observe it for **future lazy nested/out-of-cwd loads**; it cannot remove content already injected into a conversation. It does not govern the separate initial upward context scan from the launch cwd.
|
|
1250
|
+
- **Global Dispatch Arbiter policy** (`subagentArbiter`): the complete object is read/written globally and project settings cannot shadow it. Enabled runtimes consume it before future subagent spawns; it does not rewrite already-started children.
|
|
1250
1251
|
- **Runtime state** (`get_state` / `set_model` / `set_thinking_level` / `set_steering_mode` / `set_follow_up_mode` / `set_auto_compaction` / `set_auto_retry`): the state of the live session. Note that the runtime setters also persist their values as new defaults as a side effect.
|
|
1251
1252
|
|
|
1252
1253
|
A dashboard settings tab typically reads `get_state` for what is active now and `get_settings` for persistent defaults plus the current global context-trust policy.
|
|
1253
1254
|
|
|
1254
1255
|
#### get_settings
|
|
1255
1256
|
|
|
1256
|
-
Get persistent settings. Before replying, RPC flushes pending settings writes, reloads durable global and project settings, and then reads the merged view; reopening dashboard Settings therefore sees external file edits. A pending write failure, unreadable file, parse error, or reload failure returns an explicit RPC error rather than a stale snapshot. Ordinary fields are the merged global + project view;
|
|
1257
|
+
Get persistent settings. Before replying, RPC flushes pending settings writes, reloads durable global and project settings, and then reads the merged view; reopening dashboard Settings therefore sees external file edits. A pending write failure, unreadable file, parse error, or reload failure returns an explicit RPC error rather than a stale snapshot. Ordinary fields are the merged global + project view; nested-context trust and `subagentArbiter` are always global-only.
|
|
1257
1258
|
|
|
1258
1259
|
```json
|
|
1259
1260
|
{"type": "get_settings"}
|
|
@@ -1283,6 +1284,12 @@ Response:
|
|
|
1283
1284
|
"hideThinkingBlock": false,
|
|
1284
1285
|
"agentModels": {
|
|
1285
1286
|
"Explore": ["anthropic/sonnet", "openai/gpt-5"]
|
|
1287
|
+
},
|
|
1288
|
+
"subagentArbiter": {
|
|
1289
|
+
"enabled": true,
|
|
1290
|
+
"model": "anthropic/claude-sonnet-4-5",
|
|
1291
|
+
"thinking": "medium",
|
|
1292
|
+
"guidePath": "~/.dreb/agent/model-routing-guide.md"
|
|
1286
1293
|
}
|
|
1287
1294
|
}
|
|
1288
1295
|
}
|
|
@@ -1292,6 +1299,8 @@ Response:
|
|
|
1292
1299
|
|
|
1293
1300
|
`trustedContextFolders` is the raw global configured list, including invalid legacy paths that are ignored fail-closed. `effectiveTrustedContextRoots` is the canonical, existing root set actually enforced after `~` expansion, native `realpath`, deduplication, and ancestor subsumption. `autoLoadNestedContext` defaults to `false`; when `true` it is global expert trust-all for every resolvable target, not a project override. Project `.dreb/settings.json` cannot affect any of these three fields.
|
|
1294
1301
|
|
|
1302
|
+
`subagentArbiter` is absent when unconfigured. It is always the global object; project `.dreb/settings.json` cannot enable, disable, or alter it.
|
|
1303
|
+
|
|
1295
1304
|
#### set_settings
|
|
1296
1305
|
|
|
1297
1306
|
Update persistent default settings. Takes a partial payload — only the supplied keys change. The whole payload is validated before anything is applied: on any invalid field, nothing changes and the response is an explicit error. Writes target the global settings file (same scope as every runtime setter).
|
|
@@ -1330,6 +1339,14 @@ Setting per-agent model fallback lists:
|
|
|
1330
1339
|
|
|
1331
1340
|
For `agentModels`, a non-empty array writes the global fallback list for that agent. An empty array removes the global entry, so that agent uses its agent-definition default unless a project-level override exists.
|
|
1332
1341
|
|
|
1342
|
+
Replace the complete global-only Dispatch Arbiter policy (exact model is validated; explicit thinking is capability-validated):
|
|
1343
|
+
|
|
1344
|
+
```json
|
|
1345
|
+
{"type":"set_settings","settings":{"subagentArbiter":{"enabled":true,"model":"anthropic/claude-sonnet-4-5","thinking":"medium","guidePath":"~/.dreb/agent/model-routing-guide.md"}}}
|
|
1346
|
+
```
|
|
1347
|
+
|
|
1348
|
+
Set `subagentArbiter: null` to remove the global policy. Enabling requires `model`; `guidePath` defaults to the standard guide path and omitted thinking runs the arbiter call with thinking off. Runtime guide/scope validation still occurs at each spawn because the live explicit scope can change.
|
|
1349
|
+
|
|
1333
1350
|
Response is the full settings snapshot after the write (same shape as `get_settings`), plus `warnings` when the write was accepted but a project-level override shadows part of it:
|
|
1334
1351
|
|
|
1335
1352
|
```json
|
|
@@ -1406,6 +1423,7 @@ Valid keys and values:
|
|
|
1406
1423
|
| `transport` | `"sse"`, `"websocket"`, `"auto"` |
|
|
1407
1424
|
| `hideThinkingBlock` | boolean |
|
|
1408
1425
|
| `agentModels` | Plain object mapping agent names to arrays of non-empty model id strings; empty arrays remove the global entry for that agent |
|
|
1426
|
+
| `subagentArbiter` | Complete global-only object or `null`. Keys: `enabled` boolean, exact available `model`, optional valid/capability-supported `thinking`, non-empty `guidePath`. Enabling requires `model`. Unknown nested keys are rejected. |
|
|
1409
1427
|
|
|
1410
1428
|
Errors are explicit `success: false` responses (nothing is applied on any of them):
|
|
1411
1429
|
|
|
@@ -1419,6 +1437,7 @@ Errors are explicit `success: false` responses (nothing is applied on any of the
|
|
|
1419
1437
|
- Invalid trusted-root list: `trustedContextFolders must be an array of non-empty path strings` or `Invalid trustedContextFolders[0]: path must be absolute after ~ expansion` / `path must be an existing directory`
|
|
1420
1438
|
- Provider without model (or vice versa): `defaultProvider and defaultModel must be set together`
|
|
1421
1439
|
- Unavailable model: `Model not found: provider/model-id`
|
|
1440
|
+
- Invalid arbiter policy: `Enabling subagentArbiter requires an exact provider/model`, `Arbiter model not found: ...`, or a nested-key/type/thinking capability error
|
|
1422
1441
|
- Corrupt settings file: `Cannot write settings: the global settings file failed to load (fix or remove the corrupt settings.json first)` — without this guard the write would silently no-op
|
|
1423
1442
|
- Write failure (I/O error): `Failed to persist settings: ...`
|
|
1424
1443
|
|
|
@@ -1584,7 +1603,7 @@ Response:
|
|
|
1584
1603
|
|
|
1585
1604
|
| Event | Description |
|
|
1586
1605
|
|-------|-------------|
|
|
1587
|
-
| `agent_start` | Agent begins processing |
|
|
1606
|
+
| `agent_start` | Agent begins processing (resolved model and effective thinking level) |
|
|
1588
1607
|
| `agent_end` | Agent completes (includes all generated messages) |
|
|
1589
1608
|
| `turn_start` | New turn begins |
|
|
1590
1609
|
| `turn_end` | Turn completes (includes assistant message and tool results) |
|
|
@@ -1601,7 +1620,7 @@ Response:
|
|
|
1601
1620
|
| `auto_retry_start` | Auto-retry begins (after transient error) |
|
|
1602
1621
|
| `auto_retry_end` | Auto-retry completes (success or final failure) |
|
|
1603
1622
|
| `background_agent_start` | Background subagent launched (includes `sessionDir`) |
|
|
1604
|
-
| `background_agent_end` | Background subagent finished (
|
|
1623
|
+
| `background_agent_end` | Background subagent finished (canonical model/thinking, per-step chain metadata, and `sessionFile` when known) |
|
|
1605
1624
|
| `background_agent_event` | Relayed event from a background subagent's own stream |
|
|
1606
1625
|
| `parent_paused_for_background_agents` | Parent paused waiting on background agents |
|
|
1607
1626
|
| `session_name_changed` | Session display name changed (manual rename, extension rename, or auto-title) |
|
|
@@ -1615,10 +1634,10 @@ rather than validating against a closed list; new event types may be added.
|
|
|
1615
1634
|
|
|
1616
1635
|
### agent_start
|
|
1617
1636
|
|
|
1618
|
-
Emitted when the agent begins processing a prompt. Includes the resolved model.
|
|
1637
|
+
Emitted when the agent begins processing a prompt. Includes the resolved model and effective thinking level sent to the provider.
|
|
1619
1638
|
|
|
1620
1639
|
```json
|
|
1621
|
-
{"type": "agent_start", "model": {"provider": "anthropic", "id": "claude-sonnet-4-20250514"}}
|
|
1640
|
+
{"type": "agent_start", "model": {"provider": "anthropic", "id": "claude-sonnet-4-20250514"}, "thinkingLevel": "high"}
|
|
1622
1641
|
```
|
|
1623
1642
|
|
|
1624
1643
|
### agent_end
|
|
@@ -1806,9 +1825,9 @@ On final failure (max retries exceeded):
|
|
|
1806
1825
|
}
|
|
1807
1826
|
```
|
|
1808
1827
|
|
|
1809
|
-
### background_agent_start / background_agent_end / background_agent_event
|
|
1828
|
+
### background_agent_start / subagent_arbitration / background_agent_end / background_agent_event
|
|
1810
1829
|
|
|
1811
|
-
Lifecycle and live-observability events for background subagents (the `subagent` tool's background mode).
|
|
1830
|
+
Lifecycle, pre-spawn routing, and live-observability events for background subagents (the `subagent` tool's background mode).
|
|
1812
1831
|
|
|
1813
1832
|
`background_agent_start` fires at launch. `sessionDir` is the directory the child will write its session JSONL into (per-launch, known before spawn):
|
|
1814
1833
|
|
|
@@ -1822,7 +1841,22 @@ Lifecycle and live-observability events for background subagents (the `subagent`
|
|
|
1822
1841
|
}
|
|
1823
1842
|
```
|
|
1824
1843
|
|
|
1825
|
-
`
|
|
1844
|
+
When the global Dispatch Arbiter is enabled, `subagent_arbitration` fires after the requested route is made concrete and before child spawn/events. It appears for changed and unchanged successful decisions, and for failures that prevent spawn. Chain records include `step`; failures have `final: null` and bounded host-generated `errorCode`/`errorMessage`.
|
|
1845
|
+
|
|
1846
|
+
```json
|
|
1847
|
+
{
|
|
1848
|
+
"type": "subagent_arbitration",
|
|
1849
|
+
"agentId": "a1b2c3d4e5f6",
|
|
1850
|
+
"status": "success",
|
|
1851
|
+
"proposed": {"agent": "Explore", "model": "provider/frontier", "thinking": "high"},
|
|
1852
|
+
"final": {"agent": "feature-dev", "model": "provider/worker", "thinking": "medium"},
|
|
1853
|
+
"changed": ["agent", "model", "thinking"]
|
|
1854
|
+
}
|
|
1855
|
+
```
|
|
1856
|
+
|
|
1857
|
+
The event is deliberately safe and programmatic: it never contains the task, guide, conversation context, prompt, raw response, or model reasoning. The parent session persists the same fields as a non-context `custom` entry. Consumers should update displayed background-agent identity from `final.agent` before child events arrive.
|
|
1858
|
+
|
|
1859
|
+
`background_agent_end` fires after the result is delivered to the parent agent. For a single child it includes the canonical resolved `provider/model` and effective thinking level when reported; `sessionFile` is the child's session JSONL path when one was written:
|
|
1826
1860
|
|
|
1827
1861
|
```json
|
|
1828
1862
|
{
|
|
@@ -1830,10 +1864,27 @@ Lifecycle and live-observability events for background subagents (the `subagent`
|
|
|
1830
1864
|
"agentId": "a1b2c3d4e5f6",
|
|
1831
1865
|
"agentType": "Explore",
|
|
1832
1866
|
"success": true,
|
|
1867
|
+
"model": "anthropic/claude-sonnet-4-20250514",
|
|
1868
|
+
"thinking": "medium",
|
|
1833
1869
|
"sessionFile": "/home/user/.dreb/agent/subagent-sessions/a1b2c3d4e5f6/2026-07-07T12-00-00-000Z_uuid.jsonl"
|
|
1834
1870
|
}
|
|
1835
1871
|
```
|
|
1836
1872
|
|
|
1873
|
+
Chain completions omit ambiguous scalar model/thinking fields and instead include ordered per-step metadata, since steps may use different agents, providers, models, or thinking levels:
|
|
1874
|
+
|
|
1875
|
+
```json
|
|
1876
|
+
{
|
|
1877
|
+
"type": "background_agent_end",
|
|
1878
|
+
"agentId": "a1b2c3d4e5f6",
|
|
1879
|
+
"agentType": "Explore",
|
|
1880
|
+
"success": true,
|
|
1881
|
+
"steps": [
|
|
1882
|
+
{"step": 1, "agent": "Explore", "success": true, "model": "anthropic/claude-sonnet-4-6", "thinking": "low"},
|
|
1883
|
+
{"step": 2, "agent": "feature-dev", "success": true, "model": "openai/gpt-5.6-sol", "thinking": "high"}
|
|
1884
|
+
]
|
|
1885
|
+
}
|
|
1886
|
+
```
|
|
1887
|
+
|
|
1837
1888
|
`background_agent_event` relays every JSONL event the child process emits (the same event union documented here, plus the initial session header), verbatim, tagged with the child's `agentId`. This is the live-transcript transport for observers like the dashboard — no session-file tailing needed. Streaming children emit `message_update` deltas at high frequency; consumers that fan events out further (e.g. over a network) should batch or throttle:
|
|
1838
1889
|
|
|
1839
1890
|
```json
|
|
@@ -1874,7 +1925,7 @@ Extensions can request user interaction via `ctx.ui.select()`, `ctx.ui.confirm()
|
|
|
1874
1925
|
|
|
1875
1926
|
There are two categories of extension UI methods:
|
|
1876
1927
|
|
|
1877
|
-
- **Dialog methods** (`select`, `confirm`, `input`, `editor`): emit an `extension_ui_request` on stdout and block until the client sends back an `extension_ui_response` on stdin with the matching `id`.
|
|
1928
|
+
- **Dialog methods** (`select`, `confirm`, `input`, `editor`, `ask`): emit an `extension_ui_request` on stdout and block until the client sends back an `extension_ui_response` on stdin with the matching `id`.
|
|
1878
1929
|
- **Fire-and-forget methods** (`notify`, `setStatus`, `setWidget`, `setTitle`, `set_editor_text`): emit an `extension_ui_request` on stdout but do not expect a response. The client can display the information or ignore it.
|
|
1879
1930
|
|
|
1880
1931
|
If a dialog method includes a `timeout` field, the agent-side will auto-resolve with a default value when the timeout expires. The client does not need to track timeouts.
|
|
@@ -1961,6 +2012,34 @@ Open a multi-line text editor with optional prefilled content.
|
|
|
1961
2012
|
|
|
1962
2013
|
Expected response: `extension_ui_response` with `value` (the edited text) or `cancelled: true`.
|
|
1963
2014
|
|
|
2015
|
+
#### ask
|
|
2016
|
+
|
|
2017
|
+
Ask the user a rich clarifying question with Markdown-formatted question text, optional single- or multi-select options, and an optional free-text field. This powers the built-in `ask_user` tool. `options` (2-4 nonblank strings) is optional; `allowFreeText` (default `true`), `multiSelect`, and `multiline` are optional booleans.
|
|
2018
|
+
|
|
2019
|
+
```json
|
|
2020
|
+
{
|
|
2021
|
+
"type": "extension_ui_request",
|
|
2022
|
+
"id": "uuid-5",
|
|
2023
|
+
"method": "ask",
|
|
2024
|
+
"title": "Choose a database",
|
|
2025
|
+
"question": "Which persistence strategy should I use?",
|
|
2026
|
+
"options": ["SQLite", "PostgreSQL", "Keep the JSON file"],
|
|
2027
|
+
"allowFreeText": true,
|
|
2028
|
+
"multiSelect": false,
|
|
2029
|
+
"multiline": false,
|
|
2030
|
+
"timeout": 60000,
|
|
2031
|
+
"expiresAt": 1785434460000
|
|
2032
|
+
}
|
|
2033
|
+
```
|
|
2034
|
+
|
|
2035
|
+
`timeout` is the original duration in milliseconds. `expiresAt` is the corresponding absolute Unix timestamp in milliseconds; Dashboard clients should use it for the visible countdown so reload, resync, or drill-in recovery does not restart the full duration.
|
|
2036
|
+
|
|
2037
|
+
Expected response: `extension_ui_response` with `selected` (an array of strings) and optional string `customText` (the typed answer). Sending `cancelled: true`, or an empty `selected` with no nonblank `customText`, stops the current agent turn rather than continuing without an answer. A timeout has the same stop semantics. Other malformed ask responses are rejected as protocol failures.
|
|
2038
|
+
|
|
2039
|
+
```json
|
|
2040
|
+
{ "type": "extension_ui_response", "id": "uuid-5", "selected": ["SQLite"], "customText": "with WAL enabled" }
|
|
2041
|
+
```
|
|
2042
|
+
|
|
1964
2043
|
#### notify
|
|
1965
2044
|
|
|
1966
2045
|
Display a notification. Fire-and-forget, no response expected.
|
|
@@ -2038,7 +2117,7 @@ Set the text in the input editor. Fire-and-forget.
|
|
|
2038
2117
|
|
|
2039
2118
|
### Extension UI Responses (stdin)
|
|
2040
2119
|
|
|
2041
|
-
Responses are sent for dialog methods only (`select`, `confirm`, `input`, `editor`). The `id` must match the request.
|
|
2120
|
+
Responses are sent for dialog methods only (`select`, `confirm`, `input`, `editor`, `ask`). The `id` must match the request.
|
|
2042
2121
|
|
|
2043
2122
|
#### Value response (select, input, editor)
|
|
2044
2123
|
|
|
@@ -2054,12 +2133,23 @@ Responses are sent for dialog methods only (`select`, `confirm`, `input`, `edito
|
|
|
2054
2133
|
|
|
2055
2134
|
#### Cancellation response (any dialog)
|
|
2056
2135
|
|
|
2057
|
-
Dismiss any dialog method. The extension receives `undefined` (for select/input/editor) or `false` (for confirm).
|
|
2136
|
+
Dismiss any dialog method. The extension receives `undefined` (for select/input/editor) or `false` (for confirm). For `ask`, cancellation returns `undefined` while stopping the current agent turn.
|
|
2058
2137
|
|
|
2059
2138
|
```json
|
|
2060
2139
|
{"type": "extension_ui_response", "id": "uuid-3", "cancelled": true}
|
|
2061
2140
|
```
|
|
2062
2141
|
|
|
2142
|
+
After any dialog settles, RPC emits a lifecycle event on stdout so hosts can
|
|
2143
|
+
remove the matching UI even when the dialog ended locally because of timeout,
|
|
2144
|
+
abort, or runtime shutdown:
|
|
2145
|
+
|
|
2146
|
+
```json
|
|
2147
|
+
{"type": "extension_ui_response_handled", "id": "uuid-3"}
|
|
2148
|
+
```
|
|
2149
|
+
|
|
2150
|
+
Hosts should treat this event as idempotent; it can arrive after the host has
|
|
2151
|
+
already removed a successfully answered request.
|
|
2152
|
+
|
|
2063
2153
|
## Error Handling
|
|
2064
2154
|
|
|
2065
2155
|
Failed commands return a response with `success: false`:
|
package/docs/session.md
CHANGED
|
@@ -261,7 +261,13 @@ Extension state persistence. Does NOT participate in LLM context.
|
|
|
261
261
|
{"type":"custom","id":"h8i9j0k1","parentId":"g7h8i9j0","timestamp":"2024-12-03T14:20:00.000Z","customType":"my-extension","data":{"count":42}}
|
|
262
262
|
```
|
|
263
263
|
|
|
264
|
-
Use `customType` to identify your extension's entries on reload.
|
|
264
|
+
Use `customType` to identify your extension's entries on reload. Core host features can use the same non-context channel. When the Dispatch Arbiter is enabled, every attempted pre-spawn decision is stored as `customType: "subagent_arbitration"` with only safe host-validated metadata:
|
|
265
|
+
|
|
266
|
+
```json
|
|
267
|
+
{"type":"custom","customType":"subagent_arbitration","data":{"type":"subagent_arbitration","agentId":"a1b2c3","status":"success","proposed":{"agent":"Explore","model":"provider/frontier","thinking":"high"},"final":{"agent":"feature-dev","model":"provider/worker","thinking":"medium"},"changed":["agent","model","thinking"]}}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Failure records have `final: null` plus bounded host-generated `errorCode`/`errorMessage`; chain records include `step`. Arbiter prompts, raw responses, and reasoning are never stored. Because this is `custom`, replay/build-context skips it and neither the parent nor child model receives the record.
|
|
265
271
|
|
|
266
272
|
### CustomMessageEntry
|
|
267
273
|
|
|
@@ -382,7 +388,7 @@ Key methods for working with sessions programmatically.
|
|
|
382
388
|
### Instance Methods - Session Management
|
|
383
389
|
- `newSession(options?)` - Start a new session (options: `{ parentSession?: string }`)
|
|
384
390
|
- `setSessionFile(path)` - Switch to a different session file
|
|
385
|
-
- `createBranchedSession(leafId)` - Extract branch to new session file
|
|
391
|
+
- `createBranchedSession(leafId)` - Extract a branch to a new session file while preserving the current session name metadata
|
|
386
392
|
|
|
387
393
|
### Instance Methods - Appending (all return entry ID)
|
|
388
394
|
- `appendMessage(message)` - Add message
|
package/docs/settings.md
CHANGED
|
@@ -224,6 +224,38 @@ Set `parentTurnGuardrail` to `false` to let the parent keep running with no turn
|
|
|
224
224
|
}
|
|
225
225
|
```
|
|
226
226
|
|
|
227
|
+
### Dispatch Arbiter
|
|
228
|
+
|
|
229
|
+
The optional Dispatch Arbiter is a fully headless, tool-less model call in the subagent control path. It is disabled by default and can be configured **only** in global `~/.dreb/agent/settings.json` (or the global RPC settings API). A project `.dreb/settings.json` cannot enable, disable, or reconfigure it.
|
|
230
|
+
|
|
231
|
+
| Setting | Type | Default | Description |
|
|
232
|
+
|---------|------|---------|-------------|
|
|
233
|
+
| `subagentArbiter.enabled` | boolean | `false` | Run fail-closed arbitration before every actual child spawn |
|
|
234
|
+
| `subagentArbiter.model` | string | - | Required when enabled; exact canonical `provider/model` used for the direct arbiter call |
|
|
235
|
+
| `subagentArbiter.thinking` | string | `off` | Optional arbiter-call thinking: `off`, `minimal`, `low`, `medium`, `high`, or `xhigh`; explicit values are capability-validated |
|
|
236
|
+
| `subagentArbiter.guidePath` | string | `~/.dreb/agent/model-routing-guide.md` | Routing guide generated by `/skill:model-routing-guide`; `~` expands normally and relative paths resolve against the child cwd |
|
|
237
|
+
|
|
238
|
+
```json
|
|
239
|
+
{
|
|
240
|
+
"subagentArbiter": {
|
|
241
|
+
"enabled": true,
|
|
242
|
+
"model": "provider/router-model",
|
|
243
|
+
"thinking": "medium",
|
|
244
|
+
"guidePath": "~/.dreb/agent/model-routing-guide.md"
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
First-class controls are available in both interactive `/settings` and the web dashboard Settings screen. Each exposes enable/disable, an authenticated exact-model picker, thinking level, and guide path. The TUI validates current live scope and guide coverage before accepting enablement; the dashboard prevents model-less enablement, validates model/thinking through RPC, shows readiness guidance, and the runtime still revalidates live scope/guide before every dispatch. Validation errors are loud and do not silently persist an unusable enabled policy.
|
|
250
|
+
|
|
251
|
+
Enabling also requires a non-empty **live explicit session model scope** from `--models` or `enabledModels`, plus a schema-valid guide whose canonical covered IDs and `## Model:` sections exactly match that live scope. The research skill cannot discover runtime `--models`; generate its guide with matching explicit skill arguments when needed.
|
|
252
|
+
|
|
253
|
+
For each single child, parallel item, and post-substitution chain step, the arbiter may return only an existing agent name, an exact model in the live scope, and a thinking level supported by that model. Missing/invalid settings, auth, guide, scope, timeout/provider errors, malformed output, unknown agents, out-of-scope models, and unsupported thinking all stop the affected spawn. There is no fallback to the proposed route or parent model after arbitration is enabled.
|
|
254
|
+
|
|
255
|
+
The arbiter receives the immutable child task/cwd, proposed route, available agent names/descriptions/effective tools/model defaults, validated guide, canonical live candidates, bounded first/latest user intent and recent labeled parent activity—including bounded tool outputs—parent model/session title, repository/cwd/branch/dirty-count metadata, and lineage identifiers where available. Following the title setter's rolling-context pattern, ordinary file contents, diffs, command output, and other useful tool-result content are intentional routing context rather than a separate security boundary; the package receives the existing secret scrubbing before inference. The arbiter itself receives no tools. Guide files are capped at 128 KiB; the complete serialized package is capped at 180,000 characters. Individual intent/description/activity fields also have fixed bounds. Required task/guide/scope/agent data is never silently truncated—exceeding the package cap stops inference. The real child's task and cwd are not modified by scrubbing or arbitration.
|
|
256
|
+
|
|
257
|
+
Only host-validated decision metadata is persisted/emitted. Raw arbiter prompts, responses, and reasoning never enter the parent transcript, child context, session history, JSON/RPC events, or dashboard. See [Agent Model Settings](agent-models.md#dispatch-arbiter).
|
|
258
|
+
|
|
227
259
|
### Message Delivery
|
|
228
260
|
|
|
229
261
|
| Setting | Type | Default | Description |
|
|
@@ -385,7 +417,7 @@ See [packages.md](packages.md) for package management details.
|
|
|
385
417
|
|
|
386
418
|
## Project Overrides
|
|
387
419
|
|
|
388
|
-
Project settings (`.dreb/settings.json`) override global settings. Nested objects are merged. **
|
|
420
|
+
Project settings (`.dreb/settings.json`) override global settings. Nested objects are merged. **Exceptions:** `context.trustedFolders`, `context.autoLoadNested`, and the complete `subagentArbiter` policy are global-only security/control-path settings. Project settings cannot add, replace, override, enable, or disable them. Nested context from the initial startup upward scan remains separate from the lazy-load policy.
|
|
389
421
|
|
|
390
422
|
```json
|
|
391
423
|
// ~/.dreb/agent/settings.json (global)
|
package/docs/skills.md
CHANGED
|
@@ -285,11 +285,49 @@ dreb ships with **mach6**, a development workflow that orchestrates the full iss
|
|
|
285
285
|
| `mach6-review` | Explicitly user-triggered multi-agent review with scope-aware independent assessment |
|
|
286
286
|
| `mach6-implement` | Implement plans, fix review findings, or fix CI failures |
|
|
287
287
|
| `mach6-publish` | Pre-merge checks, docs update, merge, tag, release |
|
|
288
|
+
| `model-routing-guide` | Research scoped models and sanitized local subagent evidence into a validated routing guide |
|
|
288
289
|
|
|
289
290
|
Built-in skills are always available and can be overridden by placing a skill with the same name in any [user or project location](#locations). `mach6-review` is model-invocable when the user directly asks an agent to run it, as well as user-invocable through its slash command. Agents must never start formal review autonomously; implementation must first be committed and pushed.
|
|
290
291
|
|
|
291
292
|
See [docs/mach6.md](mach6.md) for full documentation.
|
|
292
293
|
|
|
294
|
+
### model-routing-guide
|
|
295
|
+
|
|
296
|
+
`model-routing-guide` is an explicit, potentially expensive research workflow with exactly two supported scope sources.
|
|
297
|
+
|
|
298
|
+
Pass comma-separated model patterns directly to make them authoritative:
|
|
299
|
+
|
|
300
|
+
```text
|
|
301
|
+
/skill:model-routing-guide anthropic/claude-*,openai/gpt-5.6-sol
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Or invoke it without arguments to use the effective non-empty `enabledModels` array:
|
|
305
|
+
|
|
306
|
+
```text
|
|
307
|
+
/skill:model-routing-guide
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
When model scope rotates, update the existing guide incrementally instead of regenerating every retained entry:
|
|
311
|
+
|
|
312
|
+
```text
|
|
313
|
+
/skill:model-routing-guide update
|
|
314
|
+
/skill:model-routing-guide update anthropic/claude-*,openai/gpt-5.6-sol
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
`update` must be the first argument. The skill validates the existing guide against its own coverage, diffs that coverage against the newly resolved authoritative scope, preserves retained model sections, removes unscoped sections and summary references, and researches only newly added canonical models. It refreshes scope/local-evidence metadata and performs the same complete final validation before atomically replacing the guide. A missing or malformed existing guide fails loudly and requires normal generation.
|
|
318
|
+
|
|
319
|
+
Model-pattern arguments after the optional `update` keyword take precedence over `enabledModels`; the skill selects one source and does not search for any other runtime or session scope. Because this Stage 1 workflow is implemented only as a skill, it cannot discover the current session's `--models` value or later in-session scope changes. To research that runtime scope, pass the same comma-separated patterns as skill arguments.
|
|
320
|
+
|
|
321
|
+
The skill refuses missing/empty and effectively all-model scopes. It obtains available candidates with `dreb --list-models`, resolves the selected patterns to canonical provider/model IDs, snapshots existing files under `~/.dreb/agent/subagent-sessions/`, and combines sanitized aggregate local observations with official documentation, model cards, benchmarks, issue trackers, forums, and practitioner reports. Existing unreadable or malformed child logs fail the run; a genuinely empty history is labeled cold-start.
|
|
322
|
+
|
|
323
|
+
The generated `~/.dreb/agent/model-routing-guide.md` is human-readable Markdown with schema-versioned YAML frontmatter and one validated section per canonical candidate. Evidence is labeled as vendor claims, measured benchmarks, community reports, or local observations, with dates, confidence, sample counts, contrary findings, and explicit unknowns. The workflow prohibits copied prompts, outputs, tool arguments, secrets, paths, and identifying project details.
|
|
324
|
+
|
|
325
|
+
Semantic local-evidence assessment uses normal dreb tools, so inspected session content is processed by the active research model's configured provider. The persisted guide is sanitized and generalized, but invoking the skill is still a decision to send the inspected evidence to that provider.
|
|
326
|
+
|
|
327
|
+
Its primary routing safeguards are practical: `Explore` is for factual collection and navigation, not planning or implementation; routine lookup, extraction, repetitive file inspection, and straightforward summarization should use the least expensive scoped model demonstrated adequate by the evidence.
|
|
328
|
+
|
|
329
|
+
The optional global-only [Dispatch Arbiter](agent-models.md#dispatch-arbiter) now consumes this file before every subagent spawn. Its live scope is the current session's exact explicit candidate set, so guide frontmatter and model headings must match that set exactly. A guide generated from `enabledModels` will work when the session uses the same resolved scope; for runtime `--models`, pass those patterns to the skill. Missing/stale/malformed guide coverage fails the child launch rather than bypassing arbitration.
|
|
330
|
+
|
|
293
331
|
## Skill Repositories
|
|
294
332
|
|
|
295
333
|
- [Anthropic Skills](https://github.com/anthropics/skills) - Document processing (docx, pdf, pptx, xlsx), web development
|