@dogpile/sdk 0.1.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 +37 -0
- package/LICENSE +16 -0
- package/README.md +842 -0
- package/dist/browser/index.d.ts +8 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +4493 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/openai-compatible.d.ts +44 -0
- package/dist/providers/openai-compatible.d.ts.map +1 -0
- package/dist/providers/openai-compatible.js +305 -0
- package/dist/providers/openai-compatible.js.map +1 -0
- package/dist/runtime/broadcast.d.ts +18 -0
- package/dist/runtime/broadcast.d.ts.map +1 -0
- package/dist/runtime/broadcast.js +335 -0
- package/dist/runtime/broadcast.js.map +1 -0
- package/dist/runtime/cancellation.d.ts +6 -0
- package/dist/runtime/cancellation.d.ts.map +1 -0
- package/dist/runtime/cancellation.js +35 -0
- package/dist/runtime/cancellation.js.map +1 -0
- package/dist/runtime/coordinator.d.ts +18 -0
- package/dist/runtime/coordinator.d.ts.map +1 -0
- package/dist/runtime/coordinator.js +434 -0
- package/dist/runtime/coordinator.js.map +1 -0
- package/dist/runtime/decisions.d.ts +5 -0
- package/dist/runtime/decisions.d.ts.map +1 -0
- package/dist/runtime/decisions.js +31 -0
- package/dist/runtime/decisions.js.map +1 -0
- package/dist/runtime/defaults.d.ts +63 -0
- package/dist/runtime/defaults.d.ts.map +1 -0
- package/dist/runtime/defaults.js +426 -0
- package/dist/runtime/defaults.js.map +1 -0
- package/dist/runtime/engine.d.ts +79 -0
- package/dist/runtime/engine.d.ts.map +1 -0
- package/dist/runtime/engine.js +723 -0
- package/dist/runtime/engine.js.map +1 -0
- package/dist/runtime/model.d.ts +14 -0
- package/dist/runtime/model.d.ts.map +1 -0
- package/dist/runtime/model.js +82 -0
- package/dist/runtime/model.js.map +1 -0
- package/dist/runtime/sequential.d.ts +18 -0
- package/dist/runtime/sequential.d.ts.map +1 -0
- package/dist/runtime/sequential.js +277 -0
- package/dist/runtime/sequential.js.map +1 -0
- package/dist/runtime/shared.d.ts +18 -0
- package/dist/runtime/shared.d.ts.map +1 -0
- package/dist/runtime/shared.js +288 -0
- package/dist/runtime/shared.js.map +1 -0
- package/dist/runtime/termination.d.ts +77 -0
- package/dist/runtime/termination.d.ts.map +1 -0
- package/dist/runtime/termination.js +355 -0
- package/dist/runtime/termination.js.map +1 -0
- package/dist/runtime/tools.d.ts +314 -0
- package/dist/runtime/tools.d.ts.map +1 -0
- package/dist/runtime/tools.js +969 -0
- package/dist/runtime/tools.js.map +1 -0
- package/dist/runtime/validation.d.ts +23 -0
- package/dist/runtime/validation.d.ts.map +1 -0
- package/dist/runtime/validation.js +656 -0
- package/dist/runtime/validation.js.map +1 -0
- package/dist/types.d.ts +2434 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +81 -0
- package/dist/types.js.map +1 -0
- package/package.json +157 -0
- package/src/browser/index.ts +7 -0
- package/src/index.ts +195 -0
- package/src/providers/openai-compatible.ts +406 -0
- package/src/runtime/broadcast.test.ts +355 -0
- package/src/runtime/broadcast.ts +428 -0
- package/src/runtime/cancellation.ts +40 -0
- package/src/runtime/coordinator.test.ts +468 -0
- package/src/runtime/coordinator.ts +581 -0
- package/src/runtime/decisions.ts +38 -0
- package/src/runtime/defaults.ts +547 -0
- package/src/runtime/engine.ts +880 -0
- package/src/runtime/model.ts +117 -0
- package/src/runtime/sequential.test.ts +262 -0
- package/src/runtime/sequential.ts +357 -0
- package/src/runtime/shared.test.ts +265 -0
- package/src/runtime/shared.ts +367 -0
- package/src/runtime/termination.ts +463 -0
- package/src/runtime/tools.ts +1518 -0
- package/src/runtime/validation.ts +771 -0
- package/src/types.ts +2729 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AgentSpec,
|
|
3
|
+
BroadcastContribution,
|
|
4
|
+
BroadcastProtocolConfig,
|
|
5
|
+
ConfiguredModelProvider,
|
|
6
|
+
CostSummary,
|
|
7
|
+
DogpileOptions,
|
|
8
|
+
JsonObject,
|
|
9
|
+
JsonValue,
|
|
10
|
+
ModelRequest,
|
|
11
|
+
ModelResponse,
|
|
12
|
+
ReplayTraceProtocolDecision,
|
|
13
|
+
ReplayTraceProviderCall,
|
|
14
|
+
RuntimeTool,
|
|
15
|
+
RunEvent,
|
|
16
|
+
RunResult,
|
|
17
|
+
TerminationCondition,
|
|
18
|
+
TerminationStopRecord,
|
|
19
|
+
Tier,
|
|
20
|
+
TranscriptEntry
|
|
21
|
+
} from "../types.js";
|
|
22
|
+
import {
|
|
23
|
+
addCost,
|
|
24
|
+
createReplayTraceBudget,
|
|
25
|
+
createReplayTraceBudgetStateChanges,
|
|
26
|
+
createReplayTraceFinalOutput,
|
|
27
|
+
createReplayTraceProtocolDecision,
|
|
28
|
+
createReplayTraceRunInputs,
|
|
29
|
+
createReplayTraceSeed,
|
|
30
|
+
createRunAccounting,
|
|
31
|
+
createRunEventLog,
|
|
32
|
+
createRunMetadata,
|
|
33
|
+
createRunUsage,
|
|
34
|
+
createTranscriptLink,
|
|
35
|
+
emptyCost
|
|
36
|
+
} from "./defaults.js";
|
|
37
|
+
import { throwIfAborted } from "./cancellation.js";
|
|
38
|
+
import { parseAgentDecision } from "./decisions.js";
|
|
39
|
+
import { generateModelTurn } from "./model.js";
|
|
40
|
+
import { evaluateTerminationStop } from "./termination.js";
|
|
41
|
+
import { createRuntimeToolExecutor, executeModelResponseToolRequests, runtimeToolAvailability } from "./tools.js";
|
|
42
|
+
|
|
43
|
+
interface BroadcastRunOptions {
|
|
44
|
+
readonly intent: string;
|
|
45
|
+
readonly protocol: BroadcastProtocolConfig;
|
|
46
|
+
readonly tier: Tier;
|
|
47
|
+
readonly model: ConfiguredModelProvider;
|
|
48
|
+
readonly agents: readonly AgentSpec[];
|
|
49
|
+
readonly tools: readonly RuntimeTool<JsonObject, JsonValue>[];
|
|
50
|
+
readonly temperature: number;
|
|
51
|
+
readonly budget?: DogpileOptions["budget"];
|
|
52
|
+
readonly seed?: string | number;
|
|
53
|
+
readonly signal?: AbortSignal;
|
|
54
|
+
readonly terminate?: TerminationCondition;
|
|
55
|
+
readonly emit?: (event: RunEvent) => void;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function runBroadcast(options: BroadcastRunOptions): Promise<RunResult> {
|
|
59
|
+
const runId = createRunId();
|
|
60
|
+
const events: RunEvent[] = [];
|
|
61
|
+
const transcript: TranscriptEntry[] = [];
|
|
62
|
+
const protocolDecisions: ReplayTraceProtocolDecision[] = [];
|
|
63
|
+
const providerCalls: ReplayTraceProviderCall[] = [];
|
|
64
|
+
let totalCost = emptyCost();
|
|
65
|
+
const maxRounds = options.protocol.maxRounds ?? 2;
|
|
66
|
+
let firstRoundContributions: readonly BroadcastContribution[] = [];
|
|
67
|
+
let lastContributions: readonly BroadcastContribution[] = [];
|
|
68
|
+
const startedAtMs = nowMs();
|
|
69
|
+
let stopped = false;
|
|
70
|
+
let termination: TerminationStopRecord | undefined;
|
|
71
|
+
|
|
72
|
+
const emit = (event: RunEvent): void => {
|
|
73
|
+
events.push(event);
|
|
74
|
+
options.emit?.(event);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const recordProtocolDecision = (
|
|
78
|
+
event: RunEvent,
|
|
79
|
+
decisionOptions?: Parameters<typeof createReplayTraceProtocolDecision>[3]
|
|
80
|
+
): void => {
|
|
81
|
+
protocolDecisions.push(
|
|
82
|
+
createReplayTraceProtocolDecision("broadcast", event, events.length - 1, decisionOptions)
|
|
83
|
+
);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const toolExecutor = createRuntimeToolExecutor({
|
|
87
|
+
runId,
|
|
88
|
+
protocol: "broadcast",
|
|
89
|
+
tier: options.tier,
|
|
90
|
+
tools: options.tools,
|
|
91
|
+
emit(event): void {
|
|
92
|
+
emit(event);
|
|
93
|
+
recordProtocolDecision(event);
|
|
94
|
+
},
|
|
95
|
+
getTrace: () => ({ events, transcript }),
|
|
96
|
+
...(options.signal !== undefined ? { abortSignal: options.signal } : {})
|
|
97
|
+
});
|
|
98
|
+
const toolAvailability = runtimeToolAvailability(toolExecutor.tools);
|
|
99
|
+
|
|
100
|
+
throwIfAborted(options.signal, options.model.id);
|
|
101
|
+
|
|
102
|
+
for (const agent of options.agents) {
|
|
103
|
+
const event: RunEvent = {
|
|
104
|
+
type: "role-assignment",
|
|
105
|
+
runId,
|
|
106
|
+
at: new Date().toISOString(),
|
|
107
|
+
agentId: agent.id,
|
|
108
|
+
role: agent.role
|
|
109
|
+
};
|
|
110
|
+
emit(event);
|
|
111
|
+
recordProtocolDecision(event);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
for (let round = 1; round <= maxRounds; round += 1) {
|
|
115
|
+
if (stopIfNeeded()) {
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const providerCallSlots: ReplayTraceProviderCall[] = [];
|
|
120
|
+
const turnResults = await Promise.all(
|
|
121
|
+
options.agents.map(async (agent, agentIndex) => {
|
|
122
|
+
const turn = transcript.length + agentIndex + 1;
|
|
123
|
+
const input = buildBroadcastInput(options.intent, round, maxRounds, firstRoundContributions);
|
|
124
|
+
const request: ModelRequest = {
|
|
125
|
+
temperature: options.temperature,
|
|
126
|
+
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
127
|
+
metadata: {
|
|
128
|
+
runId,
|
|
129
|
+
protocol: "broadcast",
|
|
130
|
+
agentId: agent.id,
|
|
131
|
+
role: agent.role,
|
|
132
|
+
tier: options.tier,
|
|
133
|
+
round,
|
|
134
|
+
...toolAvailability
|
|
135
|
+
},
|
|
136
|
+
messages: [
|
|
137
|
+
{
|
|
138
|
+
role: "system",
|
|
139
|
+
content: buildSystemPrompt(agent)
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
role: "user",
|
|
143
|
+
content: input
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
};
|
|
147
|
+
const response = await generateModelTurn({
|
|
148
|
+
model: options.model,
|
|
149
|
+
request,
|
|
150
|
+
runId,
|
|
151
|
+
agent,
|
|
152
|
+
input,
|
|
153
|
+
emit,
|
|
154
|
+
callId: providerCallIdFor(runId, providerCalls.length + agentIndex + 1),
|
|
155
|
+
onProviderCall(call): void {
|
|
156
|
+
providerCallSlots[agentIndex] = call;
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
const decision = parseAgentDecision(response.text);
|
|
160
|
+
const toolCalls = await executeModelResponseToolRequests({
|
|
161
|
+
response,
|
|
162
|
+
executor: toolExecutor,
|
|
163
|
+
agentId: agent.id,
|
|
164
|
+
role: agent.role,
|
|
165
|
+
turn,
|
|
166
|
+
metadata: {
|
|
167
|
+
round
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
throwIfAborted(options.signal, options.model.id);
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
agent,
|
|
174
|
+
agentIndex,
|
|
175
|
+
turn,
|
|
176
|
+
input,
|
|
177
|
+
response,
|
|
178
|
+
decision,
|
|
179
|
+
toolCalls,
|
|
180
|
+
turnCost: responseCost(response)
|
|
181
|
+
};
|
|
182
|
+
})
|
|
183
|
+
);
|
|
184
|
+
providerCalls.push(...providerCallSlots.filter((call): call is ReplayTraceProviderCall => call !== undefined));
|
|
185
|
+
|
|
186
|
+
const contributions: BroadcastContribution[] = [];
|
|
187
|
+
for (const result of turnResults) {
|
|
188
|
+
totalCost = addCost(totalCost, result.turnCost);
|
|
189
|
+
transcript.push({
|
|
190
|
+
agentId: result.agent.id,
|
|
191
|
+
role: result.agent.role,
|
|
192
|
+
input: result.input,
|
|
193
|
+
output: result.response.text,
|
|
194
|
+
...(result.decision !== undefined ? { decision: result.decision } : {}),
|
|
195
|
+
...(result.toolCalls.length > 0 ? { toolCalls: result.toolCalls } : {})
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
contributions.push({
|
|
199
|
+
agentId: result.agent.id,
|
|
200
|
+
role: result.agent.role,
|
|
201
|
+
output: result.response.text,
|
|
202
|
+
...(result.decision !== undefined ? { decision: result.decision } : {})
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const event: RunEvent = {
|
|
206
|
+
type: "agent-turn",
|
|
207
|
+
runId,
|
|
208
|
+
at: new Date().toISOString(),
|
|
209
|
+
agentId: result.agent.id,
|
|
210
|
+
role: result.agent.role,
|
|
211
|
+
input: result.input,
|
|
212
|
+
output: result.response.text,
|
|
213
|
+
...(result.decision !== undefined ? { decision: result.decision } : {}),
|
|
214
|
+
cost: totalCost
|
|
215
|
+
};
|
|
216
|
+
emit(event);
|
|
217
|
+
recordProtocolDecision(event, {
|
|
218
|
+
round,
|
|
219
|
+
turn: result.turn,
|
|
220
|
+
transcriptEntryCount: transcript.length,
|
|
221
|
+
contributionCount: result.agentIndex + 1
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (contributions.length === 0) {
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
if (round === 1) {
|
|
229
|
+
firstRoundContributions = contributions;
|
|
230
|
+
}
|
|
231
|
+
lastContributions = contributions;
|
|
232
|
+
|
|
233
|
+
const broadcast: RunEvent = {
|
|
234
|
+
type: "broadcast",
|
|
235
|
+
runId,
|
|
236
|
+
at: new Date().toISOString(),
|
|
237
|
+
round,
|
|
238
|
+
contributions,
|
|
239
|
+
cost: totalCost
|
|
240
|
+
};
|
|
241
|
+
emit(broadcast);
|
|
242
|
+
recordProtocolDecision(broadcast, {
|
|
243
|
+
round,
|
|
244
|
+
transcriptEntryCount: transcript.length,
|
|
245
|
+
contributionCount: contributions.length
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
if (stopIfNeeded()) {
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const output = synthesizeBroadcastOutput(lastContributions);
|
|
254
|
+
throwIfAborted(options.signal, options.model.id);
|
|
255
|
+
const final: RunEvent = {
|
|
256
|
+
type: "final",
|
|
257
|
+
runId,
|
|
258
|
+
at: new Date().toISOString(),
|
|
259
|
+
output,
|
|
260
|
+
cost: totalCost,
|
|
261
|
+
transcript: createTranscriptLink(transcript),
|
|
262
|
+
...(termination !== undefined ? { termination } : {})
|
|
263
|
+
};
|
|
264
|
+
emit(final);
|
|
265
|
+
recordProtocolDecision(final, {
|
|
266
|
+
transcriptEntryCount: transcript.length
|
|
267
|
+
});
|
|
268
|
+
const finalEvent = events.at(-1);
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
output,
|
|
272
|
+
eventLog: createRunEventLog(runId, "broadcast", events),
|
|
273
|
+
trace: {
|
|
274
|
+
schemaVersion: "1.0",
|
|
275
|
+
runId,
|
|
276
|
+
protocol: "broadcast",
|
|
277
|
+
tier: options.tier,
|
|
278
|
+
modelProviderId: options.model.id,
|
|
279
|
+
agentsUsed: options.agents,
|
|
280
|
+
inputs: createReplayTraceRunInputs({
|
|
281
|
+
intent: options.intent,
|
|
282
|
+
protocol: options.protocol,
|
|
283
|
+
tier: options.tier,
|
|
284
|
+
modelProviderId: options.model.id,
|
|
285
|
+
agents: options.agents,
|
|
286
|
+
temperature: options.temperature
|
|
287
|
+
}),
|
|
288
|
+
budget: createReplayTraceBudget({
|
|
289
|
+
tier: options.tier,
|
|
290
|
+
...(options.budget ? { caps: options.budget } : {}),
|
|
291
|
+
...(options.terminate ? { termination: options.terminate } : {})
|
|
292
|
+
}),
|
|
293
|
+
budgetStateChanges: createReplayTraceBudgetStateChanges(events),
|
|
294
|
+
seed: createReplayTraceSeed(options.seed),
|
|
295
|
+
protocolDecisions,
|
|
296
|
+
providerCalls,
|
|
297
|
+
finalOutput: createReplayTraceFinalOutput(output, finalEvent ?? {
|
|
298
|
+
type: "final",
|
|
299
|
+
runId,
|
|
300
|
+
at: "",
|
|
301
|
+
output,
|
|
302
|
+
cost: totalCost,
|
|
303
|
+
transcript: createTranscriptLink(transcript)
|
|
304
|
+
}),
|
|
305
|
+
events,
|
|
306
|
+
transcript
|
|
307
|
+
},
|
|
308
|
+
transcript,
|
|
309
|
+
usage: createRunUsage(totalCost),
|
|
310
|
+
metadata: createRunMetadata({
|
|
311
|
+
runId,
|
|
312
|
+
protocol: "broadcast",
|
|
313
|
+
tier: options.tier,
|
|
314
|
+
modelProviderId: options.model.id,
|
|
315
|
+
agentsUsed: options.agents,
|
|
316
|
+
events
|
|
317
|
+
}),
|
|
318
|
+
accounting: createRunAccounting({
|
|
319
|
+
tier: options.tier,
|
|
320
|
+
...(options.budget ? { budget: options.budget } : {}),
|
|
321
|
+
...(options.terminate ? { termination: options.terminate } : {}),
|
|
322
|
+
cost: totalCost,
|
|
323
|
+
events
|
|
324
|
+
}),
|
|
325
|
+
cost: totalCost
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
function stopIfNeeded(): boolean {
|
|
329
|
+
throwIfAborted(options.signal, options.model.id);
|
|
330
|
+
|
|
331
|
+
if (stopped || !options.terminate) {
|
|
332
|
+
return stopped;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const stopRecord = evaluateTerminationStop(options.terminate, {
|
|
336
|
+
runId,
|
|
337
|
+
protocol: "broadcast",
|
|
338
|
+
tier: options.tier,
|
|
339
|
+
cost: totalCost,
|
|
340
|
+
events,
|
|
341
|
+
transcript,
|
|
342
|
+
iteration: transcript.length,
|
|
343
|
+
elapsedMs: elapsedMs(startedAtMs)
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
if (!stopRecord) {
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
stopped = true;
|
|
351
|
+
termination = stopRecord;
|
|
352
|
+
if (stopRecord.reason === "budget") {
|
|
353
|
+
emitBudgetStop(stopRecord);
|
|
354
|
+
}
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function emitBudgetStop(record: TerminationStopRecord): void {
|
|
359
|
+
const event: RunEvent = {
|
|
360
|
+
type: "budget-stop",
|
|
361
|
+
runId,
|
|
362
|
+
at: new Date().toISOString(),
|
|
363
|
+
reason: record.budgetReason ?? "cost",
|
|
364
|
+
cost: totalCost,
|
|
365
|
+
iteration: transcript.length,
|
|
366
|
+
elapsedMs: elapsedMs(startedAtMs),
|
|
367
|
+
detail: record.detail ?? {}
|
|
368
|
+
};
|
|
369
|
+
emit(event);
|
|
370
|
+
recordProtocolDecision(event, {
|
|
371
|
+
transcriptEntryCount: transcript.length
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function buildSystemPrompt(agent: AgentSpec): string {
|
|
377
|
+
const instruction = agent.instructions ? `\nInstructions: ${agent.instructions}` : "";
|
|
378
|
+
return `You are ${agent.id}, acting as ${agent.role} in a Broadcast multi-agent protocol.${instruction}`;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function buildBroadcastInput(
|
|
382
|
+
intent: string,
|
|
383
|
+
round: number,
|
|
384
|
+
maxRounds: number,
|
|
385
|
+
firstRoundContributions: readonly BroadcastContribution[]
|
|
386
|
+
): string {
|
|
387
|
+
if (maxRounds === 1) {
|
|
388
|
+
return `Mission: ${intent}\nBroadcast round ${round}: contribute independently before synthesis.`;
|
|
389
|
+
}
|
|
390
|
+
if (round === 1) {
|
|
391
|
+
return `Mission: ${intent}\nBroadcast round 1: broadcast your intended role and participation decision. Do not produce the final plan yet.`;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const intentions = firstRoundContributions
|
|
395
|
+
.map((contribution) => `${contribution.role}:${contribution.agentId} => ${contribution.output}`)
|
|
396
|
+
.join("\n");
|
|
397
|
+
return `Mission: ${intent}\n\nRound 1 intentions:\n${intentions || "(none)"}\n\nBroadcast round ${round}: make your final contribution or abstention decision informed by all round 1 intentions.`;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function synthesizeBroadcastOutput(contributions: readonly BroadcastContribution[]): string {
|
|
401
|
+
return contributions.map((entry) => `${entry.role}:${entry.agentId} => ${entry.output}`).join("\n");
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function responseCost(response: ModelResponse): CostSummary {
|
|
405
|
+
return {
|
|
406
|
+
usd: response.costUsd ?? 0,
|
|
407
|
+
inputTokens: response.usage?.inputTokens ?? 0,
|
|
408
|
+
outputTokens: response.usage?.outputTokens ?? 0,
|
|
409
|
+
totalTokens: response.usage?.totalTokens ?? 0
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function createRunId(): string {
|
|
414
|
+
const random = globalThis.crypto?.randomUUID?.();
|
|
415
|
+
return random ?? `run-${Date.now().toString(36)}`;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function nowMs(): number {
|
|
419
|
+
return globalThis.performance?.now() ?? Date.now();
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function elapsedMs(startedAtMs: number): number {
|
|
423
|
+
return Math.max(0, nowMs() - startedAtMs);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
function providerCallIdFor(runId: string, oneBasedIndex: number): string {
|
|
427
|
+
return `${runId}:provider-call:${oneBasedIndex}`;
|
|
428
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { DogpileError, type JsonObject } from "../types.js";
|
|
2
|
+
|
|
3
|
+
export function throwIfAborted(signal: AbortSignal | undefined, providerId: string): void {
|
|
4
|
+
if (!signal?.aborted) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
throw createAbortErrorFromSignal(signal, providerId);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function createAbortError(providerId: string, detail?: JsonObject, cause?: unknown): DogpileError {
|
|
12
|
+
return new DogpileError({
|
|
13
|
+
code: "aborted",
|
|
14
|
+
message: "The operation was aborted.",
|
|
15
|
+
retryable: false,
|
|
16
|
+
providerId,
|
|
17
|
+
...(detail !== undefined ? { detail } : {}),
|
|
18
|
+
...(cause !== undefined ? { cause } : {})
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function createAbortErrorFromSignal(signal: AbortSignal, providerId: string): DogpileError {
|
|
23
|
+
if (DogpileError.isInstance(signal.reason)) {
|
|
24
|
+
return signal.reason;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return createAbortError(providerId, undefined, signal.reason);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function createTimeoutError(providerId: string, timeoutMs: number): DogpileError {
|
|
31
|
+
return new DogpileError({
|
|
32
|
+
code: "timeout",
|
|
33
|
+
message: `The operation timed out after ${timeoutMs}ms.`,
|
|
34
|
+
retryable: true,
|
|
35
|
+
providerId,
|
|
36
|
+
detail: {
|
|
37
|
+
timeoutMs
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|