1- import type { GenerateResponse , ListResponse } from 'ollama' ;
1+ import type { ChatResponse , GenerateResponse , ListResponse } from 'ollama' ;
22import { describe , it , expect , vi , beforeEach } from 'vitest' ;
33
44import type { OllamaClient , OllamaModelOptions } from './types.ts' ;
@@ -15,6 +15,7 @@ describe('OllamaBaseService', () => {
1515 mockClient = {
1616 list : vi . fn ( ) ,
1717 generate : vi . fn ( ) ,
18+ chat : vi . fn ( ) ,
1819 } ;
1920
2021 mockMakeClient = vi . fn ( ) . mockResolvedValue ( mockClient ) ;
@@ -134,6 +135,111 @@ describe('OllamaBaseService', () => {
134135 } ) ;
135136 } ) ;
136137
138+ describe ( 'chat' , ( ) => {
139+ const makeChatResponse = (
140+ overrides : Partial < ChatResponse > = { } ,
141+ ) : ChatResponse =>
142+ ( {
143+ model : 'llama3' ,
144+ message : { role : 'assistant' , content : 'hello' } ,
145+ done : true ,
146+ done_reason : 'stop' ,
147+ prompt_eval_count : 5 ,
148+ eval_count : 3 ,
149+ ...overrides ,
150+ } ) as ChatResponse ;
151+
152+ it ( 'forwards tools to the Ollama client' , async ( ) => {
153+ vi . mocked ( mockClient . chat ) . mockResolvedValue ( makeChatResponse ( ) ) ;
154+
155+ await service . chat ( {
156+ model : 'llama3' ,
157+ messages : [ { role : 'user' , content : 'hi' } ] ,
158+ tools : [
159+ {
160+ type : 'function' ,
161+ function : { name : 'get_time' , description : 'Returns the time' } ,
162+ } ,
163+ ] ,
164+ } ) ;
165+
166+ expect ( mockClient . chat ) . toHaveBeenCalledWith (
167+ expect . objectContaining ( {
168+ tools : [
169+ {
170+ type : 'function' ,
171+ function : { name : 'get_time' , description : 'Returns the time' } ,
172+ } ,
173+ ] ,
174+ } ) ,
175+ ) ;
176+ } ) ;
177+
178+ it ( 'forwards message tool_calls with parsed arguments' , async ( ) => {
179+ vi . mocked ( mockClient . chat ) . mockResolvedValue ( makeChatResponse ( ) ) ;
180+
181+ await service . chat ( {
182+ model : 'llama3' ,
183+ messages : [
184+ {
185+ role : 'assistant' ,
186+ content : null ,
187+ tool_calls : [
188+ {
189+ id : 'tc-1' ,
190+ type : 'function' ,
191+ function : { name : 'get_time' , arguments : '{"tz":"UTC"}' } ,
192+ } ,
193+ ] ,
194+ } ,
195+ ] ,
196+ } ) ;
197+
198+ expect ( mockClient . chat ) . toHaveBeenCalledWith (
199+ expect . objectContaining ( {
200+ messages : [
201+ expect . objectContaining ( {
202+ tool_calls : [
203+ { function : { name : 'get_time' , arguments : { tz : 'UTC' } } } ,
204+ ] ,
205+ } ) ,
206+ ] ,
207+ } ) ,
208+ ) ;
209+ } ) ;
210+
211+ it ( 'maps response tool_calls back with stringified arguments' , async ( ) => {
212+ vi . mocked ( mockClient . chat ) . mockResolvedValue (
213+ makeChatResponse ( {
214+ message : {
215+ role : 'assistant' ,
216+ content : '' ,
217+ tool_calls : [
218+ { function : { name : 'get_time' , arguments : { tz : 'UTC' } } } ,
219+ ] ,
220+ } ,
221+ } ) ,
222+ ) ;
223+
224+ const result = await service . chat ( {
225+ model : 'llama3' ,
226+ messages : [ { role : 'user' , content : 'what time is it?' } ] ,
227+ } ) ;
228+
229+ expect ( result . choices [ 0 ] ?. message ) . toStrictEqual ( {
230+ role : 'assistant' ,
231+ content : '' ,
232+ tool_calls : [
233+ {
234+ id : 'tool-0' ,
235+ type : 'function' ,
236+ function : { name : 'get_time' , arguments : '{"tz":"UTC"}' } ,
237+ } ,
238+ ] ,
239+ } ) ;
240+ } ) ;
241+ } ) ;
242+
137243 describe ( 'makeInstance' , ( ) => {
138244 it ( 'should create instance with model' , async ( ) => {
139245 const config : InstanceConfig < OllamaModelOptions > = {
0 commit comments