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