File tree Expand file tree Collapse file tree 2 files changed +41
-11
lines changed Expand file tree Collapse file tree 2 files changed +41
-11
lines changed Original file line number Diff line number Diff line change @@ -30,6 +30,18 @@ const taskCompletionTool: ChatCompletionInputTool = {
3030 } ,
3131 } ,
3232} ;
33+ const askQuestionTool : ChatCompletionInputTool = {
34+ type : "function" ,
35+ function : {
36+ name : "ask_question" ,
37+ description : "Ask a question to the user to get more info required to solve or clarify their problem." ,
38+ parameters : {
39+ type : "object" ,
40+ properties : { } ,
41+ } ,
42+ } ,
43+ } ;
44+ const exitLoopTools = [ taskCompletionTool , askQuestionTool ] ;
3345
3446export class Agent extends McpClient {
3547 private readonly servers : StdioServerParameters [ ] ;
@@ -66,16 +78,31 @@ export class Agent extends McpClient {
6678 content : input ,
6779 } ) ;
6880
69- let i = 0 ;
70- while (
71- ! ( this . messages . at ( - 1 ) ?. role === "tool" && this . messages . at ( - 1 ) ?. name === taskCompletionTool . function . name ) &&
72- i < MAX_NUM_TURNS
73- ) {
81+ let total = 0 ;
82+ let nextShouldCallTools = true ;
83+ while ( true ) {
7484 yield * this . processSingleTurnWithTools ( this . messages , {
75- taskCompletionTool,
85+ exitLoopTools,
86+ exitIfNoTool : total > 0 && nextShouldCallTools ,
7687 } ) ;
77- i ++ ;
78- debug ( "current role" , this . messages . at ( - 1 ) ?. role ) ;
88+ total ++ ;
89+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
90+ const currentLast = this . messages . at ( - 1 ) ! ;
91+ debug ( "current role" , currentLast . role ) ;
92+ if (
93+ currentLast . role === "tool" &&
94+ currentLast . name &&
95+ exitLoopTools . map ( ( t ) => t . function . name ) . includes ( currentLast . name )
96+ ) {
97+ return ;
98+ }
99+ if ( currentLast . role !== "tool" && total > MAX_NUM_TURNS ) {
100+ return ;
101+ }
102+ if ( currentLast . role !== "tool" && nextShouldCallTools ) {
103+ return ;
104+ }
105+ nextShouldCallTools = currentLast . role !== "tool" ;
79106 }
80107 }
81108}
Original file line number Diff line number Diff line change @@ -71,20 +71,23 @@ export class McpClient {
7171
7272 async * processSingleTurnWithTools (
7373 messages : ChatCompletionInputMessage [ ] ,
74- opts : { taskCompletionTool ?: ChatCompletionInputTool } = { }
74+ opts : { exitLoopTools ?: ChatCompletionInputTool [ ] ; exitIfNoTool ?: boolean } = { }
7575 ) : AsyncGenerator < ChatCompletionOutput | ChatCompletionInputMessageTool > {
7676 debug ( "start of single turn" ) ;
7777
7878 const response = await this . client . chatCompletion ( {
7979 provider : this . provider ,
8080 model : this . model ,
8181 messages,
82- tools : opts . taskCompletionTool ? [ ...this . availableTools , opts . taskCompletionTool ] : this . availableTools ,
82+ tools : opts . exitLoopTools ? [ ...opts . exitLoopTools , ... this . availableTools ] : this . availableTools ,
8383 tool_choice : "auto" ,
8484 } ) ;
8585
8686 const toolCalls = response . choices [ 0 ] . message . tool_calls ;
8787 if ( ! toolCalls || toolCalls . length === 0 ) {
88+ if ( opts . exitIfNoTool ) {
89+ return ;
90+ }
8891 messages . push ( {
8992 role : response . choices [ 0 ] . message . role ,
9093 content : response . choices [ 0 ] . message . content ,
@@ -101,7 +104,7 @@ export class McpClient {
101104 content : "" ,
102105 name : toolName ,
103106 } ;
104- if ( toolName === opts . taskCompletionTool ?. function . name ) {
107+ if ( opts . exitLoopTools ?. map ( ( t ) => t . function . name ) . includes ( toolName ) ) {
105108 messages . push ( message ) ;
106109 return yield message ;
107110 }
You can’t perform that action at this time.
0 commit comments