@axlsdk/testing 0.3.0 → 0.4.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 (2) hide show
  1. package/README.md +61 -44
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -18,21 +18,24 @@ Mock LLM provider with multiple response modes:
18
18
  import { MockProvider } from '@axlsdk/testing';
19
19
 
20
20
  // Sequence mode — return responses in order
21
- const provider = MockProvider.sequence(['Hello!', 'World!']);
21
+ const provider = MockProvider.sequence([
22
+ { content: 'Hello!' },
23
+ { content: 'World!' },
24
+ ]);
22
25
 
23
26
  // Echo mode — return the user's prompt back
24
27
  const provider = MockProvider.echo();
25
28
 
26
- // JSON mode — return structured data
27
- const provider = MockProvider.json({ answer: 42, confidence: 0.95 });
29
+ // JSON mode — return data matching a Zod schema
30
+ const provider = MockProvider.json(z.object({ answer: z.number() }));
28
31
 
29
32
  // Replay mode — replay from a recorded file
30
33
  const provider = MockProvider.replay('./fixtures/conversation.json');
31
34
 
32
35
  // Function mode — custom response logic
33
- const provider = MockProvider.fn((messages, options) => {
36
+ const provider = MockProvider.fn((messages, callIndex) => {
34
37
  const lastMessage = messages[messages.length - 1];
35
- return `You said: ${lastMessage.content}`;
38
+ return { content: `You said: ${lastMessage.content}` };
36
39
  });
37
40
  ```
38
41
 
@@ -48,71 +51,73 @@ const provider = MockProvider.sequence([
48
51
  function: { name: 'calculator', arguments: '{"expression":"2+2"}' },
49
52
  }],
50
53
  },
51
- 'The answer is 4.',
54
+ { content: 'The answer is 4.' },
52
55
  ]);
53
56
  ```
54
57
 
55
58
  ### `MockTool`
56
59
 
57
- Wrap a tool to intercept and record calls:
60
+ Create a mock tool to intercept and record calls:
58
61
 
59
62
  ```typescript
60
63
  import { MockTool } from '@axlsdk/testing';
61
- import { calculator } from './tools';
62
-
63
- const mock = new MockTool(calculator);
64
64
 
65
- // Use in agent
66
- const myAgent = agent({ model: 'test:mock', system: 'Test', tools: [mock] });
65
+ const mock = MockTool.create('calculator', async ({ expression }) => ({
66
+ result: eval(expression),
67
+ }));
67
68
 
68
- // After execution, inspect calls
69
- console.log(mock.calls); // [{ input: { expression: '2+2' }, output: { result: 4 } }]
69
+ // Inspect calls after execution
70
+ console.log(mock.calls); // [{ input: { expression: '2+2' } }]
70
71
  ```
71
72
 
72
73
  ### `AxlTestRuntime`
73
74
 
74
- Test runtime that mirrors `WorkflowContext` for deterministic testing:
75
+ Test runtime that wraps `WorkflowContext` for deterministic testing:
75
76
 
76
77
  ```typescript
77
78
  import { AxlTestRuntime, MockProvider } from '@axlsdk/testing';
78
79
 
79
- const provider = MockProvider.sequence(['42']);
80
- const runtime = new AxlTestRuntime({ provider });
80
+ const runtime = new AxlTestRuntime();
81
+ runtime.register(myWorkflow);
82
+
83
+ // Mock the LLM
84
+ runtime.mockProvider('openai', MockProvider.sequence([
85
+ { content: '42' },
86
+ ]));
87
+
88
+ // Mock tools
89
+ runtime.mockTool('calculator', async ({ expression }) => ({ result: 4 }));
81
90
 
82
- // Ask an agent
83
- const result = await runtime.ask(myAgent, 'What is the answer?');
84
- expect(result).toBe('42');
91
+ // Execute
92
+ const result = await runtime.execute('my-workflow', { question: 'What is 2+2?' });
85
93
 
86
94
  // Inspect recorded calls
87
95
  expect(runtime.agentCalls()).toHaveLength(1);
88
- expect(runtime.toolCalls()).toHaveLength(0);
96
+ expect(runtime.toolCalls()).toHaveLength(1);
89
97
  expect(runtime.totalCost()).toBe(0);
98
+ ```
90
99
 
91
- // Test spawn
92
- const results = await runtime.spawn(3, async (i) => runtime.ask(myAgent, `Q${i}`));
93
- expect(results.filter(r => r.ok)).toHaveLength(3);
94
-
95
- // Test vote
96
- const winner = runtime.vote(results, { strategy: 'majority', key: 'answer' });
100
+ For testing human-in-the-loop flows:
97
101
 
98
- // Test budget
99
- const budgeted = await runtime.budget({ cost: '$1.00' }, async () => {
100
- return runtime.ask(myAgent, 'Hello');
102
+ ```typescript
103
+ const runtime = new AxlTestRuntime({
104
+ humanDecisions: (opts) => ({ approved: true }),
101
105
  });
102
- expect(budgeted.budgetExceeded).toBe(false);
103
106
  ```
104
107
 
105
108
  ### Assertions
106
109
 
107
110
  ```typescript
108
- const runtime = new AxlTestRuntime({ provider });
111
+ const runtime = new AxlTestRuntime();
112
+ runtime.register(myWorkflow);
113
+ runtime.mockProvider('openai', provider);
109
114
 
110
115
  // After running your workflow:
111
116
  runtime.agentCalls(); // All recorded agent invocations
112
117
  runtime.toolCalls(); // All recorded tool invocations
113
118
  runtime.totalCost(); // Cumulative cost
114
119
  runtime.steps(); // All recorded steps (agents + tools)
115
- runtime.traces(); // All trace events
120
+ runtime.traceLog(); // All trace events
116
121
  ```
117
122
 
118
123
  ## Example: Testing a Workflow
@@ -120,19 +125,31 @@ runtime.traces(); // All trace events
120
125
  ```typescript
121
126
  import { describe, it, expect } from 'vitest';
122
127
  import { AxlTestRuntime, MockProvider } from '@axlsdk/testing';
123
- import { myAgent } from '../agents';
124
-
125
- describe('my workflow', () => {
126
- it('returns structured output', async () => {
127
- const provider = MockProvider.json({ answer: 42 });
128
- const runtime = new AxlTestRuntime({ provider });
129
-
130
- const result = await runtime.ask(myAgent, 'What is the answer?', {
131
- schema: z.object({ answer: z.number() }),
128
+ import { z } from 'zod';
129
+ import { HandleSupport } from '../workflows/support';
130
+
131
+ describe('HandleSupport workflow', () => {
132
+ it('processes a refund', async () => {
133
+ const runtime = new AxlTestRuntime();
134
+ runtime.register(HandleSupport);
135
+
136
+ runtime.mockProvider('openai', MockProvider.sequence([
137
+ { content: 'Your refund has been processed.' },
138
+ ]));
139
+
140
+ runtime.mockTool('get_order', async ({ orderId }) => ({
141
+ id: orderId, status: 'delivered', amount: 49.99,
142
+ }));
143
+ runtime.mockTool('refund_order', async ({ orderId }) => ({
144
+ success: true,
145
+ }));
146
+
147
+ const result = await runtime.execute('HandleSupport', {
148
+ msg: 'I want a refund for order 123',
132
149
  });
133
150
 
134
- expect(result).toEqual({ answer: 42 });
135
- expect(runtime.agentCalls()).toHaveLength(1);
151
+ expect(result).toContain('refund');
152
+ expect(runtime.toolCalls('refund_order')).toHaveLength(1);
136
153
  });
137
154
  });
138
155
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axlsdk/testing",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Testing utilities for Axl agentic workflows",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -22,7 +22,7 @@
22
22
  "dist"
23
23
  ],
24
24
  "dependencies": {
25
- "@axlsdk/axl": "0.3.0"
25
+ "@axlsdk/axl": "0.4.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^25.2.3",