groove-dev 0.27.150 → 0.27.151
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/node_modules/@groove-dev/cli/package.json +1 -1
- package/node_modules/@groove-dev/daemon/package.json +1 -1
- package/node_modules/@groove-dev/daemon/src/agent-loop.js +110 -12
- package/node_modules/@groove-dev/daemon/src/providers/local.js +4 -0
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/agent-loop.js +110 -12
- package/packages/daemon/src/providers/local.js +4 -0
- package/packages/gui/package.json +1 -1
|
@@ -24,6 +24,11 @@ export class AgentLoop extends EventEmitter {
|
|
|
24
24
|
this.idle = true;
|
|
25
25
|
this.abortController = null;
|
|
26
26
|
|
|
27
|
+
// Tool calling mode: 'native' uses OpenAI function-calling API fields,
|
|
28
|
+
// 'prompt' injects tool schemas into the system prompt and parses
|
|
29
|
+
// <tool_call> blocks from the model's text output.
|
|
30
|
+
this.toolMode = 'native';
|
|
31
|
+
|
|
27
32
|
// Metrics
|
|
28
33
|
this.totalTokensIn = 0;
|
|
29
34
|
this.totalTokensOut = 0;
|
|
@@ -132,7 +137,7 @@ export class AgentLoop extends EventEmitter {
|
|
|
132
137
|
const response = await this._callApi();
|
|
133
138
|
if (!response || !this.running) break;
|
|
134
139
|
|
|
135
|
-
|
|
140
|
+
let { content, toolCalls, usage, finishReason } = response;
|
|
136
141
|
consecutiveErrors = 0; // Reset on successful call
|
|
137
142
|
|
|
138
143
|
// Update token tracking from API response
|
|
@@ -140,10 +145,18 @@ export class AgentLoop extends EventEmitter {
|
|
|
140
145
|
this._updateTokens(usage);
|
|
141
146
|
}
|
|
142
147
|
|
|
148
|
+
// In prompt-based mode, parse tool calls from the model's text
|
|
149
|
+
if (this.toolMode === 'prompt' && content) {
|
|
150
|
+
const parsed = this._parseToolCallsFromText(content);
|
|
151
|
+
if (parsed.length > 0) {
|
|
152
|
+
toolCalls = parsed;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
143
156
|
// Append assistant message to conversation history
|
|
144
157
|
const assistantMsg = { role: 'assistant' };
|
|
145
158
|
if (content) assistantMsg.content = content;
|
|
146
|
-
if (toolCalls?.length > 0) {
|
|
159
|
+
if (this.toolMode === 'native' && toolCalls?.length > 0) {
|
|
147
160
|
assistantMsg.tool_calls = toolCalls.map((tc) => ({
|
|
148
161
|
id: tc.id,
|
|
149
162
|
type: 'function',
|
|
@@ -162,9 +175,12 @@ export class AgentLoop extends EventEmitter {
|
|
|
162
175
|
}
|
|
163
176
|
|
|
164
177
|
// Has tool calls — broadcast text before executing tools (if model sent text + tools)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
178
|
+
const displayContent = this.toolMode === 'prompt'
|
|
179
|
+
? (content || '').replace(/<tool_call>[\s\S]*?<\/tool_call>/g, '').trim()
|
|
180
|
+
: content;
|
|
181
|
+
if (displayContent) {
|
|
182
|
+
this._writeLog({ type: 'assistant', content: displayContent.slice(0, 2000) });
|
|
183
|
+
this.emit('output', { type: 'activity', subtype: 'assistant', data: displayContent });
|
|
168
184
|
}
|
|
169
185
|
|
|
170
186
|
// Execute each tool call
|
|
@@ -211,11 +227,19 @@ export class AgentLoop extends EventEmitter {
|
|
|
211
227
|
}
|
|
212
228
|
|
|
213
229
|
// Append tool result to conversation for the model
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
230
|
+
const resultContent = result.success ? (result.result || 'Done.') : `Error: ${result.error}`;
|
|
231
|
+
if (this.toolMode === 'native') {
|
|
232
|
+
this.messages.push({
|
|
233
|
+
role: 'tool',
|
|
234
|
+
tool_call_id: call.id,
|
|
235
|
+
content: resultContent,
|
|
236
|
+
});
|
|
237
|
+
} else {
|
|
238
|
+
this.messages.push({
|
|
239
|
+
role: 'user',
|
|
240
|
+
content: `<tool_result name="${toolName}">\n${resultContent}\n</tool_result>`,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
219
243
|
}
|
|
220
244
|
|
|
221
245
|
// Context rotation is handled by the Rotator's 15s polling loop
|
|
@@ -236,12 +260,15 @@ export class AgentLoop extends EventEmitter {
|
|
|
236
260
|
const body = {
|
|
237
261
|
model: this.config.model,
|
|
238
262
|
messages: this.messages,
|
|
239
|
-
tools: TOOL_DEFINITIONS,
|
|
240
|
-
tool_choice: 'auto',
|
|
241
263
|
temperature: this.config.temperature ?? 0.1,
|
|
242
264
|
max_tokens: this.config.maxResponseTokens || 4096,
|
|
243
265
|
};
|
|
244
266
|
|
|
267
|
+
if (this.toolMode === 'native') {
|
|
268
|
+
body.tools = TOOL_DEFINITIONS;
|
|
269
|
+
body.tool_choice = 'auto';
|
|
270
|
+
}
|
|
271
|
+
|
|
245
272
|
if (this.config.stream !== false) {
|
|
246
273
|
body.stream = true;
|
|
247
274
|
body.stream_options = { include_usage: true };
|
|
@@ -283,6 +310,18 @@ export class AgentLoop extends EventEmitter {
|
|
|
283
310
|
const text = await response.text().catch(() => '');
|
|
284
311
|
const errMsg = `API error ${response.status}: ${text.slice(0, 500)}`;
|
|
285
312
|
|
|
313
|
+
// Detect tool_choice rejection (vLLM, TGI, etc. without tool-calling flags)
|
|
314
|
+
// Fall back to prompt-based tool calling and retry immediately
|
|
315
|
+
if (response.status === 400 && this.toolMode === 'native' &&
|
|
316
|
+
(text.includes('tool_choice') || text.includes('tool-call-parser') || text.includes('enable-auto-tool-choice'))) {
|
|
317
|
+
this._writeLog({ type: 'system', event: 'tool-fallback', reason: 'Runtime rejected native tool calling — switching to prompt-based tools' });
|
|
318
|
+
this.toolMode = 'prompt';
|
|
319
|
+
this._injectToolPrompt();
|
|
320
|
+
delete body.tools;
|
|
321
|
+
delete body.tool_choice;
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
|
|
286
325
|
if (response.status === 401 || response.status === 403) {
|
|
287
326
|
this._writeLog({ type: 'error', text: errMsg });
|
|
288
327
|
this.emit('error', { message: errMsg });
|
|
@@ -405,6 +444,65 @@ export class AgentLoop extends EventEmitter {
|
|
|
405
444
|
};
|
|
406
445
|
}
|
|
407
446
|
|
|
447
|
+
// --- Prompt-Based Tool Calling Fallback ---
|
|
448
|
+
|
|
449
|
+
_injectToolPrompt() {
|
|
450
|
+
const toolPrompt = this._buildToolPrompt();
|
|
451
|
+
const systemIdx = this.messages.findIndex(m => m.role === 'system');
|
|
452
|
+
if (systemIdx >= 0) {
|
|
453
|
+
this.messages[systemIdx].content += '\n\n' + toolPrompt;
|
|
454
|
+
} else {
|
|
455
|
+
this.messages.unshift({ role: 'system', content: toolPrompt });
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
_buildToolPrompt() {
|
|
460
|
+
const toolDefs = TOOL_DEFINITIONS.map(t => {
|
|
461
|
+
const f = t.function;
|
|
462
|
+
const params = Object.entries(f.parameters.properties).map(([name, schema]) => {
|
|
463
|
+
const req = f.parameters.required?.includes(name) ? ' (required)' : ' (optional)';
|
|
464
|
+
return ` - ${name}: ${schema.type}${req} — ${schema.description}`;
|
|
465
|
+
}).join('\n');
|
|
466
|
+
return `### ${f.name}\n${f.description}\nParameters:\n${params}`;
|
|
467
|
+
}).join('\n\n');
|
|
468
|
+
|
|
469
|
+
return `## Available Tools
|
|
470
|
+
|
|
471
|
+
To use a tool, include a tool_call block in your response:
|
|
472
|
+
|
|
473
|
+
<tool_call>
|
|
474
|
+
{"name": "tool_name", "arguments": {"param1": "value1"}}
|
|
475
|
+
</tool_call>
|
|
476
|
+
|
|
477
|
+
You can make multiple tool calls in one response. After each tool call you will receive a <tool_result> with the output.
|
|
478
|
+
|
|
479
|
+
${toolDefs}
|
|
480
|
+
|
|
481
|
+
Always use tools to read, write, or search files and to run commands. Do not guess file contents.`;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
_parseToolCallsFromText(content) {
|
|
485
|
+
if (!content) return [];
|
|
486
|
+
const calls = [];
|
|
487
|
+
const regex = /<tool_call>\s*([\s\S]*?)\s*<\/tool_call>/g;
|
|
488
|
+
let match;
|
|
489
|
+
while ((match = regex.exec(content)) !== null) {
|
|
490
|
+
try {
|
|
491
|
+
const parsed = JSON.parse(match[1].trim());
|
|
492
|
+
if (parsed.name) {
|
|
493
|
+
calls.push({
|
|
494
|
+
id: `call_${Date.now()}_${calls.length}`,
|
|
495
|
+
function: {
|
|
496
|
+
name: parsed.name,
|
|
497
|
+
arguments: JSON.stringify(parsed.arguments || {}),
|
|
498
|
+
},
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
} catch { /* skip malformed tool call */ }
|
|
502
|
+
}
|
|
503
|
+
return calls;
|
|
504
|
+
}
|
|
505
|
+
|
|
408
506
|
// --- Token Tracking ---
|
|
409
507
|
|
|
410
508
|
_updateTokens(usage) {
|
|
@@ -137,6 +137,7 @@ export class LocalProvider extends Provider {
|
|
|
137
137
|
let model = agent.model || 'qwen2.5-coder:7b';
|
|
138
138
|
let apiBase = 'http://localhost:11434/v1';
|
|
139
139
|
let apiKey = agent.apiKey || null;
|
|
140
|
+
let runtimeType = 'ollama';
|
|
140
141
|
|
|
141
142
|
if (agent.apiBase) {
|
|
142
143
|
apiBase = agent.apiBase;
|
|
@@ -153,6 +154,7 @@ export class LocalProvider extends Provider {
|
|
|
153
154
|
if (rt) {
|
|
154
155
|
apiBase = rt.endpoint.includes('/v1') ? rt.endpoint : `${rt.endpoint}/v1`;
|
|
155
156
|
if (rt.apiKey) apiKey = rt.apiKey;
|
|
157
|
+
if (rt.type) runtimeType = rt.type;
|
|
156
158
|
const rtModel = rt.models?.[0];
|
|
157
159
|
model = rtModel?.id || rtModel?.name || ggufId;
|
|
158
160
|
}
|
|
@@ -167,6 +169,7 @@ export class LocalProvider extends Provider {
|
|
|
167
169
|
if (rt) {
|
|
168
170
|
apiBase = rt.endpoint.includes('/v1') ? rt.endpoint : `${rt.endpoint}/v1`;
|
|
169
171
|
if (rt.apiKey) apiKey = rt.apiKey;
|
|
172
|
+
if (rt.type) runtimeType = rt.type;
|
|
170
173
|
model = modelId;
|
|
171
174
|
}
|
|
172
175
|
}
|
|
@@ -176,6 +179,7 @@ export class LocalProvider extends Provider {
|
|
|
176
179
|
return {
|
|
177
180
|
apiBase,
|
|
178
181
|
model,
|
|
182
|
+
runtimeType,
|
|
179
183
|
contextWindow,
|
|
180
184
|
temperature: typeof agent.temperature === 'number' ? agent.temperature : 0.1,
|
|
181
185
|
maxResponseTokens: 4096,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "groove-dev",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.151",
|
|
4
4
|
"description": "Open-source agent orchestration layer — the AI company OS. Local model agent engine (GGUF/Ollama/llama-server), HuggingFace model browser, MCP integrations (Slack, Gmail, Stripe, 15+), agent scheduling (cron), business roles (CMO, CFO, EA). GUI dashboard, multi-agent coordination, zero cold-start, infinite sessions. Works with Claude Code, Codex, Gemini CLI, Ollama, any local model.",
|
|
5
5
|
"license": "FSL-1.1-Apache-2.0",
|
|
6
6
|
"author": "Groove Dev <hello@groovedev.ai> (https://groovedev.ai)",
|
|
@@ -24,6 +24,11 @@ export class AgentLoop extends EventEmitter {
|
|
|
24
24
|
this.idle = true;
|
|
25
25
|
this.abortController = null;
|
|
26
26
|
|
|
27
|
+
// Tool calling mode: 'native' uses OpenAI function-calling API fields,
|
|
28
|
+
// 'prompt' injects tool schemas into the system prompt and parses
|
|
29
|
+
// <tool_call> blocks from the model's text output.
|
|
30
|
+
this.toolMode = 'native';
|
|
31
|
+
|
|
27
32
|
// Metrics
|
|
28
33
|
this.totalTokensIn = 0;
|
|
29
34
|
this.totalTokensOut = 0;
|
|
@@ -132,7 +137,7 @@ export class AgentLoop extends EventEmitter {
|
|
|
132
137
|
const response = await this._callApi();
|
|
133
138
|
if (!response || !this.running) break;
|
|
134
139
|
|
|
135
|
-
|
|
140
|
+
let { content, toolCalls, usage, finishReason } = response;
|
|
136
141
|
consecutiveErrors = 0; // Reset on successful call
|
|
137
142
|
|
|
138
143
|
// Update token tracking from API response
|
|
@@ -140,10 +145,18 @@ export class AgentLoop extends EventEmitter {
|
|
|
140
145
|
this._updateTokens(usage);
|
|
141
146
|
}
|
|
142
147
|
|
|
148
|
+
// In prompt-based mode, parse tool calls from the model's text
|
|
149
|
+
if (this.toolMode === 'prompt' && content) {
|
|
150
|
+
const parsed = this._parseToolCallsFromText(content);
|
|
151
|
+
if (parsed.length > 0) {
|
|
152
|
+
toolCalls = parsed;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
143
156
|
// Append assistant message to conversation history
|
|
144
157
|
const assistantMsg = { role: 'assistant' };
|
|
145
158
|
if (content) assistantMsg.content = content;
|
|
146
|
-
if (toolCalls?.length > 0) {
|
|
159
|
+
if (this.toolMode === 'native' && toolCalls?.length > 0) {
|
|
147
160
|
assistantMsg.tool_calls = toolCalls.map((tc) => ({
|
|
148
161
|
id: tc.id,
|
|
149
162
|
type: 'function',
|
|
@@ -162,9 +175,12 @@ export class AgentLoop extends EventEmitter {
|
|
|
162
175
|
}
|
|
163
176
|
|
|
164
177
|
// Has tool calls — broadcast text before executing tools (if model sent text + tools)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
178
|
+
const displayContent = this.toolMode === 'prompt'
|
|
179
|
+
? (content || '').replace(/<tool_call>[\s\S]*?<\/tool_call>/g, '').trim()
|
|
180
|
+
: content;
|
|
181
|
+
if (displayContent) {
|
|
182
|
+
this._writeLog({ type: 'assistant', content: displayContent.slice(0, 2000) });
|
|
183
|
+
this.emit('output', { type: 'activity', subtype: 'assistant', data: displayContent });
|
|
168
184
|
}
|
|
169
185
|
|
|
170
186
|
// Execute each tool call
|
|
@@ -211,11 +227,19 @@ export class AgentLoop extends EventEmitter {
|
|
|
211
227
|
}
|
|
212
228
|
|
|
213
229
|
// Append tool result to conversation for the model
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
230
|
+
const resultContent = result.success ? (result.result || 'Done.') : `Error: ${result.error}`;
|
|
231
|
+
if (this.toolMode === 'native') {
|
|
232
|
+
this.messages.push({
|
|
233
|
+
role: 'tool',
|
|
234
|
+
tool_call_id: call.id,
|
|
235
|
+
content: resultContent,
|
|
236
|
+
});
|
|
237
|
+
} else {
|
|
238
|
+
this.messages.push({
|
|
239
|
+
role: 'user',
|
|
240
|
+
content: `<tool_result name="${toolName}">\n${resultContent}\n</tool_result>`,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
219
243
|
}
|
|
220
244
|
|
|
221
245
|
// Context rotation is handled by the Rotator's 15s polling loop
|
|
@@ -236,12 +260,15 @@ export class AgentLoop extends EventEmitter {
|
|
|
236
260
|
const body = {
|
|
237
261
|
model: this.config.model,
|
|
238
262
|
messages: this.messages,
|
|
239
|
-
tools: TOOL_DEFINITIONS,
|
|
240
|
-
tool_choice: 'auto',
|
|
241
263
|
temperature: this.config.temperature ?? 0.1,
|
|
242
264
|
max_tokens: this.config.maxResponseTokens || 4096,
|
|
243
265
|
};
|
|
244
266
|
|
|
267
|
+
if (this.toolMode === 'native') {
|
|
268
|
+
body.tools = TOOL_DEFINITIONS;
|
|
269
|
+
body.tool_choice = 'auto';
|
|
270
|
+
}
|
|
271
|
+
|
|
245
272
|
if (this.config.stream !== false) {
|
|
246
273
|
body.stream = true;
|
|
247
274
|
body.stream_options = { include_usage: true };
|
|
@@ -283,6 +310,18 @@ export class AgentLoop extends EventEmitter {
|
|
|
283
310
|
const text = await response.text().catch(() => '');
|
|
284
311
|
const errMsg = `API error ${response.status}: ${text.slice(0, 500)}`;
|
|
285
312
|
|
|
313
|
+
// Detect tool_choice rejection (vLLM, TGI, etc. without tool-calling flags)
|
|
314
|
+
// Fall back to prompt-based tool calling and retry immediately
|
|
315
|
+
if (response.status === 400 && this.toolMode === 'native' &&
|
|
316
|
+
(text.includes('tool_choice') || text.includes('tool-call-parser') || text.includes('enable-auto-tool-choice'))) {
|
|
317
|
+
this._writeLog({ type: 'system', event: 'tool-fallback', reason: 'Runtime rejected native tool calling — switching to prompt-based tools' });
|
|
318
|
+
this.toolMode = 'prompt';
|
|
319
|
+
this._injectToolPrompt();
|
|
320
|
+
delete body.tools;
|
|
321
|
+
delete body.tool_choice;
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
|
|
286
325
|
if (response.status === 401 || response.status === 403) {
|
|
287
326
|
this._writeLog({ type: 'error', text: errMsg });
|
|
288
327
|
this.emit('error', { message: errMsg });
|
|
@@ -405,6 +444,65 @@ export class AgentLoop extends EventEmitter {
|
|
|
405
444
|
};
|
|
406
445
|
}
|
|
407
446
|
|
|
447
|
+
// --- Prompt-Based Tool Calling Fallback ---
|
|
448
|
+
|
|
449
|
+
_injectToolPrompt() {
|
|
450
|
+
const toolPrompt = this._buildToolPrompt();
|
|
451
|
+
const systemIdx = this.messages.findIndex(m => m.role === 'system');
|
|
452
|
+
if (systemIdx >= 0) {
|
|
453
|
+
this.messages[systemIdx].content += '\n\n' + toolPrompt;
|
|
454
|
+
} else {
|
|
455
|
+
this.messages.unshift({ role: 'system', content: toolPrompt });
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
_buildToolPrompt() {
|
|
460
|
+
const toolDefs = TOOL_DEFINITIONS.map(t => {
|
|
461
|
+
const f = t.function;
|
|
462
|
+
const params = Object.entries(f.parameters.properties).map(([name, schema]) => {
|
|
463
|
+
const req = f.parameters.required?.includes(name) ? ' (required)' : ' (optional)';
|
|
464
|
+
return ` - ${name}: ${schema.type}${req} — ${schema.description}`;
|
|
465
|
+
}).join('\n');
|
|
466
|
+
return `### ${f.name}\n${f.description}\nParameters:\n${params}`;
|
|
467
|
+
}).join('\n\n');
|
|
468
|
+
|
|
469
|
+
return `## Available Tools
|
|
470
|
+
|
|
471
|
+
To use a tool, include a tool_call block in your response:
|
|
472
|
+
|
|
473
|
+
<tool_call>
|
|
474
|
+
{"name": "tool_name", "arguments": {"param1": "value1"}}
|
|
475
|
+
</tool_call>
|
|
476
|
+
|
|
477
|
+
You can make multiple tool calls in one response. After each tool call you will receive a <tool_result> with the output.
|
|
478
|
+
|
|
479
|
+
${toolDefs}
|
|
480
|
+
|
|
481
|
+
Always use tools to read, write, or search files and to run commands. Do not guess file contents.`;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
_parseToolCallsFromText(content) {
|
|
485
|
+
if (!content) return [];
|
|
486
|
+
const calls = [];
|
|
487
|
+
const regex = /<tool_call>\s*([\s\S]*?)\s*<\/tool_call>/g;
|
|
488
|
+
let match;
|
|
489
|
+
while ((match = regex.exec(content)) !== null) {
|
|
490
|
+
try {
|
|
491
|
+
const parsed = JSON.parse(match[1].trim());
|
|
492
|
+
if (parsed.name) {
|
|
493
|
+
calls.push({
|
|
494
|
+
id: `call_${Date.now()}_${calls.length}`,
|
|
495
|
+
function: {
|
|
496
|
+
name: parsed.name,
|
|
497
|
+
arguments: JSON.stringify(parsed.arguments || {}),
|
|
498
|
+
},
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
} catch { /* skip malformed tool call */ }
|
|
502
|
+
}
|
|
503
|
+
return calls;
|
|
504
|
+
}
|
|
505
|
+
|
|
408
506
|
// --- Token Tracking ---
|
|
409
507
|
|
|
410
508
|
_updateTokens(usage) {
|
|
@@ -137,6 +137,7 @@ export class LocalProvider extends Provider {
|
|
|
137
137
|
let model = agent.model || 'qwen2.5-coder:7b';
|
|
138
138
|
let apiBase = 'http://localhost:11434/v1';
|
|
139
139
|
let apiKey = agent.apiKey || null;
|
|
140
|
+
let runtimeType = 'ollama';
|
|
140
141
|
|
|
141
142
|
if (agent.apiBase) {
|
|
142
143
|
apiBase = agent.apiBase;
|
|
@@ -153,6 +154,7 @@ export class LocalProvider extends Provider {
|
|
|
153
154
|
if (rt) {
|
|
154
155
|
apiBase = rt.endpoint.includes('/v1') ? rt.endpoint : `${rt.endpoint}/v1`;
|
|
155
156
|
if (rt.apiKey) apiKey = rt.apiKey;
|
|
157
|
+
if (rt.type) runtimeType = rt.type;
|
|
156
158
|
const rtModel = rt.models?.[0];
|
|
157
159
|
model = rtModel?.id || rtModel?.name || ggufId;
|
|
158
160
|
}
|
|
@@ -167,6 +169,7 @@ export class LocalProvider extends Provider {
|
|
|
167
169
|
if (rt) {
|
|
168
170
|
apiBase = rt.endpoint.includes('/v1') ? rt.endpoint : `${rt.endpoint}/v1`;
|
|
169
171
|
if (rt.apiKey) apiKey = rt.apiKey;
|
|
172
|
+
if (rt.type) runtimeType = rt.type;
|
|
170
173
|
model = modelId;
|
|
171
174
|
}
|
|
172
175
|
}
|
|
@@ -176,6 +179,7 @@ export class LocalProvider extends Provider {
|
|
|
176
179
|
return {
|
|
177
180
|
apiBase,
|
|
178
181
|
model,
|
|
182
|
+
runtimeType,
|
|
179
183
|
contextWindow,
|
|
180
184
|
temperature: typeof agent.temperature === 'number' ? agent.temperature : 0.1,
|
|
181
185
|
maxResponseTokens: 4096,
|