osborn 0.9.218 → 0.9.219
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 +9 -0
- package/dist/claude-llm.js +65 -10
- package/package.json +1 -1
package/dist/claude-llm.d.ts
CHANGED
|
@@ -46,6 +46,10 @@ export declare const NAMED_AGENTS: {
|
|
|
46
46
|
description: string;
|
|
47
47
|
tools: string[];
|
|
48
48
|
grounded: boolean;
|
|
49
|
+
coordination: {
|
|
50
|
+
then: string[];
|
|
51
|
+
startNote: string;
|
|
52
|
+
};
|
|
49
53
|
model: string;
|
|
50
54
|
prompt: string;
|
|
51
55
|
};
|
|
@@ -63,6 +67,11 @@ export declare const NAMED_AGENTS: {
|
|
|
63
67
|
write: "anywhere";
|
|
64
68
|
};
|
|
65
69
|
reminder: string;
|
|
70
|
+
coordination: {
|
|
71
|
+
then: string[];
|
|
72
|
+
mode: "parallel";
|
|
73
|
+
startNote: string;
|
|
74
|
+
};
|
|
66
75
|
model: string;
|
|
67
76
|
prompt: string;
|
|
68
77
|
};
|
package/dist/claude-llm.js
CHANGED
|
@@ -366,6 +366,12 @@ export const NAMED_AGENTS = {
|
|
|
366
366
|
].join(' '),
|
|
367
367
|
tools: ['Read', 'Glob', 'Grep', 'Bash', 'WebSearch', 'WebFetch', 'Task'],
|
|
368
368
|
grounded: true, // applyGrounding() injects the osborn-recall command + ensures Bash
|
|
369
|
+
// Declarative flow. == today: after the researcher finishes, a reasoner-based
|
|
370
|
+
// research gate judges completeness and may send it back for more.
|
|
371
|
+
coordination: {
|
|
372
|
+
then: ['reasoner'],
|
|
373
|
+
startNote: 'When you finish, a reasoner-based gate judges whether your findings are COMPLETE and well-sourced against the task; thin or unsourced findings get sent back to you. Cite file paths + line numbers and explicitly note what you looked for but did NOT find.',
|
|
374
|
+
},
|
|
369
375
|
model: 'sonnet',
|
|
370
376
|
prompt: [
|
|
371
377
|
'You are Osborn\'s research agent. Your job is information gathering — thorough, structured, factual.',
|
|
@@ -472,6 +478,13 @@ export const NAMED_AGENTS = {
|
|
|
472
478
|
// Soft behavior via the composable `reminder` seam → SDK criticalSystemReminder_EXPERIMENTAL.
|
|
473
479
|
// Pinned into the writer's system prompt as a hard-to-ignore reminder.
|
|
474
480
|
reminder: 'BEFORE you write implementation code: make sure a test exists for the behavior you are about to change. If none exists, say so explicitly in your report so the tester can cover it — the tester is the agent that writes tests. NEVER weaken, skip, or delete a test to make your change pass.',
|
|
481
|
+
// Declarative flow (drives SubagentStop dispatch + SubagentStart injection).
|
|
482
|
+
// == today: after the writer finishes, reviewer AND tester run in parallel.
|
|
483
|
+
coordination: {
|
|
484
|
+
then: ['reviewer', 'tester'],
|
|
485
|
+
mode: 'parallel',
|
|
486
|
+
startNote: 'When you finish, your change is automatically verified in parallel: a reviewer checks correctness against the git diff, and a tester runs the suite. Make the change review-ready and leave the tree in a runnable state — do not skip cleanup expecting a second pass.',
|
|
487
|
+
},
|
|
475
488
|
model: 'opus',
|
|
476
489
|
prompt: [
|
|
477
490
|
'You are Osborn\'s writer agent. You execute file changes with a verify-first approach.',
|
|
@@ -881,15 +894,20 @@ function decideWrite(policy, filePath) {
|
|
|
881
894
|
}
|
|
882
895
|
return { decision: 'defer' };
|
|
883
896
|
}
|
|
897
|
+
/** Coordination config for the acting/target agent (null agentType = main). */
|
|
898
|
+
function coordinationFor(agentType, roster) {
|
|
899
|
+
const def = agentType ? roster?.[agentType] : null;
|
|
900
|
+
return def?.coordination ?? null;
|
|
901
|
+
}
|
|
884
902
|
/**
|
|
885
903
|
* Strip/map behavior meta-fields so the roster is a clean AgentDefinition set
|
|
886
|
-
* for the SDK: drop `policy` (
|
|
887
|
-
* `reminder` → criticalSystemReminder_EXPERIMENTAL. NEVER mutates
|
|
904
|
+
* for the SDK: drop `policy` (write-gate) and `coordination` (hook-driven),
|
|
905
|
+
* and map `reminder` → criticalSystemReminder_EXPERIMENTAL. NEVER mutates input.
|
|
888
906
|
*/
|
|
889
907
|
function finalizeRoster(agents) {
|
|
890
908
|
const out = {};
|
|
891
909
|
for (const [name, agent] of Object.entries(agents)) {
|
|
892
|
-
const { policy, reminder, ...rest } = agent;
|
|
910
|
+
const { policy, reminder, coordination, ...rest } = agent;
|
|
893
911
|
if (reminder && !rest.criticalSystemReminder_EXPERIMENTAL) {
|
|
894
912
|
rest.criticalSystemReminder_EXPERIMENTAL = reminder;
|
|
895
913
|
}
|
|
@@ -2137,6 +2155,18 @@ class ClaudeLLMStream extends llm.LLMStream {
|
|
|
2137
2155
|
}
|
|
2138
2156
|
console.log(`🔧 Tool call ${turnToolCallCount}/${TOOL_CALL_BUDGET}: ${toolName}`);
|
|
2139
2157
|
}
|
|
2158
|
+
// Delegation-point injection — when the hub spawns a sub-agent, add
|
|
2159
|
+
// that agent's discretionary delegationNote to the hub's context
|
|
2160
|
+
// (e.g. "add a tester for high-risk edits"). Empty by default → inert.
|
|
2161
|
+
if (toolName === 'Task') {
|
|
2162
|
+
const targetType = String(toolInput?.subagent_type || '');
|
|
2163
|
+
const note = coordinationFor(targetType || null, enforcementRoster)?.delegationNote;
|
|
2164
|
+
if (note) {
|
|
2165
|
+
this.#eventEmitter.emit('tool_use', { name: toolName, input: toolInput, agentRole: agentType || 'main' });
|
|
2166
|
+
console.log(`🤝 Delegation note → subagent_type=${targetType}`);
|
|
2167
|
+
return { hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext: note } };
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2140
2170
|
// Write/Edit/MultiEdit access control — DATA-DRIVEN by each agent's
|
|
2141
2171
|
// declarative policy.write (see AgentWritePolicy). Replaces the old
|
|
2142
2172
|
// hardcoded per-role branches; DB-backed custom agents get enforced too.
|
|
@@ -2506,6 +2536,12 @@ class ClaudeLLMStream extends llm.LLMStream {
|
|
|
2506
2536
|
hooks: [async (input) => {
|
|
2507
2537
|
console.log('[LIFECYCLE-PROBE] SubagentStart', JSON.stringify(input));
|
|
2508
2538
|
this.#eventEmitter.emit('agent_started', { agent_type: input?.agent_type, agent_id: input?.agent_id });
|
|
2539
|
+
// Inject the agent's declarative startNote (who it is paired with) —
|
|
2540
|
+
// reliable, always-seen at boot regardless of what the hub relayed.
|
|
2541
|
+
const startNote = coordinationFor(input?.agent_type ?? null, enforcementRoster)?.startNote;
|
|
2542
|
+
if (startNote) {
|
|
2543
|
+
return { hookSpecificOutput: { hookEventName: 'SubagentStart', additionalContext: startNote } };
|
|
2544
|
+
}
|
|
2509
2545
|
return {};
|
|
2510
2546
|
}]
|
|
2511
2547
|
}],
|
|
@@ -2518,15 +2554,34 @@ class ClaudeLLMStream extends llm.LLMStream {
|
|
|
2518
2554
|
const aid = input?.agent_id ?? ('sa-' + Date.now());
|
|
2519
2555
|
statusManager.upsertDispatch(aid, { subagentType: at, dispatchState: 'completed', artifact: msg });
|
|
2520
2556
|
this.#eventEmitter.emit('task_completed', { agent_type: at, agent_id: aid, last_assistant_message: String(msg).slice(0, 400) });
|
|
2521
|
-
// Infinite-loop guard — never re-dispatch
|
|
2557
|
+
// Infinite-loop guard — verifiers never re-dispatch (they carry no
|
|
2558
|
+
// coordination.then anyway; this is defense-in-depth against a
|
|
2559
|
+
// DB-backed agent accidentally arming a loop).
|
|
2522
2560
|
if (at === 'reviewer' || at === 'tester' || at === 'reasoner')
|
|
2523
2561
|
return {};
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2562
|
+
// Declarative verifier chaining — driven by the finishing agent's
|
|
2563
|
+
// coordination.then (replaces the hardcoded writer/researcher branches).
|
|
2564
|
+
const coord = coordinationFor(at ?? null, enforcementRoster);
|
|
2565
|
+
if (coord?.then?.length && msg) {
|
|
2566
|
+
const spawn = (role) => {
|
|
2567
|
+
if (role === 'reviewer')
|
|
2568
|
+
return this.#llmRef.spawnReviewer(aid, msg, this.#eventEmitter);
|
|
2569
|
+
if (role === 'tester')
|
|
2570
|
+
return this.#llmRef.spawnTester(aid, msg, this.#eventEmitter);
|
|
2571
|
+
if (role === 'reasoner' || role === 'gate')
|
|
2572
|
+
return this.#llmRef.spawnResearchGate(aid, msg, this.#eventEmitter);
|
|
2573
|
+
console.warn(`[DISPATCH] unknown coordination target '${role}' for ${at} — skipped`);
|
|
2574
|
+
return Promise.resolve();
|
|
2575
|
+
};
|
|
2576
|
+
if (coord.mode === 'sequential') {
|
|
2577
|
+
// Await in order WITHOUT blocking the hook return (fire the chain async).
|
|
2578
|
+
void (async () => { for (const r of coord.then)
|
|
2579
|
+
await spawn(r); })();
|
|
2580
|
+
}
|
|
2581
|
+
else {
|
|
2582
|
+
for (const r of coord.then)
|
|
2583
|
+
void spawn(r);
|
|
2584
|
+
}
|
|
2530
2585
|
}
|
|
2531
2586
|
return {};
|
|
2532
2587
|
}]
|