diff options
| author | Agando <roduccomm@gmail.com> | 2026-06-01 06:00:39 +0200 |
|---|---|---|
| committer | Agando <roduccomm@gmail.com> | 2026-06-01 06:00:39 +0200 |
| commit | 6aed9c9e0252b0c8f681a358e5a8707271454137 (patch) | |
| tree | 332a29a515c87c2295355cf81f18b818cfbaa846 /modules/core/ollama-manager.js | |
| parent | 7cc82d2d32e44ab1c5b7d042d5522d036d9aa0be (diff) | |
auto: 2026-06-01_06:00 changes
Diffstat (limited to 'modules/core/ollama-manager.js')
| -rw-r--r-- | modules/core/ollama-manager.js | 72 |
1 files changed, 68 insertions, 4 deletions
diff --git a/modules/core/ollama-manager.js b/modules/core/ollama-manager.js index ab3ec2c..9999184 100644 --- a/modules/core/ollama-manager.js +++ b/modules/core/ollama-manager.js @@ -15,9 +15,9 @@ class OllamaManager { this.optimizationEnabled = localStorage.getItem('webx11_optimization_enabled') !== 'false'; // --- Streaming Toggle --- this.streamEnabled = localStorage.getItem('webx11_stream_enabled') !== 'false'; - // --- Validator Agent Config (future) --- - this.validatorEnabled = localStorage.getItem('webx11_validator_enabled') === 'true'; - this.validatorModel = localStorage.getItem('webx11_validator_model') || ''; + // --- Validator Agent Config --- + this.validatorEnabled = localStorage.getItem('webx11_validator_enabled') !== 'false'; + this.validatorModel = localStorage.getItem('webx11_validator_model') || 'ministral-3:3b-cloud'; this.validatorEndpoint = localStorage.getItem('webx11_validator_endpoint') || ''; // Build fallback endpoints this.fallbackEndpoints = []; @@ -865,6 +865,70 @@ class OllamaManager { } } + // MiniCPM5 XML tool calling mode — sends tools in message context instead of API parameter + // Model natively outputs <function name="x"><param name="y">val</param> XML + if (useModel && useModel.includes('minicpm5') && tools && tools.length > 0) { + this.terminal.print(`🧩 Using XML tool mode for ${useModel}...`, 'info'); + try { + // Inject tool defs into a system message (the orchestrator model knows XML format) + const toolDesc = tools.map(t => JSON.stringify({type:'function',function:t.function})).join('\n'); + const toolContext = { role: 'system', content: +`You are a tool orchestrator. When you need to call a tool, output XML like: +<function name="function-name"><param name="param-name">param-value</param> + +Available tools: +<tools> +${toolDesc} +</tools> + +Only output XML function calls for tool tasks. If no tool is needed, answer normally.` }; + const msgsWithTools = [toolContext, ...messages]; + const body = { model: useModel, messages: msgsWithTools, stream: false, options: { temperature: 0.1 } }; + + const response = await fetch(`${this.endpoint}/api/chat`, { + method: 'POST', headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body), signal + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + const data = await response.json(); + const text = (data.message?.content || '').trim(); + + // Parse XML function calls from the response + const toolCalls = []; + const funcRegex = /<function\s+name="([^"]+)"(.*?)<\/function>/gs; + let match; + while ((match = funcRegex.exec(text)) !== null) { + const funcName = match[1]; + const args = {}; + const paramRegex = /<param\s+name="([^"]+)"(.*?)>(.*?)<\/param>/gs; + let pmatch; + while ((pmatch = paramRegex.exec(match[0])) !== null) { + args[pmatch[1]] = pmatch[3] + .replace('<![CDATA[', '').replace(']]>', '') + .replace(/^\s+|\s+$/g, ''); + } + if (funcName && Object.keys(args).length > 0) { + toolCalls.push({ + id: 'call_' + Math.random().toString(36).slice(2, 10), + type: 'function', + function: { name: funcName, arguments: JSON.stringify(args) } + }); + } + } + if (toolCalls.length > 0) { + this.terminal.print(`✅ XML tool call(s) parsed from ${useModel}`, 'success'); + return { message: { role: 'assistant', content: '' }, tool_calls: toolCalls, error: null }; + } + + return { message: { role: 'assistant', content: text || '(no response)' }, tool_calls: null, error: null }; + } catch (e) { + if (e.name === 'AbortError') { + return { message: null, tool_calls: null, error: 'Cancelled' }; + } + return { message: null, tool_calls: null, error: e.message }; + } + } + // Original Ollama fallback this.terminal.print(`Model doesn't support tool calling. Retrying /api/chat without tools...`, 'warning'); try { @@ -981,7 +1045,7 @@ class OllamaManager { }); const data = await res.json(); const answer = (data.message?.content || '').trim().toUpperCase(); - return answer === 'YES'; + return answer.startsWith('YES'); } catch (e) { if (this.terminal) this.terminal.print('⚠️ Validator error: ' + e.message, 'warning'); return true; |