osborn 0.9.238 → 0.9.239
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/dist/claude-llm.d.ts +8 -0
- package/dist/claude-llm.js +49 -20
- package/dist/pipeline-fastbrain.js +0 -10
- package/package.json +1 -1
package/dist/claude-llm.d.ts
CHANGED
|
@@ -120,6 +120,7 @@ export declare function decideWrite(agentType: string | null, filePath: string):
|
|
|
120
120
|
decision: 'allow' | 'defer' | 'deny';
|
|
121
121
|
reason?: string;
|
|
122
122
|
};
|
|
123
|
+
export declare const SILENT_VERIFY_PREFIX: string;
|
|
123
124
|
export declare const VERIFIER_CHAIN: Record<string, {
|
|
124
125
|
parallelAtStart?: string[];
|
|
125
126
|
afterReminder?: string;
|
|
@@ -278,6 +279,13 @@ export declare class ClaudeLLM extends llm.LLM {
|
|
|
278
279
|
stopAgent(agentId: string): boolean;
|
|
279
280
|
/** Whether a persistent session is alive and consuming messages */
|
|
280
281
|
hasSession(): boolean;
|
|
282
|
+
/**
|
|
283
|
+
* Verifier-chain dedup: records that agent_id has triggered its chain dispatch and returns
|
|
284
|
+
* true only the FIRST time (so a double-fired SubagentStop can't double-dispatch). A NEW
|
|
285
|
+
* agent_id (e.g. a fresh writer spawned for a fix round) is not in the set → returns true,
|
|
286
|
+
* correctly allowing the re-verify loop. Cleared when the persistent session closes.
|
|
287
|
+
*/
|
|
288
|
+
markChainDispatched(agentId: string): boolean;
|
|
281
289
|
/**
|
|
282
290
|
* Close the persistent session (kills subprocess).
|
|
283
291
|
* Call on disconnect, session switch, or recovery.
|
package/dist/claude-llm.js
CHANGED
|
@@ -919,6 +919,11 @@ export function decideWrite(agentType, filePath) {
|
|
|
919
919
|
// when the keyed sub-agent's Task completes, so the main agent dispatches the
|
|
920
920
|
// next verifier(s) as real Tasks (verdicts return inline). Includes RUNNING the
|
|
921
921
|
// tester's tests against the finished code. Any agent not listed chains to nothing.
|
|
922
|
+
// Prepended to a verifier-chain reminder pushed into the MAIN agent at SubagentStop. Keeps the
|
|
923
|
+
// dispatch SILENT — the model should emit ONLY the Task tool call(s), no spoken/streamed text —
|
|
924
|
+
// so the chain advances without a robotic "now running the review…" narration on the voice path.
|
|
925
|
+
export const SILENT_VERIFY_PREFIX = '[SYSTEM — SILENT CONTROL MESSAGE. Do NOT narrate, speak, or emit any assistant text this turn. ' +
|
|
926
|
+
'Silently perform the following via the Task tool only.] ';
|
|
922
927
|
export const VERIFIER_CHAIN = {
|
|
923
928
|
writer: {
|
|
924
929
|
parallelAtStart: ['tester'],
|
|
@@ -1480,6 +1485,18 @@ export class ClaudeLLM extends llm.LLM {
|
|
|
1480
1485
|
hasSession() {
|
|
1481
1486
|
return this.#persistentQuery !== null && !this.#messageChannel?.closed;
|
|
1482
1487
|
}
|
|
1488
|
+
/**
|
|
1489
|
+
* Verifier-chain dedup: records that agent_id has triggered its chain dispatch and returns
|
|
1490
|
+
* true only the FIRST time (so a double-fired SubagentStop can't double-dispatch). A NEW
|
|
1491
|
+
* agent_id (e.g. a fresh writer spawned for a fix round) is not in the set → returns true,
|
|
1492
|
+
* correctly allowing the re-verify loop. Cleared when the persistent session closes.
|
|
1493
|
+
*/
|
|
1494
|
+
markChainDispatched(agentId) {
|
|
1495
|
+
if (!agentId || this.#dispatchedFor.has(agentId))
|
|
1496
|
+
return false;
|
|
1497
|
+
this.#dispatchedFor.add(agentId);
|
|
1498
|
+
return true;
|
|
1499
|
+
}
|
|
1483
1500
|
/**
|
|
1484
1501
|
* Close the persistent session (kills subprocess).
|
|
1485
1502
|
* Call on disconnect, session switch, or recovery.
|
|
@@ -1955,23 +1972,12 @@ class ClaudeLLMStream extends llm.LLMStream {
|
|
|
1955
1972
|
console.log('[LIFECYCLE-PROBE] PostToolUse on', toolName, 'agent_id=', agentId, 'ts=', Date.now());
|
|
1956
1973
|
}
|
|
1957
1974
|
this.#eventEmitter.emit('tool_result', { name: toolName, input: toolInput, response: toolResponse, agentRole: agentTypePost || 'main' });
|
|
1958
|
-
// Pattern #1 verifier chaining
|
|
1959
|
-
//
|
|
1960
|
-
//
|
|
1961
|
-
//
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
const link = subType ? VERIFIER_CHAIN[subType] : undefined;
|
|
1965
|
-
if (link?.afterReminder) {
|
|
1966
|
-
console.log(`[DISPATCH] Pattern#1 chain: ${subType} done → reminding main agent to verify`);
|
|
1967
|
-
return {
|
|
1968
|
-
hookSpecificOutput: {
|
|
1969
|
-
hookEventName: 'PostToolUse',
|
|
1970
|
-
additionalContext: link.afterReminder,
|
|
1971
|
-
},
|
|
1972
|
-
};
|
|
1973
|
-
}
|
|
1974
|
-
}
|
|
1975
|
+
// Pattern #1 verifier chaining has MOVED to the SubagentStop hook below. Reason:
|
|
1976
|
+
// sub-agents run with run_in_background:true, so PostToolUse-on-Task fires at
|
|
1977
|
+
// DISPATCH (placeholder tool_response), not completion — injecting the "now verify"
|
|
1978
|
+
// reminder here fired while the writer/researcher was still running (mistimed).
|
|
1979
|
+
// SubagentStop is the true completion signal; it pushes the reminder into the main
|
|
1980
|
+
// agent via pushMessage.
|
|
1975
1981
|
return {};
|
|
1976
1982
|
}]
|
|
1977
1983
|
}],
|
|
@@ -2327,9 +2333,32 @@ class ClaudeLLMStream extends llm.LLMStream {
|
|
|
2327
2333
|
const aid = input?.agent_id ?? ('sa-' + Date.now());
|
|
2328
2334
|
statusManager.upsertDispatch(aid, { subagentType: at, dispatchState: 'completed', artifact: msg });
|
|
2329
2335
|
this.#eventEmitter.emit('task_completed', { agent_type: at, agent_id: aid, last_assistant_message: String(msg).slice(0, 400) });
|
|
2330
|
-
//
|
|
2331
|
-
//
|
|
2332
|
-
//
|
|
2336
|
+
// Pattern #1 verifier chaining — CORRECT timing (moved here from PostToolUse).
|
|
2337
|
+
// SubagentStop fires at REAL completion. When a chained producer (writer/researcher)
|
|
2338
|
+
// finishes, push its afterReminder into the MAIN agent's streaming input so the main
|
|
2339
|
+
// agent dispatches the next verifier(s) as real Task sub-agents (verdicts return
|
|
2340
|
+
// inline). Only writer/researcher are VERIFIER_CHAIN keys with afterReminder, so
|
|
2341
|
+
// verifiers (reviewer/tester/reasoner) never re-chain. Dedup on agent_id guards a
|
|
2342
|
+
// double-fired SubagentStop; a fresh fix-round writer has a NEW id → re-chains (the
|
|
2343
|
+
// intended bounded loop). Guarded on a live session so we never cold-start a query
|
|
2344
|
+
// just to deliver a reminder. Silent-dispatch prefix keeps it off the voice.
|
|
2345
|
+
const chainLink = at ? VERIFIER_CHAIN[at] : undefined;
|
|
2346
|
+
// Dedup MUST key on the REAL agent_id, never the fabricated 'sa-<ts>' fallback used
|
|
2347
|
+
// above for status/emit — a synthetic id is unique every call and would defeat the
|
|
2348
|
+
// double-fire guard. If the SDK omits agent_id we can't dedup safely, so skip chaining.
|
|
2349
|
+
if (chainLink?.afterReminder && input?.agent_id && this.#llmRef.hasSession() && this.#llmRef.markChainDispatched(input.agent_id)) {
|
|
2350
|
+
console.log(`[DISPATCH] Pattern#1 chain (SubagentStop): ${at} done → pushing verify reminder to main agent`);
|
|
2351
|
+
try {
|
|
2352
|
+
this.#llmRef.pushMessage(SILENT_VERIFY_PREFIX + chainLink.afterReminder, sdkOptions, {
|
|
2353
|
+
onSessionId: this.#onSessionId,
|
|
2354
|
+
onCheckpoint: this.#onCheckpoint,
|
|
2355
|
+
eventEmitter: this.#eventEmitter,
|
|
2356
|
+
});
|
|
2357
|
+
}
|
|
2358
|
+
catch (e) {
|
|
2359
|
+
console.warn('Pattern#1 chain push failed:', e);
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2333
2362
|
return {};
|
|
2334
2363
|
}]
|
|
2335
2364
|
}],
|
|
@@ -255,16 +255,6 @@ function buildSystemPrompt(chatHistory, researchContext) {
|
|
|
255
255
|
`Greetings/thanks/confirmations: respond directly, no search.`,
|
|
256
256
|
`Tasks needing live code analysis or new research: respond with [RESEARCH_NEEDED]`,
|
|
257
257
|
``,
|
|
258
|
-
`== DECISIONS: DEFER, DON'T ASSERT ==`,
|
|
259
|
-
`The grounded main agent answers the SAME question in parallel with full context — it owns`,
|
|
260
|
-
`decisions. For questions asking what was DECIDED / CHOSEN / SCOPED / AGREED / "what were the`,
|
|
261
|
-
`options" / "what did we settle on" / "remind me what we decided": do NOT state a definitive`,
|
|
262
|
-
`answer from one keyword hit. A single matched line is often a passing mention, not the`,
|
|
263
|
-
`decision (e.g. a file that "covers WhatsApp and LinkedIn" is NOT the scoping decision).`,
|
|
264
|
-
`Only assert a decision if MULTIPLE recent hits corroborate it AND one is clearly the decision`,
|
|
265
|
-
`itself. Otherwise hedge briefly and defer — e.g. "I think it involved X, but let the main`,
|
|
266
|
-
`agent confirm the exact decision" — or emit [RESEARCH_NEEDED]. Never contradict-with-confidence.`,
|
|
267
|
-
``,
|
|
268
258
|
`== STYLE ==`,
|
|
269
259
|
`1-3 sentences. Grounded in results. Never fabricate.`,
|
|
270
260
|
`If not found after thorough searching: "I didn't find that in the session history."`,
|