aboutsummaryrefslogtreecommitdiff
path: root/modules/core/ollama-manager.js
diff options
context:
space:
mode:
authorAgando <roduccomm@gmail.com>2026-06-01 06:00:39 +0200
committerAgando <roduccomm@gmail.com>2026-06-01 06:00:39 +0200
commit6aed9c9e0252b0c8f681a358e5a8707271454137 (patch)
tree332a29a515c87c2295355cf81f18b818cfbaa846 /modules/core/ollama-manager.js
parent7cc82d2d32e44ab1c5b7d042d5522d036d9aa0be (diff)
auto: 2026-06-01_06:00 changes
Diffstat (limited to 'modules/core/ollama-manager.js')
-rw-r--r--modules/core/ollama-manager.js72
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;