@kernel.chat/kbot 2.3.1 → 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.
Files changed (59) hide show
  1. package/dist/agent.d.ts.map +1 -1
  2. package/dist/agent.js +45 -22
  3. package/dist/agent.js.map +1 -1
  4. package/dist/auth.d.ts +2 -0
  5. package/dist/auth.d.ts.map +1 -1
  6. package/dist/auth.js +41 -12
  7. package/dist/auth.js.map +1 -1
  8. package/dist/auth.test.js +35 -37
  9. package/dist/auth.test.js.map +1 -1
  10. package/dist/cli.js +91 -5
  11. package/dist/cli.js.map +1 -1
  12. package/dist/cloud-sync.d.ts +19 -0
  13. package/dist/cloud-sync.d.ts.map +1 -0
  14. package/dist/cloud-sync.js +184 -0
  15. package/dist/cloud-sync.js.map +1 -0
  16. package/dist/context-manager.d.ts +55 -0
  17. package/dist/context-manager.d.ts.map +1 -0
  18. package/dist/context-manager.js +192 -0
  19. package/dist/context-manager.js.map +1 -0
  20. package/dist/embeddings.d.ts +40 -0
  21. package/dist/embeddings.d.ts.map +1 -0
  22. package/dist/embeddings.js +224 -0
  23. package/dist/embeddings.js.map +1 -0
  24. package/dist/learned-router.d.ts +54 -0
  25. package/dist/learned-router.d.ts.map +1 -0
  26. package/dist/learned-router.js +273 -0
  27. package/dist/learned-router.js.map +1 -0
  28. package/dist/learning.d.ts +1 -1
  29. package/dist/learning.d.ts.map +1 -1
  30. package/dist/learning.js +35 -20
  31. package/dist/learning.js.map +1 -1
  32. package/dist/learning.test.js +34 -43
  33. package/dist/learning.test.js.map +1 -1
  34. package/dist/permissions.d.ts.map +1 -1
  35. package/dist/permissions.js +15 -12
  36. package/dist/permissions.js.map +1 -1
  37. package/dist/plugins.d.ts.map +1 -1
  38. package/dist/plugins.js +30 -1
  39. package/dist/plugins.js.map +1 -1
  40. package/dist/prompt-cache.d.ts +53 -0
  41. package/dist/prompt-cache.d.ts.map +1 -0
  42. package/dist/prompt-cache.js +111 -0
  43. package/dist/prompt-cache.js.map +1 -0
  44. package/dist/streaming.d.ts.map +1 -1
  45. package/dist/streaming.js +6 -1
  46. package/dist/streaming.js.map +1 -1
  47. package/dist/tools/files.d.ts.map +1 -1
  48. package/dist/tools/files.js +16 -7
  49. package/dist/tools/files.js.map +1 -1
  50. package/dist/tools/index.test.js +39 -46
  51. package/dist/tools/index.test.js.map +1 -1
  52. package/dist/ui.d.ts.map +1 -1
  53. package/dist/ui.js +39 -2
  54. package/dist/ui.js.map +1 -1
  55. package/dist/updater.d.ts +11 -1
  56. package/dist/updater.d.ts.map +1 -1
  57. package/dist/updater.js +110 -17
  58. package/dist/updater.js.map +1 -1
  59. package/package.json +1 -1
@@ -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"}