@dogpile/sdk 0.2.1 → 0.3.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/CHANGELOG.md +12 -0
- package/README.md +86 -655
- package/dist/browser/index.js +337 -22
- package/dist/browser/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/runtime/broadcast.d.ts +1 -0
- package/dist/runtime/broadcast.d.ts.map +1 -1
- package/dist/runtime/broadcast.js +27 -6
- package/dist/runtime/broadcast.js.map +1 -1
- package/dist/runtime/coordinator.d.ts +1 -0
- package/dist/runtime/coordinator.d.ts.map +1 -1
- package/dist/runtime/coordinator.js +45 -8
- package/dist/runtime/coordinator.js.map +1 -1
- package/dist/runtime/engine.d.ts.map +1 -1
- package/dist/runtime/engine.js +5 -0
- package/dist/runtime/engine.js.map +1 -1
- package/dist/runtime/sequential.d.ts +1 -0
- package/dist/runtime/sequential.d.ts.map +1 -1
- package/dist/runtime/sequential.js +24 -6
- package/dist/runtime/sequential.js.map +1 -1
- package/dist/runtime/shared.d.ts +1 -0
- package/dist/runtime/shared.d.ts.map +1 -1
- package/dist/runtime/shared.js +24 -6
- package/dist/runtime/shared.js.map +1 -1
- package/dist/runtime/termination.d.ts +6 -1
- package/dist/runtime/termination.d.ts.map +1 -1
- package/dist/runtime/termination.js +75 -0
- package/dist/runtime/termination.js.map +1 -1
- package/dist/runtime/validation.d.ts.map +1 -1
- package/dist/runtime/validation.js +22 -0
- package/dist/runtime/validation.js.map +1 -1
- package/dist/runtime/wrap-up.d.ts +26 -0
- package/dist/runtime/wrap-up.d.ts.map +1 -0
- package/dist/runtime/wrap-up.js +178 -0
- package/dist/runtime/wrap-up.js.map +1 -0
- package/dist/types.d.ts +68 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/index.ts +3 -1
- package/src/runtime/broadcast.ts +49 -19
- package/src/runtime/coordinator.ts +83 -27
- package/src/runtime/engine.ts +6 -0
- package/src/runtime/sequential.ts +45 -19
- package/src/runtime/shared.ts +45 -19
- package/src/runtime/termination.ts +100 -0
- package/src/runtime/validation.ts +25 -0
- package/src/runtime/wrap-up.ts +257 -0
- package/src/types.ts +70 -0
package/src/runtime/broadcast.ts
CHANGED
|
@@ -37,8 +37,9 @@ import {
|
|
|
37
37
|
import { throwIfAborted } from "./cancellation.js";
|
|
38
38
|
import { parseAgentDecision } from "./decisions.js";
|
|
39
39
|
import { generateModelTurn } from "./model.js";
|
|
40
|
-
import { evaluateTerminationStop } from "./termination.js";
|
|
40
|
+
import { evaluateTerminationStop, warnOnProtocolTerminationMisconfiguration } from "./termination.js";
|
|
41
41
|
import { createRuntimeToolExecutor, executeModelResponseToolRequests, runtimeToolAvailability } from "./tools.js";
|
|
42
|
+
import { createWrapUpHintController } from "./wrap-up.js";
|
|
42
43
|
|
|
43
44
|
interface BroadcastRunOptions {
|
|
44
45
|
readonly intent: string;
|
|
@@ -52,6 +53,7 @@ interface BroadcastRunOptions {
|
|
|
52
53
|
readonly seed?: string | number;
|
|
53
54
|
readonly signal?: AbortSignal;
|
|
54
55
|
readonly terminate?: TerminationCondition;
|
|
56
|
+
readonly wrapUpHint?: DogpileOptions["wrapUpHint"];
|
|
55
57
|
readonly emit?: (event: RunEvent) => void;
|
|
56
58
|
}
|
|
57
59
|
|
|
@@ -68,6 +70,15 @@ export async function runBroadcast(options: BroadcastRunOptions): Promise<RunRes
|
|
|
68
70
|
const startedAtMs = nowMs();
|
|
69
71
|
let stopped = false;
|
|
70
72
|
let termination: TerminationStopRecord | undefined;
|
|
73
|
+
const wrapUpHint = createWrapUpHintController({
|
|
74
|
+
protocol: options.protocol,
|
|
75
|
+
tier: options.tier,
|
|
76
|
+
...(options.budget ? { budget: options.budget } : {}),
|
|
77
|
+
...(options.terminate ? { terminate: options.terminate } : {}),
|
|
78
|
+
...(options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {})
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
warnOnProtocolTerminationMisconfiguration(options.protocol, options.terminate);
|
|
71
82
|
|
|
72
83
|
const emit = (event: RunEvent): void => {
|
|
73
84
|
events.push(event);
|
|
@@ -133,16 +144,27 @@ export async function runBroadcast(options: BroadcastRunOptions): Promise<RunRes
|
|
|
133
144
|
round,
|
|
134
145
|
...toolAvailability
|
|
135
146
|
},
|
|
136
|
-
messages:
|
|
147
|
+
messages: wrapUpHint.inject(
|
|
148
|
+
[
|
|
149
|
+
{
|
|
150
|
+
role: "system",
|
|
151
|
+
content: buildSystemPrompt(agent)
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
role: "user",
|
|
155
|
+
content: input
|
|
156
|
+
}
|
|
157
|
+
],
|
|
137
158
|
{
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
159
|
+
runId,
|
|
160
|
+
protocol: "broadcast",
|
|
161
|
+
cost: totalCost,
|
|
162
|
+
events,
|
|
163
|
+
transcript,
|
|
164
|
+
iteration: transcript.length,
|
|
165
|
+
elapsedMs: elapsedMs(startedAtMs)
|
|
144
166
|
}
|
|
145
|
-
|
|
167
|
+
)
|
|
146
168
|
};
|
|
147
169
|
const response = await generateModelTurn({
|
|
148
170
|
model: options.model,
|
|
@@ -332,16 +354,20 @@ export async function runBroadcast(options: BroadcastRunOptions): Promise<RunRes
|
|
|
332
354
|
return stopped;
|
|
333
355
|
}
|
|
334
356
|
|
|
335
|
-
const stopRecord = evaluateTerminationStop(
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
357
|
+
const stopRecord = evaluateTerminationStop(
|
|
358
|
+
options.terminate,
|
|
359
|
+
wrapUpHint.context({
|
|
360
|
+
runId,
|
|
361
|
+
protocol: "broadcast",
|
|
362
|
+
protocolConfig: options.protocol,
|
|
363
|
+
protocolIteration: broadcastRoundsCompleted(events),
|
|
364
|
+
cost: totalCost,
|
|
365
|
+
events,
|
|
366
|
+
transcript,
|
|
367
|
+
iteration: transcript.length,
|
|
368
|
+
elapsedMs: elapsedMs(startedAtMs)
|
|
369
|
+
})
|
|
370
|
+
);
|
|
345
371
|
|
|
346
372
|
if (!stopRecord) {
|
|
347
373
|
return false;
|
|
@@ -373,6 +399,10 @@ export async function runBroadcast(options: BroadcastRunOptions): Promise<RunRes
|
|
|
373
399
|
}
|
|
374
400
|
}
|
|
375
401
|
|
|
402
|
+
function broadcastRoundsCompleted(events: readonly RunEvent[]): number {
|
|
403
|
+
return events.filter((event) => event.type === "broadcast").length;
|
|
404
|
+
}
|
|
405
|
+
|
|
376
406
|
function buildSystemPrompt(agent: AgentSpec): string {
|
|
377
407
|
const instruction = agent.instructions ? `\nInstructions: ${agent.instructions}` : "";
|
|
378
408
|
return `You are ${agent.id}, acting as ${agent.role} in a Broadcast multi-agent protocol.${instruction}`;
|
|
@@ -38,8 +38,9 @@ import {
|
|
|
38
38
|
import { throwIfAborted } from "./cancellation.js";
|
|
39
39
|
import { parseAgentDecision } from "./decisions.js";
|
|
40
40
|
import { generateModelTurn } from "./model.js";
|
|
41
|
-
import { evaluateTerminationStop } from "./termination.js";
|
|
41
|
+
import { evaluateTerminationStop, warnOnProtocolTerminationMisconfiguration } from "./termination.js";
|
|
42
42
|
import { createRuntimeToolExecutor, executeModelResponseToolRequests, runtimeToolAvailability } from "./tools.js";
|
|
43
|
+
import { createWrapUpHintController } from "./wrap-up.js";
|
|
43
44
|
|
|
44
45
|
interface CoordinatorRunOptions {
|
|
45
46
|
readonly intent: string;
|
|
@@ -53,6 +54,7 @@ interface CoordinatorRunOptions {
|
|
|
53
54
|
readonly seed?: string | number;
|
|
54
55
|
readonly signal?: AbortSignal;
|
|
55
56
|
readonly terminate?: TerminationCondition;
|
|
57
|
+
readonly wrapUpHint?: DogpileOptions["wrapUpHint"];
|
|
56
58
|
readonly emit?: (event: RunEvent) => void;
|
|
57
59
|
}
|
|
58
60
|
|
|
@@ -69,6 +71,15 @@ export async function runCoordinator(options: CoordinatorRunOptions): Promise<Ru
|
|
|
69
71
|
const startedAtMs = nowMs();
|
|
70
72
|
let stopped = false;
|
|
71
73
|
let termination: TerminationStopRecord | undefined;
|
|
74
|
+
const wrapUpHint = createWrapUpHintController({
|
|
75
|
+
protocol: options.protocol,
|
|
76
|
+
tier: options.tier,
|
|
77
|
+
...(options.budget ? { budget: options.budget } : {}),
|
|
78
|
+
...(options.terminate ? { terminate: options.terminate } : {}),
|
|
79
|
+
...(options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {})
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
warnOnProtocolTerminationMisconfiguration(options.protocol, options.terminate);
|
|
72
83
|
|
|
73
84
|
const emit = (event: RunEvent): void => {
|
|
74
85
|
events.push(event);
|
|
@@ -126,6 +137,9 @@ export async function runCoordinator(options: CoordinatorRunOptions): Promise<Ru
|
|
|
126
137
|
providerCalls,
|
|
127
138
|
toolExecutor,
|
|
128
139
|
toolAvailability,
|
|
140
|
+
events,
|
|
141
|
+
startedAtMs,
|
|
142
|
+
wrapUpHint,
|
|
129
143
|
emit,
|
|
130
144
|
recordProtocolDecision
|
|
131
145
|
});
|
|
@@ -150,6 +164,11 @@ export async function runCoordinator(options: CoordinatorRunOptions): Promise<Ru
|
|
|
150
164
|
providerCallSlots,
|
|
151
165
|
toolExecutor,
|
|
152
166
|
toolAvailability,
|
|
167
|
+
totalCost,
|
|
168
|
+
events,
|
|
169
|
+
transcript: planTranscript,
|
|
170
|
+
startedAtMs,
|
|
171
|
+
wrapUpHint,
|
|
153
172
|
emit
|
|
154
173
|
})
|
|
155
174
|
)
|
|
@@ -201,6 +220,9 @@ export async function runCoordinator(options: CoordinatorRunOptions): Promise<Ru
|
|
|
201
220
|
providerCalls,
|
|
202
221
|
toolExecutor,
|
|
203
222
|
toolAvailability,
|
|
223
|
+
events,
|
|
224
|
+
startedAtMs,
|
|
225
|
+
wrapUpHint,
|
|
204
226
|
emit,
|
|
205
227
|
recordProtocolDecision
|
|
206
228
|
});
|
|
@@ -290,16 +312,20 @@ export async function runCoordinator(options: CoordinatorRunOptions): Promise<Ru
|
|
|
290
312
|
return stopped;
|
|
291
313
|
}
|
|
292
314
|
|
|
293
|
-
const stopRecord = evaluateTerminationStop(
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
315
|
+
const stopRecord = evaluateTerminationStop(
|
|
316
|
+
options.terminate,
|
|
317
|
+
wrapUpHint.context({
|
|
318
|
+
runId,
|
|
319
|
+
protocol: "coordinator",
|
|
320
|
+
protocolConfig: options.protocol,
|
|
321
|
+
protocolIteration: transcript.length,
|
|
322
|
+
cost: totalCost,
|
|
323
|
+
events,
|
|
324
|
+
transcript,
|
|
325
|
+
iteration: transcript.length,
|
|
326
|
+
elapsedMs: elapsedMs(startedAtMs)
|
|
327
|
+
})
|
|
328
|
+
);
|
|
303
329
|
|
|
304
330
|
if (!stopRecord) {
|
|
305
331
|
return false;
|
|
@@ -343,6 +369,9 @@ interface CoordinatorTurnOptions {
|
|
|
343
369
|
readonly providerCalls: ReplayTraceProviderCall[];
|
|
344
370
|
readonly toolExecutor: RuntimeToolExecutor;
|
|
345
371
|
readonly toolAvailability: JsonObject;
|
|
372
|
+
readonly events: RunEvent[];
|
|
373
|
+
readonly startedAtMs: number;
|
|
374
|
+
readonly wrapUpHint: ReturnType<typeof createWrapUpHintController>;
|
|
346
375
|
readonly emit: (event: RunEvent) => void;
|
|
347
376
|
readonly recordProtocolDecision: (
|
|
348
377
|
event: RunEvent,
|
|
@@ -366,16 +395,27 @@ async function runCoordinatorTurn(turn: CoordinatorTurnOptions): Promise<CostSum
|
|
|
366
395
|
phase: turn.phase,
|
|
367
396
|
...turn.toolAvailability
|
|
368
397
|
},
|
|
369
|
-
messages:
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
398
|
+
messages: turn.wrapUpHint.inject(
|
|
399
|
+
[
|
|
400
|
+
{
|
|
401
|
+
role: "system",
|
|
402
|
+
content: buildSystemPrompt(turn.agent, turn.coordinator)
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
role: "user",
|
|
406
|
+
content: turn.input
|
|
407
|
+
}
|
|
408
|
+
],
|
|
374
409
|
{
|
|
375
|
-
|
|
376
|
-
|
|
410
|
+
runId: turn.runId,
|
|
411
|
+
protocol: "coordinator",
|
|
412
|
+
cost: turn.totalCost,
|
|
413
|
+
events: turn.events,
|
|
414
|
+
transcript: turn.transcript,
|
|
415
|
+
iteration: turn.transcript.length,
|
|
416
|
+
elapsedMs: elapsedMs(turn.startedAtMs)
|
|
377
417
|
}
|
|
378
|
-
|
|
418
|
+
)
|
|
379
419
|
};
|
|
380
420
|
const response = await generateModelTurn({
|
|
381
421
|
model: turn.options.model,
|
|
@@ -445,6 +485,11 @@ interface CoordinatorWorkerTurnOptions {
|
|
|
445
485
|
readonly providerCallSlots: ReplayTraceProviderCall[];
|
|
446
486
|
readonly toolExecutor: RuntimeToolExecutor;
|
|
447
487
|
readonly toolAvailability: JsonObject;
|
|
488
|
+
readonly totalCost: CostSummary;
|
|
489
|
+
readonly events: RunEvent[];
|
|
490
|
+
readonly transcript: readonly TranscriptEntry[];
|
|
491
|
+
readonly startedAtMs: number;
|
|
492
|
+
readonly wrapUpHint: ReturnType<typeof createWrapUpHintController>;
|
|
448
493
|
readonly emit: (event: RunEvent) => void;
|
|
449
494
|
}
|
|
450
495
|
|
|
@@ -473,16 +518,27 @@ async function runCoordinatorWorkerTurn(turn: CoordinatorWorkerTurnOptions): Pro
|
|
|
473
518
|
phase: "worker",
|
|
474
519
|
...turn.toolAvailability
|
|
475
520
|
},
|
|
476
|
-
messages:
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
521
|
+
messages: turn.wrapUpHint.inject(
|
|
522
|
+
[
|
|
523
|
+
{
|
|
524
|
+
role: "system",
|
|
525
|
+
content: buildSystemPrompt(turn.agent, turn.coordinator)
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
role: "user",
|
|
529
|
+
content: turn.input
|
|
530
|
+
}
|
|
531
|
+
],
|
|
481
532
|
{
|
|
482
|
-
|
|
483
|
-
|
|
533
|
+
runId: turn.runId,
|
|
534
|
+
protocol: "coordinator",
|
|
535
|
+
cost: turn.totalCost,
|
|
536
|
+
events: turn.events,
|
|
537
|
+
transcript: turn.transcript,
|
|
538
|
+
iteration: turn.turn - 1,
|
|
539
|
+
elapsedMs: elapsedMs(turn.startedAtMs)
|
|
484
540
|
}
|
|
485
|
-
|
|
541
|
+
)
|
|
486
542
|
};
|
|
487
543
|
const response = await generateModelTurn({
|
|
488
544
|
model: turn.options.model,
|
package/src/runtime/engine.ts
CHANGED
|
@@ -84,6 +84,7 @@ export function createEngine(options: EngineOptions): Engine {
|
|
|
84
84
|
...(options.seed !== undefined ? { seed: options.seed } : {}),
|
|
85
85
|
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
86
86
|
...(terminate ? { terminate } : {}),
|
|
87
|
+
...(options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {}),
|
|
87
88
|
...(options.evaluate ? { evaluate: options.evaluate } : {})
|
|
88
89
|
});
|
|
89
90
|
},
|
|
@@ -516,6 +517,7 @@ interface RunProtocolOptions {
|
|
|
516
517
|
readonly seed?: EngineOptions["seed"];
|
|
517
518
|
readonly signal?: EngineOptions["signal"];
|
|
518
519
|
readonly terminate?: EngineOptions["terminate"];
|
|
520
|
+
readonly wrapUpHint?: EngineOptions["wrapUpHint"];
|
|
519
521
|
readonly emit?: (event: RunEvent) => void;
|
|
520
522
|
}
|
|
521
523
|
|
|
@@ -618,6 +620,7 @@ function runProtocol(options: RunProtocolOptions): Promise<RunResult> {
|
|
|
618
620
|
...(options.seed !== undefined ? { seed: options.seed } : {}),
|
|
619
621
|
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
620
622
|
...(options.terminate ? { terminate: options.terminate } : {}),
|
|
623
|
+
...(options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {}),
|
|
621
624
|
...(options.emit ? { emit: options.emit } : {})
|
|
622
625
|
});
|
|
623
626
|
case "broadcast":
|
|
@@ -633,6 +636,7 @@ function runProtocol(options: RunProtocolOptions): Promise<RunResult> {
|
|
|
633
636
|
...(options.seed !== undefined ? { seed: options.seed } : {}),
|
|
634
637
|
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
635
638
|
...(options.terminate ? { terminate: options.terminate } : {}),
|
|
639
|
+
...(options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {}),
|
|
636
640
|
...(options.emit ? { emit: options.emit } : {})
|
|
637
641
|
});
|
|
638
642
|
case "coordinator":
|
|
@@ -648,6 +652,7 @@ function runProtocol(options: RunProtocolOptions): Promise<RunResult> {
|
|
|
648
652
|
...(options.seed !== undefined ? { seed: options.seed } : {}),
|
|
649
653
|
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
650
654
|
...(options.terminate ? { terminate: options.terminate } : {}),
|
|
655
|
+
...(options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {}),
|
|
651
656
|
...(options.emit ? { emit: options.emit } : {})
|
|
652
657
|
});
|
|
653
658
|
case "shared":
|
|
@@ -663,6 +668,7 @@ function runProtocol(options: RunProtocolOptions): Promise<RunResult> {
|
|
|
663
668
|
...(options.seed !== undefined ? { seed: options.seed } : {}),
|
|
664
669
|
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
665
670
|
...(options.terminate ? { terminate: options.terminate } : {}),
|
|
671
|
+
...(options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {}),
|
|
666
672
|
...(options.emit ? { emit: options.emit } : {})
|
|
667
673
|
});
|
|
668
674
|
}
|
|
@@ -37,8 +37,9 @@ import {
|
|
|
37
37
|
import { throwIfAborted } from "./cancellation.js";
|
|
38
38
|
import { isParticipatingDecision, parseAgentDecision } from "./decisions.js";
|
|
39
39
|
import { generateModelTurn } from "./model.js";
|
|
40
|
-
import { evaluateTerminationStop } from "./termination.js";
|
|
40
|
+
import { evaluateTerminationStop, warnOnProtocolTerminationMisconfiguration } from "./termination.js";
|
|
41
41
|
import { createRuntimeToolExecutor, executeModelResponseToolRequests, runtimeToolAvailability } from "./tools.js";
|
|
42
|
+
import { createWrapUpHintController } from "./wrap-up.js";
|
|
42
43
|
|
|
43
44
|
interface SequentialRunOptions {
|
|
44
45
|
readonly intent: string;
|
|
@@ -52,6 +53,7 @@ interface SequentialRunOptions {
|
|
|
52
53
|
readonly seed?: string | number;
|
|
53
54
|
readonly signal?: AbortSignal;
|
|
54
55
|
readonly terminate?: TerminationCondition;
|
|
56
|
+
readonly wrapUpHint?: DogpileOptions["wrapUpHint"];
|
|
55
57
|
readonly emit?: (event: RunEvent) => void;
|
|
56
58
|
}
|
|
57
59
|
|
|
@@ -67,6 +69,15 @@ export async function runSequential(options: SequentialRunOptions): Promise<RunR
|
|
|
67
69
|
const startedAtMs = nowMs();
|
|
68
70
|
let stopped = false;
|
|
69
71
|
let termination: TerminationStopRecord | undefined;
|
|
72
|
+
const wrapUpHint = createWrapUpHintController({
|
|
73
|
+
protocol: options.protocol,
|
|
74
|
+
tier: options.tier,
|
|
75
|
+
...(options.budget ? { budget: options.budget } : {}),
|
|
76
|
+
...(options.terminate ? { terminate: options.terminate } : {}),
|
|
77
|
+
...(options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {})
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
warnOnProtocolTerminationMisconfiguration(options.protocol, options.terminate);
|
|
70
81
|
|
|
71
82
|
const emit = (event: RunEvent): void => {
|
|
72
83
|
events.push(event);
|
|
@@ -129,16 +140,27 @@ export async function runSequential(options: SequentialRunOptions): Promise<RunR
|
|
|
129
140
|
turn,
|
|
130
141
|
...toolAvailability
|
|
131
142
|
},
|
|
132
|
-
messages:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
143
|
+
messages: wrapUpHint.inject(
|
|
144
|
+
[
|
|
145
|
+
{
|
|
146
|
+
role: "system",
|
|
147
|
+
content: buildSystemPrompt(agent)
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
role: "user",
|
|
151
|
+
content: input
|
|
152
|
+
}
|
|
153
|
+
],
|
|
137
154
|
{
|
|
138
|
-
|
|
139
|
-
|
|
155
|
+
runId,
|
|
156
|
+
protocol: "sequential",
|
|
157
|
+
cost: totalCost,
|
|
158
|
+
events,
|
|
159
|
+
transcript,
|
|
160
|
+
iteration: transcript.length,
|
|
161
|
+
elapsedMs: elapsedMs(startedAtMs)
|
|
140
162
|
}
|
|
141
|
-
|
|
163
|
+
)
|
|
142
164
|
};
|
|
143
165
|
const response = await generateModelTurn({
|
|
144
166
|
model: options.model,
|
|
@@ -277,16 +299,20 @@ export async function runSequential(options: SequentialRunOptions): Promise<RunR
|
|
|
277
299
|
return stopped;
|
|
278
300
|
}
|
|
279
301
|
|
|
280
|
-
const stopRecord = evaluateTerminationStop(
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
302
|
+
const stopRecord = evaluateTerminationStop(
|
|
303
|
+
options.terminate,
|
|
304
|
+
wrapUpHint.context({
|
|
305
|
+
runId,
|
|
306
|
+
protocol: "sequential",
|
|
307
|
+
protocolConfig: options.protocol,
|
|
308
|
+
protocolIteration: transcript.length,
|
|
309
|
+
cost: totalCost,
|
|
310
|
+
events,
|
|
311
|
+
transcript,
|
|
312
|
+
iteration: transcript.length,
|
|
313
|
+
elapsedMs: elapsedMs(startedAtMs)
|
|
314
|
+
})
|
|
315
|
+
);
|
|
290
316
|
|
|
291
317
|
if (!stopRecord) {
|
|
292
318
|
return false;
|
package/src/runtime/shared.ts
CHANGED
|
@@ -36,8 +36,9 @@ import {
|
|
|
36
36
|
import { throwIfAborted } from "./cancellation.js";
|
|
37
37
|
import { parseAgentDecision } from "./decisions.js";
|
|
38
38
|
import { generateModelTurn } from "./model.js";
|
|
39
|
-
import { evaluateTerminationStop } from "./termination.js";
|
|
39
|
+
import { evaluateTerminationStop, warnOnProtocolTerminationMisconfiguration } from "./termination.js";
|
|
40
40
|
import { createRuntimeToolExecutor, executeModelResponseToolRequests, runtimeToolAvailability } from "./tools.js";
|
|
41
|
+
import { createWrapUpHintController } from "./wrap-up.js";
|
|
41
42
|
|
|
42
43
|
interface SharedRunOptions {
|
|
43
44
|
readonly intent: string;
|
|
@@ -51,6 +52,7 @@ interface SharedRunOptions {
|
|
|
51
52
|
readonly seed?: string | number;
|
|
52
53
|
readonly signal?: AbortSignal;
|
|
53
54
|
readonly terminate?: TerminationCondition;
|
|
55
|
+
readonly wrapUpHint?: DogpileOptions["wrapUpHint"];
|
|
54
56
|
readonly emit?: (event: RunEvent) => void;
|
|
55
57
|
}
|
|
56
58
|
|
|
@@ -67,6 +69,15 @@ export async function runShared(options: SharedRunOptions): Promise<RunResult> {
|
|
|
67
69
|
const startedAtMs = nowMs();
|
|
68
70
|
let stopped = false;
|
|
69
71
|
let termination: TerminationStopRecord | undefined;
|
|
72
|
+
const wrapUpHint = createWrapUpHintController({
|
|
73
|
+
protocol: options.protocol,
|
|
74
|
+
tier: options.tier,
|
|
75
|
+
...(options.budget ? { budget: options.budget } : {}),
|
|
76
|
+
...(options.terminate ? { terminate: options.terminate } : {}),
|
|
77
|
+
...(options.wrapUpHint ? { wrapUpHint: options.wrapUpHint } : {})
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
warnOnProtocolTerminationMisconfiguration(options.protocol, options.terminate);
|
|
70
81
|
|
|
71
82
|
const emit = (event: RunEvent): void => {
|
|
72
83
|
events.push(event);
|
|
@@ -126,16 +137,27 @@ export async function runShared(options: SharedRunOptions): Promise<RunResult> {
|
|
|
126
137
|
turn,
|
|
127
138
|
...toolAvailability
|
|
128
139
|
},
|
|
129
|
-
messages:
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
140
|
+
messages: wrapUpHint.inject(
|
|
141
|
+
[
|
|
142
|
+
{
|
|
143
|
+
role: "system",
|
|
144
|
+
content: buildSystemPrompt(agent)
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
role: "user",
|
|
148
|
+
content: input
|
|
149
|
+
}
|
|
150
|
+
],
|
|
134
151
|
{
|
|
135
|
-
|
|
136
|
-
|
|
152
|
+
runId,
|
|
153
|
+
protocol: "shared",
|
|
154
|
+
cost: totalCost,
|
|
155
|
+
events,
|
|
156
|
+
transcript,
|
|
157
|
+
iteration: transcript.length,
|
|
158
|
+
elapsedMs: elapsedMs(startedAtMs)
|
|
137
159
|
}
|
|
138
|
-
|
|
160
|
+
)
|
|
139
161
|
};
|
|
140
162
|
const response = await generateModelTurn({
|
|
141
163
|
model: options.model,
|
|
@@ -285,16 +307,20 @@ export async function runShared(options: SharedRunOptions): Promise<RunResult> {
|
|
|
285
307
|
return stopped;
|
|
286
308
|
}
|
|
287
309
|
|
|
288
|
-
const stopRecord = evaluateTerminationStop(
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
310
|
+
const stopRecord = evaluateTerminationStop(
|
|
311
|
+
options.terminate,
|
|
312
|
+
wrapUpHint.context({
|
|
313
|
+
runId,
|
|
314
|
+
protocol: "shared",
|
|
315
|
+
protocolConfig: options.protocol,
|
|
316
|
+
protocolIteration: transcript.length,
|
|
317
|
+
cost: totalCost,
|
|
318
|
+
events,
|
|
319
|
+
transcript,
|
|
320
|
+
iteration: transcript.length,
|
|
321
|
+
elapsedMs: elapsedMs(startedAtMs)
|
|
322
|
+
})
|
|
323
|
+
);
|
|
298
324
|
|
|
299
325
|
if (!stopRecord) {
|
|
300
326
|
return false;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
BroadcastProtocolConfig,
|
|
2
3
|
BudgetStopReason,
|
|
3
4
|
BudgetTerminationCondition,
|
|
4
5
|
ConvergenceTerminationCondition,
|
|
6
|
+
CoordinatorProtocolConfig,
|
|
5
7
|
FirstOfTerminationCondition,
|
|
6
8
|
FirstOfTerminationConditions,
|
|
7
9
|
FirstOfTerminationOutput,
|
|
@@ -10,6 +12,9 @@ import type {
|
|
|
10
12
|
JudgeTerminationCondition,
|
|
11
13
|
JsonObject,
|
|
12
14
|
NormalizedStopReason,
|
|
15
|
+
ProtocolConfig,
|
|
16
|
+
SequentialProtocolConfig,
|
|
17
|
+
SharedProtocolConfig,
|
|
13
18
|
TerminationStopRecord,
|
|
14
19
|
StopTerminationDecision,
|
|
15
20
|
TerminationCondition,
|
|
@@ -85,6 +90,10 @@ export function evaluateTermination(
|
|
|
85
90
|
condition: TerminationCondition,
|
|
86
91
|
context: TerminationEvaluationContext
|
|
87
92
|
): TerminationDecision {
|
|
93
|
+
if (isTerminationFloorBlocked(condition, context)) {
|
|
94
|
+
return { type: "continue", condition };
|
|
95
|
+
}
|
|
96
|
+
|
|
88
97
|
switch (condition.kind) {
|
|
89
98
|
case "budget":
|
|
90
99
|
return evaluateBudget(condition, context);
|
|
@@ -166,6 +175,30 @@ export function evaluateTerminationStop(
|
|
|
166
175
|
return stopRecord(condition, decision);
|
|
167
176
|
}
|
|
168
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Warn when a protocol-level termination floor cannot be satisfied because a
|
|
180
|
+
* lower iteration cap will stop the run first.
|
|
181
|
+
*/
|
|
182
|
+
export function warnOnProtocolTerminationMisconfiguration(
|
|
183
|
+
protocol: ProtocolConfig,
|
|
184
|
+
terminate: TerminationCondition | undefined,
|
|
185
|
+
warn: (message: string) => void = console.warn
|
|
186
|
+
): void {
|
|
187
|
+
const minTurns = protocolMinTurns(protocol);
|
|
188
|
+
if (minTurns === undefined || !terminate) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const limitingIterationBudget = smallestIterationBudget(terminate);
|
|
193
|
+
if (limitingIterationBudget === undefined || limitingIterationBudget >= minTurns) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
warn(
|
|
198
|
+
`[dogpile] protocol.minTurns (${minTurns}) exceeds terminate budget maxIterations (${limitingIterationBudget}); maxIterations will win.`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
169
202
|
/**
|
|
170
203
|
* Combine independently evaluated termination decisions with SDK precedence.
|
|
171
204
|
*
|
|
@@ -384,6 +417,73 @@ function stopPrecedence(reason: NormalizedStopReason): number {
|
|
|
384
417
|
return 2;
|
|
385
418
|
}
|
|
386
419
|
|
|
420
|
+
function isTerminationFloorBlocked(condition: TerminationCondition, context: TerminationEvaluationContext): boolean {
|
|
421
|
+
if (condition.kind !== "convergence" && condition.kind !== "judge") {
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const floor = protocolTerminationFloor(context.protocolConfig);
|
|
426
|
+
if (floor === undefined || floor <= 0) {
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
const progress = protocolProgress(context);
|
|
431
|
+
return progress < floor;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function protocolTerminationFloor(protocol: ProtocolConfig | undefined): number | undefined {
|
|
435
|
+
if (!protocol) {
|
|
436
|
+
return undefined;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
switch (protocol.kind) {
|
|
440
|
+
case "broadcast":
|
|
441
|
+
return protocol.minRounds;
|
|
442
|
+
case "coordinator":
|
|
443
|
+
case "sequential":
|
|
444
|
+
case "shared":
|
|
445
|
+
return protocol.minTurns;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function protocolProgress(context: TerminationEvaluationContext): number {
|
|
450
|
+
return context.protocolIteration ?? context.iteration ?? context.transcript.length;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function protocolMinTurns(
|
|
454
|
+
protocol: ProtocolConfig
|
|
455
|
+
): SequentialProtocolConfig["minTurns"] | CoordinatorProtocolConfig["minTurns"] | SharedProtocolConfig["minTurns"] {
|
|
456
|
+
switch (protocol.kind) {
|
|
457
|
+
case "broadcast":
|
|
458
|
+
return undefined;
|
|
459
|
+
case "coordinator":
|
|
460
|
+
case "sequential":
|
|
461
|
+
case "shared":
|
|
462
|
+
return protocol.minTurns;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function smallestIterationBudget(condition: TerminationCondition): number | undefined {
|
|
467
|
+
switch (condition.kind) {
|
|
468
|
+
case "budget":
|
|
469
|
+
return condition.maxIterations;
|
|
470
|
+
case "convergence":
|
|
471
|
+
case "judge":
|
|
472
|
+
return undefined;
|
|
473
|
+
case "firstOf": {
|
|
474
|
+
let smallest: number | undefined;
|
|
475
|
+
for (const child of condition.conditions) {
|
|
476
|
+
const budget = smallestIterationBudget(child);
|
|
477
|
+
if (budget === undefined) {
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
smallest = smallest === undefined ? budget : Math.min(smallest, budget);
|
|
481
|
+
}
|
|
482
|
+
return smallest;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
387
487
|
function judgeStopDetail(decision: JudgeEvaluationDecision, minScore?: number): JsonObject {
|
|
388
488
|
return {
|
|
389
489
|
decision: decision.type,
|