@intentic/iq 1.326.0 → 1.328.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/README.md +59 -4
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +7 -3
- package/dist/app.js.map +1 -1
- package/dist/commands/sessions/sessions.routes.js +1 -1
- package/dist/commands/sessions/sessions.routes.js.map +1 -1
- package/dist/recall/fleet/conversations.d.ts +7 -0
- package/dist/recall/fleet/conversations.d.ts.map +1 -0
- package/dist/recall/fleet/conversations.js +48 -0
- package/dist/recall/fleet/conversations.js.map +1 -0
- package/dist/recall/fork/fork-point.d.ts +10 -0
- package/dist/recall/fork/fork-point.d.ts.map +1 -0
- package/dist/recall/fork/fork-point.js +74 -0
- package/dist/recall/fork/fork-point.js.map +1 -0
- package/dist/recall/fork/fork.d.ts +15 -0
- package/dist/recall/fork/fork.d.ts.map +1 -0
- package/dist/recall/fork/fork.js +108 -0
- package/dist/recall/fork/fork.js.map +1 -0
- package/dist/recall/ingest/ingest.d.ts +13 -0
- package/dist/recall/ingest/ingest.d.ts.map +1 -0
- package/dist/recall/ingest/ingest.js +180 -0
- package/dist/recall/ingest/ingest.js.map +1 -0
- package/dist/recall/rank/files.d.ts +26 -0
- package/dist/recall/rank/files.d.ts.map +1 -0
- package/dist/recall/rank/files.js +88 -0
- package/dist/recall/rank/files.js.map +1 -0
- package/dist/recall/rank/grab.d.ts +25 -0
- package/dist/recall/rank/grab.d.ts.map +1 -0
- package/dist/recall/rank/grab.js +74 -0
- package/dist/recall/rank/grab.js.map +1 -0
- package/dist/recall/rank/match.d.ts +18 -0
- package/dist/recall/rank/match.d.ts.map +1 -0
- package/dist/recall/rank/match.js +122 -0
- package/dist/recall/rank/match.js.map +1 -0
- package/dist/recall/rank/terms.d.ts +4 -0
- package/dist/recall/rank/terms.d.ts.map +1 -0
- package/dist/recall/rank/terms.js +25 -0
- package/dist/recall/rank/terms.js.map +1 -0
- package/dist/recall/recall.d.ts +52 -0
- package/dist/recall/recall.d.ts.map +1 -0
- package/dist/recall/recall.js +86 -0
- package/dist/recall/recall.js.map +1 -0
- package/dist/recall/store/db.d.ts +3 -0
- package/dist/recall/store/db.d.ts.map +1 -0
- package/dist/recall/store/db.js +91 -0
- package/dist/recall/store/db.js.map +1 -0
- package/dist/recall/transcript/line-reader.d.ts +6 -0
- package/dist/recall/transcript/line-reader.d.ts.map +1 -0
- package/dist/recall/transcript/line-reader.js +36 -0
- package/dist/recall/transcript/line-reader.js.map +1 -0
- package/dist/recall/transcript/lines.d.ts +22 -0
- package/dist/recall/transcript/lines.d.ts.map +1 -0
- package/dist/recall/transcript/lines.js +134 -0
- package/dist/recall/transcript/lines.js.map +1 -0
- package/dist/recall/transcript/slug.d.ts +3 -0
- package/dist/recall/transcript/slug.d.ts.map +1 -0
- package/dist/recall/transcript/slug.js +5 -0
- package/dist/recall/transcript/slug.js.map +1 -0
- package/package.json +17 -7
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { readdirSync, statSync } from "node:fs";
|
|
2
|
+
import { basename, isAbsolute, join, relative } from "node:path";
|
|
3
|
+
import { isMissing } from "@intentic/base/errors";
|
|
4
|
+
import { stripInjectedPreamble } from "@intentic/constants";
|
|
5
|
+
import { readLines } from "../transcript/line-reader.js";
|
|
6
|
+
import { aiTitleOf, assistantTextOf, fileTouchesOf, parseLine, timestampOf, typedPromptOf, uuidOf } from "../transcript/lines.js";
|
|
7
|
+
const RESPONSE_CAP = 4000;
|
|
8
|
+
const asString = (value) => (typeof value === "string" ? value : undefined);
|
|
9
|
+
const parseDelta = async (path, fromByte, lastOrdinal, root) => {
|
|
10
|
+
const delta = {
|
|
11
|
+
slug: undefined,
|
|
12
|
+
version: undefined,
|
|
13
|
+
gitBranch: undefined,
|
|
14
|
+
title: undefined,
|
|
15
|
+
minTs: undefined,
|
|
16
|
+
maxTs: undefined,
|
|
17
|
+
byteOffset: fromByte,
|
|
18
|
+
newTurns: [],
|
|
19
|
+
touches: new Map(),
|
|
20
|
+
responses: new Map(),
|
|
21
|
+
};
|
|
22
|
+
let ordinal = lastOrdinal;
|
|
23
|
+
let lineStart = fromByte;
|
|
24
|
+
for await (const { json, endByte } of readLines(path, fromByte)) {
|
|
25
|
+
const startByte = lineStart;
|
|
26
|
+
lineStart = endByte;
|
|
27
|
+
delta.byteOffset = endByte;
|
|
28
|
+
const line = parseLine(json);
|
|
29
|
+
if (line === undefined) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const ts = timestampOf(line);
|
|
33
|
+
if (ts !== undefined) {
|
|
34
|
+
delta.minTs = Math.min(delta.minTs ?? ts, ts);
|
|
35
|
+
delta.maxTs = Math.max(delta.maxTs ?? ts, ts);
|
|
36
|
+
}
|
|
37
|
+
delta.slug ??= asString(line["slug"]);
|
|
38
|
+
delta.version ??= asString(line["version"]);
|
|
39
|
+
delta.gitBranch ??= asString(line["gitBranch"]);
|
|
40
|
+
const title = aiTitleOf(line);
|
|
41
|
+
if (title !== undefined) {
|
|
42
|
+
delta.title = title;
|
|
43
|
+
}
|
|
44
|
+
const typed = typedPromptOf(line);
|
|
45
|
+
const uuid = uuidOf(line);
|
|
46
|
+
if (typed !== undefined && uuid !== undefined && ts !== undefined) {
|
|
47
|
+
ordinal += 1;
|
|
48
|
+
delta.newTurns.push({ uuid, ordinal, ts, prompt: stripInjectedPreamble(typed), startByte });
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (ordinal < 0) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const text = assistantTextOf(line);
|
|
55
|
+
if (text !== undefined) {
|
|
56
|
+
delta.responses.set(ordinal, text.slice(0, RESPONSE_CAP));
|
|
57
|
+
}
|
|
58
|
+
for (const { path: touched, modified } of fileTouchesOf(line)) {
|
|
59
|
+
const rel = relative(root, touched);
|
|
60
|
+
if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const byPath = delta.touches.get(ordinal) ?? new Map();
|
|
64
|
+
delta.touches.set(ordinal, byPath);
|
|
65
|
+
const touch = byPath.get(rel);
|
|
66
|
+
if (touch === undefined) {
|
|
67
|
+
byPath.set(rel, { modified, lastTs: ts ?? delta.maxTs ?? 0 });
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
touch.modified ||= modified;
|
|
71
|
+
touch.lastTs = Math.max(touch.lastTs, ts ?? 0);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return delta;
|
|
76
|
+
};
|
|
77
|
+
const applyDelta = (db, transcriptPath, sessionId, delta, stat) => {
|
|
78
|
+
db.run(`INSERT INTO sessions (session_id, slug, title, version, git_branch, first_ts, last_ts) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
79
|
+
ON CONFLICT(session_id) DO UPDATE SET
|
|
80
|
+
slug = coalesce(sessions.slug, excluded.slug),
|
|
81
|
+
title = coalesce(excluded.title, sessions.title),
|
|
82
|
+
version = coalesce(sessions.version, excluded.version),
|
|
83
|
+
git_branch = coalesce(sessions.git_branch, excluded.git_branch),
|
|
84
|
+
first_ts = min(sessions.first_ts, excluded.first_ts),
|
|
85
|
+
last_ts = max(sessions.last_ts, excluded.last_ts)`, sessionId, delta.slug ?? null, delta.title ?? null, delta.version ?? null, delta.gitBranch ?? null, delta.minTs ?? Date.now(), delta.maxTs ?? 0);
|
|
86
|
+
const sessionRowId = db.get("SELECT id FROM sessions WHERE session_id = ?", sessionId)?.["id"];
|
|
87
|
+
const newOrdinals = new Set(delta.newTurns.map((turn) => turn.ordinal));
|
|
88
|
+
for (const turn of delta.newTurns) {
|
|
89
|
+
db.run(`INSERT INTO turns (session_id, uuid, ordinal, ts, prompt, response, start_byte) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
90
|
+
ON CONFLICT(session_id, uuid) DO NOTHING`, sessionRowId, turn.uuid, turn.ordinal, turn.ts, turn.prompt, delta.responses.get(turn.ordinal) ?? "", turn.startByte);
|
|
91
|
+
}
|
|
92
|
+
for (const [ordinal, response] of delta.responses) {
|
|
93
|
+
if (!newOrdinals.has(ordinal)) {
|
|
94
|
+
db.run("UPDATE turns SET response = ? WHERE session_id = ? AND ordinal = ?", response, sessionRowId, ordinal);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
for (const [ordinal, byPath] of delta.touches) {
|
|
98
|
+
const turnId = db.get("SELECT id FROM turns WHERE session_id = ? AND ordinal = ?", sessionRowId, ordinal)?.["id"];
|
|
99
|
+
if (turnId === undefined) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
for (const [path, touch] of byPath) {
|
|
103
|
+
db.run(`INSERT INTO turn_files (turn_id, path, modified, last_ts) VALUES (?, ?, ?, ?)
|
|
104
|
+
ON CONFLICT(turn_id, path) DO UPDATE SET
|
|
105
|
+
modified = max(turn_files.modified, excluded.modified),
|
|
106
|
+
last_ts = max(turn_files.last_ts, excluded.last_ts)`, turnId, path, touch.modified ? 1 : 0, touch.lastTs);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
db.run(`INSERT INTO transcripts (path, session_id, byte_offset, mtime_ms, size) VALUES (?, ?, ?, ?, ?)
|
|
110
|
+
ON CONFLICT(path) DO UPDATE SET byte_offset = excluded.byte_offset, mtime_ms = excluded.mtime_ms, size = excluded.size`, transcriptPath, sessionId, delta.byteOffset, stat.mtimeMs, stat.size);
|
|
111
|
+
};
|
|
112
|
+
export const ingest = async (db, options) => {
|
|
113
|
+
const onDisk = new Map();
|
|
114
|
+
let entries;
|
|
115
|
+
try {
|
|
116
|
+
entries = readdirSync(options.projectsDir);
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
if (!isMissing(error)) {
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
entries = [];
|
|
123
|
+
}
|
|
124
|
+
for (const entry of entries) {
|
|
125
|
+
if (!entry.endsWith(".jsonl")) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const path = join(options.projectsDir, entry);
|
|
129
|
+
const stat = statSync(path);
|
|
130
|
+
if (stat.isFile()) {
|
|
131
|
+
onDisk.set(path, { mtimeMs: Math.trunc(stat.mtimeMs), size: stat.size });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const known = new Map(db.all("SELECT path, session_id, byte_offset, mtime_ms, size FROM transcripts").map((row) => [row["path"], row]));
|
|
135
|
+
for (const [path, row] of known) {
|
|
136
|
+
if (onDisk.has(path)) {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
db.transaction(() => {
|
|
140
|
+
db.run("DELETE FROM sessions WHERE session_id = ?", row["session_id"]);
|
|
141
|
+
db.run("DELETE FROM transcripts WHERE path = ?", path);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
const pending = [...onDisk]
|
|
145
|
+
.filter(([path, stat]) => {
|
|
146
|
+
const row = known.get(path);
|
|
147
|
+
return row === undefined || Number(row["mtime_ms"]) !== stat.mtimeMs || Number(row["size"]) !== stat.size;
|
|
148
|
+
})
|
|
149
|
+
.sort(([, a], [, b]) => b.mtimeMs - a.mtimeMs);
|
|
150
|
+
for (const [path, stat] of pending) {
|
|
151
|
+
const row = known.get(path);
|
|
152
|
+
if (options.deadlineMs !== undefined && Date.now() >= options.deadlineMs) {
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
const sessionId = basename(path, ".jsonl");
|
|
156
|
+
let fromByte = row === undefined ? 0 : Number(row["byte_offset"]);
|
|
157
|
+
if (fromByte > stat.size) {
|
|
158
|
+
db.transaction(() => {
|
|
159
|
+
db.run("DELETE FROM sessions WHERE session_id = ?", sessionId);
|
|
160
|
+
db.run("DELETE FROM transcripts WHERE path = ?", path);
|
|
161
|
+
});
|
|
162
|
+
fromByte = 0;
|
|
163
|
+
}
|
|
164
|
+
const lastOrdinal = fromByte === 0
|
|
165
|
+
? -1
|
|
166
|
+
: Number(db.get("SELECT max(t.ordinal) AS n FROM turns t JOIN sessions s ON s.id = t.session_id WHERE s.session_id = ?", sessionId)?.["n"] ?? -1);
|
|
167
|
+
const delta = await parseDelta(path, fromByte, lastOrdinal, options.root);
|
|
168
|
+
db.transaction(() => {
|
|
169
|
+
applyDelta(db, path, sessionId, delta, stat);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
const count = (sql) => Number(db.get(sql)?.["n"] ?? 0);
|
|
173
|
+
return {
|
|
174
|
+
transcripts: count("SELECT COUNT(*) AS n FROM transcripts"),
|
|
175
|
+
sessions: count("SELECT COUNT(*) AS n FROM sessions"),
|
|
176
|
+
turns: count("SELECT COUNT(*) AS n FROM turns"),
|
|
177
|
+
files: count("SELECT COUNT(DISTINCT path) AS n FROM turn_files"),
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
//# sourceMappingURL=ingest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest.js","sourceRoot":"","sources":["../../../src/recall/ingest/ingest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { SqliteDb } from "@intentic/base/sqlite";
|
|
2
|
+
export declare const decayOf: (ts: number, now: number) => number;
|
|
3
|
+
export declare const fileIdf: (db: SqliteDb, paths: readonly string[]) => Map<string, number>;
|
|
4
|
+
export interface MatchingTurn {
|
|
5
|
+
readonly turnId: number;
|
|
6
|
+
readonly sessionRowId: number;
|
|
7
|
+
readonly ts: number;
|
|
8
|
+
readonly score: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const TURN_BM25 = "-bm25(turns_fts, 1.0, 0.5)";
|
|
11
|
+
export declare const matchingTurns: (db: SqliteDb, fts: string, sinceTs: number) => MatchingTurn[];
|
|
12
|
+
export declare const matchingTitles: (db: SqliteDb, fts: string) => Map<number, number>;
|
|
13
|
+
export interface TopicFile {
|
|
14
|
+
readonly path: string;
|
|
15
|
+
readonly score: number;
|
|
16
|
+
readonly sessions: number;
|
|
17
|
+
readonly lastTouched: number;
|
|
18
|
+
readonly sampleTitle: string | undefined;
|
|
19
|
+
}
|
|
20
|
+
export interface TopicOptions {
|
|
21
|
+
readonly days?: number;
|
|
22
|
+
readonly limit?: number;
|
|
23
|
+
}
|
|
24
|
+
export declare const rankFilesForTopic: (db: SqliteDb, query: string, options?: TopicOptions) => TopicFile[];
|
|
25
|
+
export declare const sessionFiles: (db: SqliteDb, sessionRowId: number) => Set<string>;
|
|
26
|
+
//# sourceMappingURL=files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../src/recall/rank/files.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAQtD,eAAO,MAAM,OAAO,OAAQ,MAAM,OAAO,MAAM,KAAG,MAAmE,CAAC;AAatH,eAAO,MAAM,OAAO,OAAQ,QAAQ,SAAS,SAAS,MAAM,EAAE,KAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAelF,CAAC;AAEF,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CAC1B;AAGD,eAAO,MAAM,SAAS,+BAA+B,CAAC;AAGtD,eAAO,MAAM,aAAa,OAAQ,QAAQ,OAAO,MAAM,WAAW,MAAM,KAAG,YAAY,EASyD,CAAC;AAGjJ,eAAO,MAAM,cAAc,OAAQ,QAAQ,OAAO,MAAM,KAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAUxE,CAAC;AAEN,MAAM,WAAW,SAAS;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5C;AAED,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CAC3B;AAID,eAAO,MAAM,iBAAiB,OAAQ,QAAQ,SAAS,MAAM,YAAW,YAAY,KAAQ,SAAS,EA0DpG,CAAC;AAGF,eAAO,MAAM,YAAY,OAAQ,QAAQ,gBAAgB,MAAM,KAAG,GAAG,CAAC,MAAM,CAKvE,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { ftsQueryOf } from "./terms.js";
|
|
2
|
+
const HALF_LIFE_DAYS = 14;
|
|
3
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
4
|
+
export const decayOf = (ts, now) => 2 ** (-Math.max(0, now - ts) / (HALF_LIFE_DAYS * DAY_MS));
|
|
5
|
+
const chunked = (items, size) => {
|
|
6
|
+
const chunks = [];
|
|
7
|
+
for (let i = 0; i < items.length; i += size) {
|
|
8
|
+
chunks.push(items.slice(i, i + size));
|
|
9
|
+
}
|
|
10
|
+
return chunks;
|
|
11
|
+
};
|
|
12
|
+
const inList = (n) => Array.from({ length: n }, () => "?").join(", ");
|
|
13
|
+
export const fileIdf = (db, paths) => {
|
|
14
|
+
const total = Number(db.get("SELECT COUNT(*) AS n FROM sessions")?.["n"] ?? 0);
|
|
15
|
+
const idf = new Map();
|
|
16
|
+
for (const chunk of chunked(paths, 500)) {
|
|
17
|
+
const rows = db.all(`SELECT tf.path AS path, COUNT(DISTINCT t.session_id) AS n
|
|
18
|
+
FROM turn_files tf JOIN turns t ON t.id = tf.turn_id
|
|
19
|
+
WHERE tf.path IN (${inList(chunk.length)}) GROUP BY tf.path`, ...chunk);
|
|
20
|
+
for (const row of rows) {
|
|
21
|
+
idf.set(row["path"], Math.log((total + 1) / (1 + Number(row["n"]))));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return idf;
|
|
25
|
+
};
|
|
26
|
+
export const TURN_BM25 = "-bm25(turns_fts, 1.0, 0.5)";
|
|
27
|
+
export const matchingTurns = (db, fts, sinceTs) => db
|
|
28
|
+
.all(`SELECT t.id AS id, t.session_id AS session, t.ts AS ts, ${TURN_BM25} AS score
|
|
29
|
+
FROM turns_fts JOIN turns t ON t.id = turns_fts.rowid
|
|
30
|
+
WHERE turns_fts MATCH ? AND t.ts >= ?`, fts, sinceTs)
|
|
31
|
+
.map((row) => ({ turnId: Number(row["id"]), sessionRowId: Number(row["session"]), ts: Number(row["ts"]), score: Number(row["score"]) }));
|
|
32
|
+
export const matchingTitles = (db, fts) => new Map(db
|
|
33
|
+
.all(`SELECT s.id AS id, -bm25(sessions_fts) AS score
|
|
34
|
+
FROM sessions_fts JOIN sessions s ON s.id = sessions_fts.rowid
|
|
35
|
+
WHERE sessions_fts MATCH ?`, fts)
|
|
36
|
+
.map((row) => [Number(row["id"]), Number(row["score"])]));
|
|
37
|
+
export const rankFilesForTopic = (db, query, options = {}) => {
|
|
38
|
+
const fts = ftsQueryOf(query);
|
|
39
|
+
if (fts === undefined) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
const now = Date.now();
|
|
43
|
+
const sinceTs = now - (options.days ?? 90) * DAY_MS;
|
|
44
|
+
const turns = matchingTurns(db, fts, sinceTs);
|
|
45
|
+
if (turns.length === 0) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
const titles = matchingTitles(db, fts);
|
|
49
|
+
const byPath = new Map();
|
|
50
|
+
for (const chunk of chunked(turns, 500)) {
|
|
51
|
+
const byTurnId = new Map(chunk.map((turn) => [turn.turnId, turn]));
|
|
52
|
+
const rows = db.all(`SELECT turn_id, path, modified, last_ts FROM turn_files WHERE turn_id IN (${inList(chunk.length)})`, ...chunk.map((turn) => turn.turnId));
|
|
53
|
+
for (const row of rows) {
|
|
54
|
+
const turn = byTurnId.get(Number(row["turn_id"]));
|
|
55
|
+
const contribution = (turn.score + 0.5 * (titles.get(turn.sessionRowId) ?? 0)) * decayOf(turn.ts, now) * (Number(row["modified"]) === 1 ? 1.25 : 1);
|
|
56
|
+
const path = row["path"];
|
|
57
|
+
const accumulated = byPath.get(path) ?? { score: 0, sessions: new Set(), lastTouched: 0, bestContribution: 0, bestSession: 0 };
|
|
58
|
+
byPath.set(path, accumulated);
|
|
59
|
+
accumulated.score += contribution;
|
|
60
|
+
accumulated.sessions.add(turn.sessionRowId);
|
|
61
|
+
accumulated.lastTouched = Math.max(accumulated.lastTouched, Number(row["last_ts"]));
|
|
62
|
+
if (contribution > accumulated.bestContribution) {
|
|
63
|
+
accumulated.bestContribution = contribution;
|
|
64
|
+
accumulated.bestSession = turn.sessionRowId;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const idf = fileIdf(db, [...byPath.keys()]);
|
|
69
|
+
const titleOf = (sessionRowId) => {
|
|
70
|
+
const title = db.get("SELECT title FROM sessions WHERE id = ?", sessionRowId)?.["title"];
|
|
71
|
+
return typeof title === "string" ? title : undefined;
|
|
72
|
+
};
|
|
73
|
+
return [...byPath.entries()]
|
|
74
|
+
.map(([path, accumulated]) => ({
|
|
75
|
+
path,
|
|
76
|
+
score: accumulated.score * (idf.get(path) ?? 0),
|
|
77
|
+
sessions: accumulated.sessions.size,
|
|
78
|
+
lastTouched: accumulated.lastTouched,
|
|
79
|
+
sampleTitle: titleOf(accumulated.bestSession),
|
|
80
|
+
}))
|
|
81
|
+
.filter((file) => file.score > 0)
|
|
82
|
+
.toSorted((a, b) => b.score - a.score || a.path.localeCompare(b.path))
|
|
83
|
+
.slice(0, options.limit ?? 20);
|
|
84
|
+
};
|
|
85
|
+
export const sessionFiles = (db, sessionRowId) => new Set(db
|
|
86
|
+
.all("SELECT DISTINCT tf.path AS path FROM turn_files tf JOIN turns t ON t.id = tf.turn_id WHERE t.session_id = ?", sessionRowId)
|
|
87
|
+
.map((row) => row["path"]));
|
|
88
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../../src/recall/rank/files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { SqliteDb } from "@intentic/base/sqlite";
|
|
2
|
+
export interface TurnExcerpt {
|
|
3
|
+
readonly sessionId: string;
|
|
4
|
+
readonly title: string | undefined;
|
|
5
|
+
readonly ts: number;
|
|
6
|
+
readonly ordinal: number;
|
|
7
|
+
readonly turnUuid: string;
|
|
8
|
+
readonly score: number;
|
|
9
|
+
readonly prompt: string;
|
|
10
|
+
readonly fragment: string;
|
|
11
|
+
readonly repeats: number;
|
|
12
|
+
readonly bookends: SessionBookends | undefined;
|
|
13
|
+
}
|
|
14
|
+
export interface SessionBookends {
|
|
15
|
+
readonly first: string;
|
|
16
|
+
readonly last: string;
|
|
17
|
+
readonly turns: number;
|
|
18
|
+
}
|
|
19
|
+
export interface GrabOptions {
|
|
20
|
+
readonly days?: number;
|
|
21
|
+
readonly limit?: number;
|
|
22
|
+
readonly excludeSessionId?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare const grabExcerpts: (db: SqliteDb, query: string, options?: GrabOptions) => TurnExcerpt[];
|
|
25
|
+
//# sourceMappingURL=grab.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grab.d.ts","sourceRoot":"","sources":["../../../src/recall/rank/grab.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAMtD,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,SAAS,CAAC;CAClD;AAID,MAAM,WAAW,eAAe;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACtC;AAcD,eAAO,MAAM,YAAY,OAAQ,QAAQ,SAAS,MAAM,YAAW,WAAW,KAAQ,WAAW,EA8BhG,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { decayOf, TURN_BM25 } from "./files.js";
|
|
2
|
+
import { ftsQueryOf } from "./terms.js";
|
|
3
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
4
|
+
const BOOKEND_CHARS = 200;
|
|
5
|
+
const repeatKey = (prompt) => prompt.toLowerCase().replaceAll(/\d+/g, "#").replaceAll(/\s+/g, " ").trim();
|
|
6
|
+
export const grabExcerpts = (db, query, options = {}) => {
|
|
7
|
+
const fts = ftsQueryOf(query);
|
|
8
|
+
if (fts === undefined) {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
const now = Date.now();
|
|
12
|
+
const sinceTs = now - (options.days ?? 90) * DAY_MS;
|
|
13
|
+
const ranked = db
|
|
14
|
+
.all(`SELECT s.session_id AS sid, s.title AS title, t.ts AS ts, t.ordinal AS ordinal, t.uuid AS uuid,
|
|
15
|
+
t.prompt AS prompt, ${TURN_BM25} AS bm25, snippet(turns_fts, 1, '', '', '…', 48) AS fragment
|
|
16
|
+
FROM turns_fts JOIN turns t ON t.id = turns_fts.rowid JOIN sessions s ON s.id = t.session_id
|
|
17
|
+
WHERE turns_fts MATCH ? AND t.ts >= ?`, fts, sinceTs)
|
|
18
|
+
.filter((row) => row["sid"] !== options.excludeSessionId)
|
|
19
|
+
.map((row) => ({
|
|
20
|
+
sessionId: row["sid"],
|
|
21
|
+
title: typeof row["title"] === "string" ? row["title"] : undefined,
|
|
22
|
+
ts: Number(row["ts"]),
|
|
23
|
+
ordinal: Number(row["ordinal"]),
|
|
24
|
+
turnUuid: row["uuid"],
|
|
25
|
+
score: Number(row["bm25"]) * decayOf(Number(row["ts"]), now),
|
|
26
|
+
prompt: row["prompt"],
|
|
27
|
+
fragment: row["fragment"],
|
|
28
|
+
}))
|
|
29
|
+
.toSorted((a, b) => b.score - a.score || a.sessionId.localeCompare(b.sessionId) || a.ordinal - b.ordinal);
|
|
30
|
+
const collapsed = collapseRepeats(ranked).slice(0, options.limit ?? 10);
|
|
31
|
+
return withBookends(db, collapsed);
|
|
32
|
+
};
|
|
33
|
+
const collapseRepeats = (ranked) => {
|
|
34
|
+
const best = new Map();
|
|
35
|
+
for (const hit of ranked) {
|
|
36
|
+
const key = repeatKey(hit.prompt);
|
|
37
|
+
const seen = best.get(key);
|
|
38
|
+
if (seen === undefined) {
|
|
39
|
+
best.set(key, { ...hit, repeats: 0 });
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
seen.repeats += 1;
|
|
43
|
+
}
|
|
44
|
+
return [...best.values()];
|
|
45
|
+
};
|
|
46
|
+
const withBookends = (db, hits) => {
|
|
47
|
+
const ids = [...new Set(hits.map((hit) => hit.sessionId))];
|
|
48
|
+
if (ids.length === 0) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
const rows = db.all(`SELECT s.session_id AS sid,
|
|
52
|
+
(SELECT prompt FROM turns WHERE session_id = s.id ORDER BY ordinal ASC LIMIT 1) AS first_prompt,
|
|
53
|
+
(SELECT prompt FROM turns WHERE session_id = s.id ORDER BY ordinal DESC LIMIT 1) AS last_prompt,
|
|
54
|
+
(SELECT COUNT(*) FROM turns WHERE session_id = s.id) AS turns
|
|
55
|
+
FROM sessions s WHERE s.session_id IN (${ids.map(() => "?").join(",")})`, ...ids);
|
|
56
|
+
const bySession = new Map();
|
|
57
|
+
for (const row of rows) {
|
|
58
|
+
const first = row["first_prompt"];
|
|
59
|
+
const last = row["last_prompt"];
|
|
60
|
+
if (typeof first !== "string" || typeof last !== "string") {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
bySession.set(row["sid"], {
|
|
64
|
+
first: first.slice(0, BOOKEND_CHARS),
|
|
65
|
+
last: last.slice(0, BOOKEND_CHARS),
|
|
66
|
+
turns: Number(row["turns"]),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return hits.map((hit) => {
|
|
70
|
+
const bookends = bySession.get(hit.sessionId);
|
|
71
|
+
return { ...hit, bookends: bookends === undefined || bookends.turns <= 1 ? undefined : bookends };
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=grab.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grab.js","sourceRoot":"","sources":["../../../src/recall/rank/grab.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SqliteDb } from "@intentic/base/sqlite";
|
|
2
|
+
export interface SessionMatch {
|
|
3
|
+
readonly sessionId: string;
|
|
4
|
+
readonly title: string | undefined;
|
|
5
|
+
readonly lastTs: number;
|
|
6
|
+
readonly promptCount: number;
|
|
7
|
+
readonly score: number;
|
|
8
|
+
readonly bm25: number;
|
|
9
|
+
readonly coverage: number;
|
|
10
|
+
readonly strong: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface MatchOptions {
|
|
13
|
+
readonly days?: number;
|
|
14
|
+
readonly excludeSessionId?: string;
|
|
15
|
+
readonly files?: readonly string[];
|
|
16
|
+
}
|
|
17
|
+
export declare const matchSessions: (db: SqliteDb, prompt: string, options?: MatchOptions) => SessionMatch[];
|
|
18
|
+
//# sourceMappingURL=match.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match.d.ts","sourceRoot":"","sources":["../../../src/recall/rank/match.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AActD,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAEnC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAyDD,eAAO,MAAM,aAAa,OAAQ,QAAQ,UAAU,MAAM,YAAW,YAAY,KAAQ,YAAY,EAuFpG,CAAC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { decayOf, matchingTitles, matchingTurns, sessionFiles } from "./files.js";
|
|
2
|
+
import { contentTermsOf, ftsMatchOf } from "./terms.js";
|
|
3
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
4
|
+
const MIN_CONTENT_TERMS = 2;
|
|
5
|
+
const STRONG_COVERAGE = 0.5;
|
|
6
|
+
const coverageBySession = (db, terms, sinceTs) => {
|
|
7
|
+
const turnCount = Number(db.get("SELECT COUNT(*) AS n FROM turns WHERE ts >= ?", sinceTs)?.["n"] ?? 0);
|
|
8
|
+
const postings = terms.map((term) => db.all(`SELECT t.id AS id, t.session_id AS session
|
|
9
|
+
FROM turns_fts JOIN turns t ON t.id = turns_fts.rowid
|
|
10
|
+
WHERE turns_fts MATCH ? AND t.ts >= ?`, ftsMatchOf([term]), sinceTs));
|
|
11
|
+
const weights = postings.map((rows) => Math.log(1 + (turnCount - rows.length + 0.5) / (rows.length + 0.5)));
|
|
12
|
+
const total = weights.reduce((sum, weight) => sum + weight, 0);
|
|
13
|
+
const titleTerms = new Map();
|
|
14
|
+
const titleWeight = new Map();
|
|
15
|
+
terms.forEach((term, index) => {
|
|
16
|
+
for (const row of db.all("SELECT rowid AS id FROM sessions_fts WHERE sessions_fts MATCH ?", ftsMatchOf([term]))) {
|
|
17
|
+
const session = Number(row["id"]);
|
|
18
|
+
const seen = titleTerms.get(session) ?? new Set();
|
|
19
|
+
titleTerms.set(session, seen.add(index));
|
|
20
|
+
titleWeight.set(session, (titleWeight.get(session) ?? 0) + weights[index]);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
const turnWeight = new Map();
|
|
24
|
+
postings.forEach((rows, index) => {
|
|
25
|
+
for (const row of rows) {
|
|
26
|
+
const session = Number(row["session"]);
|
|
27
|
+
if (titleTerms.get(session)?.has(index) === true) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const turn = Number(row["id"]);
|
|
31
|
+
const entry = turnWeight.get(turn) ?? { session, weight: 0 };
|
|
32
|
+
entry.weight += weights[index];
|
|
33
|
+
turnWeight.set(turn, entry);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
const bestTurn = new Map();
|
|
37
|
+
for (const { session, weight } of turnWeight.values()) {
|
|
38
|
+
bestTurn.set(session, Math.max(bestTurn.get(session) ?? 0, weight));
|
|
39
|
+
}
|
|
40
|
+
const coverage = new Map();
|
|
41
|
+
for (const session of new Set([...bestTurn.keys(), ...titleWeight.keys()])) {
|
|
42
|
+
coverage.set(session, ((bestTurn.get(session) ?? 0) + (titleWeight.get(session) ?? 0)) / total);
|
|
43
|
+
}
|
|
44
|
+
return coverage;
|
|
45
|
+
};
|
|
46
|
+
export const matchSessions = (db, prompt, options = {}) => {
|
|
47
|
+
const terms = contentTermsOf(prompt);
|
|
48
|
+
if (terms.length === 0) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
const fts = ftsMatchOf(terms);
|
|
52
|
+
const now = Date.now();
|
|
53
|
+
const sinceTs = now - (options.days ?? 45) * DAY_MS;
|
|
54
|
+
const titles = matchingTitles(db, fts);
|
|
55
|
+
const bestTurn = new Map();
|
|
56
|
+
for (const turn of matchingTurns(db, fts, sinceTs)) {
|
|
57
|
+
bestTurn.set(turn.sessionRowId, Math.max(bestTurn.get(turn.sessionRowId) ?? 0, turn.score));
|
|
58
|
+
}
|
|
59
|
+
const candidateIds = new Set([...bestTurn.keys(), ...titles.keys()]);
|
|
60
|
+
if (candidateIds.size === 0) {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
const candidates = [];
|
|
64
|
+
for (const sessionRowId of candidateIds) {
|
|
65
|
+
const row = db.get(`SELECT s.session_id AS sid, s.title AS title, s.last_ts AS last_ts, COUNT(t.id) AS prompts
|
|
66
|
+
FROM sessions s LEFT JOIN turns t ON t.session_id = s.id
|
|
67
|
+
WHERE s.id = ? GROUP BY s.id`, sessionRowId);
|
|
68
|
+
if (row === undefined || Number(row["prompts"]) === 0 || Number(row["last_ts"]) < sinceTs) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const sessionId = row["sid"];
|
|
72
|
+
if (sessionId === options.excludeSessionId) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
candidates.push({
|
|
76
|
+
sessionRowId,
|
|
77
|
+
sessionId,
|
|
78
|
+
title: typeof row["title"] === "string" ? row["title"] : undefined,
|
|
79
|
+
lastTs: Number(row["last_ts"]),
|
|
80
|
+
promptCount: Number(row["prompts"]),
|
|
81
|
+
bm25: (bestTurn.get(sessionRowId) ?? 0) + 0.5 * (titles.get(sessionRowId) ?? 0),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
const maxBm25 = candidates.reduce((max, candidate) => (candidate.bm25 > max ? candidate.bm25 : max), 0);
|
|
85
|
+
if (maxBm25 === 0) {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
const coverage = coverageBySession(db, terms, sinceTs);
|
|
89
|
+
const overlapTarget = options.files !== undefined && options.files.length > 0 ? new Set(options.files) : undefined;
|
|
90
|
+
return candidates
|
|
91
|
+
.map((candidate) => {
|
|
92
|
+
const normalized = candidate.bm25 / maxBm25;
|
|
93
|
+
const recency = decayOf(candidate.lastTs, now);
|
|
94
|
+
let score;
|
|
95
|
+
if (overlapTarget === undefined) {
|
|
96
|
+
score = 0.75 * normalized + 0.25 * recency;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
const touched = sessionFiles(db, candidate.sessionRowId);
|
|
100
|
+
let shared = 0;
|
|
101
|
+
for (const path of overlapTarget) {
|
|
102
|
+
if (touched.has(path)) {
|
|
103
|
+
shared += 1;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
score = 0.6 * normalized + 0.2 * recency + 0.2 * (shared / overlapTarget.size);
|
|
107
|
+
}
|
|
108
|
+
const covered = coverage.get(candidate.sessionRowId) ?? 0;
|
|
109
|
+
return {
|
|
110
|
+
sessionId: candidate.sessionId,
|
|
111
|
+
title: candidate.title,
|
|
112
|
+
lastTs: candidate.lastTs,
|
|
113
|
+
promptCount: candidate.promptCount,
|
|
114
|
+
score,
|
|
115
|
+
bm25: candidate.bm25,
|
|
116
|
+
coverage: covered,
|
|
117
|
+
strong: terms.length >= MIN_CONTENT_TERMS && covered >= STRONG_COVERAGE,
|
|
118
|
+
};
|
|
119
|
+
})
|
|
120
|
+
.toSorted((a, b) => b.score - a.score || a.sessionId.localeCompare(b.sessionId));
|
|
121
|
+
};
|
|
122
|
+
//# sourceMappingURL=match.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match.js","sourceRoot":"","sources":["../../../src/recall/rank/match.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terms.d.ts","sourceRoot":"","sources":["../../../src/recall/rank/terms.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,cAAc,SAAU,MAAM,KAAG,MAAM,EAUnD,CAAC;AAIF,eAAO,MAAM,UAAU,UAAW,SAAS,MAAM,EAAE,KAAG,MAAuD,CAAC;AAG9G,eAAO,MAAM,UAAU,SAAU,MAAM,KAAG,MAAM,GAAG,SAGlD,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { STOPWORDS } from "@intentic/base/stopwords";
|
|
2
|
+
import { stripInjectedPreamble } from "@intentic/constants";
|
|
3
|
+
const PROMPT_FILLER = new Set([
|
|
4
|
+
"please thanks thank hi hey ok okay yes no sure",
|
|
5
|
+
"can could would should will let lets me my our us",
|
|
6
|
+
"just also now then again so if all some there here where",
|
|
7
|
+
"go ahead continue proceed next left off done finish finished work",
|
|
8
|
+
"fix make better help see want need get try did",
|
|
9
|
+
"don didn doesn isn ve re ll",
|
|
10
|
+
]
|
|
11
|
+
.join(" ")
|
|
12
|
+
.split(" "));
|
|
13
|
+
export const contentTermsOf = (text) => [
|
|
14
|
+
...new Set((stripInjectedPreamble(text)
|
|
15
|
+
.normalize("NFD")
|
|
16
|
+
.replaceAll(/\p{M}/gu, "")
|
|
17
|
+
.toLowerCase()
|
|
18
|
+
.match(/[\p{L}\p{N}_$]+/gu) ?? []).filter((term) => term.length > 1 && !STOPWORDS.has(term) && !PROMPT_FILLER.has(term))),
|
|
19
|
+
];
|
|
20
|
+
export const ftsMatchOf = (terms) => terms.map((term) => `"${term}"`).join(" OR ");
|
|
21
|
+
export const ftsQueryOf = (text) => {
|
|
22
|
+
const terms = contentTermsOf(text);
|
|
23
|
+
return terms.length === 0 ? undefined : ftsMatchOf(terms);
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=terms.js.map
|