Skip to content

Commit 578f103

Browse files
Claudehotlong
andauthored
Fix tool-routes.ts to use ToolRegistry.execute() API
- Fixed ToolRegistry API usage (use has() and execute() instead of non-existent get() method) - Added extractOutputValue() helper to safely handle different output types - Updated tests to use correct ToolRegistry.register() signature (separate definition and handler params) - Fixed test expectations to match string output from handlers - All builds and tests now passing Agent-Logs-Url: https://github.com/objectstack-ai/framework/sessions/4239d194-ecf4-4513-9729-f161ab40710d Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent be84ef7 commit 578f103

File tree

2 files changed

+56
-34
lines changed

2 files changed

+56
-34
lines changed

packages/services/service-ai/src/__tests__/tool-routes.test.ts

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,22 @@ describe('Tool Routes', () => {
2727
});
2828

2929
// Register a test tool
30-
aiService.toolRegistry.register({
31-
name: 'test_tool',
32-
description: 'A test tool for playground',
33-
parameters: {
34-
type: 'object',
35-
properties: {
36-
message: { type: 'string' },
30+
aiService.toolRegistry.register(
31+
{
32+
name: 'test_tool',
33+
description: 'A test tool for playground',
34+
parameters: {
35+
type: 'object',
36+
properties: {
37+
message: { type: 'string' },
38+
},
39+
required: ['message'],
3740
},
38-
required: ['message'],
3941
},
40-
handler: async (params: any) => {
41-
return { echo: params.message };
42-
},
43-
});
42+
async (params: any) => {
43+
return JSON.stringify({ echo: params.message });
44+
}
45+
);
4446

4547
routes = buildToolRoutes(aiService, silentLogger);
4648
});
@@ -83,7 +85,8 @@ describe('Tool Routes', () => {
8385

8486
expect(response.status).toBe(200);
8587
expect(response.body).toHaveProperty('result');
86-
expect((response.body as any).result).toEqual({ echo: 'Hello, Playground!' });
88+
// Result is a JSON string from the handler
89+
expect((response.body as any).result).toBe('{"echo":"Hello, Playground!"}');
8790
expect((response.body as any).toolName).toBe('test_tool');
8891
expect((response.body as any).duration).toBeTypeOf('number');
8992
});
@@ -135,14 +138,16 @@ describe('Tool Routes', () => {
135138

136139
it('should handle tool execution errors', async () => {
137140
// Register a tool that throws an error
138-
aiService.toolRegistry.register({
139-
name: 'error_tool',
140-
description: 'A tool that throws an error',
141-
parameters: { type: 'object', properties: {} },
142-
handler: async () => {
143-
throw new Error('Tool execution failed');
141+
aiService.toolRegistry.register(
142+
{
143+
name: 'error_tool',
144+
description: 'A tool that throws an error',
145+
parameters: { type: 'object', properties: {} },
144146
},
145-
});
147+
async () => {
148+
throw new Error('Tool execution failed');
149+
}
150+
);
146151

147152
const executeRoute = routes.find(
148153
r => r.method === 'POST' && r.path === '/api/v1/ai/tools/:toolName/execute'

packages/services/service-ai/src/routes/tool-routes.ts

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@ import type { Logger } from '@objectstack/spec/contracts';
44
import type { AIService } from '../ai-service.js';
55
import type { RouteDefinition } from './ai-routes.js';
66

7+
/**
8+
* Extract string value from tool execution result output.
9+
*/
10+
function extractOutputValue(output: any): string {
11+
if (!output) return '';
12+
if (typeof output === 'string') return output;
13+
if (typeof output === 'object' && 'value' in output) {
14+
return String(output.value ?? '');
15+
}
16+
return JSON.stringify(output);
17+
}
18+
719
/**
820
* Build tool-specific REST routes.
921
*
@@ -75,39 +87,44 @@ export function buildToolRoutes(
7587
}
7688

7789
try {
78-
// Look up the tool
79-
const tool = aiService.toolRegistry.get(toolName);
80-
if (!tool) {
90+
// Check if tool exists
91+
if (!aiService.toolRegistry.has(toolName)) {
8192
return { status: 404, body: { error: `Tool "${toolName}" not found` } };
8293
}
8394

84-
// Execute the tool
95+
// Execute the tool using ToolRegistry's execute method
8596
const startTime = Date.now();
86-
let result: any;
8797

88-
try {
89-
result = await tool.handler(parameters);
90-
} catch (err) {
91-
const duration = Date.now() - startTime;
98+
const toolCallPart = {
99+
type: 'tool-call' as const,
100+
toolCallId: `playground-${Date.now()}`,
101+
toolName,
102+
input: parameters,
103+
};
104+
105+
const result = await aiService.toolRegistry.execute(toolCallPart);
106+
const duration = Date.now() - startTime;
107+
108+
// Check if execution resulted in an error
109+
if (result.isError) {
110+
const errorMsg = extractOutputValue(result.output);
92111
logger.error(
93112
`[AI Route] Tool execution error: ${toolName}`,
94-
err instanceof Error ? err : undefined,
113+
new Error(errorMsg),
95114
);
96115
return {
97116
status: 500,
98117
body: {
99-
error: err instanceof Error ? err.message : 'Tool execution failed',
118+
error: errorMsg,
100119
duration,
101120
},
102121
};
103122
}
104123

105-
const duration = Date.now() - startTime;
106-
107124
return {
108125
status: 200,
109126
body: {
110-
result,
127+
result: extractOutputValue(result.output),
111128
duration,
112129
toolName,
113130
},

0 commit comments

Comments
 (0)