@providerprotocol/agents 0.0.2 → 0.0.4

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/LICENSE +21 -0
  2. package/dist/checkpoint/index.d.ts +43 -0
  3. package/dist/checkpoint/index.js +73 -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-T47B3VAF.js +427 -0
  10. package/dist/chunk-T47B3VAF.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-BiyEVOnf.d.ts +65 -0
  26. package/dist/types-D1egxttz.d.ts +270 -0
  27. package/dist/types-DChRdQoX.d.ts +98 -0
  28. package/package.json +41 -9
  29. package/.claude/settings.local.json +0 -29
  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
@@ -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
- });