refactor tool-call detail contract for unknown tools
This commit is contained in:
@@ -106,23 +106,23 @@ function MergedToolCallItem({ item }: { item: MergedToolCall }) {
|
||||
|
||||
{isExpanded && (
|
||||
<View style={stylesheet.toolContent}>
|
||||
{item.rawInput && (
|
||||
{item.input && (
|
||||
<View style={stylesheet.section}>
|
||||
<Text style={stylesheet.sectionTitle}>Input:</Text>
|
||||
<Text style={stylesheet.code}>
|
||||
{JSON.stringify(item.rawInput, null, 2)}
|
||||
{JSON.stringify(item.input, null, 2)}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
{item.rawOutput && (
|
||||
{item.output && (
|
||||
<View style={stylesheet.section}>
|
||||
<Text style={stylesheet.sectionTitle}>Output:</Text>
|
||||
<Text style={stylesheet.code}>
|
||||
{JSON.stringify(item.rawOutput, null, 2)}
|
||||
{JSON.stringify(item.output, null, 2)}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
{!item.rawInput && !item.rawOutput && (
|
||||
{!item.input && !item.output && (
|
||||
<Text style={stylesheet.emptyText}>
|
||||
No details available
|
||||
</Text>
|
||||
|
||||
@@ -1101,8 +1101,8 @@ function PermissionRequestCard({
|
||||
<ToolCallDetailsContent
|
||||
detail={{
|
||||
type: "unknown",
|
||||
rawInput: request.input ?? null,
|
||||
rawOutput: null,
|
||||
input: request.input ?? null,
|
||||
output: null,
|
||||
}}
|
||||
maxHeight={200}
|
||||
/>
|
||||
|
||||
@@ -1198,8 +1198,8 @@ export const ToolCall = memo(function ToolCall({
|
||||
if (args !== undefined || result !== undefined) {
|
||||
return {
|
||||
type: "unknown",
|
||||
rawInput: args ?? null,
|
||||
rawOutput: result ?? null,
|
||||
input: args ?? null,
|
||||
output: result ?? null,
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
@@ -1208,8 +1208,8 @@ export const ToolCall = memo(function ToolCall({
|
||||
const displayDetail =
|
||||
effectiveDetail ?? {
|
||||
type: "unknown",
|
||||
rawInput: null,
|
||||
rawOutput: null,
|
||||
input: null,
|
||||
output: null,
|
||||
};
|
||||
|
||||
const displayModel = useMemo(
|
||||
@@ -1235,8 +1235,8 @@ export const ToolCall = memo(function ToolCall({
|
||||
Boolean(error) ||
|
||||
(effectiveDetail
|
||||
? effectiveDetail.type !== "unknown" ||
|
||||
effectiveDetail.rawInput !== null ||
|
||||
effectiveDetail.rawOutput !== null
|
||||
effectiveDetail.input !== null ||
|
||||
effectiveDetail.output !== null
|
||||
: false);
|
||||
|
||||
const handleToggle = useCallback(() => {
|
||||
|
||||
@@ -139,8 +139,8 @@ export function ToolCallDetailsContent({
|
||||
);
|
||||
} else if (detail?.type === "unknown") {
|
||||
const sectionsFromTopLevel = [
|
||||
{ title: "Input", value: detail.rawInput },
|
||||
{ title: "Output", value: detail.rawOutput },
|
||||
{ title: "Input", value: detail.input },
|
||||
{ title: "Output", value: detail.output },
|
||||
].filter((entry) => entry.value !== null && entry.value !== undefined);
|
||||
|
||||
for (const section of sectionsFromTopLevel) {
|
||||
|
||||
@@ -41,8 +41,8 @@ export interface ToolCall {
|
||||
title: string;
|
||||
status?: 'pending' | 'in_progress' | 'completed' | 'failed';
|
||||
toolKind?: 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'think' | 'fetch' | 'switch_mode' | 'other';
|
||||
rawInput?: Record<string, unknown>;
|
||||
rawOutput?: Record<string, unknown>;
|
||||
input?: Record<string, unknown>;
|
||||
output?: Record<string, unknown>;
|
||||
content?: unknown[];
|
||||
locations?: unknown[];
|
||||
}
|
||||
@@ -53,8 +53,8 @@ export interface ToolCallUpdate {
|
||||
title?: string | null;
|
||||
status?: 'pending' | 'in_progress' | 'completed' | 'failed' | null;
|
||||
toolKind?: 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'think' | 'fetch' | 'switch_mode' | 'other' | null;
|
||||
rawInput?: Record<string, unknown>;
|
||||
rawOutput?: Record<string, unknown>;
|
||||
input?: Record<string, unknown>;
|
||||
output?: Record<string, unknown>;
|
||||
content?: unknown[] | null;
|
||||
locations?: unknown[] | null;
|
||||
}
|
||||
@@ -109,8 +109,8 @@ export interface MergedToolCall {
|
||||
title: string;
|
||||
status: 'pending' | 'in_progress' | 'completed' | 'failed';
|
||||
toolKind?: 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'think' | 'fetch' | 'switch_mode' | 'other';
|
||||
rawInput?: Record<string, unknown>;
|
||||
rawOutput?: Record<string, unknown>;
|
||||
input?: Record<string, unknown>;
|
||||
output?: Record<string, unknown>;
|
||||
content?: unknown[];
|
||||
locations?: unknown[];
|
||||
startTimestamp: Date;
|
||||
@@ -137,8 +137,8 @@ export function groupActivities(activities: AgentActivity[]): Array<GroupedTextM
|
||||
title: string;
|
||||
status: 'pending' | 'in_progress' | 'completed' | 'failed';
|
||||
toolKind?: 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'think' | 'fetch' | 'switch_mode' | 'other';
|
||||
rawInput?: Record<string, unknown>;
|
||||
rawOutput?: Record<string, unknown>;
|
||||
input?: Record<string, unknown>;
|
||||
output?: Record<string, unknown>;
|
||||
content?: unknown[];
|
||||
locations?: unknown[];
|
||||
startTimestamp: Date;
|
||||
@@ -210,8 +210,8 @@ export function groupActivities(activities: AgentActivity[]): Array<GroupedTextM
|
||||
title: update.title,
|
||||
status: update.status || 'pending',
|
||||
toolKind: update.toolKind,
|
||||
rawInput: update.rawInput,
|
||||
rawOutput: update.rawOutput,
|
||||
input: update.input,
|
||||
output: update.output,
|
||||
content: update.content,
|
||||
locations: update.locations,
|
||||
startTimestamp: activity.timestamp,
|
||||
@@ -223,8 +223,8 @@ export function groupActivities(activities: AgentActivity[]): Array<GroupedTextM
|
||||
existing.title = update.title;
|
||||
if (update.status) existing.status = update.status;
|
||||
if (update.toolKind) existing.toolKind = update.toolKind;
|
||||
if (update.rawInput) existing.rawInput = update.rawInput;
|
||||
if (update.rawOutput) existing.rawOutput = update.rawOutput;
|
||||
if (update.input) existing.input = update.input;
|
||||
if (update.output) existing.output = update.output;
|
||||
if (update.content) existing.content = update.content;
|
||||
if (update.locations) existing.locations = update.locations;
|
||||
existing.endTimestamp = activity.timestamp;
|
||||
@@ -236,8 +236,8 @@ export function groupActivities(activities: AgentActivity[]): Array<GroupedTextM
|
||||
if (update.title) existing.title = update.title;
|
||||
if (update.status) existing.status = update.status;
|
||||
if (update.toolKind) existing.toolKind = update.toolKind;
|
||||
if (update.rawInput) existing.rawInput = { ...existing.rawInput, ...update.rawInput };
|
||||
if (update.rawOutput) existing.rawOutput = { ...existing.rawOutput, ...update.rawOutput };
|
||||
if (update.input) existing.input = { ...existing.input, ...update.input };
|
||||
if (update.output) existing.output = { ...existing.output, ...update.output };
|
||||
if (update.content) existing.content = update.content;
|
||||
if (update.locations) existing.locations = update.locations;
|
||||
existing.endTimestamp = activity.timestamp;
|
||||
@@ -251,8 +251,8 @@ export function groupActivities(activities: AgentActivity[]): Array<GroupedTextM
|
||||
title: update.title || 'Tool Call',
|
||||
status: update.status || 'pending',
|
||||
toolKind: update.toolKind || undefined,
|
||||
rawInput: update.rawInput,
|
||||
rawOutput: update.rawOutput,
|
||||
input: update.input,
|
||||
output: update.output,
|
||||
content: update.content || undefined,
|
||||
locations: update.locations || undefined,
|
||||
startTimestamp: activity.timestamp,
|
||||
@@ -280,8 +280,8 @@ export function groupActivities(activities: AgentActivity[]): Array<GroupedTextM
|
||||
title: toolCall.title,
|
||||
status: toolCall.status,
|
||||
toolKind: toolCall.toolKind,
|
||||
rawInput: toolCall.rawInput,
|
||||
rawOutput: toolCall.rawOutput,
|
||||
input: toolCall.input,
|
||||
output: toolCall.output,
|
||||
content: toolCall.content,
|
||||
locations: toolCall.locations,
|
||||
startTimestamp: toolCall.startTimestamp,
|
||||
|
||||
@@ -28,8 +28,8 @@ const toolCallEvent = (): AgentStreamEventPayload => ({
|
||||
status: "running",
|
||||
detail: {
|
||||
type: "unknown",
|
||||
rawInput: { command: "echo hi" },
|
||||
rawOutput: null,
|
||||
input: { command: "echo hi" },
|
||||
output: null,
|
||||
},
|
||||
error: null,
|
||||
},
|
||||
|
||||
@@ -215,8 +215,8 @@ function buildToolEvent({
|
||||
}): AgentStreamEventPayload {
|
||||
const canonicalDetail: ToolCallDetail = detail ?? {
|
||||
type: "unknown",
|
||||
rawInput: input,
|
||||
rawOutput: output,
|
||||
input: input,
|
||||
output: output,
|
||||
};
|
||||
|
||||
const baseItem = {
|
||||
|
||||
@@ -42,8 +42,8 @@ function canonicalToolTimeline(params: {
|
||||
}): AgentStreamEventPayload {
|
||||
const detail: ToolCallDetail = params.detail ?? {
|
||||
type: "unknown",
|
||||
rawInput: params.input ?? null,
|
||||
rawOutput: params.output ?? null,
|
||||
input: params.input ?? null,
|
||||
output: params.output ?? null,
|
||||
};
|
||||
|
||||
const baseItem = {
|
||||
@@ -150,8 +150,8 @@ describe("stream reducer canonical tool calls", () => {
|
||||
assert.strictEqual(tools[0].payload.data.status, "completed");
|
||||
assert.deepStrictEqual(tools[0].payload.data.detail, {
|
||||
type: "unknown",
|
||||
rawInput: { command: "pwd" },
|
||||
rawOutput: {
|
||||
input: { command: "pwd" },
|
||||
output: {
|
||||
output: "/tmp/repo\n",
|
||||
exitCode: 0,
|
||||
},
|
||||
@@ -282,8 +282,8 @@ describe("stream reducer canonical tool calls", () => {
|
||||
assert.ok(tool);
|
||||
assert.deepStrictEqual(tool.payload.data.detail, {
|
||||
type: "unknown",
|
||||
rawInput: { path: "README.md" },
|
||||
rawOutput: { content: "hello" },
|
||||
input: { path: "README.md" },
|
||||
output: { content: "hello" },
|
||||
});
|
||||
assert.strictEqual(tool.payload.data.status, "completed");
|
||||
});
|
||||
|
||||
@@ -353,20 +353,20 @@ function mergeToolCallDetail(existing: ToolCallDetail, incoming: ToolCallDetail)
|
||||
if (existing.type === "unknown" && incoming.type === "unknown") {
|
||||
return {
|
||||
type: "unknown",
|
||||
rawInput: mergeUnknownValue(existing.rawInput, incoming.rawInput),
|
||||
rawOutput: mergeUnknownValue(existing.rawOutput, incoming.rawOutput),
|
||||
input: mergeUnknownValue(existing.input, incoming.input),
|
||||
output: mergeUnknownValue(existing.output, incoming.output),
|
||||
};
|
||||
}
|
||||
|
||||
if (existing.type === incoming.type) {
|
||||
return { ...existing, ...incoming };
|
||||
return { ...existing, ...incoming } as ToolCallDetail;
|
||||
}
|
||||
|
||||
return incoming;
|
||||
}
|
||||
|
||||
function rawInputFromDetail(detail: ToolCallDetail): unknown | null {
|
||||
return detail.type === "unknown" ? detail.rawInput : null;
|
||||
function inputFromUnknownDetail(detail: ToolCallDetail): unknown | null {
|
||||
return detail.type === "unknown" ? detail.input : null;
|
||||
}
|
||||
|
||||
function mergeAgentToolCallStatus(
|
||||
@@ -552,7 +552,7 @@ export function reduceStreamUpdate(
|
||||
// as Tasks when possible and otherwise hide it to avoid a stuck loading tool call.
|
||||
const tasks = extractTaskEntriesFromToolCall(
|
||||
item.name,
|
||||
rawInputFromDetail(item.detail)
|
||||
inputFromUnknownDetail(item.detail)
|
||||
);
|
||||
if (tasks) {
|
||||
nextState = appendTodoList(
|
||||
@@ -570,7 +570,7 @@ export function reduceStreamUpdate(
|
||||
|
||||
const tasks = extractTaskEntriesFromToolCall(
|
||||
item.name,
|
||||
rawInputFromDetail(item.detail)
|
||||
inputFromUnknownDetail(item.detail)
|
||||
);
|
||||
if (tasks) {
|
||||
nextState = appendTodoList(
|
||||
|
||||
@@ -45,8 +45,8 @@ describe("tool-call-display", () => {
|
||||
error: null,
|
||||
detail: {
|
||||
type: "unknown",
|
||||
rawInput: null,
|
||||
rawOutput: null,
|
||||
input: null,
|
||||
output: null,
|
||||
},
|
||||
metadata: {
|
||||
subAgentActivity: "Running tests",
|
||||
@@ -66,8 +66,8 @@ describe("tool-call-display", () => {
|
||||
error: null,
|
||||
detail: {
|
||||
type: "unknown",
|
||||
rawInput: null,
|
||||
rawOutput: null,
|
||||
input: null,
|
||||
output: null,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -83,8 +83,8 @@ describe("tool-call-display", () => {
|
||||
error: null,
|
||||
detail: {
|
||||
type: "unknown",
|
||||
rawInput: { command: "npm run test" },
|
||||
rawOutput: null,
|
||||
input: { command: "npm run test" },
|
||||
output: null,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -100,8 +100,8 @@ describe("tool-call-display", () => {
|
||||
error: { message: "boom" },
|
||||
detail: {
|
||||
type: "unknown",
|
||||
rawInput: { command: "false" },
|
||||
rawOutput: null,
|
||||
input: { command: "false" },
|
||||
output: null,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user