1- import { generateText , tool , stepCountIs , ModelMessage } from 'ai' ;
1+ import { generateText , stepCountIs , ModelMessage } from 'ai' ;
22import { openai } from '@ai-sdk/openai' ;
3- import { type Tool , ToolExecutionError } from '@spec2tools/core' ;
3+ import { type ToolSet , ToolExecutionError } from '@spec2tools/core' ;
44import chalk from 'chalk' ;
55
66const MAX_OUTPUT_LENGTH = 500 ;
@@ -17,7 +17,7 @@ function trimOutput(value: unknown): string {
1717}
1818
1919interface AgentConfig {
20- tools : Tool [ ] ;
20+ tools : ToolSet ;
2121 model ?: string ;
2222 maxSteps ?: number ;
2323}
@@ -26,7 +26,7 @@ interface AgentConfig {
2626 * AI Agent that uses OpenAPI tools
2727 */
2828export class Agent {
29- private tools : Tool [ ] ;
29+ private tools : ToolSet ;
3030 private model : string ;
3131 private maxSteps : number ;
3232 private conversationHistory : ModelMessage [ ] ;
@@ -42,12 +42,15 @@ export class Agent {
4242 * Get available tools description for the agent
4343 */
4444 getToolsDescription ( ) : string {
45- if ( this . tools . length === 0 ) {
45+ const names = Object . keys ( this . tools ) ;
46+ if ( names . length === 0 ) {
4647 return 'No tools available.' ;
4748 }
4849
49- const toolDescriptions = this . tools . map ( ( tool ) => {
50- return `- ${ tool . name } : ${ tool . description } ` ;
50+ const toolDescriptions = names . map ( ( name ) => {
51+ const t = this . tools [ name ] ;
52+ const desc = 'description' in t ? t . description : '' ;
53+ return `- ${ name } : ${ desc } ` ;
5154 } ) ;
5255
5356 return `I have access to the following tools:\n${ toolDescriptions . join ( '\n' ) } ` ;
@@ -64,36 +67,32 @@ export class Agent {
6467 } ) ;
6568
6669 try {
67- // Build AI SDK tools from our tool definitions
68- const aiTools : Parameters < typeof generateText > [ 0 ] [ 'tools' ] = { } ;
69-
70- for ( const t of this . tools ) {
71- const toolExecute = t . execute ;
72- const toolName = t . name ;
73-
74- aiTools ! [ t . name ] = tool ( {
75- description : t . description ,
76- inputSchema : t . parameters ,
77- execute : async ( params ) => {
78- console . log (
79- chalk . dim ( `\n[Calling ${ toolName } with ${ JSON . stringify ( params ) } ]` )
80- ) ;
81-
82- try {
83- const result = await toolExecute ( params ) ;
84- console . log (
85- chalk . dim ( `[${ toolName } returned: ${ trimOutput ( result ) } ]\n` )
86- ) ;
87- return result ;
88- } catch ( error ) {
89- if ( error instanceof ToolExecutionError ) {
90- console . log ( chalk . red ( `[${ toolName } failed: ${ error . message } ]\n` ) ) ;
91- throw error ;
70+ // Wrap each tool to add CLI logging
71+ const wrappedTools : ToolSet = { } ;
72+ for ( const [ name , t ] of Object . entries ( this . tools ) ) {
73+ const originalExecute = 'execute' in t ? t . execute : undefined ;
74+ wrappedTools [ name ] = {
75+ ...t ,
76+ execute : originalExecute
77+ ? async ( params : unknown , options : unknown ) => {
78+ console . log (
79+ chalk . dim ( `\n[Calling ${ name } with ${ JSON . stringify ( params ) } ]` )
80+ ) ;
81+ try {
82+ const result = await ( originalExecute as Function ) ( params , options ) ;
83+ console . log (
84+ chalk . dim ( `[${ name } returned: ${ trimOutput ( result ) } ]\n` )
85+ ) ;
86+ return result ;
87+ } catch ( error ) {
88+ if ( error instanceof ToolExecutionError ) {
89+ console . log ( chalk . red ( `[${ name } failed: ${ error . message } ]\n` ) ) ;
90+ }
91+ throw error ;
92+ }
9293 }
93- throw error ;
94- }
95- } ,
96- } ) ;
94+ : undefined ,
95+ } as ToolSet [ string ] ;
9796 }
9897
9998 // Build system prompt
@@ -107,7 +106,7 @@ If a tool call fails, explain the error to the user.`;
107106 model : openai ( this . model ) ,
108107 system : systemPrompt ,
109108 messages : this . conversationHistory ,
110- tools : aiTools ,
109+ tools : wrappedTools ,
111110 stopWhen : stepCountIs ( this . maxSteps ) ,
112111 } ) ;
113112
@@ -143,13 +142,13 @@ If a tool call fails, explain the error to the user.`;
143142 * Get the list of tool names
144143 */
145144 getToolNames ( ) : string [ ] {
146- return this . tools . map ( ( t ) => t . name ) ;
145+ return Object . keys ( this . tools ) ;
147146 }
148147
149148 /**
150149 * Get a specific tool by name
151150 */
152- getTool ( name : string ) : Tool | undefined {
153- return this . tools . find ( ( t ) => t . name === name ) ;
151+ getTool ( name : string ) : ToolSet [ string ] | undefined {
152+ return this . tools [ name ] ;
154153 }
155154}
0 commit comments