@kernel.chat/kbot 2.3.0 → 2.4.0
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.d.ts.map +1 -1
- package/dist/agent.js +45 -22
- package/dist/agent.js.map +1 -1
- package/dist/auth.d.ts +2 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +41 -12
- package/dist/auth.js.map +1 -1
- package/dist/auth.test.js +35 -37
- package/dist/auth.test.js.map +1 -1
- package/dist/cli.js +91 -5
- package/dist/cli.js.map +1 -1
- package/dist/cloud-sync.d.ts +19 -0
- package/dist/cloud-sync.d.ts.map +1 -0
- package/dist/cloud-sync.js +184 -0
- package/dist/cloud-sync.js.map +1 -0
- package/dist/context-manager.d.ts +55 -0
- package/dist/context-manager.d.ts.map +1 -0
- package/dist/context-manager.js +192 -0
- package/dist/context-manager.js.map +1 -0
- package/dist/embeddings.d.ts +40 -0
- package/dist/embeddings.d.ts.map +1 -0
- package/dist/embeddings.js +224 -0
- package/dist/embeddings.js.map +1 -0
- package/dist/learned-router.d.ts +54 -0
- package/dist/learned-router.d.ts.map +1 -0
- package/dist/learned-router.js +273 -0
- package/dist/learned-router.js.map +1 -0
- package/dist/learning.d.ts +1 -1
- package/dist/learning.d.ts.map +1 -1
- package/dist/learning.js +35 -20
- package/dist/learning.js.map +1 -1
- package/dist/learning.test.js +34 -43
- package/dist/learning.test.js.map +1 -1
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +15 -12
- package/dist/permissions.js.map +1 -1
- package/dist/plugins.d.ts.map +1 -1
- package/dist/plugins.js +30 -1
- package/dist/plugins.js.map +1 -1
- package/dist/prompt-cache.d.ts +53 -0
- package/dist/prompt-cache.d.ts.map +1 -0
- package/dist/prompt-cache.js +111 -0
- package/dist/prompt-cache.js.map +1 -0
- package/dist/streaming.d.ts.map +1 -1
- package/dist/streaming.js +6 -1
- package/dist/streaming.js.map +1 -1
- package/dist/tools/files.d.ts.map +1 -1
- package/dist/tools/files.js +16 -7
- package/dist/tools/files.js.map +1 -1
- package/dist/tools/index.test.js +39 -46
- package/dist/tools/index.test.js.map +1 -1
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +39 -2
- package/dist/ui.js.map +1 -1
- package/dist/updater.d.ts +11 -1
- package/dist/updater.d.ts.map +1 -1
- package/dist/updater.js +110 -17
- package/dist/updater.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// K:BOT Cloud Sync — Persist learning data across machines via kbot-engine
|
|
2
|
+
//
|
|
3
|
+
// Syncs patterns, solutions, profile, and knowledge to the cloud.
|
|
4
|
+
// Pull on startup (if cloud has newer data), push after learning.
|
|
5
|
+
// Requires a kernel.chat account token in config.
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import { loadConfig, saveConfig } from './auth.js';
|
|
10
|
+
const KBOT_DIR = join(homedir(), '.kbot');
|
|
11
|
+
const LEARN_DIR = join(KBOT_DIR, 'memory');
|
|
12
|
+
const SYNC_STATE_FILE = join(LEARN_DIR, 'sync-state.json');
|
|
13
|
+
const ENGINE_URL = 'https://eoxxpyixdieprsxlpwcs.supabase.co/functions/v1/kbot-engine';
|
|
14
|
+
function loadSyncState() {
|
|
15
|
+
try {
|
|
16
|
+
if (existsSync(SYNC_STATE_FILE)) {
|
|
17
|
+
return JSON.parse(readFileSync(SYNC_STATE_FILE, 'utf-8'));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
catch { /* fresh state */ }
|
|
21
|
+
return { lastPush: '', lastPull: '', cloudUpdatedAt: '' };
|
|
22
|
+
}
|
|
23
|
+
function saveSyncState(state) {
|
|
24
|
+
try {
|
|
25
|
+
writeFileSync(SYNC_STATE_FILE, JSON.stringify(state, null, 2));
|
|
26
|
+
}
|
|
27
|
+
catch { /* non-critical */ }
|
|
28
|
+
}
|
|
29
|
+
/** Get the kernel.chat token from config */
|
|
30
|
+
export function getCloudToken() {
|
|
31
|
+
const config = loadConfig();
|
|
32
|
+
return config?.kernel_token || null;
|
|
33
|
+
}
|
|
34
|
+
/** Set the kernel.chat token */
|
|
35
|
+
export function setCloudToken(token) {
|
|
36
|
+
const config = loadConfig() || { default_model: 'auto', default_agent: 'auto' };
|
|
37
|
+
config.kernel_token = token;
|
|
38
|
+
saveConfig(config);
|
|
39
|
+
}
|
|
40
|
+
/** Check if cloud sync is configured */
|
|
41
|
+
export function isCloudSyncEnabled() {
|
|
42
|
+
return !!getCloudToken();
|
|
43
|
+
}
|
|
44
|
+
/** Load local learning data files */
|
|
45
|
+
function loadLocalData() {
|
|
46
|
+
const load = (file) => {
|
|
47
|
+
const path = join(LEARN_DIR, file);
|
|
48
|
+
try {
|
|
49
|
+
if (existsSync(path))
|
|
50
|
+
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
51
|
+
}
|
|
52
|
+
catch { /* return default */ }
|
|
53
|
+
return file.endsWith('.json') ? (file.includes('patterns') || file.includes('solutions') || file.includes('knowledge') ? [] : {}) : {};
|
|
54
|
+
};
|
|
55
|
+
return {
|
|
56
|
+
patterns: load('patterns.json'),
|
|
57
|
+
solutions: load('solutions.json'),
|
|
58
|
+
profile: load('profile.json'),
|
|
59
|
+
knowledge: load('knowledge.json'),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** Save cloud data to local files */
|
|
63
|
+
function saveCloudDataLocally(data) {
|
|
64
|
+
const save = (file, content) => {
|
|
65
|
+
if (content && (Array.isArray(content) ? content.length > 0 : Object.keys(content).length > 0)) {
|
|
66
|
+
writeFileSync(join(LEARN_DIR, file), JSON.stringify(content, null, 2));
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
if (data.patterns)
|
|
70
|
+
save('patterns.json', data.patterns);
|
|
71
|
+
if (data.solutions)
|
|
72
|
+
save('solutions.json', data.solutions);
|
|
73
|
+
if (data.profile)
|
|
74
|
+
save('profile.json', data.profile);
|
|
75
|
+
if (data.knowledge)
|
|
76
|
+
save('knowledge.json', data.knowledge);
|
|
77
|
+
}
|
|
78
|
+
/** Pull learning data from cloud (if newer than local) */
|
|
79
|
+
export async function pullFromCloud() {
|
|
80
|
+
const token = getCloudToken();
|
|
81
|
+
if (!token)
|
|
82
|
+
return { synced: false, source: 'none' };
|
|
83
|
+
try {
|
|
84
|
+
const res = await fetch(`${ENGINE_URL}/sync`, {
|
|
85
|
+
method: 'POST',
|
|
86
|
+
headers: {
|
|
87
|
+
'Content-Type': 'application/json',
|
|
88
|
+
'Authorization': `Bearer ${token}`,
|
|
89
|
+
},
|
|
90
|
+
body: JSON.stringify({ action: 'get' }),
|
|
91
|
+
signal: AbortSignal.timeout(10_000),
|
|
92
|
+
});
|
|
93
|
+
if (!res.ok)
|
|
94
|
+
return { synced: false, source: 'none' };
|
|
95
|
+
const { memory } = await res.json();
|
|
96
|
+
if (!memory)
|
|
97
|
+
return { synced: false, source: 'none' };
|
|
98
|
+
const state = loadSyncState();
|
|
99
|
+
const cloudTime = new Date(memory.updated_at || 0).getTime();
|
|
100
|
+
const lastPull = state.lastPull ? new Date(state.lastPull).getTime() : 0;
|
|
101
|
+
// Only overwrite local if cloud is newer than our last pull
|
|
102
|
+
if (cloudTime > lastPull) {
|
|
103
|
+
saveCloudDataLocally(memory);
|
|
104
|
+
state.lastPull = new Date().toISOString();
|
|
105
|
+
state.cloudUpdatedAt = memory.updated_at;
|
|
106
|
+
saveSyncState(state);
|
|
107
|
+
return { synced: true, source: 'cloud' };
|
|
108
|
+
}
|
|
109
|
+
return { synced: false, source: 'local' };
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return { synced: false, source: 'none' };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/** Push local learning data to cloud */
|
|
116
|
+
export async function pushToCloud() {
|
|
117
|
+
const token = getCloudToken();
|
|
118
|
+
if (!token)
|
|
119
|
+
return false;
|
|
120
|
+
try {
|
|
121
|
+
const data = loadLocalData();
|
|
122
|
+
const res = await fetch(`${ENGINE_URL}/sync`, {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
headers: {
|
|
125
|
+
'Content-Type': 'application/json',
|
|
126
|
+
'Authorization': `Bearer ${token}`,
|
|
127
|
+
},
|
|
128
|
+
body: JSON.stringify({
|
|
129
|
+
action: 'push',
|
|
130
|
+
...data,
|
|
131
|
+
}),
|
|
132
|
+
signal: AbortSignal.timeout(10_000),
|
|
133
|
+
});
|
|
134
|
+
if (!res.ok)
|
|
135
|
+
return false;
|
|
136
|
+
const state = loadSyncState();
|
|
137
|
+
state.lastPush = new Date().toISOString();
|
|
138
|
+
saveSyncState(state);
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** Sync on startup: pull if cloud has newer data */
|
|
146
|
+
export async function syncOnStartup() {
|
|
147
|
+
if (!isCloudSyncEnabled())
|
|
148
|
+
return null;
|
|
149
|
+
try {
|
|
150
|
+
const result = await pullFromCloud();
|
|
151
|
+
if (result.synced && result.source === 'cloud') {
|
|
152
|
+
return 'Synced learning data from cloud';
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/** Sync after learning: push local data to cloud (debounced — call after interactions) */
|
|
161
|
+
let pushTimer = null;
|
|
162
|
+
const PUSH_DEBOUNCE_MS = 30_000; // Push at most every 30 seconds
|
|
163
|
+
export function schedulePush() {
|
|
164
|
+
if (!isCloudSyncEnabled())
|
|
165
|
+
return;
|
|
166
|
+
if (pushTimer)
|
|
167
|
+
return; // Already scheduled
|
|
168
|
+
pushTimer = setTimeout(() => {
|
|
169
|
+
pushTimer = null;
|
|
170
|
+
pushToCloud().catch(() => { }); // Fire and forget
|
|
171
|
+
}, PUSH_DEBOUNCE_MS);
|
|
172
|
+
}
|
|
173
|
+
/** Force an immediate push (call on exit) */
|
|
174
|
+
export function flushCloudSync() {
|
|
175
|
+
if (pushTimer) {
|
|
176
|
+
clearTimeout(pushTimer);
|
|
177
|
+
pushTimer = null;
|
|
178
|
+
}
|
|
179
|
+
if (isCloudSyncEnabled()) {
|
|
180
|
+
// Synchronous-ish push — best effort on exit
|
|
181
|
+
pushToCloud().catch(() => { });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=cloud-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloud-sync.js","sourceRoot":"","sources":["../src/cloud-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Max context tokens before compression kicks in */
|
|
2
|
+
export declare const MAX_CONTEXT_TOKENS = 32000;
|
|
3
|
+
/** Conversation turn (matches memory.ts) */
|
|
4
|
+
export interface ConversationTurn {
|
|
5
|
+
role: 'user' | 'assistant';
|
|
6
|
+
content: string;
|
|
7
|
+
}
|
|
8
|
+
/** Extracted key context from a long response */
|
|
9
|
+
export interface KeyContext {
|
|
10
|
+
/** File paths mentioned */
|
|
11
|
+
files: string[];
|
|
12
|
+
/** Decisions or conclusions made */
|
|
13
|
+
decisions: string[];
|
|
14
|
+
/** Errors encountered */
|
|
15
|
+
errors: string[];
|
|
16
|
+
/** User corrections or explicit instructions */
|
|
17
|
+
corrections: string[];
|
|
18
|
+
/** Code snippets (first line of each block) */
|
|
19
|
+
codeSnippets: string[];
|
|
20
|
+
}
|
|
21
|
+
/** Estimate token count using 4-chars-per-token heuristic */
|
|
22
|
+
export declare function estimateTokens(text: string): number;
|
|
23
|
+
/** Estimate total tokens for an array of turns */
|
|
24
|
+
export declare function estimateTurnTokens(turns: ConversationTurn[]): number;
|
|
25
|
+
/** Extract key context from a long text (response or tool output) */
|
|
26
|
+
export declare function extractKeyContext(text: string): KeyContext;
|
|
27
|
+
/**
|
|
28
|
+
* Fold conversation history to fit within a token budget.
|
|
29
|
+
* Implements RLM-style context management:
|
|
30
|
+
* - Keep the most recent turns verbatim (they're most relevant)
|
|
31
|
+
* - Summarize older turns into compact bullet points
|
|
32
|
+
* - Always preserve user corrections and explicit instructions
|
|
33
|
+
* - Never drop the first user message (establishes the task)
|
|
34
|
+
*/
|
|
35
|
+
export declare function foldContext(turns: ConversationTurn[], maxTokens?: number, keepRecentCount?: number): ConversationTurn[];
|
|
36
|
+
/**
|
|
37
|
+
* Decide whether content should be delegated to a sub-model.
|
|
38
|
+
* In an RLM, heavy tool outputs (file contents, search results) are
|
|
39
|
+
* processed by a cheaper model to extract only the relevant bits.
|
|
40
|
+
*/
|
|
41
|
+
export declare function shouldDelegate(contentTokens: number, currentContextTokens: number, maxTokens?: number): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Compress a tool result that's too large for the context window.
|
|
44
|
+
* Extracts key information and discards the rest.
|
|
45
|
+
*/
|
|
46
|
+
export declare function compressToolResult(result: string, maxChars?: number): string;
|
|
47
|
+
/**
|
|
48
|
+
* Auto-compact: check if context needs folding and do it.
|
|
49
|
+
* Call this before each API request.
|
|
50
|
+
*/
|
|
51
|
+
export declare function autoCompact(turns: ConversationTurn[], systemPromptTokens?: number, maxTokens?: number): {
|
|
52
|
+
turns: ConversationTurn[];
|
|
53
|
+
wasCompacted: boolean;
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=context-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-manager.d.ts","sourceRoot":"","sources":["../src/context-manager.ts"],"names":[],"mappings":"AAUA,qDAAqD;AACrD,eAAO,MAAM,kBAAkB,QAAS,CAAA;AAExC,4CAA4C;AAC5C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,iDAAiD;AACjD,MAAM,WAAW,UAAU;IACzB,2BAA2B;IAC3B,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,oCAAoC;IACpC,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,yBAAyB;IACzB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,gDAAgD;IAChD,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,EAAE,CAAA;CACvB;AAED,6DAA6D;AAC7D,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,kDAAkD;AAClD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAEpE;AAED,qEAAqE;AACrE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAgD1D;AAqBD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,gBAAgB,EAAE,EACzB,SAAS,GAAE,MAA2B,EACtC,eAAe,GAAE,MAAU,GAC1B,gBAAgB,EAAE,CA+CpB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,aAAa,EAAE,MAAM,EACrB,oBAAoB,EAAE,MAAM,EAC5B,SAAS,GAAE,MAA2B,GACrC,OAAO,CAGT;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAa,GAAG,MAAM,CAiClF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,gBAAgB,EAAE,EACzB,kBAAkB,GAAE,MAAa,EACjC,SAAS,GAAE,MAA2B,GACrC;IAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAE,CAYtD"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
// K:BOT Context Manager — RLM-style context delegation
|
|
2
|
+
//
|
|
3
|
+
// Based on Recursive Language Models (Prime Intellect, Dec 2025):
|
|
4
|
+
// Instead of stuffing everything into one context window, the agent
|
|
5
|
+
// manages its own context by compressing, delegating, and preserving
|
|
6
|
+
// only what matters.
|
|
7
|
+
//
|
|
8
|
+
// Key insight: treat the conversation history as a resource to be
|
|
9
|
+
// managed, not an ever-growing log.
|
|
10
|
+
/** Max context tokens before compression kicks in */
|
|
11
|
+
export const MAX_CONTEXT_TOKENS = 32_000;
|
|
12
|
+
/** Estimate token count using 4-chars-per-token heuristic */
|
|
13
|
+
export function estimateTokens(text) {
|
|
14
|
+
return Math.ceil(text.length / 4);
|
|
15
|
+
}
|
|
16
|
+
/** Estimate total tokens for an array of turns */
|
|
17
|
+
export function estimateTurnTokens(turns) {
|
|
18
|
+
return turns.reduce((sum, t) => sum + estimateTokens(t.content) + 4, 0); // +4 for role/formatting overhead
|
|
19
|
+
}
|
|
20
|
+
/** Extract key context from a long text (response or tool output) */
|
|
21
|
+
export function extractKeyContext(text) {
|
|
22
|
+
const files = [];
|
|
23
|
+
const decisions = [];
|
|
24
|
+
const errors = [];
|
|
25
|
+
const corrections = [];
|
|
26
|
+
const codeSnippets = [];
|
|
27
|
+
const lines = text.split('\n');
|
|
28
|
+
for (const line of lines) {
|
|
29
|
+
const trimmed = line.trim();
|
|
30
|
+
// File paths — Unix and relative paths
|
|
31
|
+
const fileMatches = trimmed.match(/(?:^|\s)((?:\.{0,2}\/|~\/|src\/|packages\/)[^\s:,)]+\.\w+)/g);
|
|
32
|
+
if (fileMatches) {
|
|
33
|
+
for (const m of fileMatches)
|
|
34
|
+
files.push(m.trim());
|
|
35
|
+
}
|
|
36
|
+
// Decisions — lines starting with action verbs or containing decision language
|
|
37
|
+
if (/^(?:✓|✗|→|•)\s/.test(trimmed) || /\b(?:decided|chose|using|switched to|will use|created|deleted|updated|fixed|added|removed)\b/i.test(trimmed)) {
|
|
38
|
+
decisions.push(trimmed.slice(0, 200));
|
|
39
|
+
}
|
|
40
|
+
// Errors
|
|
41
|
+
if (/\b(?:error|fail|exception|TypeError|SyntaxError|ReferenceError|ENOENT|EACCES|404|500|crash)\b/i.test(trimmed)) {
|
|
42
|
+
errors.push(trimmed.slice(0, 200));
|
|
43
|
+
}
|
|
44
|
+
// User corrections
|
|
45
|
+
if (/^(?:no[,.]?\s|actually[,]?\s|that's wrong|instead[,]?\s|don't|never|always)\b/i.test(trimmed)) {
|
|
46
|
+
corrections.push(trimmed.slice(0, 200));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Code snippets — first line of each code block
|
|
50
|
+
const codeBlockPattern = /```\w*\n(.+)/g;
|
|
51
|
+
let match;
|
|
52
|
+
while ((match = codeBlockPattern.exec(text)) !== null) {
|
|
53
|
+
codeSnippets.push(match[1].trim().slice(0, 100));
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
files: [...new Set(files)].slice(0, 20),
|
|
57
|
+
decisions: decisions.slice(0, 10),
|
|
58
|
+
errors: errors.slice(0, 5),
|
|
59
|
+
corrections: corrections.slice(0, 5),
|
|
60
|
+
codeSnippets: codeSnippets.slice(0, 5),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** Summarize a conversation turn into a compact bullet point */
|
|
64
|
+
function summarizeTurn(turn) {
|
|
65
|
+
const ctx = extractKeyContext(turn.content);
|
|
66
|
+
const parts = [];
|
|
67
|
+
if (turn.role === 'user') {
|
|
68
|
+
// Keep user messages short but preserve intent
|
|
69
|
+
parts.push(turn.content.slice(0, 150));
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// Summarize assistant responses by key context
|
|
73
|
+
if (ctx.decisions.length > 0)
|
|
74
|
+
parts.push(ctx.decisions.slice(0, 3).join('; '));
|
|
75
|
+
if (ctx.files.length > 0)
|
|
76
|
+
parts.push(`Files: ${ctx.files.slice(0, 5).join(', ')}`);
|
|
77
|
+
if (ctx.errors.length > 0)
|
|
78
|
+
parts.push(`Errors: ${ctx.errors.slice(0, 2).join('; ')}`);
|
|
79
|
+
if (parts.length === 0)
|
|
80
|
+
parts.push(turn.content.split('\n')[0].slice(0, 150));
|
|
81
|
+
}
|
|
82
|
+
return `[${turn.role}] ${parts.join(' | ')}`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Fold conversation history to fit within a token budget.
|
|
86
|
+
* Implements RLM-style context management:
|
|
87
|
+
* - Keep the most recent turns verbatim (they're most relevant)
|
|
88
|
+
* - Summarize older turns into compact bullet points
|
|
89
|
+
* - Always preserve user corrections and explicit instructions
|
|
90
|
+
* - Never drop the first user message (establishes the task)
|
|
91
|
+
*/
|
|
92
|
+
export function foldContext(turns, maxTokens = MAX_CONTEXT_TOKENS, keepRecentCount = 6) {
|
|
93
|
+
if (turns.length === 0)
|
|
94
|
+
return [];
|
|
95
|
+
const currentTokens = estimateTurnTokens(turns);
|
|
96
|
+
if (currentTokens <= maxTokens)
|
|
97
|
+
return turns; // No folding needed
|
|
98
|
+
// Keep the most recent turns verbatim
|
|
99
|
+
const recentTurns = turns.slice(-keepRecentCount);
|
|
100
|
+
const olderTurns = turns.slice(0, -keepRecentCount);
|
|
101
|
+
if (olderTurns.length === 0)
|
|
102
|
+
return recentTurns;
|
|
103
|
+
// Summarize older turns, but preserve corrections
|
|
104
|
+
const summaryLines = ['[Context Summary — earlier conversation]'];
|
|
105
|
+
const preservedTurns = [];
|
|
106
|
+
for (const turn of olderTurns) {
|
|
107
|
+
// Always preserve user corrections verbatim
|
|
108
|
+
if (turn.role === 'user' && /^(?:no[,.]?\s|actually|that's wrong|instead|don't|never|always)\b/i.test(turn.content.trim())) {
|
|
109
|
+
preservedTurns.push(turn);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
// Summarize everything else
|
|
113
|
+
summaryLines.push(`• ${summarizeTurn(turn)}`);
|
|
114
|
+
}
|
|
115
|
+
const summaryText = summaryLines.join('\n');
|
|
116
|
+
const summaryTokens = estimateTokens(summaryText);
|
|
117
|
+
const recentTokens = estimateTurnTokens(recentTurns);
|
|
118
|
+
const preservedTokens = estimateTurnTokens(preservedTurns);
|
|
119
|
+
// If summary + recent + preserved fits, use it
|
|
120
|
+
if (summaryTokens + recentTokens + preservedTokens <= maxTokens) {
|
|
121
|
+
return [
|
|
122
|
+
{ role: 'assistant', content: summaryText },
|
|
123
|
+
...preservedTurns,
|
|
124
|
+
...recentTurns,
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
// Still too big — aggressive compression: just keep summary header + recent
|
|
128
|
+
const aggressiveSummary = summaryLines.slice(0, 10).join('\n');
|
|
129
|
+
return [
|
|
130
|
+
{ role: 'assistant', content: aggressiveSummary },
|
|
131
|
+
...recentTurns,
|
|
132
|
+
];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Decide whether content should be delegated to a sub-model.
|
|
136
|
+
* In an RLM, heavy tool outputs (file contents, search results) are
|
|
137
|
+
* processed by a cheaper model to extract only the relevant bits.
|
|
138
|
+
*/
|
|
139
|
+
export function shouldDelegate(contentTokens, currentContextTokens, maxTokens = MAX_CONTEXT_TOKENS) {
|
|
140
|
+
// Delegate if this content would push us past 70% of budget
|
|
141
|
+
return (currentContextTokens + contentTokens) > maxTokens * 0.7;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Compress a tool result that's too large for the context window.
|
|
145
|
+
* Extracts key information and discards the rest.
|
|
146
|
+
*/
|
|
147
|
+
export function compressToolResult(result, maxChars = 4000) {
|
|
148
|
+
if (result.length <= maxChars)
|
|
149
|
+
return result;
|
|
150
|
+
const ctx = extractKeyContext(result);
|
|
151
|
+
const parts = [];
|
|
152
|
+
// Always include errors
|
|
153
|
+
if (ctx.errors.length > 0) {
|
|
154
|
+
parts.push('Errors:', ...ctx.errors.map(e => ` • ${e}`));
|
|
155
|
+
}
|
|
156
|
+
// Include file references
|
|
157
|
+
if (ctx.files.length > 0) {
|
|
158
|
+
parts.push(`Files: ${ctx.files.join(', ')}`);
|
|
159
|
+
}
|
|
160
|
+
// Include key decisions/findings
|
|
161
|
+
if (ctx.decisions.length > 0) {
|
|
162
|
+
parts.push('Key findings:', ...ctx.decisions.map(d => ` • ${d}`));
|
|
163
|
+
}
|
|
164
|
+
// Include first and last portion of raw result for context
|
|
165
|
+
const lines = result.split('\n');
|
|
166
|
+
if (lines.length > 20) {
|
|
167
|
+
parts.push('', '--- First 10 lines ---', ...lines.slice(0, 10));
|
|
168
|
+
parts.push(`... (${lines.length - 20} lines omitted) ...`);
|
|
169
|
+
parts.push('--- Last 10 lines ---', ...lines.slice(-10));
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
parts.push('', result.slice(0, maxChars));
|
|
173
|
+
}
|
|
174
|
+
const compressed = parts.join('\n').slice(0, maxChars);
|
|
175
|
+
return `[Compressed from ${result.length} chars]\n${compressed}`;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Auto-compact: check if context needs folding and do it.
|
|
179
|
+
* Call this before each API request.
|
|
180
|
+
*/
|
|
181
|
+
export function autoCompact(turns, systemPromptTokens = 2000, maxTokens = MAX_CONTEXT_TOKENS) {
|
|
182
|
+
const available = maxTokens - systemPromptTokens - 4096; // Reserve 4K for response
|
|
183
|
+
const current = estimateTurnTokens(turns);
|
|
184
|
+
if (current <= available) {
|
|
185
|
+
return { turns, wasCompacted: false };
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
turns: foldContext(turns, available),
|
|
189
|
+
wasCompacted: true,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=context-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-manager.js","sourceRoot":"","sources":["../src/context-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** Save cache to disk (debounced externally) */
|
|
2
|
+
export declare function saveEmbeddingCache(): void;
|
|
3
|
+
/**
|
|
4
|
+
* Compute semantic similarity between two texts.
|
|
5
|
+
* Uses embeddings if Ollama is available, falls back to Jaccard.
|
|
6
|
+
*/
|
|
7
|
+
export declare function semanticSimilarity(a: string, b: string): Promise<number>;
|
|
8
|
+
/**
|
|
9
|
+
* Find the best match from a list of candidates.
|
|
10
|
+
* Returns the candidate with highest similarity above the threshold.
|
|
11
|
+
*/
|
|
12
|
+
export declare function findBestMatch(query: string, candidates: Array<{
|
|
13
|
+
text: string;
|
|
14
|
+
id: string;
|
|
15
|
+
}>, threshold?: number): Promise<{
|
|
16
|
+
id: string;
|
|
17
|
+
score: number;
|
|
18
|
+
} | null>;
|
|
19
|
+
/**
|
|
20
|
+
* Rank candidates by semantic similarity to query.
|
|
21
|
+
* Returns sorted array with scores.
|
|
22
|
+
*/
|
|
23
|
+
export declare function rankBySimilarity(query: string, candidates: Array<{
|
|
24
|
+
text: string;
|
|
25
|
+
id: string;
|
|
26
|
+
}>, topK?: number): Promise<Array<{
|
|
27
|
+
id: string;
|
|
28
|
+
score: number;
|
|
29
|
+
}>>;
|
|
30
|
+
/** Warm the embedding cache with common queries (call on startup) */
|
|
31
|
+
export declare function warmCache(texts: string[]): Promise<void>;
|
|
32
|
+
/** Check if embeddings are available (Ollama + nomic-embed-text) */
|
|
33
|
+
export declare function isEmbeddingsAvailable(): Promise<boolean>;
|
|
34
|
+
/** Get cache stats */
|
|
35
|
+
export declare function getCacheStats(): {
|
|
36
|
+
size: number;
|
|
37
|
+
maxSize: number;
|
|
38
|
+
available: boolean | null;
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=embeddings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embeddings.d.ts","sourceRoot":"","sources":["../src/embeddings.ts"],"names":[],"mappings":"AAkDA,gDAAgD;AAChD,wBAAgB,kBAAkB,IAAI,IAAI,CAQzC;AAqFD;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAU9E;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,EAC/C,SAAS,GAAE,MAAY,GACtB,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA0B/C;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,EAC/C,IAAI,GAAE,MAAU,GACf,OAAO,CAAC,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAoB/C;AAED,qEAAqE;AACrE,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAU9D;AAED,oEAAoE;AACpE,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CAE9D;AAED,sBAAsB;AACtB,wBAAgB,aAAa,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAAA;CAAE,CAG5F"}
|