@@ -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
813import { 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-
2315describe ( '@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