@kernel.chat/kbot 3.99.13 → 3.99.15
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 +4 -0
- package/dist/checkpoint.d.ts +7 -0
- package/dist/checkpoint.js +39 -0
- package/dist/cli.js +3 -0
- package/dist/learning.js +5 -4
- package/dist/self-awareness.js +1 -0
- package/dist/tools/files.js +9 -0
- package/package.json +1 -1
package/dist/agent.js
CHANGED
|
@@ -1801,6 +1801,10 @@ Always quote file paths that contain spaces. Never reference internal system nam
|
|
|
1801
1801
|
// ── Telemetry: session failure ──
|
|
1802
1802
|
telemetry.emit('session_end', { status: 'failed', error: String(err), toolCallCount });
|
|
1803
1803
|
telemetry.destroy().catch(() => { });
|
|
1804
|
+
// Mark the checkpoint completed even on error — otherwise the stuck
|
|
1805
|
+
// `in_progress` record will be re-detected on every subsequent launch
|
|
1806
|
+
// and pollute the recovery banner forever.
|
|
1807
|
+
checkpointManager.markCompleted(sessionId).catch(() => { });
|
|
1804
1808
|
throw err;
|
|
1805
1809
|
}
|
|
1806
1810
|
}
|
package/dist/checkpoint.d.ts
CHANGED
|
@@ -50,6 +50,13 @@ export declare class CheckpointManager {
|
|
|
50
50
|
* Updates the most recent checkpoint's status to 'completed'.
|
|
51
51
|
*/
|
|
52
52
|
markCompleted(sessionId: string): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Flip any `in_progress` checkpoint older than `staleMs` to `completed`.
|
|
55
|
+
* A live run couldn't possibly still be pending after this cutoff — these
|
|
56
|
+
* are all crashed/killed sessions whose exit path never marked them done.
|
|
57
|
+
* Called on startup so stale checkpoints don't spam the recovery banner.
|
|
58
|
+
*/
|
|
59
|
+
expireStaleInProgress(staleMs?: number): Promise<number>;
|
|
53
60
|
/**
|
|
54
61
|
* Find all checkpoints with status 'in_progress'.
|
|
55
62
|
* Returns them sorted by timestamp descending (most recent first).
|
package/dist/checkpoint.js
CHANGED
|
@@ -91,6 +91,45 @@ export class CheckpointManager {
|
|
|
91
91
|
await writeFile(tmpPath, JSON.stringify(checkpoint, null, 2), 'utf-8');
|
|
92
92
|
await rename(tmpPath, filePath);
|
|
93
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Flip any `in_progress` checkpoint older than `staleMs` to `completed`.
|
|
96
|
+
* A live run couldn't possibly still be pending after this cutoff — these
|
|
97
|
+
* are all crashed/killed sessions whose exit path never marked them done.
|
|
98
|
+
* Called on startup so stale checkpoints don't spam the recovery banner.
|
|
99
|
+
*/
|
|
100
|
+
async expireStaleInProgress(staleMs = 30 * 60 * 1000) {
|
|
101
|
+
await this.ensureDir();
|
|
102
|
+
let files;
|
|
103
|
+
try {
|
|
104
|
+
files = await readdir(this.dir);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
109
|
+
const cutoff = Date.now() - staleMs;
|
|
110
|
+
let expired = 0;
|
|
111
|
+
for (const file of files) {
|
|
112
|
+
if (!file.endsWith('.json'))
|
|
113
|
+
continue;
|
|
114
|
+
const path = join(this.dir, file);
|
|
115
|
+
const cp = await this.readCheckpoint(path);
|
|
116
|
+
if (!cp)
|
|
117
|
+
continue;
|
|
118
|
+
if (cp.status !== 'in_progress')
|
|
119
|
+
continue;
|
|
120
|
+
if (cp.timestamp >= cutoff)
|
|
121
|
+
continue; // too recent, might still be live
|
|
122
|
+
cp.status = 'completed';
|
|
123
|
+
try {
|
|
124
|
+
const tmpPath = path + '.tmp';
|
|
125
|
+
await writeFile(tmpPath, JSON.stringify(cp, null, 2), 'utf-8');
|
|
126
|
+
await rename(tmpPath, path);
|
|
127
|
+
expired++;
|
|
128
|
+
}
|
|
129
|
+
catch { /* best-effort */ }
|
|
130
|
+
}
|
|
131
|
+
return expired;
|
|
132
|
+
}
|
|
94
133
|
/**
|
|
95
134
|
* Find all checkpoints with status 'in_progress'.
|
|
96
135
|
* Returns them sorted by timestamp descending (most recent first).
|
package/dist/cli.js
CHANGED
|
@@ -4316,6 +4316,9 @@ async function main() {
|
|
|
4316
4316
|
try {
|
|
4317
4317
|
const { CheckpointManager } = await import('./checkpoint.js');
|
|
4318
4318
|
const cpManager = new CheckpointManager();
|
|
4319
|
+
// Auto-expire checkpoints older than 30 min that never marked completed —
|
|
4320
|
+
// otherwise crashed sessions linger forever in the recovery banner.
|
|
4321
|
+
await cpManager.expireStaleInProgress().catch(() => 0);
|
|
4319
4322
|
const incomplete = await cpManager.listIncomplete();
|
|
4320
4323
|
if (incomplete.length > 0) {
|
|
4321
4324
|
const latest = incomplete[0];
|
package/dist/learning.js
CHANGED
|
@@ -597,15 +597,16 @@ export function updateProjectMemory(cwd, data) {
|
|
|
597
597
|
// Enhance the existing buildLearningContext
|
|
598
598
|
export function buildFullLearningContext(message, cwd) {
|
|
599
599
|
const parts = [];
|
|
600
|
-
// A. Pattern hint
|
|
600
|
+
// A. Pattern hint — tool-sequence recipe; safe to reuse
|
|
601
601
|
const pattern = findPattern(message);
|
|
602
602
|
if (pattern) {
|
|
603
|
-
parts.push(`[Learned Pattern — ${pattern.hits}x success]`, `Tool sequence: ${pattern.toolSequence.join(' → ')}`);
|
|
603
|
+
parts.push(`[Learned Pattern — ${pattern.hits}x success · tool recipe only, not a cached answer]`, `Tool sequence: ${pattern.toolSequence.join(' → ')}`);
|
|
604
604
|
}
|
|
605
|
-
// B. Relevant solutions
|
|
605
|
+
// B. Relevant solutions — tagged as potentially stale so the model doesn't
|
|
606
|
+
// quote past values verbatim when a tool could verify the current state.
|
|
606
607
|
const relevant = findSolutions(message, 2);
|
|
607
608
|
if (relevant.length > 0) {
|
|
608
|
-
parts.push('[Cached Solutions]');
|
|
609
|
+
parts.push('[Cached Solutions — historical hints; verify specific values via tools before repeating them]');
|
|
609
610
|
for (const s of relevant) {
|
|
610
611
|
parts.push(`Q: ${s.question}\nA: ${s.solution}`);
|
|
611
612
|
}
|
package/dist/self-awareness.js
CHANGED
|
@@ -23,6 +23,7 @@ export function getSelfAwarenessPrompt() {
|
|
|
23
23
|
const lines = [
|
|
24
24
|
'[kbot Ground Truth — AUTHORITATIVE. When asked about yourself (version, model, provider, architecture, capabilities, weaknesses, history, what you are, what you can do), answer ONLY from this block. Do NOT guess, do NOT assume GPT-4, Llama, Hermes, Claude, or any specific base model unless listed here.]',
|
|
25
25
|
'[TOOL POLICY FOR SELF-INTROSPECTION: If the user asks about YOU (your runtime, your model, your provider, your version, your architecture, your skills, your tools, your weaknesses), DO NOT call web_search, url_fetch, research, or other INTERNET-LOOKUP tools — the answer is in this block. HOWEVER, file tools (read_file, glob, grep, bash) and git tools ARE ENCOURAGED — if the user asks about a specific file (e.g., "what version is in package.json"), INVOKE read_file on that file and quote the actual contents. Hallucinating file contents without reading them is a bug; so is denying you have file access.]',
|
|
26
|
+
'[PRECEDENCE RULE: Fresh tool outputs from the CURRENT turn ALWAYS outrank anything in memory, skills, cached solutions, or prior reflections. Memory describes past state (potentially stale). Tools describe current state. If memory says "version is 3.97.0" and a tool just returned "3.99.13", the answer is 3.99.13 — never the memory value. Memory sections ([Cached Solutions], [Learned Pattern], [User Knowledge]) are hints for where to look, not facts to quote verbatim when they concern values that could have changed.]',
|
|
26
27
|
];
|
|
27
28
|
// Version (read from package.json)
|
|
28
29
|
try {
|
package/dist/tools/files.js
CHANGED
|
@@ -13,6 +13,15 @@ function resolvePath(p) {
|
|
|
13
13
|
if (p.startsWith('~/') || p === '~') {
|
|
14
14
|
return resolve(homedir(), p.slice(2) || '.');
|
|
15
15
|
}
|
|
16
|
+
// Model-path quirk: some small models prefix relative paths with "/".
|
|
17
|
+
// If "/foo/bar" doesn't exist at filesystem root but "foo/bar" exists in cwd,
|
|
18
|
+
// use the cwd-relative version. This is non-destructive — real absolute
|
|
19
|
+
// paths still resolve normally.
|
|
20
|
+
if (p.startsWith('/') && !existsSync(p)) {
|
|
21
|
+
const relative = resolve(p.slice(1));
|
|
22
|
+
if (existsSync(relative))
|
|
23
|
+
return relative;
|
|
24
|
+
}
|
|
16
25
|
return resolve(p);
|
|
17
26
|
}
|
|
18
27
|
/** Show a colored diff preview to stderr and return true if user approves */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kernel.chat/kbot",
|
|
3
|
-
"version": "3.99.
|
|
3
|
+
"version": "3.99.15",
|
|
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": {
|