@providerprotocol/agents 0.0.1 → 0.0.3

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 (74) hide show
  1. package/README.md +333 -6
  2. package/dist/checkpoint/index.d.ts +43 -0
  3. package/dist/checkpoint/index.js +64 -0
  4. package/dist/checkpoint/index.js.map +1 -0
  5. package/{src/execution/loop.ts → dist/chunk-4ESYN66B.js} +54 -162
  6. package/dist/chunk-4ESYN66B.js.map +1 -0
  7. package/dist/chunk-EKRXMSDX.js +8 -0
  8. package/dist/chunk-EKRXMSDX.js.map +1 -0
  9. package/dist/chunk-PHI5ULBV.js +427 -0
  10. package/dist/chunk-PHI5ULBV.js.map +1 -0
  11. package/dist/execution/index.d.ts +105 -0
  12. package/dist/execution/index.js +679 -0
  13. package/dist/execution/index.js.map +1 -0
  14. package/dist/index-qsPwbY86.d.ts +65 -0
  15. package/dist/index.d.ts +101 -0
  16. package/dist/index.js +218 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/middleware/index.d.ts +23 -0
  19. package/dist/middleware/index.js +82 -0
  20. package/dist/middleware/index.js.map +1 -0
  21. package/dist/thread-tree/index.d.ts +115 -0
  22. package/dist/thread-tree/index.js +4 -0
  23. package/dist/thread-tree/index.js.map +1 -0
  24. package/dist/types-2Vsthzyu.d.ts +163 -0
  25. package/dist/types-BhX9uD_d.d.ts +91 -0
  26. package/dist/types-DR02gtFv.d.ts +270 -0
  27. package/dist/types-NGQMdnaD.d.ts +65 -0
  28. package/package.json +40 -8
  29. package/.claude/settings.local.json +0 -27
  30. package/AGENTS.md +0 -681
  31. package/CLAUDE.md +0 -681
  32. package/bun.lock +0 -472
  33. package/eslint.config.js +0 -75
  34. package/index.ts +0 -1
  35. package/llms.md +0 -796
  36. package/specs/UAP-1.0.md +0 -2355
  37. package/src/agent/index.ts +0 -384
  38. package/src/agent/types.ts +0 -91
  39. package/src/checkpoint/file.ts +0 -126
  40. package/src/checkpoint/index.ts +0 -40
  41. package/src/checkpoint/types.ts +0 -95
  42. package/src/execution/index.ts +0 -37
  43. package/src/execution/plan.ts +0 -497
  44. package/src/execution/react.ts +0 -340
  45. package/src/execution/tool-ordering.ts +0 -186
  46. package/src/execution/types.ts +0 -315
  47. package/src/index.ts +0 -80
  48. package/src/middleware/index.ts +0 -7
  49. package/src/middleware/logging.ts +0 -123
  50. package/src/middleware/types.ts +0 -69
  51. package/src/state/index.ts +0 -301
  52. package/src/state/types.ts +0 -173
  53. package/src/thread-tree/index.ts +0 -249
  54. package/src/thread-tree/types.ts +0 -29
  55. package/src/utils/uuid.ts +0 -7
  56. package/tests/live/agent-anthropic.test.ts +0 -288
  57. package/tests/live/agent-strategy-hooks.test.ts +0 -268
  58. package/tests/live/checkpoint.test.ts +0 -243
  59. package/tests/live/execution-strategies.test.ts +0 -255
  60. package/tests/live/plan-strategy.test.ts +0 -160
  61. package/tests/live/subagent-events.live.test.ts +0 -249
  62. package/tests/live/thread-tree.test.ts +0 -186
  63. package/tests/unit/agent.test.ts +0 -703
  64. package/tests/unit/checkpoint.test.ts +0 -232
  65. package/tests/unit/execution/equivalence.test.ts +0 -402
  66. package/tests/unit/execution/loop.test.ts +0 -437
  67. package/tests/unit/execution/plan.test.ts +0 -590
  68. package/tests/unit/execution/react.test.ts +0 -604
  69. package/tests/unit/execution/subagent-events.test.ts +0 -235
  70. package/tests/unit/execution/tool-ordering.test.ts +0 -310
  71. package/tests/unit/middleware/logging.test.ts +0 -276
  72. package/tests/unit/state.test.ts +0 -573
  73. package/tests/unit/thread-tree.test.ts +0 -249
  74. package/tsconfig.json +0 -29
@@ -0,0 +1,679 @@
1
+ export { loop } from '../chunk-4ESYN66B.js';
2
+ import { generateUUID } from '../chunk-EKRXMSDX.js';
3
+ import { UserMessage } from '@providerprotocol/ai';
4
+
5
+ var DEFAULT_REACT_OPTIONS = {
6
+ maxSteps: Infinity,
7
+ reasoningPrompt: "Think step by step about what you need to do next. Consider the current state, what tools are available, and what action would be most helpful."
8
+ };
9
+ function react(options = {}) {
10
+ const opts = { ...DEFAULT_REACT_OPTIONS, ...options };
11
+ return {
12
+ name: "react",
13
+ async execute(context) {
14
+ const { llm, input, state, strategy, signal } = context;
15
+ let currentState = state.withMessage(input).withMetadata("agentId", context.agent.id);
16
+ let step = 0;
17
+ let finalTurn;
18
+ const messages = [...currentState.messages];
19
+ while (true) {
20
+ step++;
21
+ currentState = currentState.withStep(step);
22
+ if (signal?.aborted) {
23
+ throw new Error("Execution aborted");
24
+ }
25
+ strategy.onStepStart?.(step, currentState);
26
+ const reasoningMessages = [
27
+ ...messages,
28
+ new UserMessage(opts.reasoningPrompt)
29
+ ];
30
+ const reasoningTurn = await llm.generate(reasoningMessages);
31
+ const reasoning = reasoningTurn.response.text;
32
+ currentState = currentState.withReasoning(reasoning);
33
+ strategy.onReason?.(step, reasoning);
34
+ messages.push(...reasoningTurn.messages);
35
+ const actionPrompt = new UserMessage(
36
+ "Based on your reasoning, take the appropriate action. Use tools if needed, or provide a final answer."
37
+ );
38
+ messages.push(actionPrompt);
39
+ const actionTurn = await llm.generate(messages);
40
+ finalTurn = actionTurn;
41
+ messages.push(...actionTurn.messages);
42
+ currentState = currentState.withMessages(actionTurn.messages);
43
+ if (actionTurn.response.hasToolCalls) {
44
+ strategy.onAct?.(step, actionTurn.response.toolCalls ?? []);
45
+ }
46
+ if (actionTurn.toolExecutions && actionTurn.toolExecutions.length > 0) {
47
+ strategy.onObserve?.(step, actionTurn.toolExecutions);
48
+ }
49
+ strategy.onStepEnd?.(step, { turn: actionTurn, state: currentState });
50
+ const shouldStop = await strategy.stopCondition?.(currentState);
51
+ if (shouldStop) {
52
+ break;
53
+ }
54
+ if (!actionTurn.response.hasToolCalls) {
55
+ break;
56
+ }
57
+ if (opts.maxSteps !== Infinity && step >= opts.maxSteps) {
58
+ break;
59
+ }
60
+ }
61
+ if (!finalTurn) {
62
+ throw new Error("No turn generated");
63
+ }
64
+ let finalState = currentState;
65
+ if (context.sessionId) {
66
+ finalState = currentState.withMetadata("sessionId", context.sessionId);
67
+ }
68
+ const result = {
69
+ turn: finalTurn,
70
+ state: finalState
71
+ };
72
+ strategy.onComplete?.(result);
73
+ return result;
74
+ },
75
+ stream(context) {
76
+ const { llm, input, state, strategy, signal } = context;
77
+ const agentId = context.agent.id;
78
+ let aborted = false;
79
+ const abortController = new AbortController();
80
+ if (signal) {
81
+ signal.addEventListener("abort", () => abortController.abort());
82
+ }
83
+ let resolveResult;
84
+ let rejectResult;
85
+ const resultPromise = new Promise((resolve, reject) => {
86
+ resolveResult = resolve;
87
+ rejectResult = reject;
88
+ });
89
+ async function* generateEvents() {
90
+ let currentState = state.withMessage(input).withMetadata("agentId", context.agent.id);
91
+ let step = 0;
92
+ let finalTurn;
93
+ const messages = [...currentState.messages];
94
+ try {
95
+ while (!aborted) {
96
+ step++;
97
+ currentState = currentState.withStep(step);
98
+ if (abortController.signal.aborted) {
99
+ throw new Error("Execution aborted");
100
+ }
101
+ strategy.onStepStart?.(step, currentState);
102
+ yield {
103
+ source: "uap",
104
+ uap: {
105
+ type: "step_start",
106
+ step,
107
+ agentId,
108
+ data: { phase: "reasoning" }
109
+ }
110
+ };
111
+ const reasoningMessages = [
112
+ ...messages,
113
+ new UserMessage(opts.reasoningPrompt)
114
+ ];
115
+ const reasoningStream = llm.stream(reasoningMessages);
116
+ let reasoningText = "";
117
+ for await (const event of reasoningStream) {
118
+ if (abortController.signal.aborted) {
119
+ throw new Error("Execution aborted");
120
+ }
121
+ yield { source: "upp", upp: event };
122
+ if (event.type === "text_delta" && event.delta.text) {
123
+ reasoningText += event.delta.text;
124
+ }
125
+ }
126
+ const reasoningTurn = await reasoningStream.turn;
127
+ currentState = currentState.withReasoning(reasoningText || reasoningTurn.response.text);
128
+ strategy.onReason?.(step, reasoningText || reasoningTurn.response.text);
129
+ yield {
130
+ source: "uap",
131
+ uap: {
132
+ type: "reasoning",
133
+ step,
134
+ agentId,
135
+ data: { reasoning: reasoningText || reasoningTurn.response.text }
136
+ }
137
+ };
138
+ messages.push(...reasoningTurn.messages);
139
+ const actionPrompt = new UserMessage(
140
+ "Based on your reasoning, take the appropriate action. Use tools if needed, or provide a final answer."
141
+ );
142
+ messages.push(actionPrompt);
143
+ const actionStream = llm.stream(messages);
144
+ for await (const event of actionStream) {
145
+ if (abortController.signal.aborted) {
146
+ throw new Error("Execution aborted");
147
+ }
148
+ yield { source: "upp", upp: event };
149
+ }
150
+ const actionTurn = await actionStream.turn;
151
+ finalTurn = actionTurn;
152
+ messages.push(...actionTurn.messages);
153
+ currentState = currentState.withMessages(actionTurn.messages);
154
+ if (actionTurn.response.hasToolCalls) {
155
+ strategy.onAct?.(step, actionTurn.response.toolCalls ?? []);
156
+ yield {
157
+ source: "uap",
158
+ uap: {
159
+ type: "action",
160
+ step,
161
+ agentId,
162
+ data: { toolCalls: actionTurn.response.toolCalls }
163
+ }
164
+ };
165
+ }
166
+ if (actionTurn.toolExecutions && actionTurn.toolExecutions.length > 0) {
167
+ strategy.onObserve?.(step, actionTurn.toolExecutions);
168
+ yield {
169
+ source: "uap",
170
+ uap: {
171
+ type: "observation",
172
+ step,
173
+ agentId,
174
+ data: { observations: actionTurn.toolExecutions }
175
+ }
176
+ };
177
+ }
178
+ strategy.onStepEnd?.(step, { turn: actionTurn, state: currentState });
179
+ yield {
180
+ source: "uap",
181
+ uap: {
182
+ type: "step_end",
183
+ step,
184
+ agentId,
185
+ data: { phase: "complete" }
186
+ }
187
+ };
188
+ const shouldStop = await strategy.stopCondition?.(currentState);
189
+ if (shouldStop) {
190
+ break;
191
+ }
192
+ if (!actionTurn.response.hasToolCalls) {
193
+ break;
194
+ }
195
+ if (opts.maxSteps !== Infinity && step >= opts.maxSteps) {
196
+ break;
197
+ }
198
+ }
199
+ if (!finalTurn) {
200
+ throw new Error("No turn generated");
201
+ }
202
+ let finalState = currentState;
203
+ if (context.sessionId) {
204
+ finalState = currentState.withMetadata("sessionId", context.sessionId);
205
+ }
206
+ const result = {
207
+ turn: finalTurn,
208
+ state: finalState
209
+ };
210
+ strategy.onComplete?.(result);
211
+ resolveResult(result);
212
+ } catch (error) {
213
+ const err = error instanceof Error ? error : new Error(String(error));
214
+ strategy.onError?.(err, currentState);
215
+ rejectResult(err);
216
+ throw err;
217
+ }
218
+ }
219
+ const iterator = generateEvents();
220
+ return {
221
+ [Symbol.asyncIterator]() {
222
+ return iterator;
223
+ },
224
+ result: resultPromise,
225
+ abort() {
226
+ aborted = true;
227
+ abortController.abort();
228
+ }
229
+ };
230
+ }
231
+ };
232
+ }
233
+ var DEFAULT_PLAN_OPTIONS = {
234
+ maxPlanSteps: Infinity,
235
+ allowReplan: true,
236
+ planSchema: {
237
+ type: "object",
238
+ properties: {
239
+ steps: {
240
+ type: "array",
241
+ items: {
242
+ type: "object",
243
+ properties: {
244
+ id: { type: "string", description: "Unique step identifier" },
245
+ description: { type: "string", description: "What this step does" },
246
+ tool: { type: "string", description: "Tool to use (if applicable)" },
247
+ dependsOn: {
248
+ type: "array",
249
+ items: { type: "string" },
250
+ description: "IDs of steps this depends on"
251
+ }
252
+ },
253
+ required: ["id", "description", "dependsOn"]
254
+ }
255
+ }
256
+ },
257
+ required: ["steps"]
258
+ }
259
+ };
260
+ var PLAN_PROMPT = `Create a detailed execution plan to accomplish the task.
261
+ Break it down into clear steps, specifying which tool to use for each step if applicable.
262
+ Include dependencies between steps (which steps must complete before others can start).
263
+ Return your plan as a JSON object with a "steps" array.`;
264
+ function plan(options = {}) {
265
+ const opts = { ...DEFAULT_PLAN_OPTIONS, ...options };
266
+ return {
267
+ name: "plan",
268
+ async execute(context) {
269
+ const { llm, input, state, strategy, signal } = context;
270
+ let currentState = state.withMessage(input).withMetadata("agentId", context.agent.id);
271
+ let step = 0;
272
+ let finalTurn;
273
+ const messages = [...currentState.messages];
274
+ step++;
275
+ currentState = currentState.withStep(step);
276
+ if (signal?.aborted) {
277
+ throw new Error("Execution aborted");
278
+ }
279
+ strategy.onStepStart?.(step, currentState);
280
+ const planMessages = [
281
+ ...messages,
282
+ new UserMessage(PLAN_PROMPT)
283
+ ];
284
+ const planTurn = await llm.generate(planMessages);
285
+ let planData;
286
+ try {
287
+ if (planTurn.data) {
288
+ planData = planTurn.data;
289
+ } else {
290
+ const jsonMatch = planTurn.response.text.match(/\{[\s\S]*\}/);
291
+ if (jsonMatch) {
292
+ planData = JSON.parse(jsonMatch[0]);
293
+ } else {
294
+ throw new Error("Could not parse plan from response");
295
+ }
296
+ }
297
+ } catch (err) {
298
+ throw new Error(`Failed to parse execution plan: ${err instanceof Error ? err.message : String(err)}`);
299
+ }
300
+ let planSteps = planData.steps.map((s) => ({
301
+ id: s.id || generateUUID(),
302
+ description: s.description,
303
+ tool: s.tool,
304
+ dependsOn: s.dependsOn || [],
305
+ status: "pending"
306
+ }));
307
+ if (opts.maxPlanSteps !== Infinity && planSteps.length > opts.maxPlanSteps) {
308
+ planSteps = planSteps.slice(0, opts.maxPlanSteps);
309
+ }
310
+ currentState = currentState.withPlan(planSteps);
311
+ messages.push(...planTurn.messages);
312
+ strategy.onStepEnd?.(step, { turn: planTurn, state: currentState });
313
+ const completedSteps = /* @__PURE__ */ new Set();
314
+ while (planSteps.some((s) => s.status === "pending")) {
315
+ const nextStep = planSteps.find(
316
+ (s) => s.status === "pending" && s.dependsOn.every((depId) => completedSteps.has(depId))
317
+ );
318
+ if (!nextStep) {
319
+ break;
320
+ }
321
+ step++;
322
+ currentState = currentState.withStep(step);
323
+ if (signal?.aborted) {
324
+ throw new Error("Execution aborted");
325
+ }
326
+ strategy.onStepStart?.(step, currentState);
327
+ nextStep.status = "in_progress";
328
+ currentState = currentState.withPlan([...planSteps]);
329
+ const stepPrompt = new UserMessage(
330
+ `Execute step "${nextStep.id}": ${nextStep.description}${nextStep.tool ? ` using the ${nextStep.tool} tool` : ""}`
331
+ );
332
+ messages.push(stepPrompt);
333
+ try {
334
+ const stepTurn = await llm.generate(messages);
335
+ finalTurn = stepTurn;
336
+ messages.push(...stepTurn.messages);
337
+ currentState = currentState.withMessages(stepTurn.messages);
338
+ if (stepTurn.response.hasToolCalls) {
339
+ strategy.onAct?.(step, stepTurn.response.toolCalls ?? []);
340
+ }
341
+ if (stepTurn.toolExecutions && stepTurn.toolExecutions.length > 0) {
342
+ strategy.onObserve?.(step, stepTurn.toolExecutions);
343
+ }
344
+ nextStep.status = "completed";
345
+ completedSteps.add(nextStep.id);
346
+ currentState = currentState.withPlan([...planSteps]);
347
+ strategy.onStepEnd?.(step, { turn: stepTurn, state: currentState });
348
+ } catch (err) {
349
+ nextStep.status = "failed";
350
+ currentState = currentState.withPlan([...planSteps]);
351
+ throw err;
352
+ }
353
+ const shouldStop = await strategy.stopCondition?.(currentState);
354
+ if (shouldStop) {
355
+ break;
356
+ }
357
+ }
358
+ if (!finalTurn) {
359
+ finalTurn = planTurn;
360
+ }
361
+ let finalState = currentState;
362
+ if (context.sessionId) {
363
+ finalState = currentState.withMetadata("sessionId", context.sessionId);
364
+ }
365
+ const result = {
366
+ turn: finalTurn,
367
+ state: finalState
368
+ };
369
+ strategy.onComplete?.(result);
370
+ return result;
371
+ },
372
+ stream(context) {
373
+ const { llm, input, state, strategy, signal } = context;
374
+ const agentId = context.agent.id;
375
+ let aborted = false;
376
+ const abortController = new AbortController();
377
+ if (signal) {
378
+ signal.addEventListener("abort", () => abortController.abort());
379
+ }
380
+ let resolveResult;
381
+ let rejectResult;
382
+ const resultPromise = new Promise((resolve, reject) => {
383
+ resolveResult = resolve;
384
+ rejectResult = reject;
385
+ });
386
+ async function* generateEvents() {
387
+ let currentState = state.withMessage(input).withMetadata("agentId", context.agent.id);
388
+ let step = 0;
389
+ let finalTurn;
390
+ const messages = [...currentState.messages];
391
+ try {
392
+ step++;
393
+ currentState = currentState.withStep(step);
394
+ if (abortController.signal.aborted) {
395
+ throw new Error("Execution aborted");
396
+ }
397
+ strategy.onStepStart?.(step, currentState);
398
+ yield {
399
+ source: "uap",
400
+ uap: {
401
+ type: "step_start",
402
+ step,
403
+ agentId,
404
+ data: { phase: "planning" }
405
+ }
406
+ };
407
+ const planMessages = [
408
+ ...messages,
409
+ new UserMessage(PLAN_PROMPT)
410
+ ];
411
+ const planStream = llm.stream(planMessages);
412
+ for await (const event of planStream) {
413
+ if (abortController.signal.aborted) {
414
+ throw new Error("Execution aborted");
415
+ }
416
+ yield { source: "upp", upp: event };
417
+ }
418
+ const planTurn = await planStream.turn;
419
+ let planData;
420
+ try {
421
+ if (planTurn.data) {
422
+ planData = planTurn.data;
423
+ } else {
424
+ const jsonMatch = planTurn.response.text.match(/\{[\s\S]*\}/);
425
+ if (jsonMatch) {
426
+ planData = JSON.parse(jsonMatch[0]);
427
+ } else {
428
+ throw new Error("Could not parse plan from response");
429
+ }
430
+ }
431
+ } catch (err) {
432
+ throw new Error(`Failed to parse execution plan: ${err instanceof Error ? err.message : String(err)}`);
433
+ }
434
+ let planSteps = planData.steps.map((s) => ({
435
+ id: s.id || generateUUID(),
436
+ description: s.description,
437
+ tool: s.tool,
438
+ dependsOn: s.dependsOn || [],
439
+ status: "pending"
440
+ }));
441
+ if (opts.maxPlanSteps !== Infinity && planSteps.length > opts.maxPlanSteps) {
442
+ planSteps = planSteps.slice(0, opts.maxPlanSteps);
443
+ }
444
+ currentState = currentState.withPlan(planSteps);
445
+ messages.push(...planTurn.messages);
446
+ yield {
447
+ source: "uap",
448
+ uap: {
449
+ type: "plan_created",
450
+ step,
451
+ agentId,
452
+ data: { plan: planSteps }
453
+ }
454
+ };
455
+ strategy.onStepEnd?.(step, { turn: planTurn, state: currentState });
456
+ yield {
457
+ source: "uap",
458
+ uap: {
459
+ type: "step_end",
460
+ step,
461
+ agentId,
462
+ data: { phase: "planning" }
463
+ }
464
+ };
465
+ const completedSteps = /* @__PURE__ */ new Set();
466
+ while (planSteps.some((s) => s.status === "pending") && !aborted) {
467
+ const nextStep = planSteps.find(
468
+ (s) => s.status === "pending" && s.dependsOn.every((depId) => completedSteps.has(depId))
469
+ );
470
+ if (!nextStep) {
471
+ break;
472
+ }
473
+ step++;
474
+ currentState = currentState.withStep(step);
475
+ if (abortController.signal.aborted) {
476
+ throw new Error("Execution aborted");
477
+ }
478
+ strategy.onStepStart?.(step, currentState);
479
+ yield {
480
+ source: "uap",
481
+ uap: {
482
+ type: "plan_step_start",
483
+ step,
484
+ agentId,
485
+ data: { planStep: nextStep }
486
+ }
487
+ };
488
+ nextStep.status = "in_progress";
489
+ currentState = currentState.withPlan([...planSteps]);
490
+ const stepPrompt = new UserMessage(
491
+ `Execute step "${nextStep.id}": ${nextStep.description}${nextStep.tool ? ` using the ${nextStep.tool} tool` : ""}`
492
+ );
493
+ messages.push(stepPrompt);
494
+ const stepStream = llm.stream(messages);
495
+ for await (const event of stepStream) {
496
+ if (abortController.signal.aborted) {
497
+ throw new Error("Execution aborted");
498
+ }
499
+ yield { source: "upp", upp: event };
500
+ }
501
+ const stepTurn = await stepStream.turn;
502
+ finalTurn = stepTurn;
503
+ messages.push(...stepTurn.messages);
504
+ currentState = currentState.withMessages(stepTurn.messages);
505
+ if (stepTurn.response.hasToolCalls) {
506
+ strategy.onAct?.(step, stepTurn.response.toolCalls ?? []);
507
+ yield {
508
+ source: "uap",
509
+ uap: {
510
+ type: "action",
511
+ step,
512
+ agentId,
513
+ data: { toolCalls: stepTurn.response.toolCalls }
514
+ }
515
+ };
516
+ }
517
+ if (stepTurn.toolExecutions && stepTurn.toolExecutions.length > 0) {
518
+ strategy.onObserve?.(step, stepTurn.toolExecutions);
519
+ yield {
520
+ source: "uap",
521
+ uap: {
522
+ type: "observation",
523
+ step,
524
+ agentId,
525
+ data: { observations: stepTurn.toolExecutions }
526
+ }
527
+ };
528
+ }
529
+ nextStep.status = "completed";
530
+ completedSteps.add(nextStep.id);
531
+ currentState = currentState.withPlan([...planSteps]);
532
+ strategy.onStepEnd?.(step, { turn: stepTurn, state: currentState });
533
+ yield {
534
+ source: "uap",
535
+ uap: {
536
+ type: "plan_step_end",
537
+ step,
538
+ agentId,
539
+ data: { planStep: nextStep }
540
+ }
541
+ };
542
+ const shouldStop = await strategy.stopCondition?.(currentState);
543
+ if (shouldStop) {
544
+ break;
545
+ }
546
+ }
547
+ if (!finalTurn) {
548
+ finalTurn = planTurn;
549
+ }
550
+ let finalState = currentState;
551
+ if (context.sessionId) {
552
+ finalState = currentState.withMetadata("sessionId", context.sessionId);
553
+ }
554
+ const result = {
555
+ turn: finalTurn,
556
+ state: finalState
557
+ };
558
+ strategy.onComplete?.(result);
559
+ resolveResult(result);
560
+ } catch (error) {
561
+ const err = error instanceof Error ? error : new Error(String(error));
562
+ strategy.onError?.(err, currentState);
563
+ rejectResult(err);
564
+ throw err;
565
+ }
566
+ }
567
+ const iterator = generateEvents();
568
+ return {
569
+ [Symbol.asyncIterator]() {
570
+ return iterator;
571
+ },
572
+ result: resultPromise,
573
+ abort() {
574
+ aborted = true;
575
+ abortController.abort();
576
+ }
577
+ };
578
+ }
579
+ };
580
+ }
581
+
582
+ // src/execution/tool-ordering.ts
583
+ function buildToolMap(tools) {
584
+ const map = /* @__PURE__ */ new Map();
585
+ for (const tool of tools) {
586
+ map.set(tool.name, tool);
587
+ }
588
+ return map;
589
+ }
590
+ function getModelDependencies(call) {
591
+ const orderedCall = call;
592
+ return orderedCall.after ?? [];
593
+ }
594
+ function orderToolCalls(toolCalls, tools) {
595
+ if (toolCalls.length === 0) {
596
+ return [];
597
+ }
598
+ const toolMap = buildToolMap(tools);
599
+ const groups = [];
600
+ const completedCallIds = /* @__PURE__ */ new Set();
601
+ const completedToolNames = /* @__PURE__ */ new Set();
602
+ const pending = [...toolCalls];
603
+ while (pending.length > 0) {
604
+ const readyForExecution = [];
605
+ let hasSequential = false;
606
+ const stillPending = [];
607
+ for (const call of pending) {
608
+ const tool = toolMap.get(call.toolName);
609
+ const toolDependsOn = tool?.dependsOn ?? [];
610
+ const modelDependsOn = getModelDependencies(call);
611
+ const toolDepsOk = toolDependsOn.every(
612
+ (depName) => completedToolNames.has(depName)
613
+ );
614
+ const modelDepsOk = modelDependsOn.every(
615
+ (depId) => completedCallIds.has(depId)
616
+ );
617
+ if (toolDepsOk && modelDepsOk) {
618
+ readyForExecution.push(call);
619
+ if (tool?.sequential) {
620
+ hasSequential = true;
621
+ }
622
+ } else {
623
+ stillPending.push(call);
624
+ }
625
+ }
626
+ if (readyForExecution.length === 0 && stillPending.length > 0) {
627
+ groups.push({
628
+ calls: stillPending,
629
+ isBarrier: false
630
+ });
631
+ break;
632
+ }
633
+ if (hasSequential) {
634
+ for (const call of readyForExecution) {
635
+ const tool = toolMap.get(call.toolName);
636
+ groups.push({
637
+ calls: [call],
638
+ isBarrier: tool?.sequential ?? false
639
+ });
640
+ completedCallIds.add(call.toolCallId);
641
+ completedToolNames.add(call.toolName);
642
+ }
643
+ } else {
644
+ groups.push({
645
+ calls: readyForExecution,
646
+ isBarrier: false
647
+ });
648
+ for (const call of readyForExecution) {
649
+ completedCallIds.add(call.toolCallId);
650
+ completedToolNames.add(call.toolName);
651
+ }
652
+ }
653
+ pending.length = 0;
654
+ pending.push(...stillPending);
655
+ }
656
+ return groups;
657
+ }
658
+ function hasToolDependencies(tools) {
659
+ for (const tool of tools) {
660
+ const t = tool;
661
+ if (t.sequential || t.dependsOn && t.dependsOn.length > 0) {
662
+ return true;
663
+ }
664
+ }
665
+ return false;
666
+ }
667
+ function hasCallDependencies(toolCalls) {
668
+ for (const call of toolCalls) {
669
+ const ordered = call;
670
+ if (ordered.after && ordered.after.length > 0) {
671
+ return true;
672
+ }
673
+ }
674
+ return false;
675
+ }
676
+
677
+ export { hasCallDependencies, hasToolDependencies, orderToolCalls, plan, react };
678
+ //# sourceMappingURL=index.js.map
679
+ //# sourceMappingURL=index.js.map