@kernel.chat/kbot 3.99.7 → 3.99.9
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/dist/agent.js +14 -0
- package/dist/auth.js +26 -0
- package/dist/doctor.js +25 -0
- package/dist/model-capabilities.d.ts +14 -0
- package/dist/model-capabilities.js +71 -0
- package/package.json +1 -1
package/dist/agent.js
CHANGED
|
@@ -105,6 +105,8 @@ async function safeReadBody(res, maxBytes = MAX_RESPONSE_BODY) {
|
|
|
105
105
|
}
|
|
106
106
|
return decoder.decode(merged);
|
|
107
107
|
}
|
|
108
|
+
// Track whether we've already warned about a weak-tool-calling model this process.
|
|
109
|
+
let weakModelWarningShown = false;
|
|
108
110
|
// ── Local-first execution ──
|
|
109
111
|
async function tryLocalFirst(message) {
|
|
110
112
|
const lower = message.toLowerCase().trim();
|
|
@@ -790,6 +792,18 @@ export async function runAgent(message, options = {}) {
|
|
|
790
792
|
if (isLocal && byokProvider === 'ollama') {
|
|
791
793
|
warmOllamaModelCache().catch(() => { }); // non-blocking
|
|
792
794
|
}
|
|
795
|
+
// Step 0b: One-time-per-session warning if configured model lacks tool calling
|
|
796
|
+
if (isLocal && !weakModelWarningShown) {
|
|
797
|
+
weakModelWarningShown = true;
|
|
798
|
+
try {
|
|
799
|
+
const { getWeakModelWarning } = await import('./model-capabilities.js');
|
|
800
|
+
const model = getProviderModel(byokProvider, 'default');
|
|
801
|
+
const warning = await getWeakModelWarning(byokProvider, model);
|
|
802
|
+
if (warning)
|
|
803
|
+
ui.onWarning(warning);
|
|
804
|
+
}
|
|
805
|
+
catch { /* capability check is non-critical */ }
|
|
806
|
+
}
|
|
793
807
|
// Step 0: Parse multimodal content (images in message)
|
|
794
808
|
const parsed = options.multimodal || parseMultimodalMessage(message);
|
|
795
809
|
if (parsed.isMultimodal) {
|
package/dist/auth.js
CHANGED
|
@@ -490,8 +490,34 @@ export function getProviderModel(provider, speed, taskHint) {
|
|
|
490
490
|
if (provider === 'ollama' && speed === 'default' && taskHint) {
|
|
491
491
|
return selectOllamaModel(taskHint);
|
|
492
492
|
}
|
|
493
|
+
// Respect user's configured local_model (Ollama) / fast_model / thinking_model
|
|
494
|
+
// from ~/.kbot/config.json BEFORE falling back to hardcoded defaults.
|
|
495
|
+
if (provider === 'ollama') {
|
|
496
|
+
try {
|
|
497
|
+
const cfg = loadConfigRaw();
|
|
498
|
+
if (speed === 'fast' && cfg.fast_model)
|
|
499
|
+
return cfg.fast_model;
|
|
500
|
+
if (speed === 'default' && cfg.local_model)
|
|
501
|
+
return cfg.local_model;
|
|
502
|
+
}
|
|
503
|
+
catch { /* config missing — fall through */ }
|
|
504
|
+
}
|
|
493
505
|
return speed === 'fast' ? p.fastModel : p.defaultModel;
|
|
494
506
|
}
|
|
507
|
+
/** Lightweight config read — avoids circular dep with full loadConfig. */
|
|
508
|
+
function loadConfigRaw() {
|
|
509
|
+
try {
|
|
510
|
+
const { readFileSync } = require('node:fs');
|
|
511
|
+
const { join } = require('node:path');
|
|
512
|
+
const { homedir } = require('node:os');
|
|
513
|
+
const path = join(homedir(), '.kbot', 'config.json');
|
|
514
|
+
const content = readFileSync(path, 'utf-8');
|
|
515
|
+
return JSON.parse(content);
|
|
516
|
+
}
|
|
517
|
+
catch {
|
|
518
|
+
return {};
|
|
519
|
+
}
|
|
520
|
+
}
|
|
495
521
|
/** Get the provider API URL */
|
|
496
522
|
export function getProviderUrl(provider) {
|
|
497
523
|
return PROVIDERS[provider].apiUrl;
|
package/dist/doctor.js
CHANGED
|
@@ -404,6 +404,29 @@ async function checkOllamaMLX() {
|
|
|
404
404
|
message: `Ollama ${version} — upgrade to 0.19+ for MLX backend (2x faster on Apple Silicon)`,
|
|
405
405
|
};
|
|
406
406
|
}
|
|
407
|
+
async function checkToolCapability() {
|
|
408
|
+
try {
|
|
409
|
+
const { getByokProvider, getProviderModel } = await import('./auth.js');
|
|
410
|
+
const { supportsToolCalls } = await import('./model-capabilities.js');
|
|
411
|
+
const provider = getByokProvider();
|
|
412
|
+
const model = getProviderModel(provider, 'default');
|
|
413
|
+
const ok = await supportsToolCalls(provider, model);
|
|
414
|
+
if (ok === true) {
|
|
415
|
+
return { name: 'Tool calling', status: 'pass', message: `${model} supports tool calls` };
|
|
416
|
+
}
|
|
417
|
+
if (ok === false) {
|
|
418
|
+
return {
|
|
419
|
+
name: 'Tool calling',
|
|
420
|
+
status: 'fail',
|
|
421
|
+
message: `${model} does NOT support tool calls — file reads, bash, git will hallucinate. Switch with \`kbot auth\` to qwen2.5-coder:14b, mistral:7b, or any Ollama model with the "tools" capability.`,
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
return { name: 'Tool calling', status: 'warn', message: `could not determine tool-call support for ${model}` };
|
|
425
|
+
}
|
|
426
|
+
catch {
|
|
427
|
+
return { name: 'Tool calling', status: 'warn', message: 'check failed unexpectedly' };
|
|
428
|
+
}
|
|
429
|
+
}
|
|
407
430
|
// ── Hardware checks (uses machine.ts) ──
|
|
408
431
|
async function checkHardware() {
|
|
409
432
|
const results = [];
|
|
@@ -491,6 +514,8 @@ export async function runDoctor() {
|
|
|
491
514
|
// Ollama MLX check (Apple Silicon only)
|
|
492
515
|
if (ollamaMLXResult)
|
|
493
516
|
checks.push(ollamaMLXResult);
|
|
517
|
+
// Tool-calling capability of configured model
|
|
518
|
+
checks.push(await checkToolCapability());
|
|
494
519
|
// Hardware checks
|
|
495
520
|
checks.push(...hardwareResults);
|
|
496
521
|
// More synchronous checks
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ByokProvider } from './auth.js';
|
|
2
|
+
/**
|
|
3
|
+
* Check whether a specific model can invoke tools.
|
|
4
|
+
* For Ollama/local: queries the model's capabilities endpoint.
|
|
5
|
+
* For cloud providers: returns true for the known-capable list.
|
|
6
|
+
* Returns `null` if the answer can't be determined (non-fatal — caller decides).
|
|
7
|
+
*/
|
|
8
|
+
export declare function supportsToolCalls(provider: ByokProvider, model: string): Promise<boolean | null>;
|
|
9
|
+
/**
|
|
10
|
+
* Human-readable recommendation when a model lacks tool support.
|
|
11
|
+
* Returns null if the model is fine OR if we can't tell.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getWeakModelWarning(provider: ByokProvider, model: string): Promise<string | null>;
|
|
14
|
+
//# sourceMappingURL=model-capabilities.d.ts.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Model Capability Detection
|
|
2
|
+
//
|
|
3
|
+
// kbot's agent loop depends on tool calling. When the configured model
|
|
4
|
+
// doesn't support tools, users see weird bugs: answers hallucinated instead
|
|
5
|
+
// of reading files, capabilities denied instead of exercised, tool-call
|
|
6
|
+
// syntax printed as markdown instead of invoked.
|
|
7
|
+
//
|
|
8
|
+
// This module answers one question reliably: does the configured model
|
|
9
|
+
// support tool calls?
|
|
10
|
+
//
|
|
11
|
+
// For Ollama, we query `/api/show` which returns `capabilities: ['tools', ...]`
|
|
12
|
+
// for tool-capable models. For cloud providers, tool support is assumed
|
|
13
|
+
// (Anthropic, OpenAI, Google, Groq, Mistral, DeepSeek all support it).
|
|
14
|
+
/** Cloud providers with reliable tool-calling support */
|
|
15
|
+
const CLOUD_TOOL_CAPABLE = new Set([
|
|
16
|
+
'anthropic', 'openai', 'google', 'groq', 'mistral',
|
|
17
|
+
'deepseek', 'cohere', 'xai', 'openrouter', 'together',
|
|
18
|
+
]);
|
|
19
|
+
/**
|
|
20
|
+
* Check whether a specific model can invoke tools.
|
|
21
|
+
* For Ollama/local: queries the model's capabilities endpoint.
|
|
22
|
+
* For cloud providers: returns true for the known-capable list.
|
|
23
|
+
* Returns `null` if the answer can't be determined (non-fatal — caller decides).
|
|
24
|
+
*/
|
|
25
|
+
export async function supportsToolCalls(provider, model) {
|
|
26
|
+
// Cloud providers — trust the allowlist
|
|
27
|
+
if (CLOUD_TOOL_CAPABLE.has(provider))
|
|
28
|
+
return true;
|
|
29
|
+
// Ollama — ask the server directly
|
|
30
|
+
if (provider === 'ollama') {
|
|
31
|
+
try {
|
|
32
|
+
const res = await fetch('http://localhost:11434/api/show', {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
headers: { 'Content-Type': 'application/json' },
|
|
35
|
+
body: JSON.stringify({ name: model }),
|
|
36
|
+
signal: AbortSignal.timeout(3000),
|
|
37
|
+
});
|
|
38
|
+
if (!res.ok)
|
|
39
|
+
return null;
|
|
40
|
+
const data = await res.json();
|
|
41
|
+
if (!Array.isArray(data.capabilities))
|
|
42
|
+
return null;
|
|
43
|
+
return data.capabilities.includes('tools');
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Unknown — don't speculate
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Human-readable recommendation when a model lacks tool support.
|
|
54
|
+
* Returns null if the model is fine OR if we can't tell.
|
|
55
|
+
*/
|
|
56
|
+
export async function getWeakModelWarning(provider, model) {
|
|
57
|
+
const ok = await supportsToolCalls(provider, model);
|
|
58
|
+
if (ok !== false)
|
|
59
|
+
return null; // true or null → no warning
|
|
60
|
+
const recs = {
|
|
61
|
+
ollama: ['qwen2.5-coder:14b', 'qwen2.5-coder:7b', 'mistral:7b', 'llama3.1:8b', 'kernel-coder:latest'],
|
|
62
|
+
};
|
|
63
|
+
const suggestions = recs[provider]?.filter(s => s !== model).slice(0, 3) ?? [];
|
|
64
|
+
const suggestionStr = suggestions.length > 0
|
|
65
|
+
? ` Suggested tool-capable alternatives: ${suggestions.join(', ')}.`
|
|
66
|
+
: '';
|
|
67
|
+
return `Model "${model}" does not support tool calls. ` +
|
|
68
|
+
`kbot's file reads, shell commands, and git operations will silently fail or be hallucinated.${suggestionStr} ` +
|
|
69
|
+
`Switch with: \`kbot auth\` or set a tool-capable model in ~/.kbot/config.json.`;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=model-capabilities.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kernel.chat/kbot",
|
|
3
|
-
"version": "3.99.
|
|
3
|
+
"version": "3.99.9",
|
|
4
4
|
"description": "Open-source terminal AI agent. 787+ tools, 35 agents, 20 providers. Dreams, learns, watches your system. Controls your phone. Fully local, fully sovereign. MIT.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|