@edeng23/pines 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 +202 -0
- package/README.md +37 -0
- package/dist/cli.js +83 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/ansi.js +37 -0
- package/dist/client/ansi.js.map +1 -0
- package/dist/client/app.js +1868 -0
- package/dist/client/app.js.map +1 -0
- package/dist/client/boot.js +221 -0
- package/dist/client/boot.js.map +1 -0
- package/dist/client/commands.js +133 -0
- package/dist/client/commands.js.map +1 -0
- package/dist/client/daemon-client.js +99 -0
- package/dist/client/daemon-client.js.map +1 -0
- package/dist/client/forest/camera.js +88 -0
- package/dist/client/forest/camera.js.map +1 -0
- package/dist/client/forest/canvas.js +175 -0
- package/dist/client/forest/canvas.js.map +1 -0
- package/dist/client/forest/sidebar.js +182 -0
- package/dist/client/forest/sidebar.js.map +1 -0
- package/dist/client/forest/status.js +39 -0
- package/dist/client/forest/status.js.map +1 -0
- package/dist/client/forest/style.js +70 -0
- package/dist/client/forest/style.js.map +1 -0
- package/dist/client/forest/styles.js +429 -0
- package/dist/client/forest/styles.js.map +1 -0
- package/dist/client/forest/view.js +181 -0
- package/dist/client/forest/view.js.map +1 -0
- package/dist/client/forest/wordmark.js +26 -0
- package/dist/client/forest/wordmark.js.map +1 -0
- package/dist/client/input.js +89 -0
- package/dist/client/input.js.map +1 -0
- package/dist/client/theme.js +27 -0
- package/dist/client/theme.js.map +1 -0
- package/dist/client/tree/asciitree.js +277 -0
- package/dist/client/tree/asciitree.js.map +1 -0
- package/dist/client/tree/convmap.js +260 -0
- package/dist/client/tree/convmap.js.map +1 -0
- package/dist/client/tree/lanegraph.js +260 -0
- package/dist/client/tree/lanegraph.js.map +1 -0
- package/dist/client/tree/merge.js +161 -0
- package/dist/client/tree/merge.js.map +1 -0
- package/dist/client/tree/sessionview.js +163 -0
- package/dist/client/tree/sessionview.js.map +1 -0
- package/dist/client/tree/view.js +238 -0
- package/dist/client/tree/view.js.map +1 -0
- package/dist/client/uistate.js +45 -0
- package/dist/client/uistate.js.map +1 -0
- package/dist/daemon/agents.js +102 -0
- package/dist/daemon/agents.js.map +1 -0
- package/dist/daemon/branch.js +149 -0
- package/dist/daemon/branch.js.map +1 -0
- package/dist/daemon/embed-worker.js +74 -0
- package/dist/daemon/embed-worker.js.map +1 -0
- package/dist/daemon/essence.js +194 -0
- package/dist/daemon/essence.js.map +1 -0
- package/dist/daemon/extbridge.js +138 -0
- package/dist/daemon/extbridge.js.map +1 -0
- package/dist/daemon/lifecycle.js +134 -0
- package/dist/daemon/lifecycle.js.map +1 -0
- package/dist/daemon/pty-compat.js +53 -0
- package/dist/daemon/pty-compat.js.map +1 -0
- package/dist/daemon/semantic.js +337 -0
- package/dist/daemon/semantic.js.map +1 -0
- package/dist/daemon/server.js +808 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/supervisor.js +311 -0
- package/dist/daemon/supervisor.js.map +1 -0
- package/dist/extension/pines-extension.js +191 -0
- package/dist/extension/pines-extension.js.map +1 -0
- package/dist/layout/lexical.js +104 -0
- package/dist/layout/lexical.js.map +1 -0
- package/dist/layout/pca.js +91 -0
- package/dist/layout/pca.js.map +1 -0
- package/dist/layout/relax.js +47 -0
- package/dist/layout/relax.js.map +1 -0
- package/dist/session/ingest.js +95 -0
- package/dist/session/ingest.js.map +1 -0
- package/dist/session/parser.js +254 -0
- package/dist/session/parser.js.map +1 -0
- package/dist/shared/config.js +30 -0
- package/dist/shared/config.js.map +1 -0
- package/dist/shared/paths.js +47 -0
- package/dist/shared/paths.js.map +1 -0
- package/dist/shared/protocol.js +9 -0
- package/dist/shared/protocol.js.map +1 -0
- package/dist/shared/types.js +3 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/shared/wire.js +51 -0
- package/dist/shared/wire.js.map +1 -0
- package/dist/store/db.js +203 -0
- package/dist/store/db.js.map +1 -0
- package/dist/store/watcher.js +69 -0
- package/dist/store/watcher.js.map +1 -0
- package/package.json +80 -0
- package/scripts/fix-node-pty.mjs +34 -0
- package/src/extension/pines-extension.ts +192 -0
- package/src/store/schema.sql +60 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentProc: one live pi process hosted in a PTY, with server-side VT screen
|
|
3
|
+
* state so late-attaching clients get a faithful snapshot.
|
|
4
|
+
*
|
|
5
|
+
* Output flow: pty → @xterm/headless Terminal (screen state + scrollback)
|
|
6
|
+
* → raw ANSI passthrough to every attached client.
|
|
7
|
+
*/
|
|
8
|
+
import pty from "node-pty";
|
|
9
|
+
import xterm from "@xterm/headless";
|
|
10
|
+
import { SerializeAddon } from "@xterm/addon-serialize";
|
|
11
|
+
import { ensureNodePtyReady } from "./pty-compat.js";
|
|
12
|
+
const SNAPSHOT_QUIET_MS = 30;
|
|
13
|
+
const SNAPSHOT_MAX_WAIT_MS = 200;
|
|
14
|
+
export class AgentProc {
|
|
15
|
+
opts;
|
|
16
|
+
treeId;
|
|
17
|
+
pid;
|
|
18
|
+
pty;
|
|
19
|
+
term;
|
|
20
|
+
serializer;
|
|
21
|
+
lastDataAt = 0;
|
|
22
|
+
exited = false;
|
|
23
|
+
cols;
|
|
24
|
+
rows;
|
|
25
|
+
constructor(opts) {
|
|
26
|
+
this.opts = opts;
|
|
27
|
+
ensureNodePtyReady();
|
|
28
|
+
this.treeId = opts.treeId;
|
|
29
|
+
this.cols = opts.cols;
|
|
30
|
+
this.rows = opts.rows;
|
|
31
|
+
this.term = new xterm.Terminal({
|
|
32
|
+
cols: opts.cols,
|
|
33
|
+
rows: opts.rows,
|
|
34
|
+
scrollback: 10_000,
|
|
35
|
+
allowProposedApi: true,
|
|
36
|
+
});
|
|
37
|
+
this.serializer = new SerializeAddon();
|
|
38
|
+
this.term.loadAddon(this.serializer);
|
|
39
|
+
this.pty = pty.spawn(opts.command, opts.args, {
|
|
40
|
+
name: "xterm-256color",
|
|
41
|
+
cols: opts.cols,
|
|
42
|
+
rows: opts.rows,
|
|
43
|
+
cwd: opts.cwd,
|
|
44
|
+
env: {
|
|
45
|
+
...process.env,
|
|
46
|
+
TERM: "xterm-256color",
|
|
47
|
+
COLORTERM: "truecolor",
|
|
48
|
+
...opts.env,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
this.pid = this.pty.pid;
|
|
52
|
+
this.pty.onData((data) => {
|
|
53
|
+
this.lastDataAt = Date.now();
|
|
54
|
+
this.term.write(data);
|
|
55
|
+
opts.onData(data);
|
|
56
|
+
});
|
|
57
|
+
this.pty.onExit(({ exitCode }) => {
|
|
58
|
+
this.exited = true;
|
|
59
|
+
opts.onExit(exitCode);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
get isRunning() {
|
|
63
|
+
return !this.exited;
|
|
64
|
+
}
|
|
65
|
+
write(data) {
|
|
66
|
+
if (!this.exited)
|
|
67
|
+
this.pty.write(data);
|
|
68
|
+
}
|
|
69
|
+
resize(cols, rows) {
|
|
70
|
+
if (this.exited || (cols === this.cols && rows === this.rows))
|
|
71
|
+
return;
|
|
72
|
+
this.cols = cols;
|
|
73
|
+
this.rows = rows;
|
|
74
|
+
this.pty.resize(cols, rows);
|
|
75
|
+
this.term.resize(cols, rows);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Serialize current screen + scrollback to an ANSI string a client replays.
|
|
79
|
+
* Waits for a short quiet period so we don't serialize mid-frame (pi-tui uses
|
|
80
|
+
* CSI 2026 synchronized updates; a snapshot torn inside one renders garbage).
|
|
81
|
+
*/
|
|
82
|
+
async snapshot(scrollback = 2000) {
|
|
83
|
+
const start = Date.now();
|
|
84
|
+
while (Date.now() - this.lastDataAt < SNAPSHOT_QUIET_MS &&
|
|
85
|
+
Date.now() - start < SNAPSHOT_MAX_WAIT_MS) {
|
|
86
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
87
|
+
}
|
|
88
|
+
return this.serializer.serialize({ scrollback });
|
|
89
|
+
}
|
|
90
|
+
/** Immediate (non-debounced) serialize — used when the process has exited. */
|
|
91
|
+
snapshotSync(scrollback = 2000) {
|
|
92
|
+
return this.serializer.serialize({ scrollback });
|
|
93
|
+
}
|
|
94
|
+
kill(signal = "SIGTERM") {
|
|
95
|
+
if (!this.exited)
|
|
96
|
+
this.pty.kill(signal);
|
|
97
|
+
}
|
|
98
|
+
dispose() {
|
|
99
|
+
this.term.dispose();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=agents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/daemon/agents.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branch-from-node orchestration.
|
|
3
|
+
*
|
|
4
|
+
* Ownership rule: a live tree's JSONL is written only by its pi process (we go
|
|
5
|
+
* through the extension); dormant trees are written by the daemon via pi's SDK.
|
|
6
|
+
* Pines never hand-writes session JSONL.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync } from "node:fs";
|
|
9
|
+
async function piSdk() {
|
|
10
|
+
return import("@earendil-works/pi-coding-agent");
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* In-place branch: move the tree's leaf to `nodeId` so the next message
|
|
14
|
+
* continues from that context, inside the same session file.
|
|
15
|
+
*/
|
|
16
|
+
export async function branchInPlace(deps, rec, nodeId) {
|
|
17
|
+
if (rec.agent?.isRunning) {
|
|
18
|
+
if (!deps.extBridge.hasExtension(rec.treeId)) {
|
|
19
|
+
return { ok: false, err: "live agent has no pines extension connected" };
|
|
20
|
+
}
|
|
21
|
+
// Extension stages `/pines-nav <id>` in pi's editor (navigateTree needs a
|
|
22
|
+
// user-initiated command context); we submit it by sending CR to the PTY.
|
|
23
|
+
const res = await deps.extBridge.command(rec.treeId, {
|
|
24
|
+
op: "navigate_tree",
|
|
25
|
+
targetId: nodeId,
|
|
26
|
+
});
|
|
27
|
+
if (!res.ok) {
|
|
28
|
+
// Multiplexing must never block on a generating agent: queue the move
|
|
29
|
+
// and let the daemon run it the moment the agent settles.
|
|
30
|
+
if (res.err?.includes("busy") && deps.queueNav) {
|
|
31
|
+
deps.queueNav(rec.treeId, nodeId);
|
|
32
|
+
return {
|
|
33
|
+
ok: true,
|
|
34
|
+
note: "agent is mid-task — will continue from that node when it settles",
|
|
35
|
+
newTreeId: rec.treeId,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return { ok: false, err: res.err };
|
|
39
|
+
}
|
|
40
|
+
rec.agent.write("\r");
|
|
41
|
+
return { ok: true, newTreeId: rec.treeId };
|
|
42
|
+
}
|
|
43
|
+
if (!rec.sessionPath)
|
|
44
|
+
return { ok: false, err: "tree has no session file" };
|
|
45
|
+
try {
|
|
46
|
+
const { SessionManager } = await piSdk();
|
|
47
|
+
const sm = SessionManager.open(rec.sessionPath);
|
|
48
|
+
if (!sm.getEntry(nodeId))
|
|
49
|
+
return { ok: false, err: `no entry ${nodeId} in session` };
|
|
50
|
+
sm.branch(nodeId);
|
|
51
|
+
// branch() only moves the in-memory pointer; append a pines marker (not in
|
|
52
|
+
// LLM context) so the new leaf position survives the next resume.
|
|
53
|
+
sm.appendCustomEntry("pines.branch", { from: nodeId, treeId: rec.treeId });
|
|
54
|
+
await deps.ingest(rec.sessionPath);
|
|
55
|
+
return { ok: true, newTreeId: rec.treeId };
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
return { ok: false, err: err instanceof Error ? err.message : String(err) };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* New-tree branch: materialize the root→node path as a fresh session file
|
|
63
|
+
* (pi's createBranchedSession), register it, optionally spawn a pi on it.
|
|
64
|
+
*/
|
|
65
|
+
export async function branchToNewTree(deps, rec, nodeId, opts) {
|
|
66
|
+
if (!rec.sessionPath)
|
|
67
|
+
return { ok: false, err: "tree has no session file" };
|
|
68
|
+
try {
|
|
69
|
+
const { SessionManager } = await piSdk();
|
|
70
|
+
// Reading the source is safe while a pi appends (append-only file).
|
|
71
|
+
const sm = SessionManager.open(rec.sessionPath);
|
|
72
|
+
if (!sm.getEntry(nodeId))
|
|
73
|
+
return { ok: false, err: `no entry ${nodeId} in session` };
|
|
74
|
+
const newPath = sm.createBranchedSession(nodeId);
|
|
75
|
+
if (!newPath)
|
|
76
|
+
return { ok: false, err: "createBranchedSession returned nothing" };
|
|
77
|
+
if (!existsSync(newPath)) {
|
|
78
|
+
// pi SDK edge case: branching from the session's first entry returns a
|
|
79
|
+
// path without ever writing the file. Surface it honestly.
|
|
80
|
+
return {
|
|
81
|
+
ok: false,
|
|
82
|
+
err: "pi wrote no branch file for this node — branching from the first entry isn't supported, pick a later node",
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const newRec = await deps.ingest(newPath);
|
|
86
|
+
if (!newRec)
|
|
87
|
+
return { ok: false, err: "failed to ingest branched session" };
|
|
88
|
+
newRec.parentSessionPath ??= rec.sessionPath;
|
|
89
|
+
deps.setGraftParent(newRec.treeId, rec.sessionPath, nodeId);
|
|
90
|
+
// Seed the new tree's position near its parent so it sprouts visibly
|
|
91
|
+
// adjacent instead of waiting for a relayout. Siblings fan out around the
|
|
92
|
+
// parent (golden-angle steps) instead of stacking on one spot.
|
|
93
|
+
if (newRec.x === 0 && newRec.y === 0) {
|
|
94
|
+
const siblings = [...deps.supervisor.trees.values()].filter((t) => t.parentSessionPath === rec.sessionPath && t.treeId !== newRec.treeId).length;
|
|
95
|
+
const angle = 0.7 + siblings * 2.399963;
|
|
96
|
+
const r = 2.6 + 0.4 * siblings;
|
|
97
|
+
newRec.x = rec.x + r * Math.cos(angle);
|
|
98
|
+
newRec.y = rec.y + r * Math.sin(angle);
|
|
99
|
+
}
|
|
100
|
+
deps.supervisor.notify(newRec);
|
|
101
|
+
if (opts.spawn) {
|
|
102
|
+
if (!newRec.cwd)
|
|
103
|
+
return { ok: false, err: "branched session has no cwd" };
|
|
104
|
+
if (!existsSync(newRec.cwd)) {
|
|
105
|
+
// The branched tree itself is fine — only the agent can't start.
|
|
106
|
+
return {
|
|
107
|
+
ok: false,
|
|
108
|
+
err: `branched, but cwd no longer exists: ${newRec.cwd} — agent not spawned`,
|
|
109
|
+
newTreeId: newRec.treeId,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
deps.supervisor.spawnAgent({
|
|
113
|
+
cwd: newRec.cwd,
|
|
114
|
+
sessionPath: newPath,
|
|
115
|
+
existing: newRec,
|
|
116
|
+
cols: opts.cols,
|
|
117
|
+
rows: opts.rows,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return { ok: true, newTreeId: newRec.treeId };
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
return { ok: false, err: err instanceof Error ? err.message : String(err) };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/** Set or clear a label on a node, honoring the ownership rule. */
|
|
127
|
+
export async function setNodeLabel(deps, rec, nodeId, label) {
|
|
128
|
+
if (rec.agent?.isRunning && deps.extBridge.hasExtension(rec.treeId)) {
|
|
129
|
+
const res = await deps.extBridge.command(rec.treeId, {
|
|
130
|
+
op: "set_label",
|
|
131
|
+
entryId: nodeId,
|
|
132
|
+
label,
|
|
133
|
+
});
|
|
134
|
+
return { ok: res.ok, err: res.err };
|
|
135
|
+
}
|
|
136
|
+
if (!rec.sessionPath)
|
|
137
|
+
return { ok: false, err: "tree has no session file" };
|
|
138
|
+
try {
|
|
139
|
+
const { SessionManager } = await piSdk();
|
|
140
|
+
const sm = SessionManager.open(rec.sessionPath);
|
|
141
|
+
sm.appendLabelChange(nodeId, label ?? undefined);
|
|
142
|
+
await deps.ingest(rec.sessionPath);
|
|
143
|
+
return { ok: true };
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
return { ok: false, err: err instanceof Error ? err.message : String(err) };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=branch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch.js","sourceRoot":"","sources":["../../src/daemon/branch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedding worker (worker_thread): loads the embedding pipeline lazily so the
|
|
3
|
+
* daemon's event loop and startup are never blocked by model init/download.
|
|
4
|
+
*
|
|
5
|
+
* Messages in: { reqId: string, texts: string[] }
|
|
6
|
+
* Messages out: { reqId: string, vectors: number[][] } | { reqId, error: string }
|
|
7
|
+
* | { ready: true } | { fatal: string }
|
|
8
|
+
*
|
|
9
|
+
* The model defaults to MiniLM and can be overridden via PINES_EMBED_MODEL
|
|
10
|
+
* (set from config by SemanticLayout when spawning the worker).
|
|
11
|
+
*/
|
|
12
|
+
import { parentPort } from "node:worker_threads";
|
|
13
|
+
import { modelsDir } from "../shared/paths.js";
|
|
14
|
+
if (!parentPort)
|
|
15
|
+
throw new Error("embed-worker must run as a worker thread");
|
|
16
|
+
const port = parentPort;
|
|
17
|
+
let extractorPromise = null;
|
|
18
|
+
function getExtractor() {
|
|
19
|
+
extractorPromise ??= (async () => {
|
|
20
|
+
process.env.HF_HOME ??= modelsDir();
|
|
21
|
+
const { pipeline, env } = await import("@huggingface/transformers");
|
|
22
|
+
// Keep everything on-disk and offline-friendly after first download.
|
|
23
|
+
env.cacheDir = modelsDir();
|
|
24
|
+
const model = process.env.PINES_EMBED_MODEL || "Xenova/all-MiniLM-L6-v2";
|
|
25
|
+
const pipe = await pipeline("feature-extraction", model, {
|
|
26
|
+
dtype: "q8",
|
|
27
|
+
});
|
|
28
|
+
port.postMessage({ ready: true });
|
|
29
|
+
return pipe;
|
|
30
|
+
})();
|
|
31
|
+
return extractorPromise;
|
|
32
|
+
}
|
|
33
|
+
const queue = [];
|
|
34
|
+
let draining = false;
|
|
35
|
+
async function drain() {
|
|
36
|
+
if (draining)
|
|
37
|
+
return;
|
|
38
|
+
draining = true;
|
|
39
|
+
try {
|
|
40
|
+
const extractor = await getExtractor();
|
|
41
|
+
while (queue.length > 0) {
|
|
42
|
+
const job = queue.shift();
|
|
43
|
+
try {
|
|
44
|
+
// One text at a time keeps memory bounded for large batches; the
|
|
45
|
+
// worker is the throughput ceiling either way.
|
|
46
|
+
const vectors = [];
|
|
47
|
+
for (const text of job.texts) {
|
|
48
|
+
const out = await extractor(text, { pooling: "mean", normalize: true });
|
|
49
|
+
vectors.push(Array.from(out.data));
|
|
50
|
+
}
|
|
51
|
+
port.postMessage({ reqId: job.reqId, vectors });
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
port.postMessage({
|
|
55
|
+
reqId: job.reqId,
|
|
56
|
+
error: err instanceof Error ? err.message : String(err),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
// Model never loaded (offline first run, missing optional dep, …).
|
|
63
|
+
port.postMessage({ fatal: err instanceof Error ? err.message : String(err) });
|
|
64
|
+
queue.length = 0;
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
draining = false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
port.on("message", (msg) => {
|
|
71
|
+
queue.push(msg);
|
|
72
|
+
void drain();
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=embed-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embed-worker.js","sourceRoot":"","sources":["../../src/daemon/embed-worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Essence extraction: turns a parsed session into the chunks worth embedding
|
|
3
|
+
* and pools their vectors into one tree-level embedding.
|
|
4
|
+
*
|
|
5
|
+
* What captures a chat's essence, in decreasing signal-per-byte:
|
|
6
|
+
* - name + labels (human-assigned meaning)
|
|
7
|
+
* - user messages (intent; assistant/tool *output* is noise at embedding size)
|
|
8
|
+
* - compaction/branch summaries (already-distilled history)
|
|
9
|
+
* - tool activity digest (which files/tools the agent actually touched)
|
|
10
|
+
*
|
|
11
|
+
* Chunks are keyed by entry id (stable in append-only session files) or by a
|
|
12
|
+
* content hash for the digest chunks, so incremental ingest re-embeds only
|
|
13
|
+
* what changed. Pooling is a recency-weighted spherical mean: late messages
|
|
14
|
+
* dominate, but the opening message keeps a floor weight so a tree never
|
|
15
|
+
* forgets what it set out to do.
|
|
16
|
+
*/
|
|
17
|
+
import { createHash } from "node:crypto";
|
|
18
|
+
/** Per-chunk clip: MiniLM sees ~256-512 tokens, so one chunk fits its window. */
|
|
19
|
+
const CHUNK_MAX_CHARS = 1500;
|
|
20
|
+
/** Pooling window: newest N user messages (the first is always kept too). */
|
|
21
|
+
export const MAX_USER_CHUNKS = 24;
|
|
22
|
+
/** Pooling window: newest N summaries. */
|
|
23
|
+
export const MAX_SUMMARY_CHUNKS = 8;
|
|
24
|
+
/** Storage cap for cached user-chunk vectors (see pruneUserChunks). */
|
|
25
|
+
export const USER_CHUNK_CACHE = 64;
|
|
26
|
+
function hash12(text) {
|
|
27
|
+
return createHash("sha1").update(text).digest("hex").slice(0, 12);
|
|
28
|
+
}
|
|
29
|
+
function clip(text) {
|
|
30
|
+
return text.length <= CHUNK_MAX_CHARS ? text : text.slice(0, CHUNK_MAX_CHARS);
|
|
31
|
+
}
|
|
32
|
+
/** Tool-call parts of an assistant message ({type:"toolCall", name, arguments}). */
|
|
33
|
+
function toolCallsOf(entry) {
|
|
34
|
+
if (entry.type !== "message" || entry.role !== "assistant")
|
|
35
|
+
return [];
|
|
36
|
+
const msg = entry.raw.message;
|
|
37
|
+
const content = msg?.content;
|
|
38
|
+
if (!Array.isArray(content))
|
|
39
|
+
return [];
|
|
40
|
+
const calls = [];
|
|
41
|
+
for (const part of content) {
|
|
42
|
+
if (typeof part !== "object" || part === null)
|
|
43
|
+
continue;
|
|
44
|
+
const p = part;
|
|
45
|
+
if (p.type !== "toolCall" || typeof p.name !== "string")
|
|
46
|
+
continue;
|
|
47
|
+
calls.push({ name: p.name, args: p.arguments ?? {} });
|
|
48
|
+
}
|
|
49
|
+
return calls;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Readable digest of the session's tool activity: which files were worked on
|
|
53
|
+
* and which tools ran (with the leading word of bash commands). Frequency-
|
|
54
|
+
* ranked and capped, so it embeds as one stable, meaningful chunk. Content is
|
|
55
|
+
* ordered by count then name — the digest text (and thus its content-hash key)
|
|
56
|
+
* only changes when tool activity actually changes.
|
|
57
|
+
*/
|
|
58
|
+
export function toolsDigest(parsed) {
|
|
59
|
+
const paths = new Map();
|
|
60
|
+
const tools = new Map();
|
|
61
|
+
const bump = (m, k) => m.set(k, (m.get(k) ?? 0) + 1);
|
|
62
|
+
for (const e of parsed.entries) {
|
|
63
|
+
for (const call of toolCallsOf(e)) {
|
|
64
|
+
let toolKey = call.name;
|
|
65
|
+
for (const argKey of ["path", "file_path", "filePath"]) {
|
|
66
|
+
const v = call.args[argKey];
|
|
67
|
+
if (typeof v === "string" && v)
|
|
68
|
+
bump(paths, v);
|
|
69
|
+
}
|
|
70
|
+
if (typeof call.args.command === "string" && call.args.command) {
|
|
71
|
+
const word = call.args.command.trim().split(/\s+/)[0] ?? "";
|
|
72
|
+
if (word)
|
|
73
|
+
toolKey = `${call.name} (${word.slice(0, 24)})`;
|
|
74
|
+
}
|
|
75
|
+
bump(tools, toolKey);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (paths.size === 0 && tools.size === 0)
|
|
79
|
+
return "";
|
|
80
|
+
const top = (m, n) => [...m.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, n);
|
|
81
|
+
const parts = [];
|
|
82
|
+
if (paths.size > 0) {
|
|
83
|
+
parts.push(`worked on: ${top(paths, 20).map(([p]) => p).join(", ")}`);
|
|
84
|
+
}
|
|
85
|
+
if (tools.size > 0) {
|
|
86
|
+
parts.push(`tools: ${top(tools, 16).map(([t, n]) => (n > 1 ? `${t} ×${n}` : t)).join(", ")}`);
|
|
87
|
+
}
|
|
88
|
+
return clip(parts.join(" · "));
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The chunks that represent this session, already selected down to the
|
|
92
|
+
* pooling window (newest user messages + first, newest summaries, digests).
|
|
93
|
+
*/
|
|
94
|
+
export function essenceChunks(name, parsed) {
|
|
95
|
+
const chunks = [];
|
|
96
|
+
const metaText = [name ?? parsed.name ?? "", ...parsed.labels.values()]
|
|
97
|
+
.filter(Boolean)
|
|
98
|
+
.join("\n");
|
|
99
|
+
if (metaText.trim()) {
|
|
100
|
+
chunks.push({ key: `meta:${hash12(metaText)}`, kind: "meta", pos: -1, text: clip(metaText) });
|
|
101
|
+
}
|
|
102
|
+
const digest = toolsDigest(parsed);
|
|
103
|
+
if (digest.trim()) {
|
|
104
|
+
chunks.push({ key: `tools:${hash12(digest)}`, kind: "tools", pos: -1, text: digest });
|
|
105
|
+
}
|
|
106
|
+
const users = [];
|
|
107
|
+
const summaries = [];
|
|
108
|
+
parsed.entries.forEach((e, pos) => {
|
|
109
|
+
if (!e.text.trim())
|
|
110
|
+
return;
|
|
111
|
+
if (e.type === "message" && e.role === "user") {
|
|
112
|
+
users.push({ key: e.id, kind: "user", pos, text: clip(e.text) });
|
|
113
|
+
}
|
|
114
|
+
else if (e.type === "compaction" || e.type === "branch_summary") {
|
|
115
|
+
summaries.push({ key: e.id, kind: "summary", pos, text: clip(e.text) });
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
// Newest-N window, but the opening message always stays in: it anchors what
|
|
119
|
+
// the tree set out to do even when the window has scrolled far past it.
|
|
120
|
+
const userWindow = users.slice(-MAX_USER_CHUNKS);
|
|
121
|
+
if (users.length > MAX_USER_CHUNKS)
|
|
122
|
+
userWindow.unshift(users[0]);
|
|
123
|
+
chunks.push(...userWindow, ...summaries.slice(-MAX_SUMMARY_CHUNKS));
|
|
124
|
+
return chunks;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Chunk keys that are currently valid for this session — the full universe,
|
|
128
|
+
* not the capped selection, so a cached chunk that merely scrolled out of the
|
|
129
|
+
* pooling window is not churned. Used to diff away stale rows (renames, file
|
|
130
|
+
* shrink/fork flows).
|
|
131
|
+
*/
|
|
132
|
+
export function validChunkKeys(name, parsed) {
|
|
133
|
+
const keys = new Set();
|
|
134
|
+
for (const c of essenceChunks(name, parsed))
|
|
135
|
+
keys.add(c.key);
|
|
136
|
+
for (const e of parsed.entries) {
|
|
137
|
+
if (!e.text.trim())
|
|
138
|
+
continue;
|
|
139
|
+
if (e.type === "message" && e.role === "user")
|
|
140
|
+
keys.add(e.id);
|
|
141
|
+
else if (e.type === "compaction" || e.type === "branch_summary")
|
|
142
|
+
keys.add(e.id);
|
|
143
|
+
}
|
|
144
|
+
return keys;
|
|
145
|
+
}
|
|
146
|
+
/** Recency decay per step back from the newest user message. */
|
|
147
|
+
const USER_DECAY = 0.85;
|
|
148
|
+
/** The opening message never drops below this weight. */
|
|
149
|
+
const FIRST_USER_FLOOR = 0.5;
|
|
150
|
+
/** Any pooled user message keeps at least a whisper of weight. */
|
|
151
|
+
const USER_FLOOR = 0.05;
|
|
152
|
+
const SUMMARY_TOP = 0.9;
|
|
153
|
+
const SUMMARY_DECAY = 0.8;
|
|
154
|
+
const META_WEIGHT = 1.0;
|
|
155
|
+
const TOOLS_WEIGHT = 0.6;
|
|
156
|
+
/**
|
|
157
|
+
* Recency-weighted spherical mean of unit chunk vectors → unit tree vector.
|
|
158
|
+
* Returns null when there is nothing to pool (or the sum degenerates).
|
|
159
|
+
*/
|
|
160
|
+
export function poolChunks(chunks) {
|
|
161
|
+
if (chunks.length === 0)
|
|
162
|
+
return null;
|
|
163
|
+
const dim = chunks[0].vec.length;
|
|
164
|
+
const sum = new Float32Array(dim);
|
|
165
|
+
const users = chunks.filter((c) => c.kind === "user").sort((a, b) => a.pos - b.pos);
|
|
166
|
+
const summaries = chunks.filter((c) => c.kind === "summary").sort((a, b) => a.pos - b.pos);
|
|
167
|
+
const add = (vec, w) => {
|
|
168
|
+
for (let i = 0; i < dim; i++)
|
|
169
|
+
sum[i] += vec[i] * w;
|
|
170
|
+
};
|
|
171
|
+
users.forEach((c, i) => {
|
|
172
|
+
const recency = Math.pow(USER_DECAY, users.length - 1 - i);
|
|
173
|
+
add(c.vec, Math.max(recency, i === 0 ? FIRST_USER_FLOOR : USER_FLOOR));
|
|
174
|
+
});
|
|
175
|
+
summaries.forEach((c, j) => {
|
|
176
|
+
add(c.vec, SUMMARY_TOP * Math.pow(SUMMARY_DECAY, summaries.length - 1 - j));
|
|
177
|
+
});
|
|
178
|
+
for (const c of chunks) {
|
|
179
|
+
if (c.kind === "meta")
|
|
180
|
+
add(c.vec, META_WEIGHT);
|
|
181
|
+
else if (c.kind === "tools")
|
|
182
|
+
add(c.vec, TOOLS_WEIGHT);
|
|
183
|
+
}
|
|
184
|
+
let norm = 0;
|
|
185
|
+
for (let i = 0; i < dim; i++)
|
|
186
|
+
norm += sum[i] * sum[i];
|
|
187
|
+
norm = Math.sqrt(norm);
|
|
188
|
+
if (!Number.isFinite(norm) || norm < 1e-6)
|
|
189
|
+
return null;
|
|
190
|
+
for (let i = 0; i < dim; i++)
|
|
191
|
+
sum[i] /= norm;
|
|
192
|
+
return sum;
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=essence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"essence.js","sourceRoot":"","sources":["../../src/daemon/essence.ts"],"names":[],"mappings":"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"}
|