From d7c6a93643c4ac0f425d14fe4ee499ade6701b44 Mon Sep 17 00:00:00 2001 From: Jeremy Tuloup Date: Wed, 15 Oct 2025 15:03:12 +0200 Subject: [PATCH 1/4] Better format tool calls that need approval --- src/chat-model.ts | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/chat-model.ts b/src/chat-model.ts index f01dee7c..e6756acf 100644 --- a/src/chat-model.ts +++ b/src/chat-model.ts @@ -274,6 +274,26 @@ export class AIChatModel extends AbstractChatModel { }; } + /** + * Formats tool input for display, handling both objects and pre-stringified JSON. + * @param input The tool input to format (object or string) + * @returns Pretty-printed JSON string + */ + private _formatToolInput(input: any): string { + if (typeof input === 'string') { + try { + // If it's already a JSON string, parse and re-stringify with formatting + const parsed = JSON.parse(input); + return JSON.stringify(parsed, null, 2); + } catch { + // If parsing fails, return the string as-is + return input; + } + } + // If it's an object, stringify it with formatting + return JSON.stringify(input, null, 2); + } + /** * Handles settings changes and updates chat configuration accordingly. */ @@ -481,7 +501,7 @@ export class AIChatModel extends AbstractChatModel {
[APPROVAL_BUTTONS:${event.data.interruptionId}]
@@ -504,7 +524,9 @@ export class AIChatModel extends AbstractChatModel { ${assistantName} wants to execute this tool. Do you approve? -${JSON.stringify(event.data.toolInput, null, 2)} +\`\`\`json +${this._formatToolInput(event.data.toolInput)} +\`\`\` [APPROVAL_BUTTONS:${event.data.interruptionId}]`, sender: this._getAIUser(), @@ -531,7 +553,7 @@ ${JSON.stringify(event.data.toolInput, null, 2)} const toolsList = event.data.approvals .map( (info, index) => - `**${index + 1}. ${info.toolName}**\n${JSON.stringify(info.toolInput, null, 2)}\n` + `**${index + 1}. ${info.toolName}**\n\`\`\`json\n${this._formatToolInput(info.toolInput)}\n\`\`\`\n` ) .join('\n\n'); From c9c0ad177e7beebfaf01376ff0183c78b5676c6f Mon Sep 17 00:00:00 2001 From: Jeremy Tuloup Date: Wed, 15 Oct 2025 15:26:51 +0200 Subject: [PATCH 2/4] fix typings --- src/chat-model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat-model.ts b/src/chat-model.ts index e6756acf..12ad81d9 100644 --- a/src/chat-model.ts +++ b/src/chat-model.ts @@ -279,7 +279,7 @@ export class AIChatModel extends AbstractChatModel { * @param input The tool input to format (object or string) * @returns Pretty-printed JSON string */ - private _formatToolInput(input: any): string { + private _formatToolInput(input: string | object): string { if (typeof input === 'string') { try { // If it's already a JSON string, parse and re-stringify with formatting From 573bc51846fa08862ba1b2f496be650b3f0bbc53 Mon Sep 17 00:00:00 2001 From: Jeremy Tuloup Date: Wed, 15 Oct 2025 21:28:59 +0200 Subject: [PATCH 3/4] Refactor tool input formatting --- src/agent.ts | 34 +++++++++++++++++++++++++++------- src/chat-model.ts | 28 ++++------------------------ 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/agent.ts b/src/agent.ts index f1b54699..60be184c 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -184,18 +184,18 @@ export interface IAgentEventTypeMap { tool_call_start: { callId: string; toolName: string; - input: any; + input: string; }; tool_call_complete: { callId: string; toolName: string; - output: any; + output: string; isError: boolean; }; tool_approval_required: { interruptionId: string; toolName: string; - toolInput: any; + toolInput: string; callId?: string; }; grouped_approval_required: { @@ -203,7 +203,7 @@ export interface IAgentEventTypeMap { approvals: Array<{ interruptionId: string; toolName: string; - toolInput: any; + toolInput: string; }>; }; error: { @@ -718,6 +718,26 @@ export class AgentManager { } } + /** + * Formats tool input for display, handling both objects and pre-stringified JSON. + * @param input The tool input to format (object or string) + * @returns Pretty-printed JSON string + */ + private _formatToolInput(input: string | object): string { + if (typeof input === 'string') { + try { + // If it's already a JSON string, parse and re-stringify with formatting + const parsed = JSON.parse(input); + return JSON.stringify(parsed, null, 2); + } catch { + // If parsing fails, return the string as-is + return input; + } + } + // If it's an object, stringify it with formatting + return JSON.stringify(input, null, 2); + } + /** * Handles the start of a tool call from the model event. * @param modelEvent The model event containing tool call information @@ -738,7 +758,7 @@ export class AgentManager { data: { callId: toolCallId, toolName, - input: parsedToolInput + input: this._formatToolInput(parsedToolInput) } }); } @@ -795,7 +815,7 @@ export class AgentManager { data: { interruptionId, toolName, - toolInput, + toolInput: this._formatToolInput(toolInput), callId } }); @@ -819,7 +839,7 @@ export class AgentManager { return { interruptionId, toolName, - toolInput + toolInput: this._formatToolInput(toolInput) }; }); diff --git a/src/chat-model.ts b/src/chat-model.ts index 12ad81d9..69e1943d 100644 --- a/src/chat-model.ts +++ b/src/chat-model.ts @@ -274,26 +274,6 @@ export class AIChatModel extends AbstractChatModel { }; } - /** - * Formats tool input for display, handling both objects and pre-stringified JSON. - * @param input The tool input to format (object or string) - * @returns Pretty-printed JSON string - */ - private _formatToolInput(input: string | object): string { - if (typeof input === 'string') { - try { - // If it's already a JSON string, parse and re-stringify with formatting - const parsed = JSON.parse(input); - return JSON.stringify(parsed, null, 2); - } catch { - // If parsing fails, return the string as-is - return input; - } - } - // If it's an object, stringify it with formatting - return JSON.stringify(input, null, 2); - } - /** * Handles settings changes and updates chat configuration accordingly. */ @@ -403,7 +383,7 @@ export class AIChatModel extends AbstractChatModel { `, @@ -501,7 +481,7 @@ export class AIChatModel extends AbstractChatModel { @@ -525,7 +505,7 @@ export class AIChatModel extends AbstractChatModel { ${assistantName} wants to execute this tool. Do you approve? \`\`\`json -${this._formatToolInput(event.data.toolInput)} +${event.data.toolInput} \`\`\` [APPROVAL_BUTTONS:${event.data.interruptionId}]`, @@ -553,7 +533,7 @@ ${this._formatToolInput(event.data.toolInput)} const toolsList = event.data.approvals .map( (info, index) => - `**${index + 1}. ${info.toolName}**\n\`\`\`json\n${this._formatToolInput(info.toolInput)}\n\`\`\`\n` + `**${index + 1}. ${info.toolName}**\n\`\`\`json\n${info.toolInput}\n\`\`\`\n` ) .join('\n\n'); From 0519a28c45af765c719e78a98b0206ffb0a4c596 Mon Sep 17 00:00:00 2001 From: Jeremy Tuloup Date: Mon, 20 Oct 2025 14:48:24 +0200 Subject: [PATCH 4/4] fix types and formatting method --- src/agent.ts | 47 ++++++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/src/agent.ts b/src/agent.ts index 60be184c..11e70dbe 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -719,23 +719,19 @@ export class AgentManager { } /** - * Formats tool input for display, handling both objects and pre-stringified JSON. - * @param input The tool input to format (object or string) + * Formats tool input for display by pretty-printing JSON strings. + * @param input The tool input string to format * @returns Pretty-printed JSON string */ - private _formatToolInput(input: string | object): string { - if (typeof input === 'string') { - try { - // If it's already a JSON string, parse and re-stringify with formatting - const parsed = JSON.parse(input); - return JSON.stringify(parsed, null, 2); - } catch { - // If parsing fails, return the string as-is - return input; - } + private _formatToolInput(input: string): string { + try { + // Parse and re-stringify with formatting + const parsed = JSON.parse(input); + return JSON.stringify(parsed, null, 2); + } catch { + // If parsing fails, return the string as-is + return input; } - // If it's an object, stringify it with formatting - return JSON.stringify(input, null, 2); } /** @@ -746,19 +742,13 @@ export class AgentManager { const toolCallId = modelEvent.toolCallId; const toolName = modelEvent.toolName; const toolInput = modelEvent.input; - let parsedToolInput; - try { - parsedToolInput = JSON.parse(toolInput); - } catch (error) { - parsedToolInput = {}; - } this._agentEvent.emit({ type: 'tool_call_start', data: { callId: toolCallId, toolName, - input: this._formatToolInput(parsedToolInput) + input: this._formatToolInput(toolInput) } }); } @@ -778,7 +768,7 @@ export class AgentManager { const isError = toolCallOutput.rawItem.type === 'function_call_result' && - (toolCallOutput.rawItem as any).error; + toolCallOutput.rawItem.status === 'incomplete'; const toolName = toolCallOutput.rawItem.type === 'function_call_result' @@ -803,10 +793,13 @@ export class AgentManager { private async _handleSingleToolApproval( interruption: RunToolApprovalItem ): Promise { - const toolName = (interruption.rawItem as any)?.name || 'Unknown Tool'; - const toolInput = (interruption.rawItem as any)?.arguments || {}; + const toolName = interruption.rawItem.name || 'Unknown Tool'; + const toolInput = interruption.rawItem.arguments || '{}'; const interruptionId = `int-${Date.now()}-${Math.random()}`; - const callId = (interruption.rawItem as any)?.callId; + const callId = + interruption.rawItem.type === 'function_call' + ? interruption.rawItem.callId + : undefined; this._pendingApprovals.set(interruptionId, { interruption }); @@ -830,8 +823,8 @@ export class AgentManager { ): Promise { const groupId = `group-${Date.now()}-${Math.random()}`; const approvals = interruptions.map(interruption => { - const toolName = (interruption.rawItem as any)?.name || 'Unknown Tool'; - const toolInput = (interruption.rawItem as any)?.arguments || {}; + const toolName = interruption.rawItem.name || 'Unknown Tool'; + const toolInput = interruption.rawItem.arguments || '{}'; const interruptionId = `int-${Date.now()}-${Math.random()}`; this._pendingApprovals.set(interruptionId, { interruption, groupId });