bikky 0.1.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/LICENSE +661 -0
- package/README.md +323 -0
- package/bin/bikky.js +6 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +51 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +59 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +141 -0
- package/dist/config.js.map +1 -0
- package/dist/config.test.d.ts +8 -0
- package/dist/config.test.d.ts.map +1 -0
- package/dist/config.test.js +449 -0
- package/dist/config.test.js.map +1 -0
- package/dist/daemon/consolidation.d.ts +60 -0
- package/dist/daemon/consolidation.d.ts.map +1 -0
- package/dist/daemon/consolidation.js +448 -0
- package/dist/daemon/consolidation.js.map +1 -0
- package/dist/daemon/extraction.d.ts +17 -0
- package/dist/daemon/extraction.d.ts.map +1 -0
- package/dist/daemon/extraction.js +465 -0
- package/dist/daemon/extraction.js.map +1 -0
- package/dist/daemon/index.d.ts +3 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +3 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/loop.d.ts +3 -0
- package/dist/daemon/loop.d.ts.map +1 -0
- package/dist/daemon/loop.js +93 -0
- package/dist/daemon/loop.js.map +1 -0
- package/dist/daemon/qdrant.d.ts +103 -0
- package/dist/daemon/qdrant.d.ts.map +1 -0
- package/dist/daemon/qdrant.js +273 -0
- package/dist/daemon/qdrant.js.map +1 -0
- package/dist/daemon/qdrant.test.d.ts +8 -0
- package/dist/daemon/qdrant.test.d.ts.map +1 -0
- package/dist/daemon/qdrant.test.js +209 -0
- package/dist/daemon/qdrant.test.js.map +1 -0
- package/dist/daemon/relations.d.ts +54 -0
- package/dist/daemon/relations.d.ts.map +1 -0
- package/dist/daemon/relations.js +290 -0
- package/dist/daemon/relations.js.map +1 -0
- package/dist/daemon/staleness.d.ts +24 -0
- package/dist/daemon/staleness.d.ts.map +1 -0
- package/dist/daemon/staleness.js +63 -0
- package/dist/daemon/staleness.js.map +1 -0
- package/dist/daemon/watcher.d.ts +11 -0
- package/dist/daemon/watcher.d.ts.map +1 -0
- package/dist/daemon/watcher.js +38 -0
- package/dist/daemon/watcher.js.map +1 -0
- package/dist/daemon/watcher.test.d.ts +8 -0
- package/dist/daemon/watcher.test.d.ts.map +1 -0
- package/dist/daemon/watcher.test.js +214 -0
- package/dist/daemon/watcher.test.js.map +1 -0
- package/dist/install.d.ts +5 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +49 -0
- package/dist/install.js.map +1 -0
- package/dist/install.test.d.ts +9 -0
- package/dist/install.test.d.ts.map +1 -0
- package/dist/install.test.js +126 -0
- package/dist/install.test.js.map +1 -0
- package/dist/llm/embedding.d.ts +13 -0
- package/dist/llm/embedding.d.ts.map +1 -0
- package/dist/llm/embedding.js +127 -0
- package/dist/llm/embedding.js.map +1 -0
- package/dist/llm/embedding.test.d.ts +8 -0
- package/dist/llm/embedding.test.d.ts.map +1 -0
- package/dist/llm/embedding.test.js +117 -0
- package/dist/llm/embedding.test.js.map +1 -0
- package/dist/llm/index.d.ts +4 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +3 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/inference.d.ts +12 -0
- package/dist/llm/inference.d.ts.map +1 -0
- package/dist/llm/inference.js +146 -0
- package/dist/llm/inference.js.map +1 -0
- package/dist/llm/inference.test.d.ts +8 -0
- package/dist/llm/inference.test.d.ts.map +1 -0
- package/dist/llm/inference.test.js +117 -0
- package/dist/llm/inference.test.js.map +1 -0
- package/dist/llm/types.d.ts +41 -0
- package/dist/llm/types.d.ts.map +1 -0
- package/dist/llm/types.js +5 -0
- package/dist/llm/types.js.map +1 -0
- package/dist/logger.d.ts +13 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +41 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp/api.d.ts +30 -0
- package/dist/mcp/api.d.ts.map +1 -0
- package/dist/mcp/api.js +150 -0
- package/dist/mcp/api.js.map +1 -0
- package/dist/mcp/helpers.d.ts +35 -0
- package/dist/mcp/helpers.d.ts.map +1 -0
- package/dist/mcp/helpers.js +152 -0
- package/dist/mcp/helpers.js.map +1 -0
- package/dist/mcp/helpers.test.d.ts +5 -0
- package/dist/mcp/helpers.test.d.ts.map +1 -0
- package/dist/mcp/helpers.test.js +487 -0
- package/dist/mcp/helpers.test.js.map +1 -0
- package/dist/mcp/index.d.ts +9 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +67 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/taxonomy.d.ts +38 -0
- package/dist/mcp/taxonomy.d.ts.map +1 -0
- package/dist/mcp/taxonomy.js +223 -0
- package/dist/mcp/taxonomy.js.map +1 -0
- package/dist/mcp/taxonomy.test.d.ts +5 -0
- package/dist/mcp/taxonomy.test.d.ts.map +1 -0
- package/dist/mcp/taxonomy.test.js +341 -0
- package/dist/mcp/taxonomy.test.js.map +1 -0
- package/dist/mcp/tools.d.ts +6 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +958 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mcp/types.d.ts +118 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +5 -0
- package/dist/mcp/types.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Events-based memory extraction — reads Copilot CLI events.jsonl transcripts,
|
|
3
|
+
* extracts facts via LLM, and stores them in Qdrant with source: "daemon".
|
|
4
|
+
*
|
|
5
|
+
* Uses a JSON file for extraction state (high-water byte offsets) instead of SQLite.
|
|
6
|
+
* Active session detection scans ~/.copilot/session-state/ for lock files.
|
|
7
|
+
*/
|
|
8
|
+
import { readFile, stat } from "node:fs/promises";
|
|
9
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
10
|
+
import { createHash } from "node:crypto";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { glob } from "node:fs/promises";
|
|
13
|
+
import { loadConfig, STATE_DIR } from "../config.js";
|
|
14
|
+
import * as qdrant from "./qdrant.js";
|
|
15
|
+
import { chatCompletion } from "../llm/index.js";
|
|
16
|
+
import { detectContradiction } from "./consolidation.js";
|
|
17
|
+
// ── Module state ─────────────────────────────────────────────────────────────
|
|
18
|
+
let logFn = (() => { });
|
|
19
|
+
let lastTickAt = 0;
|
|
20
|
+
export const setLogger = (fn) => {
|
|
21
|
+
logFn = fn;
|
|
22
|
+
};
|
|
23
|
+
// ── Constants ────────────────────────────────────────────────────────────────
|
|
24
|
+
const EXTRACTABLE_TYPES = new Set([
|
|
25
|
+
"user.message",
|
|
26
|
+
"assistant.message",
|
|
27
|
+
"session.compaction_complete",
|
|
28
|
+
]);
|
|
29
|
+
const EXTRACTION_PROMPT = `You are a knowledge extraction agent. Extract atomic facts from this conversation transcript that would be USEFUL TO A FUTURE ENGINEERING SESSION working on a different task.
|
|
30
|
+
|
|
31
|
+
## Utility test (apply to every fact before including it)
|
|
32
|
+
Ask: "Would a different engineer, working on a different task next week, benefit from knowing this?"
|
|
33
|
+
- YES → include it (architecture, decisions with rationale, infrastructure quirks, team ownership, durable project status)
|
|
34
|
+
- NO → skip it (debugging observations, test case details, intermediate errors, transient state)
|
|
35
|
+
|
|
36
|
+
## What to extract
|
|
37
|
+
- Architectural decisions with rationale ("chose X over Y because Z")
|
|
38
|
+
- Infrastructure details (endpoints, configs, service quirks, where credentials live)
|
|
39
|
+
- Project milestones and outcomes (PR merged, feature shipped, migration completed)
|
|
40
|
+
- Team ownership and roles (who owns what service)
|
|
41
|
+
- Tool configurations and conventions (deployment patterns, naming conventions)
|
|
42
|
+
- Durable observations (a service has a known limitation, a pattern that recurs)
|
|
43
|
+
|
|
44
|
+
## What to SKIP (critical — these are the most common mistakes)
|
|
45
|
+
- Debugging details: "test 67 fails because BSB has no hyphen" — transient, session-specific
|
|
46
|
+
- Intermediate errors: "got a 404 when calling X" — unless it reveals a permanent quirk
|
|
47
|
+
- Test case specifics: "CSV for test 82 was updated" — code change detail, not knowledge
|
|
48
|
+
- Step-by-step narration: "the user asked to fix X, then we looked at Y" — that's a log, not a fact
|
|
49
|
+
- Obvious or redundant: "the bot sends messages" — too generic to be useful
|
|
50
|
+
- Point-in-time debugging state: "there are 8 failures in tests 33, 34, 35..." — will be stale immediately
|
|
51
|
+
- Vague summaries without actionable detail: "WhatsApp bot adopted the enricher" — which enricher? which PR? If you can't add the detail, skip it
|
|
52
|
+
|
|
53
|
+
## Output format
|
|
54
|
+
Each fact must include an importance score (0.0-1.0):
|
|
55
|
+
- 0.8-1.0: Architectural decisions, infrastructure endpoints, security configurations
|
|
56
|
+
- 0.5-0.7: Project milestones, team ownership, tool conventions
|
|
57
|
+
- 0.2-0.4: Transient observations that might help short-term (if you must include them)
|
|
58
|
+
- Below 0.2: Don't include — it's noise
|
|
59
|
+
|
|
60
|
+
{"facts": [
|
|
61
|
+
{
|
|
62
|
+
"content": "The EC2 instance has no git installed; deploys use pre-built Docker images pulled from ECR",
|
|
63
|
+
"category": "infrastructure",
|
|
64
|
+
"entities": ["ec2", "ecr", "docker"],
|
|
65
|
+
"confidence": 0.9,
|
|
66
|
+
"importance": 0.8
|
|
67
|
+
}
|
|
68
|
+
]}
|
|
69
|
+
|
|
70
|
+
- Category must be one of: infrastructure, decisions, observation, preferences, projects, team
|
|
71
|
+
- Entities should be lowercase identifiers (e.g. "qdrant", "redis", "platform")
|
|
72
|
+
- Confidence 0.0-1.0: how certain (0.9 for explicit statements, 0.6 for inferences)
|
|
73
|
+
- Importance 0.0-1.0: how useful to future sessions (see scale above)
|
|
74
|
+
|
|
75
|
+
If there is nothing worth extracting, return: {"facts": []}`;
|
|
76
|
+
// ── JSON-file state persistence ──────────────────────────────────────────────
|
|
77
|
+
const EXTRACTION_STATE_PATH = join(STATE_DIR, "extraction-state.json");
|
|
78
|
+
const loadExtractionStates = () => {
|
|
79
|
+
try {
|
|
80
|
+
if (existsSync(EXTRACTION_STATE_PATH)) {
|
|
81
|
+
return JSON.parse(readFileSync(EXTRACTION_STATE_PATH, "utf-8"));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
logFn("WARN", "Failed to load extraction state, starting fresh");
|
|
86
|
+
}
|
|
87
|
+
return {};
|
|
88
|
+
};
|
|
89
|
+
const saveExtractionStates = (states) => {
|
|
90
|
+
mkdirSync(STATE_DIR, { recursive: true });
|
|
91
|
+
writeFileSync(EXTRACTION_STATE_PATH, JSON.stringify(states, null, 2) + "\n", "utf-8");
|
|
92
|
+
};
|
|
93
|
+
const getExtractionState = (sessionId) => {
|
|
94
|
+
const states = loadExtractionStates();
|
|
95
|
+
return states[sessionId] ?? null;
|
|
96
|
+
};
|
|
97
|
+
const upsertExtractionState = (state) => {
|
|
98
|
+
const states = loadExtractionStates();
|
|
99
|
+
states[state.session_id] = state;
|
|
100
|
+
saveExtractionStates(states);
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Scan lock files to build PID → Copilot UUID mapping.
|
|
104
|
+
* Copilot CLI writes `inuse.<pid>.lock` in each session directory.
|
|
105
|
+
*/
|
|
106
|
+
const resolveLockFiles = async () => {
|
|
107
|
+
const cfg = loadConfig();
|
|
108
|
+
const copilotStateDir = cfg.watchers.copilot.path;
|
|
109
|
+
const mappings = [];
|
|
110
|
+
try {
|
|
111
|
+
const pattern = join(copilotStateDir, "*/inuse.*.lock");
|
|
112
|
+
for await (const lockPath of glob(pattern)) {
|
|
113
|
+
const lockPathStr = String(lockPath);
|
|
114
|
+
const parts = lockPathStr.split("/");
|
|
115
|
+
const lockFile = parts.at(-1) ?? ""; // inuse.12345.lock
|
|
116
|
+
const uuid = parts.at(-2) ?? ""; // session UUID
|
|
117
|
+
const pidMatch = lockFile.match(/^inuse\.(\d+)\.lock$/);
|
|
118
|
+
if (!pidMatch || !uuid)
|
|
119
|
+
continue;
|
|
120
|
+
const pid = parseInt(pidMatch[1], 10);
|
|
121
|
+
const eventsPath = join(copilotStateDir, uuid, "events.jsonl");
|
|
122
|
+
// Verify events.jsonl exists
|
|
123
|
+
try {
|
|
124
|
+
await stat(eventsPath);
|
|
125
|
+
mappings.push({ pid, uuid, eventsPath });
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// No events.jsonl — skip
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
logFn("WARN", `Lock file scan failed: ${e.message}`);
|
|
134
|
+
}
|
|
135
|
+
return mappings;
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* Check if a process is still running.
|
|
139
|
+
*/
|
|
140
|
+
const isProcessAlive = (pid) => {
|
|
141
|
+
try {
|
|
142
|
+
process.kill(pid, 0);
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Read new events from events.jsonl starting at the given byte offset.
|
|
151
|
+
* Returns parsed extractable events and the new byte offset.
|
|
152
|
+
*/
|
|
153
|
+
const readNewEvents = async (eventsPath, byteOffset) => {
|
|
154
|
+
const fileStat = await stat(eventsPath);
|
|
155
|
+
if (fileStat.size <= byteOffset) {
|
|
156
|
+
return { events: [], newOffset: byteOffset, totalLines: 0 };
|
|
157
|
+
}
|
|
158
|
+
// Read from byte offset to end of file
|
|
159
|
+
const buf = await readFile(eventsPath);
|
|
160
|
+
const newContent = buf.subarray(byteOffset).toString("utf-8");
|
|
161
|
+
const events = [];
|
|
162
|
+
let totalLines = 0;
|
|
163
|
+
for (const line of newContent.split("\n")) {
|
|
164
|
+
if (!line.trim())
|
|
165
|
+
continue;
|
|
166
|
+
totalLines++;
|
|
167
|
+
try {
|
|
168
|
+
const obj = JSON.parse(line);
|
|
169
|
+
if (!EXTRACTABLE_TYPES.has(obj.type))
|
|
170
|
+
continue;
|
|
171
|
+
const data = obj.data || {};
|
|
172
|
+
let content = "";
|
|
173
|
+
if (obj.type === "user.message") {
|
|
174
|
+
content = data.content || "";
|
|
175
|
+
}
|
|
176
|
+
else if (obj.type === "assistant.message") {
|
|
177
|
+
const parts = [];
|
|
178
|
+
if (data.content)
|
|
179
|
+
parts.push(data.content);
|
|
180
|
+
if (data.reasoningText)
|
|
181
|
+
parts.push(data.reasoningText);
|
|
182
|
+
// Skip reasoningOpaque — encrypted noise
|
|
183
|
+
content = parts.join("\n");
|
|
184
|
+
}
|
|
185
|
+
else if (obj.type === "session.compaction_complete") {
|
|
186
|
+
content = data.summaryContent || "";
|
|
187
|
+
}
|
|
188
|
+
if (content.length > 0) {
|
|
189
|
+
events.push({
|
|
190
|
+
type: obj.type,
|
|
191
|
+
content,
|
|
192
|
+
timestamp: obj.timestamp || new Date().toISOString(),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// Malformed line — skip
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return { events, newOffset: fileStat.size, totalLines };
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* Build a compressed transcript from parsed events for LLM extraction.
|
|
204
|
+
*/
|
|
205
|
+
const buildTranscript = (events) => {
|
|
206
|
+
const lines = [];
|
|
207
|
+
for (const ev of events) {
|
|
208
|
+
const role = ev.type === "user.message"
|
|
209
|
+
? "USER"
|
|
210
|
+
: ev.type === "assistant.message"
|
|
211
|
+
? "ASSISTANT"
|
|
212
|
+
: "SUMMARY";
|
|
213
|
+
// Truncate very long content (e.g. reasoning text)
|
|
214
|
+
const text = ev.content.length > 2000
|
|
215
|
+
? ev.content.slice(0, 2000) + "…[truncated]"
|
|
216
|
+
: ev.content;
|
|
217
|
+
lines.push(`[${role}] ${text}`);
|
|
218
|
+
}
|
|
219
|
+
return lines.join("\n\n");
|
|
220
|
+
};
|
|
221
|
+
/**
|
|
222
|
+
* Call the LLM to extract facts from a conversation transcript.
|
|
223
|
+
*/
|
|
224
|
+
const extractFacts = async (transcript) => {
|
|
225
|
+
if (!transcript.trim())
|
|
226
|
+
return [];
|
|
227
|
+
const result = await chatCompletion({
|
|
228
|
+
messages: [
|
|
229
|
+
{ role: "system", content: EXTRACTION_PROMPT },
|
|
230
|
+
{ role: "user", content: transcript },
|
|
231
|
+
],
|
|
232
|
+
temperature: 0.1,
|
|
233
|
+
max_tokens: 4000,
|
|
234
|
+
response_format: { type: "json_object" },
|
|
235
|
+
});
|
|
236
|
+
if (!result) {
|
|
237
|
+
logFn("WARN", "Extraction LLM call returned null");
|
|
238
|
+
return [];
|
|
239
|
+
}
|
|
240
|
+
try {
|
|
241
|
+
// Parse — handle {facts: [...]}, raw array, or single-fact object
|
|
242
|
+
let parsed = JSON.parse(result);
|
|
243
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
244
|
+
const obj = parsed;
|
|
245
|
+
const unwrapped = obj.facts || obj.results || obj.items;
|
|
246
|
+
if (Array.isArray(unwrapped)) {
|
|
247
|
+
parsed = unwrapped;
|
|
248
|
+
}
|
|
249
|
+
else if (obj.content && typeof obj.content === "string") {
|
|
250
|
+
// Single fact object — wrap in array
|
|
251
|
+
parsed = [obj];
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
// Try first array value from the object
|
|
255
|
+
const firstVal = Object.values(obj).find(v => Array.isArray(v));
|
|
256
|
+
parsed = firstVal || [obj];
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (!Array.isArray(parsed)) {
|
|
260
|
+
logFn("WARN", `Extraction LLM returned non-array: ${result.slice(0, 300)}`);
|
|
261
|
+
return [];
|
|
262
|
+
}
|
|
263
|
+
return parsed
|
|
264
|
+
.filter(f => f.content && typeof f.content === "string" && f.category)
|
|
265
|
+
.map(f => ({
|
|
266
|
+
content: f.content,
|
|
267
|
+
category: f.category,
|
|
268
|
+
entities: Array.isArray(f.entities) ? f.entities.map(e => String(e).toLowerCase()) : [],
|
|
269
|
+
confidence: typeof f.confidence === "number" ? f.confidence : 0.7,
|
|
270
|
+
importance: typeof f.importance === "number" ? f.importance : 0.5,
|
|
271
|
+
}))
|
|
272
|
+
.filter(f => {
|
|
273
|
+
if (f.importance < 0.3) {
|
|
274
|
+
logFn("DEBUG", `Extraction: dropping low-importance fact (${f.importance}): "${f.content.slice(0, 80)}…"`);
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
return true;
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
catch (e) {
|
|
281
|
+
logFn("WARN", `Extraction LLM parse error: ${e.message} — raw: ${result.slice(0, 200)}`);
|
|
282
|
+
return [];
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
// ── Fact storage ─────────────────────────────────────────────────────────────
|
|
286
|
+
const contentHash = (text) => createHash("sha256").update(text).digest("hex");
|
|
287
|
+
/**
|
|
288
|
+
* Dedup-check and store extracted facts in Qdrant.
|
|
289
|
+
* Returns count of facts actually inserted.
|
|
290
|
+
*/
|
|
291
|
+
const storeFacts = async (facts, sessionId, config) => {
|
|
292
|
+
if (!qdrant.isReady()) {
|
|
293
|
+
logFn("WARN", "Extraction: Qdrant not ready, skipping store");
|
|
294
|
+
return 0;
|
|
295
|
+
}
|
|
296
|
+
const baseMeta = { extracted_from_session: sessionId };
|
|
297
|
+
let stored = 0;
|
|
298
|
+
for (const fact of facts) {
|
|
299
|
+
const hash = contentHash(fact.content);
|
|
300
|
+
try {
|
|
301
|
+
const dedup = await qdrant.dedupCheck(fact.content, hash);
|
|
302
|
+
if (dedup.action === "skip") {
|
|
303
|
+
// Reinforce existing fact
|
|
304
|
+
if (dedup.existingId) {
|
|
305
|
+
await qdrant.reinforceFact(dedup.existingId, dedup.existingCount || 1);
|
|
306
|
+
}
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
// Run contradiction detection for non-trivial facts
|
|
310
|
+
if (config && (fact.confidence ?? 0.5) >= 0.5) {
|
|
311
|
+
try {
|
|
312
|
+
const contradiction = await detectContradiction(fact, config);
|
|
313
|
+
if (contradiction.contradiction && contradiction.existingId) {
|
|
314
|
+
logFn("INFO", `Extraction: contradiction detected for "${fact.content.slice(0, 60)}..." vs ${contradiction.existingId}: ${contradiction.reason}`);
|
|
315
|
+
// Log contradiction instead of writing to inbox
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
catch (e) {
|
|
319
|
+
logFn("WARN", `Extraction: contradiction check failed: ${e.message}`);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
const storePayload = {
|
|
323
|
+
content: fact.content,
|
|
324
|
+
category: fact.category,
|
|
325
|
+
entities: fact.entities,
|
|
326
|
+
source: "daemon",
|
|
327
|
+
kind: "fact",
|
|
328
|
+
confidence: fact.confidence,
|
|
329
|
+
importance: fact.importance,
|
|
330
|
+
content_hash: hash,
|
|
331
|
+
metadata: baseMeta,
|
|
332
|
+
};
|
|
333
|
+
if (dedup.action === "supersede" && dedup.existingId) {
|
|
334
|
+
const newId = await qdrant.storeFact(storePayload);
|
|
335
|
+
await qdrant.supersedeFact(dedup.existingId, newId);
|
|
336
|
+
stored++;
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
await qdrant.storeFact(storePayload);
|
|
340
|
+
stored++;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
catch (e) {
|
|
344
|
+
logFn("WARN", `Extraction: failed to store fact: ${e.message}`);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return stored;
|
|
348
|
+
};
|
|
349
|
+
// ── Tick entry point ─────────────────────────────────────────────────────────
|
|
350
|
+
// Max transcript size per LLM call (~60K chars ≈ 15K tokens)
|
|
351
|
+
const MAX_TRANSCRIPT_CHARS = 60_000;
|
|
352
|
+
/**
|
|
353
|
+
* Periodic extraction tick — called from the daemon tick loop.
|
|
354
|
+
* For each active Copilot session with events.jsonl, reads new events
|
|
355
|
+
* since the last high-water mark, extracts facts via LLM, and stores in Qdrant.
|
|
356
|
+
*/
|
|
357
|
+
export const tick = async (config) => {
|
|
358
|
+
if (config.daemon.extract_every_sec === 0) {
|
|
359
|
+
logFn("DEBUG", "Extraction: disabled by config (extract_every_sec=0)");
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
if (!qdrant.isReady()) {
|
|
363
|
+
logFn("DEBUG", "Extraction: Qdrant not ready, skipping");
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
// Respect extract_every_sec at the global level
|
|
367
|
+
const intervalMs = (config.daemon.extract_every_sec || 300) * 1000;
|
|
368
|
+
const now = Date.now();
|
|
369
|
+
if (now - lastTickAt < intervalMs)
|
|
370
|
+
return;
|
|
371
|
+
lastTickAt = now;
|
|
372
|
+
const minEvents = config.daemon.extract_min_events || 5;
|
|
373
|
+
try {
|
|
374
|
+
// Extract from ALL active Copilot sessions with events.jsonl
|
|
375
|
+
const lockMappings = await resolveLockFiles();
|
|
376
|
+
const aliveMappings = lockMappings.filter(m => isProcessAlive(m.pid));
|
|
377
|
+
logFn("INFO", `Extraction tick: ${aliveMappings.length} active copilot session(s) with events.jsonl`);
|
|
378
|
+
for (const mapping of aliveMappings) {
|
|
379
|
+
await extractForUuid(mapping, minEvents, config);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
catch (e) {
|
|
383
|
+
logFn("ERROR", `Extraction tick failed: ${e.message}`);
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
/**
|
|
387
|
+
* Extract facts for a single Copilot session identified by UUID.
|
|
388
|
+
* Uses UUID as the extraction_state key.
|
|
389
|
+
* Automatically chunks large transcripts into multiple LLM calls.
|
|
390
|
+
*/
|
|
391
|
+
const extractForUuid = async (mapping, minEvents, config) => {
|
|
392
|
+
const { uuid, eventsPath } = mapping;
|
|
393
|
+
// Use UUID as session_id in extraction_state (prefix with "uuid:" to avoid collisions)
|
|
394
|
+
const stateKey = `uuid:${uuid}`;
|
|
395
|
+
let state = getExtractionState(stateKey);
|
|
396
|
+
if (!state) {
|
|
397
|
+
state = {
|
|
398
|
+
session_id: stateKey,
|
|
399
|
+
copilot_uuid: uuid,
|
|
400
|
+
events_path: eventsPath,
|
|
401
|
+
byte_offset: 0,
|
|
402
|
+
last_extracted_at: null,
|
|
403
|
+
event_count: 0,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
// Read new events
|
|
407
|
+
const { events, newOffset, totalLines } = await readNewEvents(eventsPath, state.byte_offset);
|
|
408
|
+
if (events.length < minEvents) {
|
|
409
|
+
// Still update offset to avoid re-scanning non-extractable events
|
|
410
|
+
if (newOffset > state.byte_offset) {
|
|
411
|
+
state.byte_offset = newOffset;
|
|
412
|
+
state.event_count += totalLines;
|
|
413
|
+
upsertExtractionState(state);
|
|
414
|
+
}
|
|
415
|
+
return 0;
|
|
416
|
+
}
|
|
417
|
+
// Chunk events into transcript-sized batches to stay within LLM limits
|
|
418
|
+
const chunks = chunkEvents(events, MAX_TRANSCRIPT_CHARS);
|
|
419
|
+
let totalFacts = 0;
|
|
420
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
421
|
+
const transcript = buildTranscript(chunks[i]);
|
|
422
|
+
logFn("DEBUG", `Extraction: UUID ${uuid.slice(0, 8)} — chunk ${i + 1}/${chunks.length}, ${chunks[i].length} events, ${transcript.length} chars`);
|
|
423
|
+
const facts = await extractFacts(transcript);
|
|
424
|
+
if (facts.length > 0) {
|
|
425
|
+
const stored = await storeFacts(facts, stateKey, config);
|
|
426
|
+
totalFacts += stored;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
if (totalFacts > 0) {
|
|
430
|
+
logFn("INFO", `Extraction: UUID ${uuid.slice(0, 8)} — ${totalFacts} facts stored (${events.length} events, ${chunks.length} chunk(s))`);
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
logFn("DEBUG", `Extraction: UUID ${uuid.slice(0, 8)} — ${events.length} events but 0 facts extracted`);
|
|
434
|
+
}
|
|
435
|
+
// Update high-water mark
|
|
436
|
+
state.byte_offset = newOffset;
|
|
437
|
+
state.event_count += totalLines;
|
|
438
|
+
state.last_extracted_at = new Date().toISOString();
|
|
439
|
+
state.copilot_uuid = uuid;
|
|
440
|
+
state.events_path = eventsPath;
|
|
441
|
+
upsertExtractionState(state);
|
|
442
|
+
return totalFacts;
|
|
443
|
+
};
|
|
444
|
+
/**
|
|
445
|
+
* Split events into chunks where each chunk's transcript stays under maxChars.
|
|
446
|
+
*/
|
|
447
|
+
const chunkEvents = (events, maxChars) => {
|
|
448
|
+
const chunks = [];
|
|
449
|
+
let current = [];
|
|
450
|
+
let currentSize = 0;
|
|
451
|
+
for (const ev of events) {
|
|
452
|
+
const evSize = Math.min(ev.content.length, 2000) + 20; // account for role prefix + newlines
|
|
453
|
+
if (currentSize + evSize > maxChars && current.length > 0) {
|
|
454
|
+
chunks.push(current);
|
|
455
|
+
current = [];
|
|
456
|
+
currentSize = 0;
|
|
457
|
+
}
|
|
458
|
+
current.push(ev);
|
|
459
|
+
currentSize += evSize;
|
|
460
|
+
}
|
|
461
|
+
if (current.length > 0)
|
|
462
|
+
chunks.push(current);
|
|
463
|
+
return chunks;
|
|
464
|
+
};
|
|
465
|
+
//# sourceMappingURL=extraction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extraction.js","sourceRoot":"","sources":["../../src/daemon/extraction.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/daemon/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/daemon/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/daemon/loop.ts"],"names":[],"mappings":"AAwBA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAqEjD;AAED,wBAAgB,UAAU,IAAI,IAAI,CAOjC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon tick loop — orchestrates extraction, consolidation, relations, staleness.
|
|
3
|
+
*/
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { loadConfig, LOG_DIR } from "../config.js";
|
|
6
|
+
import { createLogger } from "../logger.js";
|
|
7
|
+
import { initLLM } from "../llm/index.js";
|
|
8
|
+
// Import daemon modules
|
|
9
|
+
import * as qdrantClient from "./qdrant.js";
|
|
10
|
+
import { tick as extractionTick, setLogger as setExtractionLogger } from "./extraction.js";
|
|
11
|
+
import { tick as consolidationTick, setLogger as setConsolidationLogger } from "./consolidation.js";
|
|
12
|
+
import { tick as relationsTick, setLogger as setRelationsLogger } from "./relations.js";
|
|
13
|
+
import { scanStaleFacts, setLogger as setStalenessLogger } from "./staleness.js";
|
|
14
|
+
// createLogger returns (LogLevel, ...args) but daemon modules accept (string, ...args).
|
|
15
|
+
// The daemon only calls with valid LogLevel values, so the cast is safe.
|
|
16
|
+
const log = createLogger("daemon", path.join(LOG_DIR, "daemon.log"));
|
|
17
|
+
let running = false;
|
|
18
|
+
let tickCount = 0;
|
|
19
|
+
let intervalHandle = null;
|
|
20
|
+
export async function startDaemon() {
|
|
21
|
+
const cfg = loadConfig();
|
|
22
|
+
log("INFO", `Starting bikky daemon (PID ${process.pid})`);
|
|
23
|
+
// Wire up loggers for all daemon sub-modules
|
|
24
|
+
qdrantClient.setLogger(log);
|
|
25
|
+
setExtractionLogger(log);
|
|
26
|
+
setConsolidationLogger(log);
|
|
27
|
+
setRelationsLogger(log);
|
|
28
|
+
setStalenessLogger(log);
|
|
29
|
+
// Initialize LLM client from config
|
|
30
|
+
initLLM({
|
|
31
|
+
config: {
|
|
32
|
+
provider: cfg.llm.provider,
|
|
33
|
+
ollama_url: cfg.llm.base_url,
|
|
34
|
+
ollama_model: cfg.llm.model,
|
|
35
|
+
openai_api_key: cfg.llm.api_key,
|
|
36
|
+
openai_model: cfg.llm.model,
|
|
37
|
+
bedrock_region: cfg.llm.bedrock_region,
|
|
38
|
+
bedrock_model: cfg.llm.model,
|
|
39
|
+
},
|
|
40
|
+
logger: log,
|
|
41
|
+
});
|
|
42
|
+
// Initialize Qdrant client
|
|
43
|
+
const ready = qdrantClient.init();
|
|
44
|
+
if (!ready) {
|
|
45
|
+
log("WARN", "Qdrant not configured — daemon will retry on each tick");
|
|
46
|
+
}
|
|
47
|
+
running = true;
|
|
48
|
+
const intervalMs = (cfg.daemon.tick_interval_sec || 5) * 1000;
|
|
49
|
+
const tickFn = async () => {
|
|
50
|
+
if (!running)
|
|
51
|
+
return;
|
|
52
|
+
tickCount++;
|
|
53
|
+
try {
|
|
54
|
+
await extractionTick(cfg);
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
log("ERROR", `Extraction tick failed: ${e.message}`);
|
|
58
|
+
}
|
|
59
|
+
// Consolidation runs less frequently (handled internally via tick counts)
|
|
60
|
+
try {
|
|
61
|
+
await consolidationTick(cfg);
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
log("ERROR", `Consolidation tick failed: ${e.message}`);
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
await relationsTick(cfg);
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
log("ERROR", `Relations tick failed: ${e.message}`);
|
|
71
|
+
}
|
|
72
|
+
// Staleness scans every 1000 ticks (~83 min at 5s interval)
|
|
73
|
+
if (tickCount % 1000 === 0) {
|
|
74
|
+
try {
|
|
75
|
+
await scanStaleFacts(cfg);
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
log("ERROR", `Staleness scan failed: ${e.message}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
intervalHandle = setInterval(() => { tickFn().catch(e => log("ERROR", `Tick loop error: ${e.message}`)); }, intervalMs);
|
|
83
|
+
log("INFO", `Daemon running — tick interval ${intervalMs}ms`);
|
|
84
|
+
}
|
|
85
|
+
export function stopDaemon() {
|
|
86
|
+
running = false;
|
|
87
|
+
if (intervalHandle) {
|
|
88
|
+
clearInterval(intervalHandle);
|
|
89
|
+
intervalHandle = null;
|
|
90
|
+
}
|
|
91
|
+
log("INFO", "Daemon stopping");
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/daemon/loop.ts"],"names":[],"mappings":"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"}
|