@ontos-ai/knowhere-claw 0.1.0-beta.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 +163 -0
- package/dist/_virtual/_rolldown/runtime.js +37 -0
- package/dist/client.d.ts +33 -0
- package/dist/client.js +395 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.js +132 -0
- package/dist/error-message.d.ts +1 -0
- package/dist/error-message.js +48 -0
- package/dist/hooks.d.ts +8 -0
- package/dist/hooks.js +415 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +43 -0
- package/dist/node_modules/.pnpm/@knowhere-ai_sdk@0.1.1/node_modules/@knowhere-ai/sdk/dist/index.js +717 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/adapters/adapters.js +83 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/adapters/fetch.js +170 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/adapters/xhr.js +106 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/axios.js +57 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/cancel/CancelToken.js +90 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/cancel/CanceledError.js +20 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/cancel/isCancel.js +6 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/core/Axios.js +174 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/core/AxiosError.js +70 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/core/AxiosHeaders.js +204 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/core/InterceptorManager.js +60 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/core/buildFullPath.js +20 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/core/dispatchRequest.js +52 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/core/mergeConfig.js +81 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/core/settle.js +18 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/core/transformData.js +25 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/defaults/index.js +107 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/defaults/transitional.js +9 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/env/data.js +4 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/AxiosURLSearchParams.js +50 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/HttpStatusCode.js +77 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/bind.js +15 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/buildURL.js +40 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/combineURLs.js +14 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/composeSignals.js +39 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/cookies.js +31 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/formDataToJSON.js +67 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/isAbsoluteURL.js +14 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/isAxiosError.js +14 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/isURLSameOrigin.js +8 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/parseHeaders.js +53 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/parseProtocol.js +7 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/progressEventReducer.js +38 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/resolveConfig.js +36 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/speedometer.js +36 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/spread.js +29 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/throttle.js +38 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/toFormData.js +151 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/toURLEncodedForm.js +18 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/trackStream.js +69 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/helpers/validator.js +76 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/platform/browser/classes/Blob.js +4 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/platform/browser/classes/FormData.js +4 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/platform/browser/classes/URLSearchParams.js +5 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/platform/browser/index.js +22 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/platform/common/utils.js +46 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/platform/index.js +9 -0
- package/dist/node_modules/.pnpm/axios@1.13.6/node_modules/axios/lib/utils.js +698 -0
- package/dist/node_modules/.pnpm/fflate@0.8.2/node_modules/fflate/esm/browser.js +426 -0
- package/dist/node_modules/.pnpm/jszip@3.10.1/node_modules/jszip/dist/jszip.min.js +3110 -0
- package/dist/parser.d.ts +16 -0
- package/dist/parser.js +323 -0
- package/dist/session.d.ts +11 -0
- package/dist/session.js +78 -0
- package/dist/store.d.ts +62 -0
- package/dist/store.js +482 -0
- package/dist/text.d.ts +10 -0
- package/dist/text.js +34 -0
- package/dist/tools.d.ts +9 -0
- package/dist/tools.js +1177 -0
- package/dist/tracker-progress.d.ts +8 -0
- package/dist/tracker-progress.js +197 -0
- package/dist/types.d.ts +247 -0
- package/dist/types.js +9 -0
- package/openclaw.plugin.json +107 -0
- package/package.json +61 -0
- package/skills/knowhere/SKILL.md +243 -0
package/dist/parser.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { KnowhereDownloadedResult, KnowhereManifest, KnowhereParseResult, KnowhereStatistics, StoredBrowseIndex, StoredChunk } from "./types";
|
|
2
|
+
type KnowhereStoredResultSummary = {
|
|
3
|
+
manifest: KnowhereManifest;
|
|
4
|
+
chunkCount: number;
|
|
5
|
+
statistics: KnowhereStatistics;
|
|
6
|
+
};
|
|
7
|
+
export declare const STORED_BROWSE_INDEX_VERSION = 2;
|
|
8
|
+
export declare function resolveResultEntryPath(rootDir: string, entryPath: string): string;
|
|
9
|
+
export declare function buildStoredPathPrefixes(storedPath: string): string[];
|
|
10
|
+
export declare function isStoredBrowseIndex(value: unknown): value is StoredBrowseIndex;
|
|
11
|
+
export declare function buildStoredBrowseIndex(resultDir: string, manifest: KnowhereManifest, chunks: StoredChunk[]): Promise<StoredBrowseIndex>;
|
|
12
|
+
export declare function extractKnowhereResultArchive(downloadedResult: KnowhereDownloadedResult, targetDir: string): Promise<void>;
|
|
13
|
+
export declare function readStoredKnowhereResultSummary(resultDir: string): Promise<KnowhereStoredResultSummary>;
|
|
14
|
+
export declare function readStoredKnowhereResultContent(resultDir: string): Promise<Omit<KnowhereParseResult, "browseIndex">>;
|
|
15
|
+
export declare function readStoredKnowhereParseResult(resultDir: string): Promise<KnowhereParseResult>;
|
|
16
|
+
export {};
|
package/dist/parser.js
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { isNodeError, isRecord } from "./types.js";
|
|
2
|
+
import { strFromU8, unzipSync } from "./node_modules/.pnpm/fflate@0.8.2/node_modules/fflate/esm/browser.js";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import fs from "node:fs/promises";
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
const CHUNKS_FILE_NAME = "chunks.json";
|
|
7
|
+
const FULL_MARKDOWN_FILE_NAME = "full.md";
|
|
8
|
+
const HIERARCHY_FILE_NAME = "hierarchy.json";
|
|
9
|
+
const HIERARCHY_VIEW_FILE_NAME = "hierarchy_view.html";
|
|
10
|
+
const KB_CSV_FILE_NAME = "kb.csv";
|
|
11
|
+
const MANIFEST_FILE_NAME = "manifest.json";
|
|
12
|
+
function readZipText(entries, fileName) {
|
|
13
|
+
const entry = entries[fileName];
|
|
14
|
+
return entry ? strFromU8(entry) : null;
|
|
15
|
+
}
|
|
16
|
+
async function ensureDir(targetPath) {
|
|
17
|
+
await fs.mkdir(targetPath, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
async function readTextFile(targetPath) {
|
|
20
|
+
try {
|
|
21
|
+
return await fs.readFile(targetPath, "utf-8");
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (isNodeError(error) && error.code === "ENOENT") return null;
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function readJsonFile(targetPath) {
|
|
28
|
+
const text = await readTextFile(targetPath);
|
|
29
|
+
if (text === null) return null;
|
|
30
|
+
return JSON.parse(text);
|
|
31
|
+
}
|
|
32
|
+
function resolveResultEntryPath(rootDir, entryPath) {
|
|
33
|
+
const normalizedEntryPath = normalizeRelativePath(entryPath);
|
|
34
|
+
const resolvedPath = path.resolve(rootDir, normalizedEntryPath);
|
|
35
|
+
const relativePath = path.relative(rootDir, resolvedPath);
|
|
36
|
+
if (relativePath.startsWith("..") || path.isAbsolute(relativePath)) throw new Error(`Knowhere result entry escapes storage root: ${entryPath}`);
|
|
37
|
+
return resolvedPath;
|
|
38
|
+
}
|
|
39
|
+
function normalizeRelativePath(value) {
|
|
40
|
+
return value.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
41
|
+
}
|
|
42
|
+
function normalizeStoredPath(value) {
|
|
43
|
+
if (typeof value !== "string") return null;
|
|
44
|
+
return value.trim() || null;
|
|
45
|
+
}
|
|
46
|
+
function readChunkNumber(rawChunk, metadata, key) {
|
|
47
|
+
const metadataValue = metadata[key];
|
|
48
|
+
if (typeof metadataValue === "number" && Number.isFinite(metadataValue)) return metadataValue;
|
|
49
|
+
const rawValue = rawChunk[key];
|
|
50
|
+
if (typeof rawValue === "number" && Number.isFinite(rawValue)) return rawValue;
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
function readChunkStringArray(rawChunk, metadata, key) {
|
|
54
|
+
const metadataValue = metadata[key];
|
|
55
|
+
if (Array.isArray(metadataValue)) return metadataValue.filter((entry) => typeof entry === "string");
|
|
56
|
+
const rawValue = rawChunk[key];
|
|
57
|
+
if (Array.isArray(rawValue)) return rawValue.filter((entry) => typeof entry === "string");
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
function readChunkArray(rawChunk, metadata, key) {
|
|
61
|
+
const metadataValue = metadata[key];
|
|
62
|
+
if (Array.isArray(metadataValue)) return metadataValue;
|
|
63
|
+
const rawValue = rawChunk[key];
|
|
64
|
+
if (Array.isArray(rawValue)) return rawValue;
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
function extractAssetFilePath(rawChunk, metadata) {
|
|
68
|
+
const candidates = [rawChunk.file_path, metadata.file_path];
|
|
69
|
+
for (const candidate of candidates) if (typeof candidate === "string" && candidate.trim()) return normalizeRelativePath(candidate.trim());
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
function parseRawChunks(value) {
|
|
73
|
+
if (Array.isArray(value)) return value.filter((entry) => isRecord(entry));
|
|
74
|
+
if (isRecord(value) && Array.isArray(value.chunks)) return value.chunks.filter((entry) => isRecord(entry));
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
function parseManifest(value) {
|
|
78
|
+
return isRecord(value) ? value : {};
|
|
79
|
+
}
|
|
80
|
+
function buildChunk(rawChunk) {
|
|
81
|
+
const metadata = isRecord(rawChunk.metadata) ? rawChunk.metadata : {};
|
|
82
|
+
const type = rawChunk.type === "image" || rawChunk.type === "table" || rawChunk.type === "text" ? rawChunk.type : "text";
|
|
83
|
+
return {
|
|
84
|
+
chunkId: typeof rawChunk.chunk_id === "string" ? rawChunk.chunk_id : "",
|
|
85
|
+
type,
|
|
86
|
+
path: normalizeStoredPath(rawChunk.path),
|
|
87
|
+
summary: typeof metadata.summary === "string" ? metadata.summary : typeof rawChunk.summary === "string" ? rawChunk.summary : "",
|
|
88
|
+
content: typeof rawChunk.content === "string" ? rawChunk.content : "",
|
|
89
|
+
tokens: readChunkNumber(rawChunk, metadata, "tokens"),
|
|
90
|
+
keywords: readChunkStringArray(rawChunk, metadata, "keywords"),
|
|
91
|
+
relationships: readChunkArray(rawChunk, metadata, "relationships"),
|
|
92
|
+
metadata,
|
|
93
|
+
assetFilePath: extractAssetFilePath(rawChunk, metadata),
|
|
94
|
+
originalName: typeof metadata.original_name === "string" ? metadata.original_name : typeof rawChunk.original_name === "string" ? rawChunk.original_name : null,
|
|
95
|
+
tableType: typeof metadata.table_type === "string" ? metadata.table_type : typeof rawChunk.table_type === "string" ? rawChunk.table_type : null
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function normalizeStatistics(manifest, rawChunks) {
|
|
99
|
+
if (manifest.statistics) return manifest.statistics;
|
|
100
|
+
return {
|
|
101
|
+
total_chunks: rawChunks.length,
|
|
102
|
+
text_chunks: rawChunks.filter((chunk) => chunk.type !== "image" && chunk.type !== "table").length,
|
|
103
|
+
image_chunks: rawChunks.filter((chunk) => chunk.type === "image").length,
|
|
104
|
+
table_chunks: rawChunks.filter((chunk) => chunk.type === "table").length,
|
|
105
|
+
total_pages: 0
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function validateKnowhereResultChecksum(zipBuffer, manifest) {
|
|
109
|
+
const checksum = manifest.checksum?.value;
|
|
110
|
+
if (typeof checksum !== "string" || !checksum) return;
|
|
111
|
+
if (createHash("sha256").update(zipBuffer).digest("hex") !== checksum) throw new Error("Knowhere result ZIP checksum mismatch.");
|
|
112
|
+
}
|
|
113
|
+
function tokenizeStoredPath(storedPath) {
|
|
114
|
+
const slashSegments = storedPath.split("/").map((segment) => segment.trim()).filter(Boolean);
|
|
115
|
+
const tokens = [];
|
|
116
|
+
for (const slashSegment of slashSegments) {
|
|
117
|
+
const arrowSegments = slashSegment.split("-->").map((segment) => segment.trim()).filter(Boolean);
|
|
118
|
+
if (arrowSegments.length === 0) continue;
|
|
119
|
+
tokens.push({
|
|
120
|
+
delimiter: tokens.length === 0 ? null : "/",
|
|
121
|
+
segment: arrowSegments[0] || ""
|
|
122
|
+
});
|
|
123
|
+
for (const arrowSegment of arrowSegments.slice(1)) tokens.push({
|
|
124
|
+
delimiter: "-->",
|
|
125
|
+
segment: arrowSegment
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return tokens;
|
|
129
|
+
}
|
|
130
|
+
function buildStoredPathPrefixes(storedPath) {
|
|
131
|
+
const tokens = tokenizeStoredPath(storedPath);
|
|
132
|
+
const prefixes = [];
|
|
133
|
+
let currentPath = "";
|
|
134
|
+
for (const token of tokens) {
|
|
135
|
+
currentPath = token.delimiter ? `${currentPath}${token.delimiter}${token.segment}` : token.segment;
|
|
136
|
+
prefixes.push(currentPath);
|
|
137
|
+
}
|
|
138
|
+
return prefixes;
|
|
139
|
+
}
|
|
140
|
+
function ensurePathAccumulator(accumulators, pathValue, parentPath, depth) {
|
|
141
|
+
const existing = accumulators.get(pathValue);
|
|
142
|
+
if (existing) {
|
|
143
|
+
if (parentPath && !existing.parentPath) existing.parentPath = parentPath;
|
|
144
|
+
return existing;
|
|
145
|
+
}
|
|
146
|
+
const next = {
|
|
147
|
+
childPaths: /* @__PURE__ */ new Set(),
|
|
148
|
+
chunkCount: 0,
|
|
149
|
+
chunkIds: [],
|
|
150
|
+
depth,
|
|
151
|
+
directChunkCount: 0,
|
|
152
|
+
imageChunkCount: 0,
|
|
153
|
+
parentPath,
|
|
154
|
+
path: pathValue,
|
|
155
|
+
tableChunkCount: 0,
|
|
156
|
+
textChunkCount: 0
|
|
157
|
+
};
|
|
158
|
+
accumulators.set(pathValue, next);
|
|
159
|
+
return next;
|
|
160
|
+
}
|
|
161
|
+
function incrementPathCounters(accumulator, chunkType) {
|
|
162
|
+
accumulator.chunkCount += 1;
|
|
163
|
+
if (chunkType === "image") {
|
|
164
|
+
accumulator.imageChunkCount += 1;
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (chunkType === "table") {
|
|
168
|
+
accumulator.tableChunkCount += 1;
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
accumulator.textChunkCount += 1;
|
|
172
|
+
}
|
|
173
|
+
function buildPathRecords(chunks) {
|
|
174
|
+
const accumulators = /* @__PURE__ */ new Map();
|
|
175
|
+
for (const chunk of chunks) {
|
|
176
|
+
if (!chunk.path) continue;
|
|
177
|
+
const prefixes = buildStoredPathPrefixes(chunk.path);
|
|
178
|
+
for (const [index, prefix] of prefixes.entries()) {
|
|
179
|
+
const parentPath = index > 0 ? prefixes[index - 1] || null : null;
|
|
180
|
+
const accumulator = ensurePathAccumulator(accumulators, prefix, parentPath, index + 1);
|
|
181
|
+
incrementPathCounters(accumulator, chunk.type);
|
|
182
|
+
if (parentPath) ensurePathAccumulator(accumulators, parentPath, index > 1 ? prefixes[index - 2] || null : null, index).childPaths.add(prefix);
|
|
183
|
+
if (index === prefixes.length - 1) {
|
|
184
|
+
accumulator.directChunkCount += 1;
|
|
185
|
+
if (chunk.chunkId) accumulator.chunkIds.push(chunk.chunkId);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return [...accumulators.values()].sort((left, right) => left.depth - right.depth || left.path.localeCompare(right.path)).map((entry) => ({
|
|
190
|
+
path: entry.path,
|
|
191
|
+
parentPath: entry.parentPath,
|
|
192
|
+
depth: entry.depth,
|
|
193
|
+
childPaths: [...entry.childPaths].sort((left, right) => left.localeCompare(right)),
|
|
194
|
+
chunkIds: [...entry.chunkIds],
|
|
195
|
+
directChunkCount: entry.directChunkCount,
|
|
196
|
+
chunkCount: entry.chunkCount,
|
|
197
|
+
textChunkCount: entry.textChunkCount,
|
|
198
|
+
imageChunkCount: entry.imageChunkCount,
|
|
199
|
+
tableChunkCount: entry.tableChunkCount
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
function readManifestAssetEntries(manifest, key) {
|
|
203
|
+
const rawEntries = (isRecord(manifest.files) ? manifest.files : {})[key];
|
|
204
|
+
if (!Array.isArray(rawEntries)) return [];
|
|
205
|
+
return rawEntries.filter((entry) => isRecord(entry));
|
|
206
|
+
}
|
|
207
|
+
function buildResultFileChunkLookup(manifest, chunks) {
|
|
208
|
+
const entries = /* @__PURE__ */ new Map();
|
|
209
|
+
for (const key of ["images", "tables"]) {
|
|
210
|
+
const assetEntries = readManifestAssetEntries(manifest, key);
|
|
211
|
+
for (const entry of assetEntries) {
|
|
212
|
+
const filePath = typeof entry.file_path === "string" && entry.file_path.trim() ? normalizeRelativePath(entry.file_path.trim()) : null;
|
|
213
|
+
if (!filePath) continue;
|
|
214
|
+
entries.set(filePath, {
|
|
215
|
+
chunkId: typeof entry.id === "string" ? entry.id : null,
|
|
216
|
+
format: typeof entry.format === "string" ? entry.format : null
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
for (const chunk of chunks) {
|
|
221
|
+
if (!chunk.assetFilePath || entries.has(chunk.assetFilePath)) continue;
|
|
222
|
+
entries.set(chunk.assetFilePath, {
|
|
223
|
+
chunkId: chunk.chunkId || null,
|
|
224
|
+
format: null
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return entries;
|
|
228
|
+
}
|
|
229
|
+
function inferResultFileKind(relativePath) {
|
|
230
|
+
if (relativePath === MANIFEST_FILE_NAME) return "manifest";
|
|
231
|
+
if (relativePath === CHUNKS_FILE_NAME) return "chunks";
|
|
232
|
+
if (relativePath === FULL_MARKDOWN_FILE_NAME) return "fullMarkdown";
|
|
233
|
+
if (relativePath === KB_CSV_FILE_NAME) return "kbCsv";
|
|
234
|
+
if (relativePath === HIERARCHY_FILE_NAME) return "hierarchy";
|
|
235
|
+
if (relativePath === HIERARCHY_VIEW_FILE_NAME) return "hierarchyView";
|
|
236
|
+
if (relativePath.startsWith("images/")) return "image";
|
|
237
|
+
if (relativePath.startsWith("tables/")) return "table";
|
|
238
|
+
return "other";
|
|
239
|
+
}
|
|
240
|
+
function inferResultFileFormat(relativePath) {
|
|
241
|
+
return path.posix.extname(relativePath).replace(/^\./, "").trim() || null;
|
|
242
|
+
}
|
|
243
|
+
function isStringArray(value) {
|
|
244
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
245
|
+
}
|
|
246
|
+
function isStoredBrowseIndex(value) {
|
|
247
|
+
if (!isRecord(value)) return false;
|
|
248
|
+
if (value.version !== 2) return false;
|
|
249
|
+
if (!isStringArray(value.chunkOrder)) return false;
|
|
250
|
+
if (!Array.isArray(value.paths) || !Array.isArray(value.resultFiles)) return false;
|
|
251
|
+
if (!value.paths.every((entry) => isRecord(entry) && typeof entry.path === "string" && (entry.parentPath === null || typeof entry.parentPath === "string") && typeof entry.depth === "number" && Number.isFinite(entry.depth) && isStringArray(entry.childPaths) && isStringArray(entry.chunkIds) && typeof entry.directChunkCount === "number" && typeof entry.chunkCount === "number" && typeof entry.textChunkCount === "number" && typeof entry.imageChunkCount === "number" && typeof entry.tableChunkCount === "number")) return false;
|
|
252
|
+
return value.resultFiles.every((entry) => isRecord(entry) && typeof entry.relativePath === "string" && typeof entry.kind === "string" && (entry.chunkId === null || typeof entry.chunkId === "string") && (entry.format === null || typeof entry.format === "string") && (entry.sizeBytes === null || typeof entry.sizeBytes === "number" && Number.isFinite(entry.sizeBytes)));
|
|
253
|
+
}
|
|
254
|
+
async function listResultFiles(rootDir, currentDir = rootDir) {
|
|
255
|
+
const entries = await fs.readdir(currentDir, { withFileTypes: true });
|
|
256
|
+
const files = [];
|
|
257
|
+
for (const entry of entries) {
|
|
258
|
+
const absolutePath = path.join(currentDir, entry.name);
|
|
259
|
+
if (entry.isDirectory()) {
|
|
260
|
+
files.push(...await listResultFiles(rootDir, absolutePath));
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
if (!entry.isFile()) continue;
|
|
264
|
+
files.push(normalizeRelativePath(path.relative(rootDir, absolutePath)));
|
|
265
|
+
}
|
|
266
|
+
return files.sort((left, right) => left.localeCompare(right));
|
|
267
|
+
}
|
|
268
|
+
async function buildResultFileRecords(resultDir, manifest, chunks) {
|
|
269
|
+
const lookup = buildResultFileChunkLookup(manifest, chunks);
|
|
270
|
+
const relativePaths = await listResultFiles(resultDir);
|
|
271
|
+
return Promise.all(relativePaths.map(async (relativePath) => {
|
|
272
|
+
const absolutePath = resolveResultEntryPath(resultDir, relativePath);
|
|
273
|
+
const stats = await fs.stat(absolutePath);
|
|
274
|
+
const manifestEntry = lookup.get(relativePath);
|
|
275
|
+
return {
|
|
276
|
+
relativePath,
|
|
277
|
+
kind: inferResultFileKind(relativePath),
|
|
278
|
+
chunkId: manifestEntry?.chunkId ?? null,
|
|
279
|
+
format: manifestEntry?.format ?? inferResultFileFormat(relativePath),
|
|
280
|
+
sizeBytes: stats.isFile() ? stats.size : null
|
|
281
|
+
};
|
|
282
|
+
}));
|
|
283
|
+
}
|
|
284
|
+
async function buildStoredBrowseIndex(resultDir, manifest, chunks) {
|
|
285
|
+
return {
|
|
286
|
+
version: 2,
|
|
287
|
+
paths: buildPathRecords(chunks),
|
|
288
|
+
chunkOrder: chunks.map((chunk) => chunk.chunkId).filter((chunkId) => chunkId.length > 0),
|
|
289
|
+
resultFiles: await buildResultFileRecords(resultDir, manifest, chunks)
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
async function extractKnowhereResultArchive(downloadedResult, targetDir) {
|
|
293
|
+
const zipBuffer = Buffer.isBuffer(downloadedResult.zipBytes) ? downloadedResult.zipBytes : Buffer.from(downloadedResult.zipBytes);
|
|
294
|
+
const entries = unzipSync(new Uint8Array(zipBuffer));
|
|
295
|
+
const manifestText = readZipText(entries, MANIFEST_FILE_NAME);
|
|
296
|
+
if (!manifestText) throw new Error("Knowhere result ZIP does not contain manifest.json.");
|
|
297
|
+
validateKnowhereResultChecksum(zipBuffer, parseManifest(JSON.parse(manifestText)));
|
|
298
|
+
await ensureDir(targetDir);
|
|
299
|
+
for (const [entryPath, entryBytes] of Object.entries(entries)) {
|
|
300
|
+
const outputPath = resolveResultEntryPath(targetDir, entryPath);
|
|
301
|
+
await ensureDir(path.dirname(outputPath));
|
|
302
|
+
await fs.writeFile(outputPath, entryBytes);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
async function readStoredKnowhereResultSummary(resultDir) {
|
|
306
|
+
const manifest = parseManifest(await readJsonFile(path.join(resultDir, MANIFEST_FILE_NAME)));
|
|
307
|
+
const rawChunks = parseRawChunks(await readJsonFile(path.join(resultDir, CHUNKS_FILE_NAME)));
|
|
308
|
+
return {
|
|
309
|
+
manifest,
|
|
310
|
+
chunkCount: rawChunks.length,
|
|
311
|
+
statistics: normalizeStatistics(manifest, rawChunks)
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
async function readStoredKnowhereResultContent(resultDir) {
|
|
315
|
+
return {
|
|
316
|
+
manifest: parseManifest(await readJsonFile(path.join(resultDir, MANIFEST_FILE_NAME))),
|
|
317
|
+
chunks: parseRawChunks(await readJsonFile(path.join(resultDir, CHUNKS_FILE_NAME))).map((rawChunk) => buildChunk(rawChunk)),
|
|
318
|
+
fullMarkdown: await readTextFile(path.join(resultDir, FULL_MARKDOWN_FILE_NAME)) || "",
|
|
319
|
+
hierarchy: await readJsonFile(path.join(resultDir, HIERARCHY_FILE_NAME))
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
//#endregion
|
|
323
|
+
export { buildStoredBrowseIndex, extractKnowhereResultArchive, isStoredBrowseIndex, readStoredKnowhereResultContent, readStoredKnowhereResultSummary, resolveResultEntryPath };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type ParsedConversationSessionKey = {
|
|
2
|
+
agentId: string;
|
|
3
|
+
surface: string;
|
|
4
|
+
remainder: string;
|
|
5
|
+
segments: string[];
|
|
6
|
+
};
|
|
7
|
+
export declare function parseConversationSessionKey(sessionKey: string | undefined): ParsedConversationSessionKey | undefined;
|
|
8
|
+
export declare function normalizeConversationScopeKey(sessionKey: string | undefined): string | undefined;
|
|
9
|
+
export declare function resolveSharedConversationScopeKey(sessionKey: string | undefined): string | undefined;
|
|
10
|
+
export declare function findConversationSegmentValue(session: ParsedConversationSessionKey | undefined, ...keys: string[]): string | undefined;
|
|
11
|
+
export declare function deriveMessageContextScopeKey(context: unknown): string | undefined;
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { normalizeWhitespace } from "./text.js";
|
|
2
|
+
//#region src/session.ts
|
|
3
|
+
const RESERVED_AGENT_SESSION_ROOTS = new Set([
|
|
4
|
+
"main",
|
|
5
|
+
"subagent",
|
|
6
|
+
"direct",
|
|
7
|
+
"global"
|
|
8
|
+
]);
|
|
9
|
+
const CONVERSATION_KIND_SEGMENTS = new Set([
|
|
10
|
+
"channel",
|
|
11
|
+
"chat",
|
|
12
|
+
"conversation",
|
|
13
|
+
"direct",
|
|
14
|
+
"dm",
|
|
15
|
+
"forum",
|
|
16
|
+
"group",
|
|
17
|
+
"guild",
|
|
18
|
+
"member",
|
|
19
|
+
"room",
|
|
20
|
+
"space",
|
|
21
|
+
"thread",
|
|
22
|
+
"user"
|
|
23
|
+
]);
|
|
24
|
+
function isRecord(value) {
|
|
25
|
+
return typeof value === "object" && value !== null;
|
|
26
|
+
}
|
|
27
|
+
function readNormalizedString(value) {
|
|
28
|
+
return normalizeWhitespace(value) || void 0;
|
|
29
|
+
}
|
|
30
|
+
function looksLikeConversationSegments(segments) {
|
|
31
|
+
return segments.some((segment) => CONVERSATION_KIND_SEGMENTS.has(normalizeWhitespace(segment).toLowerCase()));
|
|
32
|
+
}
|
|
33
|
+
function parseConversationSessionKey(sessionKey) {
|
|
34
|
+
const normalized = normalizeWhitespace(sessionKey);
|
|
35
|
+
if (!normalized) return;
|
|
36
|
+
const match = normalized.match(/^agent:([^:]+):(.+)$/);
|
|
37
|
+
if (!match?.[1] || !match[2]) return;
|
|
38
|
+
const remainder = match[2];
|
|
39
|
+
const segments = remainder.split(":").filter(Boolean);
|
|
40
|
+
if (segments.length < 2) return;
|
|
41
|
+
const surface = normalizeWhitespace(segments[0]).toLowerCase();
|
|
42
|
+
if (!surface || RESERVED_AGENT_SESSION_ROOTS.has(surface)) return;
|
|
43
|
+
if (!looksLikeConversationSegments(segments.slice(1))) return;
|
|
44
|
+
return {
|
|
45
|
+
agentId: normalizeWhitespace(match[1]),
|
|
46
|
+
surface,
|
|
47
|
+
remainder,
|
|
48
|
+
segments
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function findConversationSegmentValue(session, ...keys) {
|
|
52
|
+
if (!session || keys.length === 0) return;
|
|
53
|
+
const expected = new Set(keys.map((key) => normalizeWhitespace(key).toLowerCase()));
|
|
54
|
+
for (let index = 0; index < session.segments.length - 1; index += 1) {
|
|
55
|
+
const segment = normalizeWhitespace(session.segments[index]).toLowerCase();
|
|
56
|
+
if (!expected.has(segment)) continue;
|
|
57
|
+
const value = normalizeWhitespace(session.segments[index + 1]);
|
|
58
|
+
if (value) return value;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function deriveMessageContextScopeKey(context) {
|
|
62
|
+
if (!isRecord(context)) return;
|
|
63
|
+
const surface = readNormalizedString(context.channelId ?? context.provider ?? context.surface)?.toLowerCase();
|
|
64
|
+
if (!surface) return;
|
|
65
|
+
const conversationId = readNormalizedString(context.conversationId);
|
|
66
|
+
const groupId = readNormalizedString(context.groupId);
|
|
67
|
+
const threadId = readNormalizedString(context.threadId) ?? readNormalizedString(context.messageThreadId);
|
|
68
|
+
if (!conversationId && !groupId && !threadId) return;
|
|
69
|
+
const parts = ["shared", surface];
|
|
70
|
+
const accountId = readNormalizedString(context.accountId);
|
|
71
|
+
if (accountId) parts.push("account", accountId);
|
|
72
|
+
if (groupId) parts.push("group", groupId);
|
|
73
|
+
if (conversationId) parts.push("conversation", conversationId);
|
|
74
|
+
if (threadId) parts.push("thread", threadId);
|
|
75
|
+
return parts.join(":");
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
export { deriveMessageContextScopeKey, findConversationSegmentValue, parseConversationSessionKey };
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { KnowhereScope, PluginLogger, SaveStoredDocumentPayload, ScopeMode, StoredDocumentPayload, StoredDocumentRecord } from "./types";
|
|
2
|
+
export declare class KnowhereStore {
|
|
3
|
+
private readonly rootDir;
|
|
4
|
+
private readonly scopeMode;
|
|
5
|
+
private readonly logger;
|
|
6
|
+
private readonly indexCache;
|
|
7
|
+
private readonly documentPayloadCache;
|
|
8
|
+
private readonly scopeAccessChains;
|
|
9
|
+
private readonly scopeKeyAliases;
|
|
10
|
+
private readonly sessionScopeKeysBySessionId;
|
|
11
|
+
private readonly sessionScopeKeysBySessionKey;
|
|
12
|
+
constructor(params: {
|
|
13
|
+
rootDir: string;
|
|
14
|
+
scopeMode: ScopeMode;
|
|
15
|
+
logger: PluginLogger;
|
|
16
|
+
});
|
|
17
|
+
registerScopeAlias(context: {
|
|
18
|
+
scopeKey: string;
|
|
19
|
+
sessionKey?: string;
|
|
20
|
+
sessionId?: string;
|
|
21
|
+
}): string;
|
|
22
|
+
registerMessageScope(context: {
|
|
23
|
+
sessionKey?: string;
|
|
24
|
+
sessionId?: string;
|
|
25
|
+
messageContext: unknown;
|
|
26
|
+
}): string | undefined;
|
|
27
|
+
inheritScopeAlias(context: {
|
|
28
|
+
childSessionKey?: string;
|
|
29
|
+
childSessionId?: string;
|
|
30
|
+
requesterSessionKey?: string;
|
|
31
|
+
requesterSessionId?: string;
|
|
32
|
+
}): string | undefined;
|
|
33
|
+
resolveScope(context?: {
|
|
34
|
+
agentId?: string;
|
|
35
|
+
sessionKey?: string;
|
|
36
|
+
sessionId?: string;
|
|
37
|
+
}): KnowhereScope;
|
|
38
|
+
listDocuments(scope: KnowhereScope): Promise<StoredDocumentRecord[]>;
|
|
39
|
+
loadDocumentPayload(scope: KnowhereScope, docId: string): Promise<StoredDocumentPayload | null>;
|
|
40
|
+
readResultFile(scope: KnowhereScope, docId: string, relativePath: string): Promise<{
|
|
41
|
+
document: StoredDocumentRecord;
|
|
42
|
+
relativePath: string;
|
|
43
|
+
text: string | null;
|
|
44
|
+
} | null>;
|
|
45
|
+
saveDownloadedDocument(scope: KnowhereScope, payload: SaveStoredDocumentPayload, options?: {
|
|
46
|
+
overwrite?: boolean;
|
|
47
|
+
}): Promise<StoredDocumentRecord>;
|
|
48
|
+
removeDocument(scope: KnowhereScope, docId: string): Promise<StoredDocumentRecord | null>;
|
|
49
|
+
clearScope(scope: KnowhereScope): Promise<StoredDocumentRecord[]>;
|
|
50
|
+
private getIndex;
|
|
51
|
+
private persistIndex;
|
|
52
|
+
private runWithScopeAccessLock;
|
|
53
|
+
private removeDocumentArtifacts;
|
|
54
|
+
private buildDocumentPayloadCacheKey;
|
|
55
|
+
private touchDocumentPayloadCache;
|
|
56
|
+
private deleteDocumentPayloadCache;
|
|
57
|
+
private deleteScopeDocumentPayloadCaches;
|
|
58
|
+
private loadOrBuildBrowseIndex;
|
|
59
|
+
private resolveCanonicalScopeKey;
|
|
60
|
+
private resolveKnownScopeKey;
|
|
61
|
+
private rebuildIndex;
|
|
62
|
+
}
|