mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	wooo, tool execution container shows for openai
This commit is contained in:
		| @@ -97,6 +97,21 @@ export async function setupStreamingResponse( | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             if (message.type === 'tool_result' && message.toolExecution) { |             if (message.type === 'tool_result' && message.toolExecution) { | ||||||
|  |                 console.log(`[${responseId}] Processing tool result: ${JSON.stringify(message.toolExecution)}`); | ||||||
|  |                  | ||||||
|  |                 // If tool execution doesn't have an action, add 'result' as the default | ||||||
|  |                 if (!message.toolExecution.action) { | ||||||
|  |                     message.toolExecution.action = 'result'; | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 // First send a 'start' action to ensure the container is created | ||||||
|  |                 onToolExecution({ | ||||||
|  |                     action: 'start', | ||||||
|  |                     tool: 'tools', | ||||||
|  |                     result: 'Tool execution initialized' | ||||||
|  |                 }); | ||||||
|  |                  | ||||||
|  |                 // Then send the actual tool execution data | ||||||
|                 onToolExecution(message.toolExecution); |                 onToolExecution(message.toolExecution); | ||||||
|                 return; // Skip accumulating content from this message |                 return; // Skip accumulating content from this message | ||||||
|             } |             } | ||||||
| @@ -157,6 +172,41 @@ export async function setupStreamingResponse( | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|              |              | ||||||
|  |             // Handle tool calls from the raw data or direct in message (OpenAI format) | ||||||
|  |             const toolCalls = message.tool_calls || (message.raw && message.raw.tool_calls); | ||||||
|  |             if (toolCalls && Array.isArray(toolCalls)) { | ||||||
|  |                 console.log(`[${responseId}] Received tool calls: ${toolCalls.length} tools`); | ||||||
|  |                  | ||||||
|  |                 // First send a 'start' action to ensure the container is created | ||||||
|  |                 onToolExecution({ | ||||||
|  |                     action: 'start', | ||||||
|  |                     tool: 'tools', | ||||||
|  |                     result: 'Tool execution initialized' | ||||||
|  |                 }); | ||||||
|  |                  | ||||||
|  |                 // Then process each tool call | ||||||
|  |                 for (const toolCall of toolCalls) { | ||||||
|  |                     let args = toolCall.function?.arguments || {}; | ||||||
|  |                      | ||||||
|  |                     // Try to parse arguments if they're a string | ||||||
|  |                     if (typeof args === 'string') { | ||||||
|  |                         try { | ||||||
|  |                             args = JSON.parse(args); | ||||||
|  |                         } catch (e) { | ||||||
|  |                             console.log(`[${responseId}] Could not parse tool arguments as JSON: ${e}`); | ||||||
|  |                             args = { raw: args }; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                      | ||||||
|  |                     onToolExecution({ | ||||||
|  |                         action: 'executing', | ||||||
|  |                         tool: toolCall.function?.name || 'unknown', | ||||||
|  |                         toolCallId: toolCall.id, | ||||||
|  |                         args: args | ||||||
|  |                     }); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|             // Handle thinking state updates |             // Handle thinking state updates | ||||||
|             if (message.thinking) { |             if (message.thinking) { | ||||||
|                 console.log(`[${responseId}] Received thinking update: ${message.thinking.substring(0, 50)}...`); |                 console.log(`[${responseId}] Received thinking update: ${message.thinking.substring(0, 50)}...`); | ||||||
| @@ -200,10 +250,15 @@ export async function setupStreamingResponse( | |||||||
|                     onContentUpdate(assistantResponse, true); |                     onContentUpdate(assistantResponse, true); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 // Clean up and resolve |                 // Set a short delay before cleanup to allow any immediately following | ||||||
|                 cleanupEventListener(eventListener); |                 // tool execution messages to be processed | ||||||
|                 onComplete(); |                 setTimeout(() => { | ||||||
|                 resolve(); |                     // Clean up and resolve | ||||||
|  |                     console.log(`[${responseId}] Cleaning up event listener after delay`); | ||||||
|  |                     cleanupEventListener(eventListener); | ||||||
|  |                     onComplete(); | ||||||
|  |                     resolve(); | ||||||
|  |                 }, 1000); // 1 second delay to allow tool execution messages to arrive | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -997,6 +997,23 @@ export default class LlmChatPanel extends BasicWidget { | |||||||
|     private showToolExecutionInfo(toolExecutionData: any) { |     private showToolExecutionInfo(toolExecutionData: any) { | ||||||
|         console.log(`Showing tool execution info: ${JSON.stringify(toolExecutionData)}`); |         console.log(`Showing tool execution info: ${JSON.stringify(toolExecutionData)}`); | ||||||
|          |          | ||||||
|  |         // Enhanced debugging for tool execution | ||||||
|  |         if (!toolExecutionData) { | ||||||
|  |             console.error('Tool execution data is missing or undefined'); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // Check for required properties | ||||||
|  |         const actionType = toolExecutionData.action || ''; | ||||||
|  |         const toolName = toolExecutionData.tool || 'unknown'; | ||||||
|  |         console.log(`Tool execution details: action=${actionType}, tool=${toolName}, hasResult=${!!toolExecutionData.result}`); | ||||||
|  |          | ||||||
|  |         // Force action to 'result' if missing but result is present | ||||||
|  |         if (!actionType && toolExecutionData.result) { | ||||||
|  |             console.log('Setting missing action to "result" since result is present'); | ||||||
|  |             toolExecutionData.action = 'result'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // Create or get the tool execution container |         // Create or get the tool execution container | ||||||
|         let toolExecutionElement = this.noteContextChatMessages.querySelector('.chat-tool-execution'); |         let toolExecutionElement = this.noteContextChatMessages.querySelector('.chat-tool-execution'); | ||||||
|         if (!toolExecutionElement) { |         if (!toolExecutionElement) { | ||||||
| @@ -1065,8 +1082,8 @@ export default class LlmChatPanel extends BasicWidget { | |||||||
|  |  | ||||||
|             let resultDisplay = ''; |             let resultDisplay = ''; | ||||||
|  |  | ||||||
|             // Special handling for search_notes tool which has a specific structure |             // Special handling for note search tools which have a specific structure | ||||||
|             if (toolExecutionData.tool === 'search_notes' && |             if ((toolExecutionData.tool === 'search_notes' || toolExecutionData.tool === 'keyword_search_notes') && | ||||||
|                 typeof toolExecutionData.result === 'object' && |                 typeof toolExecutionData.result === 'object' && | ||||||
|                 toolExecutionData.result.results) { |                 toolExecutionData.result.results) { | ||||||
|  |  | ||||||
| @@ -1110,8 +1127,8 @@ export default class LlmChatPanel extends BasicWidget { | |||||||
|             `; |             `; | ||||||
|             stepsContainer.appendChild(step); |             stepsContainer.appendChild(step); | ||||||
|  |  | ||||||
|             // Add event listeners for note links if this is a search_notes result |             // Add event listeners for note links if this is a note search result | ||||||
|             if (toolExecutionData.tool === 'search_notes') { |             if (toolExecutionData.tool === 'search_notes' || toolExecutionData.tool === 'keyword_search_notes') { | ||||||
|                 const noteLinks = step.querySelectorAll('.note-link'); |                 const noteLinks = step.querySelectorAll('.note-link'); | ||||||
|                 noteLinks.forEach(link => { |                 noteLinks.forEach(link => { | ||||||
|                     link.addEventListener('click', (e) => { |                     link.addEventListener('click', (e) => { | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| import options from '../../options.js'; | import options from '../../options.js'; | ||||||
| import { BaseAIService } from '../base_ai_service.js'; | import { BaseAIService } from '../base_ai_service.js'; | ||||||
| import type { ChatCompletionOptions, ChatResponse, Message } from '../ai_interface.js'; | import type { ChatCompletionOptions, ChatResponse, Message, StreamChunk } from '../ai_interface.js'; | ||||||
| import { getOpenAIOptions } from './providers.js'; | import { getOpenAIOptions } from './providers.js'; | ||||||
| import OpenAI from 'openai'; | import OpenAI from 'openai'; | ||||||
|  |  | ||||||
| @@ -135,12 +135,22 @@ export class OpenAIService extends BaseAIService { | |||||||
|                                     } |                                     } | ||||||
|  |  | ||||||
|                                     // Send the chunk to the caller with raw data and any accumulated tool calls |                                     // Send the chunk to the caller with raw data and any accumulated tool calls | ||||||
|                                     await callback({ |                                     const streamChunk: StreamChunk & { raw: any } = { | ||||||
|                                         text: content, |                                         text: content, | ||||||
|                                         done: isDone, |                                         done: isDone, | ||||||
|                                         raw: chunk, |                                         raw: chunk | ||||||
|                                         tool_calls: accumulatedToolCalls.length > 0 ? accumulatedToolCalls.filter(Boolean) : undefined |                                     }; | ||||||
|                                     }); |                                      | ||||||
|  |                                     // Add accumulated tool calls to raw data for compatibility with tool execution display | ||||||
|  |                                     if (accumulatedToolCalls.length > 0) { | ||||||
|  |                                         // Add tool calls to raw data for proper display | ||||||
|  |                                         streamChunk.raw = { | ||||||
|  |                                             ...streamChunk.raw, | ||||||
|  |                                             tool_calls: accumulatedToolCalls.filter(Boolean) | ||||||
|  |                                         }; | ||||||
|  |                                     } | ||||||
|  |                                      | ||||||
|  |                                     await callback(streamChunk); | ||||||
|  |  | ||||||
|                                     if (isDone) { |                                     if (isDone) { | ||||||
|                                         break; |                                         break; | ||||||
|   | |||||||
| @@ -1242,6 +1242,80 @@ class RestChatService { | |||||||
|                             } as LLMStreamMessage); |                             } as LLMStreamMessage); | ||||||
|                         } |                         } | ||||||
|                          |                          | ||||||
|  |                         // Handle direct tool_calls in the response (for OpenAI) | ||||||
|  |                         if (chunk.tool_calls && chunk.tool_calls.length > 0) { | ||||||
|  |                             log.info(`Detected direct tool_calls in stream chunk: ${chunk.tool_calls.length} tools`); | ||||||
|  |                              | ||||||
|  |                             // Send tool execution notification | ||||||
|  |                             wsService.sendMessageToAllClients({ | ||||||
|  |                                 type: 'tool_execution_start', | ||||||
|  |                                 sessionId | ||||||
|  |                             } as LLMStreamMessage); | ||||||
|  |                              | ||||||
|  |                             // Process each tool call | ||||||
|  |                             for (const toolCall of chunk.tool_calls) { | ||||||
|  |                                 // Process arguments | ||||||
|  |                                 let args = toolCall.function?.arguments; | ||||||
|  |                                 if (typeof args === 'string') { | ||||||
|  |                                     try { | ||||||
|  |                                         args = JSON.parse(args); | ||||||
|  |                                     } catch (e) { | ||||||
|  |                                         log.info(`Could not parse tool arguments as JSON: ${e}`); | ||||||
|  |                                         args = { raw: args }; | ||||||
|  |                                     } | ||||||
|  |                                 } | ||||||
|  |                                  | ||||||
|  |                                 // Format into a standardized tool execution message | ||||||
|  |                                 wsService.sendMessageToAllClients({ | ||||||
|  |                                     type: 'tool_result', | ||||||
|  |                                     sessionId, | ||||||
|  |                                     toolExecution: { | ||||||
|  |                                         action: 'executing', | ||||||
|  |                                         tool: toolCall.function?.name || 'unknown', | ||||||
|  |                                         toolCallId: toolCall.id, | ||||||
|  |                                         args: args | ||||||
|  |                                     } | ||||||
|  |                                 } as LLMStreamMessage); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                          | ||||||
|  |                         // Also handle tool_calls in raw data if present but not directly in chunk | ||||||
|  |                         if (!chunk.tool_calls && chunk.raw?.tool_calls && Array.isArray(chunk.raw.tool_calls)) { | ||||||
|  |                             log.info(`Detected tool_calls in raw data: ${chunk.raw.tool_calls.length} tools`); | ||||||
|  |                              | ||||||
|  |                             // Send tool execution notification if we haven't already | ||||||
|  |                             wsService.sendMessageToAllClients({ | ||||||
|  |                                 type: 'tool_execution_start', | ||||||
|  |                                 sessionId | ||||||
|  |                             } as LLMStreamMessage); | ||||||
|  |                              | ||||||
|  |                             // Process each tool call | ||||||
|  |                             for (const toolCall of chunk.raw.tool_calls) { | ||||||
|  |                                 // Process arguments | ||||||
|  |                                 let args = toolCall.function?.arguments; | ||||||
|  |                                 if (typeof args === 'string') { | ||||||
|  |                                     try { | ||||||
|  |                                         args = JSON.parse(args); | ||||||
|  |                                     } catch (e) { | ||||||
|  |                                         log.info(`Could not parse tool arguments as JSON: ${e}`); | ||||||
|  |                                         args = { raw: args }; | ||||||
|  |                                     } | ||||||
|  |                                 } | ||||||
|  |                                  | ||||||
|  |                                 // Format into a standardized tool execution message | ||||||
|  |                                 wsService.sendMessageToAllClients({ | ||||||
|  |                                     type: 'tool_result', | ||||||
|  |                                     sessionId, | ||||||
|  |                                     toolExecution: { | ||||||
|  |                                         action: 'executing', | ||||||
|  |                                         tool: toolCall.function?.name || 'unknown', | ||||||
|  |                                         toolCallId: toolCall.id, | ||||||
|  |                                         args: args | ||||||
|  |                                     } | ||||||
|  |                                 } as LLMStreamMessage); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |  | ||||||
|                         // Signal completion when done |                         // Signal completion when done | ||||||
|                         if (chunk.done) { |                         if (chunk.done) { | ||||||
|                             log.info(`Stream completed from ${service.getName()}, total content: ${messageContent.length} chars`); |                             log.info(`Stream completed from ${service.getName()}, total content: ${messageContent.length} chars`); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user