@dreb/coding-agent 2.45.4 → 2.46.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 +6 -2
- 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 +75 -15
- 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/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/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/index.d.ts +7 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- 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/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 +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +75 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +2 -2
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +65 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +8 -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 +8 -2
- package/docs/json.md +31 -5
- package/docs/rpc.md +60 -9
- package/docs/session.md +7 -1
- 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
|
@@ -22,11 +22,13 @@ import { sleep } from "../utils/sleep.js";
|
|
|
22
22
|
import { executeBash as executeBashCommand, executeBashWithOperations } from "./bash-executor.js";
|
|
23
23
|
import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, generateBranchSummary, prepareCompaction, shouldCompact, } from "./compaction/index.js";
|
|
24
24
|
import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
|
|
25
|
+
import { DispatchArbiter } from "./dispatch-arbiter.js";
|
|
25
26
|
import { exportSessionToHtml } from "./export-html/index.js";
|
|
26
27
|
import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
|
|
27
28
|
import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
|
|
28
29
|
import { checkScriptContent, extractScriptPaths, isForbiddenCommand } from "./forbidden-commands.js";
|
|
29
|
-
import { getGitRepoState } from "./git-repo-state.js";
|
|
30
|
+
import { getGitRepoState, getGitStatusMetadata } from "./git-repo-state.js";
|
|
31
|
+
import { findGitRoot } from "./git-root.js";
|
|
30
32
|
import { log } from "./logger.js";
|
|
31
33
|
import { computeNestedContextBlock } from "./nested-context.js";
|
|
32
34
|
import { PerformanceTracker } from "./performance-tracker.js";
|
|
@@ -153,6 +155,8 @@ export class AgentSession {
|
|
|
153
155
|
_ownsPerformanceTracker;
|
|
154
156
|
// Git repo state captured once at session start
|
|
155
157
|
_gitRepoState;
|
|
158
|
+
// Fully headless pre-spawn router. It owns only bounded parent activity context.
|
|
159
|
+
_dispatchArbiter;
|
|
156
160
|
constructor(config) {
|
|
157
161
|
this.agent = config.agent;
|
|
158
162
|
this.sessionManager = config.sessionManager;
|
|
@@ -181,6 +185,29 @@ export class AgentSession {
|
|
|
181
185
|
this._uiType = config.uiType;
|
|
182
186
|
// Capture git repo state once at session start (before building runtime/system prompt)
|
|
183
187
|
this._gitRepoState = getGitRepoState(this._cwd) ?? undefined;
|
|
188
|
+
this._dispatchArbiter = new DispatchArbiter({
|
|
189
|
+
getSettings: () => this.settingsManager.getGlobalSubagentArbiterSettings(),
|
|
190
|
+
getCandidateModels: () => this._scopedModels,
|
|
191
|
+
getModelRegistry: () => this._modelRegistry,
|
|
192
|
+
getMessages: () => this.agent.state.messages,
|
|
193
|
+
getParentModel: () => this.model,
|
|
194
|
+
getSessionTitle: () => this.sessionName,
|
|
195
|
+
getRepoMetadata: (cwd) => {
|
|
196
|
+
const gitRoot = findGitRoot(cwd);
|
|
197
|
+
const isSessionCwd = resolve(cwd) === resolve(this._cwd);
|
|
198
|
+
const currentStatus = gitRoot
|
|
199
|
+
? (getGitStatusMetadata(cwd) ?? (isSessionCwd ? this._gitRepoState : undefined))
|
|
200
|
+
: undefined;
|
|
201
|
+
return {
|
|
202
|
+
repo: gitRoot ? basename(gitRoot) : undefined,
|
|
203
|
+
cwd,
|
|
204
|
+
branch: currentStatus?.branch,
|
|
205
|
+
dirtyCount: currentStatus?.dirtyCount,
|
|
206
|
+
};
|
|
207
|
+
},
|
|
208
|
+
getExtraSecretPatterns: () => this._compileExtraSecretPatterns(),
|
|
209
|
+
complete: config.dispatchArbiterComplete,
|
|
210
|
+
});
|
|
184
211
|
// Always subscribe to agent events for internal handling
|
|
185
212
|
// (session persistence, extensions, auto-compaction, retry logic)
|
|
186
213
|
this._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);
|
|
@@ -199,6 +226,21 @@ export class AgentSession {
|
|
|
199
226
|
getPerformanceTracker() {
|
|
200
227
|
return this.performanceTracker;
|
|
201
228
|
}
|
|
229
|
+
_compileExtraSecretPatterns() {
|
|
230
|
+
return this.settingsManager.getSecretOutputPatterns()?.flatMap((pattern) => {
|
|
231
|
+
if (!pattern.pattern || typeof pattern.pattern !== "string" || pattern.pattern.trim() === "") {
|
|
232
|
+
console.warn(`[secret-scrubber] Skipping empty or invalid pattern in secretOutputPatterns: "${pattern.name}"`);
|
|
233
|
+
return [];
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
return [{ name: pattern.name, pattern: new RegExp(pattern.pattern, "g") }];
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
console.warn(`[secret-scrubber] Skipping invalid regex in secretOutputPatterns "${pattern.name}": ${pattern.pattern} — ${error instanceof Error ? error.message : String(error)}`);
|
|
240
|
+
return [];
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
}
|
|
202
244
|
/**
|
|
203
245
|
* Install tool hooks once on the Agent instance.
|
|
204
246
|
*
|
|
@@ -285,20 +327,7 @@ export class AgentSession {
|
|
|
285
327
|
this.agent.setAfterToolCall(async ({ toolCall, args, result, isError }) => {
|
|
286
328
|
// Scrub secrets from tool output — runs before extensions, cannot be bypassed
|
|
287
329
|
let scrubbedContent = result.content;
|
|
288
|
-
const
|
|
289
|
-
const compiledExtras = extraSecretPatterns?.flatMap((p) => {
|
|
290
|
-
if (!p.pattern || typeof p.pattern !== "string" || p.pattern.trim() === "") {
|
|
291
|
-
console.warn(`[secret-scrubber] Skipping empty or invalid pattern in secretOutputPatterns: "${p.name}"`);
|
|
292
|
-
return [];
|
|
293
|
-
}
|
|
294
|
-
try {
|
|
295
|
-
return [{ name: p.name, pattern: new RegExp(p.pattern, "g") }];
|
|
296
|
-
}
|
|
297
|
-
catch (err) {
|
|
298
|
-
console.warn(`[secret-scrubber] Skipping invalid regex in secretOutputPatterns "${p.name}": ${p.pattern} — ${err instanceof Error ? err.message : String(err)}`);
|
|
299
|
-
return [];
|
|
300
|
-
}
|
|
301
|
-
});
|
|
330
|
+
const compiledExtras = this._compileExtraSecretPatterns();
|
|
302
331
|
let totalRedactions = 0;
|
|
303
332
|
scrubbedContent = scrubbedContent.map((item) => {
|
|
304
333
|
if (item.type === "text" && item.text) {
|
|
@@ -513,6 +542,15 @@ export class AgentSession {
|
|
|
513
542
|
*/
|
|
514
543
|
_handleBackgroundComplete(agentId, result, cancelled) {
|
|
515
544
|
const parts = [];
|
|
545
|
+
if (result.model || result.thinking) {
|
|
546
|
+
const metadata = [
|
|
547
|
+
result.model ? `model: ${result.model}` : undefined,
|
|
548
|
+
result.thinking ? `thinking: ${result.thinking}` : undefined,
|
|
549
|
+
]
|
|
550
|
+
.filter((value) => value !== undefined)
|
|
551
|
+
.join(", ");
|
|
552
|
+
parts.push(`Execution metadata: ${metadata}`);
|
|
553
|
+
}
|
|
516
554
|
if (cancelled) {
|
|
517
555
|
parts.push("This agent was cancelled by the user.");
|
|
518
556
|
}
|
|
@@ -585,6 +623,9 @@ export class AgentSession {
|
|
|
585
623
|
agentId,
|
|
586
624
|
agentType: result.agent,
|
|
587
625
|
success: result.exitCode === 0,
|
|
626
|
+
model: result.model,
|
|
627
|
+
thinking: result.thinking,
|
|
628
|
+
steps: result.steps,
|
|
588
629
|
sessionFile: result.sessionFile,
|
|
589
630
|
});
|
|
590
631
|
}
|
|
@@ -738,6 +779,17 @@ export class AgentSession {
|
|
|
738
779
|
await this._emitExtensionEvent(event);
|
|
739
780
|
// Notify all listeners
|
|
740
781
|
this._emit(event);
|
|
782
|
+
// Keep a small, mode-independent rolling context for the headless arbiter.
|
|
783
|
+
if (event.type === "message_end") {
|
|
784
|
+
this._dispatchArbiter.onMessageEnd(event.message);
|
|
785
|
+
}
|
|
786
|
+
else if (event.type === "tool_execution_end") {
|
|
787
|
+
this._dispatchArbiter.onToolEnd({
|
|
788
|
+
toolName: event.toolName,
|
|
789
|
+
isError: event.isError,
|
|
790
|
+
result: event.result,
|
|
791
|
+
});
|
|
792
|
+
}
|
|
741
793
|
// Handle session persistence
|
|
742
794
|
if (event.type === "message_end") {
|
|
743
795
|
// Check if this is a custom message from extensions
|
|
@@ -1587,6 +1639,7 @@ export class AgentSession {
|
|
|
1587
1639
|
this._disconnectFromAgent();
|
|
1588
1640
|
await this.abort();
|
|
1589
1641
|
this.agent.reset();
|
|
1642
|
+
this._dispatchArbiter.clearContext();
|
|
1590
1643
|
this.sessionManager.newSession({ parentSession: options?.parentSession });
|
|
1591
1644
|
this.agent.sessionId = this.sessionManager.getSessionId();
|
|
1592
1645
|
this._steeringMessages = [];
|
|
@@ -2467,6 +2520,12 @@ export class AgentSession {
|
|
|
2467
2520
|
parentSessionFile: () => this.sessionFile,
|
|
2468
2521
|
modelRegistry: this._modelRegistry,
|
|
2469
2522
|
getAgentModelsForAgent: (name) => this.settingsManager?.getAgentModelsForAgent(name),
|
|
2523
|
+
defaultThinkingLevel: () => this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL,
|
|
2524
|
+
arbitrate: (request, signal) => this._dispatchArbiter.arbitrate(request, signal),
|
|
2525
|
+
onArbitration: (event) => {
|
|
2526
|
+
this.sessionManager.appendCustomEntry("subagent_arbitration", event);
|
|
2527
|
+
this._emit(event);
|
|
2528
|
+
},
|
|
2470
2529
|
onBackgroundStart: (agentId, agentType, taskSummary, sessionDir) => {
|
|
2471
2530
|
this._emit({ type: "background_agent_start", agentId, agentType, taskSummary, sessionDir });
|
|
2472
2531
|
},
|
|
@@ -2783,6 +2842,7 @@ export class AgentSession {
|
|
|
2783
2842
|
this._steeringMessages = [];
|
|
2784
2843
|
this._followUpMessages = [];
|
|
2785
2844
|
this._pendingNextTurnMessages = [];
|
|
2845
|
+
this._dispatchArbiter.clearContext();
|
|
2786
2846
|
// Set new session
|
|
2787
2847
|
this.sessionManager.setSessionFile(sessionPath);
|
|
2788
2848
|
this.agent.sessionId = this.sessionManager.getSessionId();
|