diff --git a/src/api/routes/modelconversation.js b/src/api/routes/modelconversation.js index 081d9b9..363b513 100644 --- a/src/api/routes/modelconversation.js +++ b/src/api/routes/modelconversation.js @@ -557,7 +557,7 @@ export function register(app, basePath = '') { return res.status(400).json({ error: parsedId.error }); } - const { message, tool_call_id, role, content, answer } = req.body ?? {}; + const { message, tool_call_id, role, content, answer, name } = req.body ?? {}; try { const manager = getOrCreateManager(parsedId.id, { @@ -574,6 +574,7 @@ export function register(app, basePath = '') { tool_call_id, content, answer: answer !== undefined ? answer : message, + name, }); } else { if (!message) { diff --git a/src/services/conversationManager.js b/src/services/conversationManager.js index 0accad5..0ae4d76 100644 --- a/src/services/conversationManager.js +++ b/src/services/conversationManager.js @@ -337,7 +337,7 @@ export class ConversationManager { * @returns {Promise} The created tool message * @throws {Error} 'Conversation is not idle' while a run is active. */ - async handleToolMessage(googleAuthId, { tool_call_id, content, answer }) { + async handleToolMessage(googleAuthId, { tool_call_id, content, answer, name }) { if (!tool_call_id) throw new Error('tool_call_id is required'); if (this.isProcessing) throw new Error('Conversation is not idle'); this.isProcessing = true; @@ -347,7 +347,11 @@ export class ConversationManager { const rawContent = content !== undefined ? (typeof content === 'string' ? content : JSON.stringify(content)) : JSON.stringify({ answer: answer ?? '' }); - const payload = JSON.stringify({ content: rawContent, tool_call_id }); + const payload = JSON.stringify({ + content: rawContent, + tool_call_id, + name: name || 'ask_user', + }); toolMsg = await db.addMessage(googleAuthId, this.conversationId, { message: payload, role: 'tool' }); await db.setState(googleAuthId, this.conversationId, 'busy'); } catch (err) { @@ -439,11 +443,15 @@ export class ConversationManager { } const trimmedContent = (content || text).trim(); - if (trimmedContent) { + const hasToolCalls = Array.isArray(tool_calls) && tool_calls.length > 0; + if (trimmedContent || hasToolCalls) { try { await db.addMessage(googleAuthId, this.conversationId, { role: 'assistant', - message: JSON.stringify({ content: trimmedContent }), + message: JSON.stringify({ + content: trimmedContent, + ...(hasToolCalls ? { tool_calls } : {}), + }), }); text = ''; emitCompanyEvent('modelconversation', { companyId: this.companyId }); @@ -452,7 +460,17 @@ export class ConversationManager { } } }, - onToolCall: async () => {}, + onToolCall: async ({ name, args, id, callItem }) => { + const rawArgs = callItem?.function?.arguments || (typeof args === 'string' ? args : JSON.stringify(args || {})); + console.log(`[conversation ${this.conversationId}] tool call: ${name} args=${rawArgs}`); + this.broadcast('state', { + state: 'toolcall', + id: id || callItem?.id || '', + name, + arguments: rawArgs, + content: rawArgs, + }); + }, onToolResult: async ({ name, result, id, callItem }) => { const rawArgs = callItem?.function?.arguments || ''; this.broadcast('state', { @@ -591,6 +609,10 @@ export class ConversationManager { // Direct return (e.g. from ask_user) halts without adding an additional assistant message. if (result?.directReturn) { + console.log( + `[conversation ${this.conversationId}] direct return halted loop: ` + + JSON.stringify(result.data) + ); return; }