fix(tooling): surface non-executable tool-use warnings

This commit is contained in:
William Valentin
2026-02-17 16:34:54 -08:00
parent 061b96fd68
commit 5451f8a1de
6 changed files with 126 additions and 4 deletions
+30
View File
@@ -270,6 +270,36 @@ describe('NativeAgent tool loop', () => {
expect(mockClient.chat).toHaveBeenCalledTimes(3);
});
it('surfaces warning when model emits textual tool_use block without structured tool calls', async () => {
const mockClient: ModelClient = {
chat: vi.fn().mockResolvedValue({
content: 'Let me read the full email to evaluate legitimacy:{"type":"tool_use","id":"call_123","name":"gmail_read","input":{"id":"abc"}}',
stopReason: 'end_turn',
usage: { inputTokens: 10, outputTokens: 5 },
}),
};
const registry = new ToolRegistry();
registry.register(echoTool);
const hooks = new HookEngine({ confirm: [], log: [], silent: [] });
const executor = new ToolExecutor(registry, hooks);
const agent = new NativeAgent({
modelClient: mockClient,
systemPrompt: 'You are helpful.',
toolRegistry: registry,
toolExecutor: executor,
});
const response = await agent.process('read latest email');
expect(response).toContain('Tool call was emitted as plain text and was not executed.');
expect(response).toContain('Tool: gmail_read (id: call_123)');
expect(response).toContain('"type":"tool_use"');
const history = agent.getHistory();
expect(history[history.length - 1]).toEqual({ role: 'assistant', content: response });
});
it('works without tools (backward compatible)', async () => {
const mockClient: ModelClient = {
chat: vi.fn().mockResolvedValue({