fix: forward entire tool call confirmation object through useToolScheduler (#481)

This commit is contained in:
Brandon Keiji 2025-05-22 06:00:36 +00:00 committed by GitHub
parent 02eec5c8ca
commit 4e3ba687a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 30 additions and 37 deletions

View File

@ -10,7 +10,6 @@ import { DiffRenderer } from './DiffRenderer.js';
import { Colors } from '../../colors.js';
import {
ToolCallConfirmationDetails,
ToolEditConfirmationDetails,
ToolConfirmationOutcome,
ToolExecuteConfirmationDetails,
} from '@gemini-code/server';
@ -23,12 +22,6 @@ export interface ToolConfirmationMessageProps {
confirmationDetails: ToolCallConfirmationDetails;
}
function isEditDetails(
props: ToolCallConfirmationDetails,
): props is ToolEditConfirmationDetails {
return (props as ToolEditConfirmationDetails).fileName !== undefined;
}
export const ToolConfirmationMessage: React.FC<
ToolConfirmationMessageProps
> = ({ confirmationDetails }) => {
@ -49,7 +42,7 @@ export const ToolConfirmationMessage: React.FC<
RadioSelectItem<ToolConfirmationOutcome>
>();
if (isEditDetails(confirmationDetails)) {
if (confirmationDetails.type === 'edit') {
// Body content is now the DiffRenderer, passing filename to it
// The bordered box is removed from here and handled within DiffRenderer
bodyContent = (

View File

@ -10,6 +10,7 @@ import {
ToolCallResponseInfo,
ToolConfirmationOutcome,
Tool,
ToolCallConfirmationDetails,
} from '@gemini-code/server';
import { Part } from '@google/genai';
import { useCallback, useEffect, useState } from 'react';
@ -55,7 +56,7 @@ type WaitingToolCall = {
status: 'awaiting_approval';
request: ToolCallRequestInfo;
tool: Tool;
confirm: (outcome: ToolConfirmationOutcome) => Promise<void>;
confirmationDetails: ToolCallConfirmationDetails;
};
export type Status = ToolCall['status'];
@ -119,17 +120,20 @@ export function useToolScheduler(
status: 'awaiting_approval',
request: r,
tool,
confirm: async (outcome) => {
await userApproval.onConfirm(outcome);
setToolCalls(
outcome === ToolConfirmationOutcome.Cancel
? setStatus(
r.callId,
'cancelled',
'User did not allow tool call',
)
: setStatus(r.callId, 'scheduled'),
);
confirmationDetails: {
...userApproval,
onConfirm: async (outcome) => {
await userApproval.onConfirm(outcome);
setToolCalls(
outcome === ToolConfirmationOutcome.Cancel
? setStatus(
r.callId,
'cancelled',
'User did not allow tool call',
)
: setStatus(r.callId, 'scheduled'),
);
},
},
};
}
@ -249,7 +253,7 @@ function setStatus(
function setStatus(
targetCallId: string,
status: 'awaiting_approval',
confirm: (t: ToolConfirmationOutcome) => Promise<void>,
confirm: ToolCallConfirmationDetails,
): (t: ToolCall[]) => ToolCall[];
function setStatus(
targetCallId: string,
@ -296,9 +300,7 @@ function setStatus(
const next: WaitingToolCall = {
...t,
status: 'awaiting_approval',
confirm: auxiliaryData as (
o: ToolConfirmationOutcome,
) => Promise<void>,
confirmationDetails: auxiliaryData as ToolCallConfirmationDetails,
};
return next;
}
@ -426,10 +428,7 @@ export function mapToDisplay(
description: t.tool.getDescription(t.request.args),
resultDisplay: undefined,
status: mapStatus(t.status),
confirmationDetails: {
title: t.request.name,
onConfirm: t.confirm,
},
confirmationDetails: t.confirmationDetails,
};
case 'executing':
return {

View File

@ -291,6 +291,7 @@ Expectation for parameters:
{ context: 3 },
);
const confirmationDetails: ToolEditConfirmationDetails = {
type: 'edit',
title: `Confirm Edit: ${shortenPath(makeRelative(params.file_path, this.rootDirectory))}`,
fileName,
fileDiff,

View File

@ -107,6 +107,7 @@ export class ShellTool extends BaseTool<ShellToolParams, ToolResult> {
return false; // already approved and whitelisted
}
const confirmationDetails: ToolExecuteConfirmationDetails = {
type: 'exec',
title: 'Confirm Shell Command',
command: params.command,
rootCommand,

View File

@ -171,25 +171,23 @@ export interface FileDiff {
fileName: string;
}
export interface ToolCallConfirmationDetailsDefault {
export interface ToolEditConfirmationDetails {
type: 'edit';
title: string;
onConfirm: (outcome: ToolConfirmationOutcome) => Promise<void>;
}
export interface ToolEditConfirmationDetails
extends ToolCallConfirmationDetailsDefault {
fileName: string;
fileDiff: string;
}
export interface ToolExecuteConfirmationDetails
extends ToolCallConfirmationDetailsDefault {
export interface ToolExecuteConfirmationDetails {
type: 'exec';
title: string;
onConfirm: (outcome: ToolConfirmationOutcome) => Promise<void>;
command: string;
rootCommand: string;
}
export type ToolCallConfirmationDetails =
| ToolCallConfirmationDetailsDefault
| ToolEditConfirmationDetails
| ToolExecuteConfirmationDetails;

View File

@ -158,6 +158,7 @@ export class WriteFileTool extends BaseTool<WriteFileToolParams, ToolResult> {
);
const confirmationDetails: ToolEditConfirmationDetails = {
type: 'edit',
title: `Confirm Write: ${shortenPath(relativePath)}`,
fileName,
fileDiff,

View File

@ -94,7 +94,7 @@ export async function checkNextSpeaker(
return null;
} catch (error) {
console.warn(
'Failed to talk to Gemiin endpoint when seeing if conversation should continue.',
'Failed to talk to Gemini endpoint when seeing if conversation should continue.',
error,
);
return null;