Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 32 additions & 19 deletions src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,26 +184,26 @@ 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: {
groupId: string;
approvals: Array<{
interruptionId: string;
toolName: string;
toolInput: any;
toolInput: string;
}>;
};
error: {
Expand Down Expand Up @@ -718,6 +718,22 @@ export class AgentManager {
}
}

/**
* 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): 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;
}
}

/**
* Handles the start of a tool call from the model event.
* @param modelEvent The model event containing tool call information
Expand All @@ -726,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: parsedToolInput
input: this._formatToolInput(toolInput)
}
});
}
Expand All @@ -758,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'
Expand All @@ -783,10 +793,13 @@ export class AgentManager {
private async _handleSingleToolApproval(
interruption: RunToolApprovalItem
): Promise<void> {
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 });

Expand All @@ -795,7 +808,7 @@ export class AgentManager {
data: {
interruptionId,
toolName,
toolInput,
toolInput: this._formatToolInput(toolInput),
callId
}
});
Expand All @@ -810,16 +823,16 @@ export class AgentManager {
): Promise<void> {
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 });

return {
interruptionId,
toolName,
toolInput
toolInput: this._formatToolInput(toolInput)
};
});

Expand Down
10 changes: 6 additions & 4 deletions src/chat-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ export class AIChatModel extends AbstractChatModel {
<div class="jp-ai-tool-body">
<div class="jp-ai-tool-section">
<div class="jp-ai-tool-label">Input</div>
<pre class="jp-ai-tool-code"><code>${JSON.stringify(event.data.input, null, 2)}</code></pre>
<pre class="jp-ai-tool-code"><code>${event.data.input}</code></pre>
</div>
</div>
</details>`,
Expand Down Expand Up @@ -481,7 +481,7 @@ export class AIChatModel extends AbstractChatModel {
<div class="jp-ai-tool-body">
<div class="jp-ai-tool-section">
<div class="jp-ai-tool-label">${assistantName} wants to execute this tool. Do you approve?</div>
<pre class="jp-ai-tool-code"><code>${JSON.stringify(event.data.toolInput, null, 2)}</code></pre>
<pre class="jp-ai-tool-code"><code>${event.data.toolInput}</code></pre>
</div>
[APPROVAL_BUTTONS:${event.data.interruptionId}]
</div>
Expand All @@ -504,7 +504,9 @@ export class AIChatModel extends AbstractChatModel {

${assistantName} wants to execute this tool. Do you approve?

${JSON.stringify(event.data.toolInput, null, 2)}
\`\`\`json
${event.data.toolInput}
\`\`\`

[APPROVAL_BUTTONS:${event.data.interruptionId}]`,
sender: this._getAIUser(),
Expand All @@ -531,7 +533,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${info.toolInput}\n\`\`\`\n`
)
.join('\n\n');

Expand Down
Loading