@providerprotocol/agents 0.0.2 → 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 (73) hide show
  1. package/dist/checkpoint/index.d.ts +43 -0
  2. package/dist/checkpoint/index.js +64 -0
  3. package/dist/checkpoint/index.js.map +1 -0
  4. package/{src/execution/loop.ts → dist/chunk-4ESYN66B.js} +54 -162
  5. package/dist/chunk-4ESYN66B.js.map +1 -0
  6. package/dist/chunk-EKRXMSDX.js +8 -0
  7. package/dist/chunk-EKRXMSDX.js.map +1 -0
  8. package/dist/chunk-PHI5ULBV.js +427 -0
  9. package/dist/chunk-PHI5ULBV.js.map +1 -0
  10. package/dist/execution/index.d.ts +105 -0
  11. package/dist/execution/index.js +679 -0
  12. package/dist/execution/index.js.map +1 -0
  13. package/dist/index-qsPwbY86.d.ts +65 -0
  14. package/dist/index.d.ts +101 -0
  15. package/dist/index.js +218 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/middleware/index.d.ts +23 -0
  18. package/dist/middleware/index.js +82 -0
  19. package/dist/middleware/index.js.map +1 -0
  20. package/dist/thread-tree/index.d.ts +115 -0
  21. package/dist/thread-tree/index.js +4 -0
  22. package/dist/thread-tree/index.js.map +1 -0
  23. package/dist/types-2Vsthzyu.d.ts +163 -0
  24. package/dist/types-BhX9uD_d.d.ts +91 -0
  25. package/dist/types-DR02gtFv.d.ts +270 -0
  26. package/dist/types-NGQMdnaD.d.ts +65 -0
  27. package/package.json +40 -8
  28. package/.claude/settings.local.json +0 -29
  29. package/AGENTS.md +0 -681
  30. package/CLAUDE.md +0 -681
  31. package/bun.lock +0 -472
  32. package/eslint.config.js +0 -75
  33. package/index.ts +0 -1
  34. package/llms.md +0 -796
  35. package/specs/UAP-1.0.md +0 -2355
  36. package/src/agent/index.ts +0 -384
  37. package/src/agent/types.ts +0 -91
  38. package/src/checkpoint/file.ts +0 -126
  39. package/src/checkpoint/index.ts +0 -40
  40. package/src/checkpoint/types.ts +0 -95
  41. package/src/execution/index.ts +0 -37
  42. package/src/execution/plan.ts +0 -497
  43. package/src/execution/react.ts +0 -340
  44. package/src/execution/tool-ordering.ts +0 -186
  45. package/src/execution/types.ts +0 -315
  46. package/src/index.ts +0 -80
  47. package/src/middleware/index.ts +0 -7
  48. package/src/middleware/logging.ts +0 -123
  49. package/src/middleware/types.ts +0 -69
  50. package/src/state/index.ts +0 -301
  51. package/src/state/types.ts +0 -173
  52. package/src/thread-tree/index.ts +0 -249
  53. package/src/thread-tree/types.ts +0 -29
  54. package/src/utils/uuid.ts +0 -7
  55. package/tests/live/agent-anthropic.test.ts +0 -288
  56. package/tests/live/agent-strategy-hooks.test.ts +0 -268
  57. package/tests/live/checkpoint.test.ts +0 -243
  58. package/tests/live/execution-strategies.test.ts +0 -255
  59. package/tests/live/plan-strategy.test.ts +0 -160
  60. package/tests/live/subagent-events.live.test.ts +0 -249
  61. package/tests/live/thread-tree.test.ts +0 -186
  62. package/tests/unit/agent.test.ts +0 -703
  63. package/tests/unit/checkpoint.test.ts +0 -232
  64. package/tests/unit/execution/equivalence.test.ts +0 -402
  65. package/tests/unit/execution/loop.test.ts +0 -437
  66. package/tests/unit/execution/plan.test.ts +0 -590
  67. package/tests/unit/execution/react.test.ts +0 -604
  68. package/tests/unit/execution/subagent-events.test.ts +0 -235
  69. package/tests/unit/execution/tool-ordering.test.ts +0 -310
  70. package/tests/unit/middleware/logging.test.ts +0 -276
  71. package/tests/unit/state.test.ts +0 -573
  72. package/tests/unit/thread-tree.test.ts +0 -249
  73. package/tsconfig.json +0 -29
@@ -1,590 +0,0 @@
1
- import { describe, test, expect, mock, beforeEach } from 'bun:test';
2
- import { UserMessage, AssistantMessage } from '@providerprotocol/ai';
3
- import type { Turn, LLMInstance, Tool, ToolCall, ToolExecution } from '@providerprotocol/ai';
4
- import { plan } from '../../../src/execution/plan.ts';
5
- import { AgentState } from '../../../src/state/index.ts';
6
- import type { ExecutionContext } from '../../../src/execution/types.ts';
7
-
8
- // Mock Turn factory
9
- function createMockTurn(options: {
10
- text?: string;
11
- toolCalls?: ToolCall[];
12
- toolExecutions?: ToolExecution[];
13
- data?: unknown;
14
- }): Turn {
15
- const response = new AssistantMessage(options.text ?? 'Hello', options.toolCalls);
16
- return {
17
- response,
18
- messages: [response],
19
- toolExecutions: options.toolExecutions ?? [],
20
- data: options.data,
21
- usage: {
22
- inputTokens: 10,
23
- outputTokens: 20,
24
- totalTokens: 30,
25
- },
26
- cycles: 1,
27
- } as unknown as Turn;
28
- }
29
-
30
- // Mock LLM factory
31
- function createMockLLM(turnSequence: Turn[]): LLMInstance {
32
- let callIndex = 0;
33
-
34
- return {
35
- generate: mock(async () => {
36
- const turn = turnSequence[callIndex] ?? turnSequence[turnSequence.length - 1];
37
- callIndex++;
38
- return turn;
39
- }),
40
- stream: mock(() => {
41
- const turn = turnSequence[callIndex] ?? turnSequence[turnSequence.length - 1];
42
- callIndex++;
43
-
44
- const events: Array<{ type: string; delta?: { text?: string } }> = [];
45
- if (turn) {
46
- events.push({ type: 'text_delta', delta: { text: turn.response.text } });
47
- events.push({ type: 'message_stop' });
48
- }
49
-
50
- return {
51
- async *[Symbol.asyncIterator]() {
52
- for (const event of events) {
53
- yield event;
54
- }
55
- },
56
- turn: Promise.resolve(turn),
57
- };
58
- }),
59
- } as unknown as LLMInstance;
60
- }
61
-
62
- // Create a plan response turn
63
- function createPlanTurn(steps: Array<{ id: string; description: string; tool?: string; dependsOn?: string[] }>): Turn {
64
- const planData = {
65
- steps: steps.map((s) => ({
66
- id: s.id,
67
- description: s.description,
68
- tool: s.tool,
69
- dependsOn: s.dependsOn ?? [],
70
- })),
71
- };
72
-
73
- return createMockTurn({
74
- text: JSON.stringify(planData),
75
- data: planData,
76
- });
77
- }
78
-
79
- describe('plan() execution strategy', () => {
80
- let state: AgentState;
81
- let input: UserMessage;
82
- let tools: Tool[];
83
-
84
- beforeEach(() => {
85
- state = AgentState.initial();
86
- input = new UserMessage('Complete this task');
87
- tools = [];
88
- });
89
-
90
- describe('execute()', () => {
91
- test('returns turn and updated state', async () => {
92
- const planTurn = createPlanTurn([
93
- { id: 'step-1', description: 'First step' },
94
- ]);
95
- const executionTurn = createMockTurn({ text: 'Step 1 completed.' });
96
-
97
- const llm = createMockLLM([planTurn, executionTurn]);
98
-
99
- const strategy = plan();
100
- const context: ExecutionContext = {
101
- agent: { id: 'test-agent' },
102
- llm,
103
- input,
104
- state,
105
- tools,
106
- strategy: {},
107
- };
108
-
109
- const result = await strategy.execute(context);
110
-
111
- expect(result.turn).toBeDefined();
112
- expect(result.state).toBeDefined();
113
- });
114
-
115
- test('creates plan in first phase', async () => {
116
- const planTurn = createPlanTurn([
117
- { id: 'step-1', description: 'First step' },
118
- { id: 'step-2', description: 'Second step', dependsOn: ['step-1'] },
119
- ]);
120
- const step1Turn = createMockTurn({ text: 'Step 1 done.' });
121
- const step2Turn = createMockTurn({ text: 'Step 2 done.' });
122
-
123
- const llm = createMockLLM([planTurn, step1Turn, step2Turn]);
124
-
125
- const strategy = plan();
126
- const context: ExecutionContext = {
127
- agent: { id: 'test-agent' },
128
- llm,
129
- input,
130
- state,
131
- tools,
132
- strategy: {},
133
- };
134
-
135
- const result = await strategy.execute(context);
136
-
137
- expect(result.state.plan).toBeDefined();
138
- expect(result.state.plan).toHaveLength(2);
139
- });
140
-
141
- test('executes plan steps in order', async () => {
142
- const planTurn = createPlanTurn([
143
- { id: 'step-1', description: 'First step' },
144
- { id: 'step-2', description: 'Second step', dependsOn: ['step-1'] },
145
- ]);
146
- const step1Turn = createMockTurn({ text: 'Step 1 done.' });
147
- const step2Turn = createMockTurn({ text: 'Step 2 done.' });
148
-
149
- const llm = createMockLLM([planTurn, step1Turn, step2Turn]);
150
-
151
- const strategy = plan();
152
- const context: ExecutionContext = {
153
- agent: { id: 'test-agent' },
154
- llm,
155
- input,
156
- state,
157
- tools,
158
- strategy: {},
159
- };
160
-
161
- const result = await strategy.execute(context);
162
-
163
- // 3 calls: planning + step1 + step2
164
- expect(llm.generate).toHaveBeenCalledTimes(3);
165
-
166
- // Both steps should be completed
167
- const completedSteps = result.state.plan?.filter((s) => s.status === 'completed');
168
- expect(completedSteps).toHaveLength(2);
169
- });
170
-
171
- test('respects step dependencies', async () => {
172
- // step-3 depends on step-1 and step-2
173
- const planTurn = createPlanTurn([
174
- { id: 'step-1', description: 'First step' },
175
- { id: 'step-2', description: 'Second step' },
176
- { id: 'step-3', description: 'Third step', dependsOn: ['step-1', 'step-2'] },
177
- ]);
178
- const step1Turn = createMockTurn({ text: 'Step 1.' });
179
- const step2Turn = createMockTurn({ text: 'Step 2.' });
180
- const step3Turn = createMockTurn({ text: 'Step 3.' });
181
-
182
- const llm = createMockLLM([planTurn, step1Turn, step2Turn, step3Turn]);
183
-
184
- const strategy = plan();
185
- const context: ExecutionContext = {
186
- agent: { id: 'test-agent' },
187
- llm,
188
- input,
189
- state,
190
- tools,
191
- strategy: {},
192
- };
193
-
194
- const result = await strategy.execute(context);
195
-
196
- // All 3 steps + planning = 4 calls
197
- expect(llm.generate).toHaveBeenCalledTimes(4);
198
-
199
- // All should be completed
200
- const completedSteps = result.state.plan?.filter((s) => s.status === 'completed');
201
- expect(completedSteps).toHaveLength(3);
202
- });
203
-
204
- test('respects maxPlanSteps', async () => {
205
- const planTurn = createPlanTurn([
206
- { id: 'step-1', description: 'First step' },
207
- { id: 'step-2', description: 'Second step' },
208
- { id: 'step-3', description: 'Third step' },
209
- { id: 'step-4', description: 'Fourth step' },
210
- { id: 'step-5', description: 'Fifth step' },
211
- ]);
212
- const stepTurn = createMockTurn({ text: 'Step done.' });
213
-
214
- const llm = createMockLLM([planTurn, stepTurn, stepTurn, stepTurn, stepTurn, stepTurn]);
215
-
216
- const strategy = plan({ maxPlanSteps: 3 });
217
- const context: ExecutionContext = {
218
- agent: { id: 'test-agent' },
219
- llm,
220
- input,
221
- state,
222
- tools,
223
- strategy: {},
224
- };
225
-
226
- const result = await strategy.execute(context);
227
-
228
- // Plan should be truncated to 3 steps
229
- expect(result.state.plan).toHaveLength(3);
230
- });
231
-
232
- test('defaults to Infinity maxPlanSteps', () => {
233
- const strategy = plan();
234
- expect(strategy.name).toBe('plan');
235
- });
236
-
237
- test('parses plan from JSON in response text', async () => {
238
- // Plan without data field, only in text
239
- const planText = JSON.stringify({
240
- steps: [
241
- { id: 'step-1', description: 'First step', dependsOn: [] },
242
- ],
243
- });
244
- const planTurn = createMockTurn({ text: `Here is the plan: ${planText}` });
245
- const stepTurn = createMockTurn({ text: 'Done.' });
246
-
247
- const llm = createMockLLM([planTurn, stepTurn]);
248
-
249
- const strategy = plan();
250
- const context: ExecutionContext = {
251
- agent: { id: 'test-agent' },
252
- llm,
253
- input,
254
- state,
255
- tools,
256
- strategy: {},
257
- };
258
-
259
- const result = await strategy.execute(context);
260
-
261
- expect(result.state.plan).toHaveLength(1);
262
- expect(result.state.plan?.[0]?.id).toBe('step-1');
263
- });
264
-
265
- test('calls onStepStart hook', async () => {
266
- const planTurn = createPlanTurn([
267
- { id: 'step-1', description: 'First step' },
268
- ]);
269
- const stepTurn = createMockTurn({ text: 'Done.' });
270
-
271
- const llm = createMockLLM([planTurn, stepTurn]);
272
- const onStepStart = mock(() => {});
273
-
274
- const strategy = plan();
275
- const context: ExecutionContext = {
276
- agent: { id: 'test-agent' },
277
- llm,
278
- input,
279
- state,
280
- tools,
281
- strategy: { onStepStart },
282
- };
283
-
284
- await strategy.execute(context);
285
-
286
- // Called for planning step + execution step
287
- expect(onStepStart).toHaveBeenCalledTimes(2);
288
- });
289
-
290
- test('calls onStepEnd hook', async () => {
291
- const planTurn = createPlanTurn([
292
- { id: 'step-1', description: 'First step' },
293
- ]);
294
- const stepTurn = createMockTurn({ text: 'Done.' });
295
-
296
- const llm = createMockLLM([planTurn, stepTurn]);
297
- const onStepEnd = mock(() => {});
298
-
299
- const strategy = plan();
300
- const context: ExecutionContext = {
301
- agent: { id: 'test-agent' },
302
- llm,
303
- input,
304
- state,
305
- tools,
306
- strategy: { onStepEnd },
307
- };
308
-
309
- await strategy.execute(context);
310
-
311
- // Called for planning step + execution step
312
- expect(onStepEnd).toHaveBeenCalledTimes(2);
313
- });
314
-
315
- test('calls onAct hook on tool calls', async () => {
316
- const toolCall: ToolCall = {
317
- toolCallId: 'call-1',
318
- toolName: 'test_tool',
319
- arguments: {},
320
- };
321
-
322
- const planTurn = createPlanTurn([
323
- { id: 'step-1', description: 'Use tool', tool: 'test_tool' },
324
- ]);
325
- const stepTurn = createMockTurn({
326
- text: 'Used tool.',
327
- toolCalls: [toolCall],
328
- });
329
-
330
- const llm = createMockLLM([planTurn, stepTurn]);
331
- const onAct = mock(() => {});
332
-
333
- const strategy = plan();
334
- const context: ExecutionContext = {
335
- agent: { id: 'test-agent' },
336
- llm,
337
- input,
338
- state,
339
- tools,
340
- strategy: { onAct },
341
- };
342
-
343
- await strategy.execute(context);
344
-
345
- expect(onAct).toHaveBeenCalledWith(2, [toolCall]);
346
- });
347
-
348
- test('calls onObserve hook on tool executions', async () => {
349
- const execution: ToolExecution = {
350
- toolCallId: 'call-1',
351
- toolName: 'test_tool',
352
- arguments: {},
353
- result: 'result',
354
- duration: 100,
355
- isError: false,
356
- };
357
-
358
- const planTurn = createPlanTurn([
359
- { id: 'step-1', description: 'Observe results' },
360
- ]);
361
- const stepTurn = createMockTurn({
362
- text: 'Observed.',
363
- toolExecutions: [execution],
364
- });
365
-
366
- const llm = createMockLLM([planTurn, stepTurn]);
367
- const onObserve = mock(() => {});
368
-
369
- const strategy = plan();
370
- const context: ExecutionContext = {
371
- agent: { id: 'test-agent' },
372
- llm,
373
- input,
374
- state,
375
- tools,
376
- strategy: { onObserve },
377
- };
378
-
379
- await strategy.execute(context);
380
-
381
- expect(onObserve).toHaveBeenCalledWith(2, [execution]);
382
- });
383
-
384
- test('calls onComplete hook', async () => {
385
- const planTurn = createPlanTurn([
386
- { id: 'step-1', description: 'Only step' },
387
- ]);
388
- const stepTurn = createMockTurn({ text: 'Done.' });
389
-
390
- const llm = createMockLLM([planTurn, stepTurn]);
391
- const onComplete = mock(() => {});
392
-
393
- const strategy = plan();
394
- const context: ExecutionContext = {
395
- agent: { id: 'test-agent' },
396
- llm,
397
- input,
398
- state,
399
- tools,
400
- strategy: { onComplete },
401
- };
402
-
403
- await strategy.execute(context);
404
-
405
- expect(onComplete).toHaveBeenCalledTimes(1);
406
- });
407
-
408
- test('respects stopCondition', async () => {
409
- const planTurn = createPlanTurn([
410
- { id: 'step-1', description: 'First' },
411
- { id: 'step-2', description: 'Second' },
412
- { id: 'step-3', description: 'Third' },
413
- ]);
414
- const stepTurn = createMockTurn({ text: 'Done.' });
415
-
416
- const llm = createMockLLM([planTurn, stepTurn, stepTurn, stepTurn]);
417
-
418
- const strategy = plan();
419
- const context: ExecutionContext = {
420
- agent: { id: 'test-agent' },
421
- llm,
422
- input,
423
- state,
424
- tools,
425
- strategy: {
426
- stopCondition: (s) => s.step >= 2, // Stop after first execution step
427
- },
428
- };
429
-
430
- const result = await strategy.execute(context);
431
-
432
- // Should have stopped early
433
- const completedSteps = result.state.plan?.filter((s) => s.status === 'completed');
434
- expect(completedSteps?.length).toBeLessThan(3);
435
- });
436
-
437
- test('updates step status during execution', async () => {
438
- const planTurn = createPlanTurn([
439
- { id: 'step-1', description: 'First step' },
440
- ]);
441
- const stepTurn = createMockTurn({ text: 'Step done.' });
442
-
443
- const llm = createMockLLM([planTurn, stepTurn]);
444
-
445
- const strategy = plan();
446
- const context: ExecutionContext = {
447
- agent: { id: 'test-agent' },
448
- llm,
449
- input,
450
- state,
451
- tools,
452
- strategy: {},
453
- };
454
-
455
- const result = await strategy.execute(context);
456
-
457
- // Step should be completed
458
- expect(result.state.plan?.[0]?.status).toBe('completed');
459
- });
460
- });
461
-
462
- describe('stream()', () => {
463
- test('yields events and resolves result', async () => {
464
- const planTurn = createPlanTurn([
465
- { id: 'step-1', description: 'Only step' },
466
- ]);
467
- const stepTurn = createMockTurn({ text: 'Done.' });
468
-
469
- const llm = createMockLLM([planTurn, stepTurn]);
470
-
471
- const strategy = plan();
472
- const context: ExecutionContext = {
473
- agent: { id: 'test-agent' },
474
- llm,
475
- input,
476
- state,
477
- tools,
478
- strategy: {},
479
- };
480
-
481
- const streamResult = strategy.stream(context);
482
- const events: unknown[] = [];
483
-
484
- for await (const event of streamResult) {
485
- events.push(event);
486
- }
487
-
488
- const result = await streamResult.result;
489
-
490
- expect(events.length).toBeGreaterThan(0);
491
- expect(result.turn).toBeDefined();
492
- expect(result.state).toBeDefined();
493
- });
494
-
495
- test('emits plan_created event', async () => {
496
- const planTurn = createPlanTurn([
497
- { id: 'step-1', description: 'First step' },
498
- ]);
499
- const stepTurn = createMockTurn({ text: 'Done.' });
500
-
501
- const llm = createMockLLM([planTurn, stepTurn]);
502
-
503
- const strategy = plan();
504
- const context: ExecutionContext = {
505
- agent: { id: 'test-agent' },
506
- llm,
507
- input,
508
- state,
509
- tools,
510
- strategy: {},
511
- };
512
-
513
- const streamResult = strategy.stream(context);
514
- const uapEvents: Array<{ source: string; uap?: { type: string } }> = [];
515
-
516
- for await (const event of streamResult) {
517
- if (event.source === 'uap') {
518
- uapEvents.push(event as typeof uapEvents[0]);
519
- }
520
- }
521
-
522
- await streamResult.result;
523
-
524
- const planCreated = uapEvents.find((e) => e.uap?.type === 'plan_created');
525
- expect(planCreated).toBeDefined();
526
- });
527
-
528
- test('emits plan_step_start and plan_step_end events', async () => {
529
- const planTurn = createPlanTurn([
530
- { id: 'step-1', description: 'First step' },
531
- ]);
532
- const stepTurn = createMockTurn({ text: 'Done.' });
533
-
534
- const llm = createMockLLM([planTurn, stepTurn]);
535
-
536
- const strategy = plan();
537
- const context: ExecutionContext = {
538
- agent: { id: 'test-agent' },
539
- llm,
540
- input,
541
- state,
542
- tools,
543
- strategy: {},
544
- };
545
-
546
- const streamResult = strategy.stream(context);
547
- const uapEvents: Array<{ source: string; uap?: { type: string } }> = [];
548
-
549
- for await (const event of streamResult) {
550
- if (event.source === 'uap') {
551
- uapEvents.push(event as typeof uapEvents[0]);
552
- }
553
- }
554
-
555
- await streamResult.result;
556
-
557
- const stepStart = uapEvents.find((e) => e.uap?.type === 'plan_step_start');
558
- const stepEnd = uapEvents.find((e) => e.uap?.type === 'plan_step_end');
559
-
560
- expect(stepStart).toBeDefined();
561
- expect(stepEnd).toBeDefined();
562
- });
563
-
564
- test('supports abort()', async () => {
565
- const planTurn = createPlanTurn([
566
- { id: 'step-1', description: 'Only step' },
567
- ]);
568
- const stepTurn = createMockTurn({ text: 'Done.' });
569
-
570
- const llm = createMockLLM([planTurn, stepTurn]);
571
-
572
- const strategy = plan();
573
- const context: ExecutionContext = {
574
- agent: { id: 'test-agent' },
575
- llm,
576
- input,
577
- state,
578
- tools,
579
- strategy: {},
580
- };
581
-
582
- const streamResult = strategy.stream(context);
583
-
584
- // Abort immediately
585
- streamResult.abort();
586
-
587
- expect(typeof streamResult.abort).toBe('function');
588
- });
589
- });
590
- });