Skip to content

Commit 0dbeba8

Browse files
committed
test: refactor unit tests to shared helpers
1 parent 938c003 commit 0dbeba8

2 files changed

Lines changed: 69 additions & 304 deletions

File tree

packages/agent/__tests__/agent.test.ts

Lines changed: 33 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -4,117 +4,35 @@ import {
44
createAssistantMessageEventStream,
55
type ModelDescriptor,
66
} from 'agentic-kit';
7+
import {
8+
createScriptedProvider,
9+
makeFakeAssistantMessage,
10+
makeFakeModel,
11+
} from '@test/index';
712

813
import { Agent } from '../src';
914

10-
function createModel(): ModelDescriptor {
11-
return {
12-
id: 'demo',
13-
name: 'Demo',
14-
api: 'fake',
15-
provider: 'fake',
16-
baseUrl: 'http://fake.local',
17-
input: ['text'],
18-
reasoning: false,
19-
tools: true,
20-
};
21-
}
22-
2315
describe('@agentic-kit/agent', () => {
2416
it('runs a minimal sequential tool loop', async () => {
2517
const responses = [
26-
{
27-
role: 'assistant' as const,
28-
api: 'fake',
29-
provider: 'fake',
30-
model: 'demo',
31-
usage: {
32-
input: 1,
33-
output: 1,
34-
cacheRead: 0,
35-
cacheWrite: 0,
36-
totalTokens: 2,
37-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
38-
},
39-
stopReason: 'toolUse' as const,
40-
timestamp: Date.now(),
18+
makeFakeAssistantMessage({
19+
usage: makeUsage(),
20+
stopReason: 'toolUse',
4121
content: [
42-
{ type: 'toolCall' as const, id: 'tool_1', name: 'echo', arguments: { text: 'hello' } },
22+
{ type: 'toolCall', id: 'tool_1', name: 'echo', arguments: { text: 'hello' } },
4323
],
44-
},
45-
{
46-
role: 'assistant' as const,
47-
api: 'fake',
48-
provider: 'fake',
49-
model: 'demo',
50-
usage: {
51-
input: 1,
52-
output: 1,
53-
cacheRead: 0,
54-
cacheWrite: 0,
55-
totalTokens: 2,
56-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
57-
},
58-
stopReason: 'stop' as const,
59-
timestamp: Date.now(),
60-
content: [{ type: 'text' as const, text: 'done' }],
61-
},
24+
}),
25+
makeFakeAssistantMessage({
26+
usage: makeUsage(),
27+
stopReason: 'stop',
28+
content: [{ type: 'text', text: 'done' }],
29+
}),
6230
];
6331

64-
let callIndex = 0;
65-
const streamFn = (_model: ModelDescriptor, _context: Context) => {
66-
const stream = createAssistantMessageEventStream();
67-
const response = responses[callIndex++];
68-
69-
queueMicrotask(() => {
70-
stream.push({ type: 'start', partial: response });
71-
if (response.content[0].type === 'toolCall') {
72-
stream.push({
73-
type: 'toolcall_start',
74-
contentIndex: 0,
75-
partial: response,
76-
});
77-
stream.push({
78-
type: 'toolcall_end',
79-
contentIndex: 0,
80-
toolCall: response.content[0],
81-
partial: response,
82-
});
83-
} else {
84-
stream.push({
85-
type: 'text_start',
86-
contentIndex: 0,
87-
partial: response,
88-
});
89-
stream.push({
90-
type: 'text_delta',
91-
contentIndex: 0,
92-
delta: 'done',
93-
partial: response,
94-
});
95-
stream.push({
96-
type: 'text_end',
97-
contentIndex: 0,
98-
content: 'done',
99-
partial: response,
100-
});
101-
}
102-
stream.push({
103-
type: 'done',
104-
reason: response.stopReason === 'toolUse' ? 'toolUse' : 'stop',
105-
message: response,
106-
});
107-
stream.end(response);
108-
});
109-
110-
return stream;
111-
};
112-
32+
const provider = createScriptedProvider({ responses });
11333
const agent = new Agent({
114-
initialState: {
115-
model: createModel(),
116-
},
117-
streamFn,
34+
initialState: { model: makeFakeModel({ id: 'demo', name: 'Demo' }) },
35+
streamFn: provider.stream,
11836
});
11937

12038
agent.setTools([
@@ -155,20 +73,20 @@ describe('@agentic-kit/agent', () => {
15573

15674
it('turns tool argument validation failures into error tool results and continues', async () => {
15775
const responses = [
158-
createAssistantResponse({
76+
makeFakeAssistantMessage({
15977
stopReason: 'toolUse',
16078
content: [{ type: 'toolCall', id: 'tool_1', name: 'echo', arguments: {} }],
16179
}),
162-
createAssistantResponse({
80+
makeFakeAssistantMessage({
16381
stopReason: 'stop',
16482
content: [{ type: 'text', text: 'recovered' }],
16583
}),
16684
];
16785

168-
let callIndex = 0;
86+
const provider = createScriptedProvider({ responses });
16987
const agent = new Agent({
170-
initialState: { model: createModel() },
171-
streamFn: () => streamMessage(responses[callIndex++]),
88+
initialState: { model: makeFakeModel({ id: 'demo', name: 'Demo' }) },
89+
streamFn: provider.stream,
17290
});
17391

17492
const execute = jest.fn(async () => ({
@@ -211,10 +129,10 @@ describe('@agentic-kit/agent', () => {
211129

212130
it('records aborted assistant turns when the active stream is cancelled', async () => {
213131
const agent = new Agent({
214-
initialState: { model: createModel() },
132+
initialState: { model: makeFakeModel({ id: 'demo', name: 'Demo' }) },
215133
streamFn: (_model: ModelDescriptor, _context: Context, options) => {
216134
const stream = createAssistantMessageEventStream();
217-
const partial = createAssistantResponse({
135+
const partial = makeFakeAssistantMessage({
218136
stopReason: 'stop',
219137
content: [{ type: 'text', text: '' }],
220138
});
@@ -225,7 +143,7 @@ describe('@agentic-kit/agent', () => {
225143
options?.signal?.addEventListener(
226144
'abort',
227145
() => {
228-
const aborted = createAssistantResponse({
146+
const aborted: AssistantMessage = makeFakeAssistantMessage({
229147
stopReason: 'aborted',
230148
errorMessage: 'aborted by test',
231149
content: [],
@@ -256,76 +174,13 @@ describe('@agentic-kit/agent', () => {
256174
});
257175
});
258176

259-
function createAssistantResponse(overrides: Partial<AssistantMessage>): AssistantMessage {
177+
function makeUsage() {
260178
return {
261-
...createAssistantResponseBase(),
262-
...overrides,
179+
input: 1,
180+
output: 1,
181+
cacheRead: 0,
182+
cacheWrite: 0,
183+
totalTokens: 2,
184+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
263185
};
264186
}
265-
266-
function createAssistantResponseBase(): AssistantMessage {
267-
return {
268-
role: 'assistant' as const,
269-
api: 'fake',
270-
provider: 'fake',
271-
model: 'demo',
272-
usage: {
273-
input: 1,
274-
output: 1,
275-
cacheRead: 0,
276-
cacheWrite: 0,
277-
totalTokens: 2,
278-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
279-
},
280-
stopReason: 'stop' as const,
281-
timestamp: Date.now(),
282-
content: [] as AssistantMessage['content'],
283-
};
284-
}
285-
286-
function streamMessage(message: AssistantMessage) {
287-
const stream = createAssistantMessageEventStream();
288-
289-
queueMicrotask(() => {
290-
stream.push({ type: 'start', partial: message });
291-
if (message.content[0]?.type === 'toolCall') {
292-
stream.push({
293-
type: 'toolcall_start',
294-
contentIndex: 0,
295-
partial: message,
296-
});
297-
stream.push({
298-
type: 'toolcall_end',
299-
contentIndex: 0,
300-
toolCall: message.content[0],
301-
partial: message,
302-
});
303-
} else {
304-
stream.push({
305-
type: 'text_start',
306-
contentIndex: 0,
307-
partial: message,
308-
});
309-
stream.push({
310-
type: 'text_delta',
311-
contentIndex: 0,
312-
delta: message.content[0]?.type === 'text' ? message.content[0].text : '',
313-
partial: message,
314-
});
315-
stream.push({
316-
type: 'text_end',
317-
contentIndex: 0,
318-
content: message.content[0]?.type === 'text' ? message.content[0].text : '',
319-
partial: message,
320-
});
321-
}
322-
stream.push({
323-
type: 'done',
324-
reason: message.stopReason === 'toolUse' ? 'toolUse' : 'stop',
325-
message,
326-
});
327-
stream.end(message);
328-
});
329-
330-
return stream;
331-
}

0 commit comments

Comments
 (0)