Merge pull request #1615 from QwenLM/mingholy/fix/acp-tool-name
Some checks are pending
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run

Fix: Add toolName metadata for ACP tool call messages
This commit is contained in:
Mingholy 2026-01-26 20:17:21 +08:00 committed by GitHub
commit eef9c49e49
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 34 additions and 3 deletions

View file

@ -366,6 +366,7 @@ export type Usage = z.infer<typeof usageSchema>;
export const sessionUpdateMetaSchema = z.object({
usage: usageSchema.optional().nullable(),
durationMs: z.number().optional().nullable(),
toolName: z.string().optional().nullable(),
});
export type SessionUpdateMeta = z.infer<typeof sessionUpdateMetaSchema>;
@ -573,6 +574,7 @@ export const sessionUpdateSchema = z.union([
kind: toolKindSchema,
locations: z.array(toolCallLocationSchema).optional(),
rawInput: z.unknown().optional(),
_meta: sessionUpdateMetaSchema.optional().nullable(),
sessionUpdate: z.literal('tool_call'),
status: toolCallStatusSchema,
title: z.string(),
@ -584,6 +586,7 @@ export const sessionUpdateSchema = z.union([
locations: z.array(toolCallLocationSchema).optional().nullable(),
rawInput: z.unknown().optional(),
rawOutput: z.unknown().optional(),
_meta: sessionUpdateMetaSchema.optional().nullable(),
sessionUpdate: z.literal('tool_call_update'),
status: toolCallStatusSchema.optional().nullable(),
title: z.string().optional().nullable(),

View file

@ -228,6 +228,7 @@ describe('HistoryReplayer', () => {
status: 'in_progress',
title: 'read_file',
rawInput: { path: '/test.ts' },
_meta: { toolName: 'read_file' },
}),
);
});
@ -280,6 +281,7 @@ describe('HistoryReplayer', () => {
],
// resultDisplay is included as rawOutput
rawOutput: 'File contents here',
_meta: { toolName: 'read_file' },
});
});

View file

@ -647,7 +647,11 @@ export class Session implements SessionContext {
const error = e instanceof Error ? e : new Error(String(e));
// Use ToolCallEmitter for error handling
await this.toolCallEmitter.emitError(callId, error);
await this.toolCallEmitter.emitError(
callId,
fc.name ?? 'unknown_tool',
error,
);
// Record tool error for session management
const errorParts = [

View file

@ -77,6 +77,7 @@ describe('ToolCallEmitter', () => {
locations: [],
kind: 'other',
rawInput: { arg1: 'value1' },
_meta: { toolName: 'unknown_tool' },
});
});
@ -100,6 +101,7 @@ describe('ToolCallEmitter', () => {
locations: [{ path: '/test/file.ts', line: 10 }],
kind: 'edit',
rawInput: { path: '/test.ts' },
_meta: { toolName: 'edit_file' },
});
});
@ -123,6 +125,7 @@ describe('ToolCallEmitter', () => {
expect(sendUpdateSpy).toHaveBeenCalledWith(
expect.objectContaining({
rawInput: {},
_meta: { toolName: 'test_tool' },
}),
);
});
@ -150,6 +153,7 @@ describe('ToolCallEmitter', () => {
locations: [], // Fallback to empty
kind: 'other', // Fallback to other
rawInput: { invalid: true },
_meta: { toolName: 'failing_tool' },
});
});
});
@ -170,6 +174,7 @@ describe('ToolCallEmitter', () => {
toolCallId: 'call-123',
status: 'completed',
rawOutput: 'Tool completed successfully',
_meta: { toolName: 'test_tool' },
}),
);
});
@ -193,6 +198,7 @@ describe('ToolCallEmitter', () => {
content: { type: 'text', text: 'Something went wrong' },
},
],
_meta: { toolName: 'test_tool' },
});
});
@ -222,6 +228,7 @@ describe('ToolCallEmitter', () => {
newText: 'new content',
},
],
_meta: { toolName: 'edit_file' },
}),
);
});
@ -247,6 +254,7 @@ describe('ToolCallEmitter', () => {
},
],
rawOutput: 'raw output',
_meta: { toolName: 'test_tool' },
}),
);
});
@ -264,6 +272,7 @@ describe('ToolCallEmitter', () => {
toolCallId: 'call-empty',
status: 'completed',
content: [],
_meta: { toolName: 'test_tool' },
});
});
@ -343,7 +352,7 @@ describe('ToolCallEmitter', () => {
it('should emit tool_call_update with failed status and error message', async () => {
const error = new Error('Connection timeout');
await emitter.emitError('call-123', error);
await emitter.emitError('call-123', 'test_tool', error);
expect(sendUpdateSpy).toHaveBeenCalledWith({
sessionUpdate: 'tool_call_update',
@ -355,6 +364,7 @@ describe('ToolCallEmitter', () => {
content: { type: 'text', text: 'Connection timeout' },
},
],
_meta: { toolName: 'test_tool' },
});
});
});
@ -498,6 +508,7 @@ describe('ToolCallEmitter', () => {
},
],
rawOutput: { unknownField: 'value', nested: { data: 123 } },
_meta: { toolName: 'test_tool' },
}),
);
});
@ -519,6 +530,7 @@ describe('ToolCallEmitter', () => {
toolCallId: 'call-extra',
status: 'completed',
rawOutput: 'Result text',
_meta: { toolName: 'test_tool' },
}),
);
});
@ -533,6 +545,7 @@ describe('ToolCallEmitter', () => {
const call = sendUpdateSpy.mock.calls[0][0];
expect(call.rawOutput).toBeUndefined();
expect(call._meta).toEqual({ toolName: 'test_tool' });
});
});
@ -623,6 +636,7 @@ describe('ToolCallEmitter', () => {
content: { type: 'text', text: 'Text content from message' },
},
],
_meta: { toolName: 'test_tool' },
});
});
@ -654,6 +668,7 @@ describe('ToolCallEmitter', () => {
},
],
rawOutput: 'raw result',
_meta: { toolName: 'test_tool' },
}),
);
});

View file

@ -65,6 +65,7 @@ export class ToolCallEmitter extends BaseEmitter {
locations,
kind,
rawInput: params.args ?? {},
_meta: { toolName: params.toolName },
});
return true;
@ -120,6 +121,7 @@ export class ToolCallEmitter extends BaseEmitter {
toolCallId: params.callId,
status: params.success ? 'completed' : 'failed',
content: contentArray,
_meta: { toolName: params.toolName },
};
// Add rawOutput from resultDisplay
@ -137,7 +139,11 @@ export class ToolCallEmitter extends BaseEmitter {
* @param callId - The tool call ID
* @param error - The error that occurred
*/
async emitError(callId: string, error: Error): Promise<void> {
async emitError(
callId: string,
toolName: string,
error: Error,
): Promise<void> {
await this.sendUpdate({
sessionUpdate: 'tool_call_update',
toolCallId: callId,
@ -145,6 +151,7 @@ export class ToolCallEmitter extends BaseEmitter {
content: [
{ type: 'content', content: { type: 'text', text: error.message } },
],
_meta: { toolName },
});
}