chatlab-cli 0.24.1 → 0.25.1
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/dist/chat-command-5XMRLXZM.mjs +166 -0
- package/dist/chat-command-5XMRLXZM.mjs.map +1 -0
- package/dist/{chunk-N5DGZQB4.mjs → chunk-7VG6QGQ2.mjs} +1543 -664
- package/dist/chunk-7VG6QGQ2.mjs.map +1 -0
- package/dist/{chunk-QJI6AOAT.mjs → chunk-CUCDRAY6.mjs} +17 -25
- package/dist/chunk-CUCDRAY6.mjs.map +1 -0
- package/dist/chunk-FDK6SPCG.mjs +40 -0
- package/dist/chunk-FDK6SPCG.mjs.map +1 -0
- package/dist/{chunk-ZL322NVL.mjs → chunk-GTCTDD2Z.mjs} +116 -504
- package/dist/chunk-GTCTDD2Z.mjs.map +1 -0
- package/dist/{chunk-43XWYC3M.mjs → chunk-JE3FOFF7.mjs} +219 -123
- package/dist/chunk-JE3FOFF7.mjs.map +1 -0
- package/dist/{chunk-QY6P2YS7.mjs → chunk-PDQFSQO6.mjs} +59 -33
- package/dist/chunk-PDQFSQO6.mjs.map +1 -0
- package/dist/chunk-WYHGWTA4.mjs +485 -0
- package/dist/chunk-WYHGWTA4.mjs.map +1 -0
- package/dist/{chunk-CIIQ3S2X.mjs → chunk-YZYP5ST6.mjs} +37 -8
- package/dist/chunk-YZYP5ST6.mjs.map +1 -0
- package/dist/cli.mjs +3 -2
- package/dist/{http-TPX74BLK.mjs → http-C3CGXUBU.mjs} +8 -6
- package/dist/{import-B745DRHD.mjs → import-VS7L5JDX.mjs} +4 -4
- package/dist/index.mjs +10 -8
- package/dist/{mcp-YWAVG5XW.mjs → mcp-6VXDPUQK.mjs} +11 -6
- package/dist/mcp-6VXDPUQK.mjs.map +1 -0
- package/dist/{stream-import-OPALPVWF.mjs → stream-import-TFDBNVIW.mjs} +3 -3
- package/dist-web/assets/{DebugToolsPanel-DaSNc1o-.css → DebugToolsPanel-vn-bnUxn.css} +1 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-B1xZmp9r.js +161 -0
- package/dist-web/assets/{EChartWordcloud-VpNJDurs.js → EChartWordcloud-CzhfrEF_.js} +1 -1
- package/dist-web/assets/{MessageExportModal-CSfaY25B.js → MessageExportModal-B79pPBL9.js} +1 -1
- package/dist-web/assets/{electron-BUeXfvxT.js → electron-DRkrjeIl.js} +1 -1
- package/dist-web/assets/electron-Dv8jdn_2.js +1 -0
- package/dist-web/assets/{fetch-RDFt3hmp.js → fetch-BmZIm6mS.js} +1 -1
- package/dist-web/assets/fetch-BqLy63aj.js +1 -0
- package/dist-web/assets/fetch-BstX-wd4.js +1 -0
- package/dist-web/assets/{fetch-BohUj3CQ.js → fetch-Bvcxe5PI.js} +1 -1
- package/dist-web/assets/{fetch-BneHn5qk.js → fetch-CDamdvtb.js} +1 -1
- package/dist-web/assets/{fetch-DypPduyQ.js → fetch-DWg-2kOp.js} +1 -1
- package/dist-web/assets/{fetch-CARsBVl0.js → fetch-DfgdagMN.js} +1 -1
- package/dist-web/assets/{fetch-Ck3tjoLa.js → fetch-Drk9dLaF.js} +1 -1
- package/dist-web/assets/{fetch-B2q6973s.js → fetch-Y-_WsCuk.js} +1 -1
- package/dist-web/assets/{fetch-BGMRmQx0.js → fetch-ph2_d79v.js} +1 -1
- package/dist-web/assets/{index-Bvlj3dMn.js → index-9urfJP1r.js} +1 -1
- package/dist-web/assets/index-CfKjh0Jr.js +9 -0
- package/dist-web/assets/index-CprJOAB1.css +1 -0
- package/dist-web/assets/{index-BvaWRM6_.js → index-DMWf5On7.js} +1 -1
- package/dist-web/assets/{index-DCWvD-4L.js → index-D_hHm7bQ.js} +2 -2
- package/dist-web/assets/index-MCdpiX_O.js +173 -0
- package/dist-web/assets/{index-C5LrQG3N.js → index-deYDOVUa.js} +4 -4
- package/dist-web/assets/vendor-echarts-CITQeskI.js +11 -0
- package/dist-web/assets/{vendor-echarts-wordcloud-CZ9gsX8l.js → vendor-echarts-wordcloud-B1kQMklB.js} +1 -1
- package/dist-web/assets/{vendor-nuxt-ui-BYU7dz8t.js → vendor-nuxt-ui-C_8CsH6e.js} +1 -1
- package/dist-web/assets/{vendor-reka-ui-CnB0mMNX.js → vendor-reka-ui-CIMXwvEp.js} +1 -1
- package/dist-web/assets/{web-CXPkmhis.js → web-XJV6Vj5t.js} +1 -1
- package/dist-web/index.html +4 -4
- package/package.json +1 -1
- package/dist/chunk-43XWYC3M.mjs.map +0 -1
- package/dist/chunk-CIIQ3S2X.mjs.map +0 -1
- package/dist/chunk-N5DGZQB4.mjs.map +0 -1
- package/dist/chunk-QJI6AOAT.mjs.map +0 -1
- package/dist/chunk-QY6P2YS7.mjs.map +0 -1
- package/dist/chunk-ZL322NVL.mjs.map +0 -1
- package/dist/mcp-YWAVG5XW.mjs.map +0 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-BBDrsJfe.js +0 -161
- package/dist-web/assets/electron-BynNUuEA.js +0 -1
- package/dist-web/assets/fetch-BtHwWs8A.js +0 -1
- package/dist-web/assets/fetch-DzNuFdFM.js +0 -1
- package/dist-web/assets/index-BRwEubUe.js +0 -173
- package/dist-web/assets/index-DB-iqXzV.css +0 -1
- package/dist-web/assets/index-DS1rzk1I.js +0 -8
- package/dist-web/assets/vendor-echarts-C5u62NnM.js +0 -11
- /package/dist/{http-TPX74BLK.mjs.map → http-C3CGXUBU.mjs.map} +0 -0
- /package/dist/{import-B745DRHD.mjs.map → import-VS7L5JDX.mjs.map} +0 -0
- /package/dist/{stream-import-OPALPVWF.mjs.map → stream-import-TFDBNVIW.mjs.map} +0 -0
|
@@ -619,8 +619,8 @@ var require_FilterBase = __commonJS({
|
|
|
619
619
|
var FilterBase = class _FilterBase extends Transform {
|
|
620
620
|
static stringFilter(string, separator) {
|
|
621
621
|
return (stack) => {
|
|
622
|
-
const
|
|
623
|
-
return
|
|
622
|
+
const path36 = stack.join(separator);
|
|
623
|
+
return path36.length === string.length && path36 === string || path36.length > string.length && path36.substr(0, string.length) === string && path36.substr(string.length, separator.length) === separator;
|
|
624
624
|
};
|
|
625
625
|
}
|
|
626
626
|
static regExpFilter(regExp, separator) {
|
|
@@ -1074,12 +1074,12 @@ var require_Assembler = __commonJS({
|
|
|
1074
1074
|
return (this.stack.length >> 1) + (this.done ? 0 : 1);
|
|
1075
1075
|
}
|
|
1076
1076
|
get path() {
|
|
1077
|
-
const
|
|
1077
|
+
const path36 = [];
|
|
1078
1078
|
for (let i = 0; i < this.stack.length; i += 2) {
|
|
1079
1079
|
const key = this.stack[i + 1];
|
|
1080
|
-
|
|
1080
|
+
path36.push(key === null ? this.stack[i].length : key);
|
|
1081
1081
|
}
|
|
1082
|
-
return
|
|
1082
|
+
return path36;
|
|
1083
1083
|
}
|
|
1084
1084
|
dropToLevel(level) {
|
|
1085
1085
|
if (level < this.depth) {
|
|
@@ -1854,63 +1854,6 @@ var ALL_MIGRATIONS = [
|
|
|
1854
1854
|
m004EncryptedKeysToAuthProfiles
|
|
1855
1855
|
];
|
|
1856
1856
|
|
|
1857
|
-
// ../../packages/node-runtime/src/better-sqlite3-adapter.ts
|
|
1858
|
-
import Database from "better-sqlite3";
|
|
1859
|
-
var BetterSqlitePreparedStatement = class {
|
|
1860
|
-
constructor(stmt) {
|
|
1861
|
-
this.stmt = stmt;
|
|
1862
|
-
this.readonly = stmt.readonly;
|
|
1863
|
-
}
|
|
1864
|
-
stmt;
|
|
1865
|
-
readonly;
|
|
1866
|
-
get(...params) {
|
|
1867
|
-
return this.stmt.get(...params);
|
|
1868
|
-
}
|
|
1869
|
-
all(...params) {
|
|
1870
|
-
return this.stmt.all(...params);
|
|
1871
|
-
}
|
|
1872
|
-
run(...params) {
|
|
1873
|
-
const result = this.stmt.run(...params);
|
|
1874
|
-
return {
|
|
1875
|
-
changes: result.changes,
|
|
1876
|
-
lastInsertRowid: result.lastInsertRowid
|
|
1877
|
-
};
|
|
1878
|
-
}
|
|
1879
|
-
};
|
|
1880
|
-
var BetterSqliteAdapter = class {
|
|
1881
|
-
constructor(db) {
|
|
1882
|
-
this.db = db;
|
|
1883
|
-
this.readonly = db.readonly;
|
|
1884
|
-
}
|
|
1885
|
-
db;
|
|
1886
|
-
readonly;
|
|
1887
|
-
exec(sql) {
|
|
1888
|
-
this.db.exec(sql);
|
|
1889
|
-
}
|
|
1890
|
-
prepare(sql) {
|
|
1891
|
-
return new BetterSqlitePreparedStatement(this.db.prepare(sql));
|
|
1892
|
-
}
|
|
1893
|
-
transaction(fn) {
|
|
1894
|
-
return this.db.transaction(fn)();
|
|
1895
|
-
}
|
|
1896
|
-
pragma(pragma) {
|
|
1897
|
-
return this.db.pragma(pragma);
|
|
1898
|
-
}
|
|
1899
|
-
close() {
|
|
1900
|
-
this.db.close();
|
|
1901
|
-
}
|
|
1902
|
-
};
|
|
1903
|
-
function openBetterSqliteDatabase(filePath, options) {
|
|
1904
|
-
const db = new Database(filePath, {
|
|
1905
|
-
readonly: options?.readonly ?? false,
|
|
1906
|
-
nativeBinding: options?.nativeBinding
|
|
1907
|
-
});
|
|
1908
|
-
if (!options?.readonly) {
|
|
1909
|
-
db.pragma("journal_mode = WAL");
|
|
1910
|
-
}
|
|
1911
|
-
return new BetterSqliteAdapter(db);
|
|
1912
|
-
}
|
|
1913
|
-
|
|
1914
1857
|
// ../../packages/core/src/query/filters.ts
|
|
1915
1858
|
function buildTimeFilter(filter, tableAlias) {
|
|
1916
1859
|
const conditions = [];
|
|
@@ -2165,8 +2108,8 @@ function getSessionInfo(db) {
|
|
|
2165
2108
|
return buildSessionInfo(meta, overview, sc);
|
|
2166
2109
|
}
|
|
2167
2110
|
function getSummaryCount(db) {
|
|
2168
|
-
if (!hasTable(db, "
|
|
2169
|
-
const row = db.prepare("SELECT COUNT(*) as count FROM
|
|
2111
|
+
if (!hasTable(db, "segment")) return 0;
|
|
2112
|
+
const row = db.prepare("SELECT COUNT(*) as count FROM segment WHERE summary IS NOT NULL AND summary != ''").get();
|
|
2170
2113
|
return row?.count ?? 0;
|
|
2171
2114
|
}
|
|
2172
2115
|
function isChatSessionDb(db) {
|
|
@@ -2231,11 +2174,11 @@ function getChatOverview(db, topN = 10) {
|
|
|
2231
2174
|
topMembers
|
|
2232
2175
|
};
|
|
2233
2176
|
}
|
|
2234
|
-
function
|
|
2235
|
-
if (!hasTable(db, "
|
|
2177
|
+
function searchSegments(db, keywords, timeFilter, limit = 20, previewCount = 5, ftsMatchExpression) {
|
|
2178
|
+
if (!hasTable(db, "segment")) return [];
|
|
2236
2179
|
let sessionSql = `
|
|
2237
2180
|
SELECT cs.id, cs.start_ts as startTs, cs.end_ts as endTs, cs.message_count as messageCount
|
|
2238
|
-
FROM
|
|
2181
|
+
FROM segment cs WHERE 1=1
|
|
2239
2182
|
`;
|
|
2240
2183
|
const params = [];
|
|
2241
2184
|
if (timeFilter?.startTs !== void 0) {
|
|
@@ -2250,7 +2193,7 @@ function searchSessions(db, keywords, timeFilter, limit = 20, previewCount = 5,
|
|
|
2250
2193
|
if (ftsMatchExpression) {
|
|
2251
2194
|
sessionSql += `
|
|
2252
2195
|
AND cs.id IN (
|
|
2253
|
-
SELECT DISTINCT mc.
|
|
2196
|
+
SELECT DISTINCT mc.segment_id FROM message_context mc
|
|
2254
2197
|
WHERE mc.message_id IN (SELECT rowid FROM message_fts WHERE content MATCH ?)
|
|
2255
2198
|
)
|
|
2256
2199
|
`;
|
|
@@ -2259,7 +2202,7 @@ function searchSessions(db, keywords, timeFilter, limit = 20, previewCount = 5,
|
|
|
2259
2202
|
const keywordConditions = keywords.map(() => "m.content LIKE ?").join(" OR ");
|
|
2260
2203
|
sessionSql += `
|
|
2261
2204
|
AND cs.id IN (
|
|
2262
|
-
SELECT DISTINCT mc.
|
|
2205
|
+
SELECT DISTINCT mc.segment_id FROM message_context mc
|
|
2263
2206
|
JOIN message m ON m.id = mc.message_id
|
|
2264
2207
|
WHERE (${keywordConditions})
|
|
2265
2208
|
)
|
|
@@ -2280,7 +2223,7 @@ function searchSessions(db, keywords, timeFilter, limit = 20, previewCount = 5,
|
|
|
2280
2223
|
FROM message_context mc
|
|
2281
2224
|
JOIN message m ON m.id = mc.message_id
|
|
2282
2225
|
JOIN member mb ON mb.id = m.sender_id
|
|
2283
|
-
WHERE mc.
|
|
2226
|
+
WHERE mc.segment_id = ? ORDER BY m.ts ASC LIMIT ?
|
|
2284
2227
|
`;
|
|
2285
2228
|
return sessions.map((session) => {
|
|
2286
2229
|
const previewMessages = db.prepare(previewSql).all(session.id, previewCount);
|
|
@@ -2294,12 +2237,12 @@ function searchSessions(db, keywords, timeFilter, limit = 20, previewCount = 5,
|
|
|
2294
2237
|
};
|
|
2295
2238
|
});
|
|
2296
2239
|
}
|
|
2297
|
-
function
|
|
2298
|
-
if (!hasTable(db, "
|
|
2240
|
+
function getSegmentMessages(db, segmentId, limit = 500) {
|
|
2241
|
+
if (!hasTable(db, "segment")) return null;
|
|
2299
2242
|
const session = db.prepare(
|
|
2300
2243
|
`SELECT id, start_ts as startTs, end_ts as endTs, message_count as messageCount
|
|
2301
|
-
FROM
|
|
2302
|
-
).get(
|
|
2244
|
+
FROM segment WHERE id = ?`
|
|
2245
|
+
).get(segmentId);
|
|
2303
2246
|
if (!session) return null;
|
|
2304
2247
|
const messages = db.prepare(
|
|
2305
2248
|
`SELECT m.id, mb.id as senderId,
|
|
@@ -2309,14 +2252,14 @@ function getSessionMessages(db, chatSessionId, limit = 500) {
|
|
|
2309
2252
|
FROM message_context mc
|
|
2310
2253
|
JOIN message m ON m.id = mc.message_id
|
|
2311
2254
|
JOIN member mb ON mb.id = m.sender_id
|
|
2312
|
-
WHERE mc.
|
|
2313
|
-
).all(
|
|
2255
|
+
WHERE mc.segment_id = ? ORDER BY m.ts ASC LIMIT ?`
|
|
2256
|
+
).all(segmentId, limit);
|
|
2314
2257
|
const participantsSet = /* @__PURE__ */ new Set();
|
|
2315
2258
|
for (const msg of messages) {
|
|
2316
2259
|
participantsSet.add(msg.senderName);
|
|
2317
2260
|
}
|
|
2318
2261
|
return {
|
|
2319
|
-
|
|
2262
|
+
segmentId: session.id,
|
|
2320
2263
|
startTs: session.startTs,
|
|
2321
2264
|
endTs: session.endTs,
|
|
2322
2265
|
messageCount: session.messageCount,
|
|
@@ -2325,13 +2268,13 @@ function getSessionMessages(db, chatSessionId, limit = 500) {
|
|
|
2325
2268
|
messages
|
|
2326
2269
|
};
|
|
2327
2270
|
}
|
|
2328
|
-
function
|
|
2329
|
-
if (!hasTable(db, "
|
|
2271
|
+
function getSegmentSummaries(db, options) {
|
|
2272
|
+
if (!hasTable(db, "segment")) return [];
|
|
2330
2273
|
const { limit = 50, timeFilter } = options ?? {};
|
|
2331
2274
|
let sql = `
|
|
2332
2275
|
SELECT cs.id, cs.start_ts as startTs, cs.end_ts as endTs,
|
|
2333
2276
|
cs.message_count as messageCount, cs.summary
|
|
2334
|
-
FROM
|
|
2277
|
+
FROM segment cs
|
|
2335
2278
|
WHERE cs.summary IS NOT NULL AND cs.summary != ''
|
|
2336
2279
|
`;
|
|
2337
2280
|
const params = [];
|
|
@@ -2351,7 +2294,7 @@ function getSessionSummaries(db, options) {
|
|
|
2351
2294
|
FROM message_context mc
|
|
2352
2295
|
JOIN message m ON m.id = mc.message_id
|
|
2353
2296
|
JOIN member mb ON mb.id = m.sender_id
|
|
2354
|
-
WHERE mc.
|
|
2297
|
+
WHERE mc.segment_id = ? LIMIT 10
|
|
2355
2298
|
`;
|
|
2356
2299
|
return sessions.map((session) => {
|
|
2357
2300
|
const participants = db.prepare(participantsSql).all(session.id);
|
|
@@ -2368,9 +2311,9 @@ function getSessionSummaries(db, options) {
|
|
|
2368
2311
|
var DEFAULT_SESSION_GAP_THRESHOLD = 1800;
|
|
2369
2312
|
function getSessionIndexStats(db) {
|
|
2370
2313
|
let sessionCount = 0;
|
|
2371
|
-
if (hasTable(db, "
|
|
2314
|
+
if (hasTable(db, "segment")) {
|
|
2372
2315
|
try {
|
|
2373
|
-
const row = db.prepare("SELECT COUNT(*) as count FROM
|
|
2316
|
+
const row = db.prepare("SELECT COUNT(*) as count FROM segment").get();
|
|
2374
2317
|
sessionCount = row?.count ?? 0;
|
|
2375
2318
|
} catch {
|
|
2376
2319
|
}
|
|
@@ -2386,7 +2329,7 @@ function getSessionIndexStats(db) {
|
|
|
2386
2329
|
return { sessionCount, hasIndex: sessionCount > 0, gapThreshold };
|
|
2387
2330
|
}
|
|
2388
2331
|
function getChatSessionList(db) {
|
|
2389
|
-
if (!hasTable(db, "
|
|
2332
|
+
if (!hasTable(db, "segment")) return [];
|
|
2390
2333
|
try {
|
|
2391
2334
|
return db.prepare(
|
|
2392
2335
|
`SELECT
|
|
@@ -2396,24 +2339,24 @@ function getChatSessionList(db) {
|
|
|
2396
2339
|
cs.message_count as messageCount,
|
|
2397
2340
|
cs.summary,
|
|
2398
2341
|
(SELECT mc.message_id FROM message_context mc
|
|
2399
|
-
WHERE mc.
|
|
2400
|
-
FROM
|
|
2342
|
+
WHERE mc.segment_id = cs.id ORDER BY mc.message_id LIMIT 1) as firstMessageId
|
|
2343
|
+
FROM segment cs
|
|
2401
2344
|
ORDER BY cs.start_ts ASC`
|
|
2402
2345
|
).all();
|
|
2403
2346
|
} catch {
|
|
2404
2347
|
return [];
|
|
2405
2348
|
}
|
|
2406
2349
|
}
|
|
2407
|
-
function
|
|
2350
|
+
function getSegmentSummary(db, segmentId) {
|
|
2408
2351
|
try {
|
|
2409
|
-
const row = db.prepare("SELECT summary FROM
|
|
2352
|
+
const row = db.prepare("SELECT summary FROM segment WHERE id = ?").get(segmentId);
|
|
2410
2353
|
return row?.summary ?? null;
|
|
2411
2354
|
} catch {
|
|
2412
2355
|
return null;
|
|
2413
2356
|
}
|
|
2414
2357
|
}
|
|
2415
|
-
function
|
|
2416
|
-
db.prepare("UPDATE
|
|
2358
|
+
function saveSegmentSummary(db, segmentId, summary) {
|
|
2359
|
+
db.prepare("UPDATE segment SET summary = ? WHERE id = ?").run(summary, segmentId);
|
|
2417
2360
|
}
|
|
2418
2361
|
function updateSessionOwnerId(db, ownerId) {
|
|
2419
2362
|
db.prepare("UPDATE meta SET owner_id = ?").run(ownerId);
|
|
@@ -2423,7 +2366,7 @@ function renameSession(db, newName) {
|
|
|
2423
2366
|
}
|
|
2424
2367
|
function clearSessionIndex(db) {
|
|
2425
2368
|
db.exec("DELETE FROM message_context");
|
|
2426
|
-
db.exec("DELETE FROM
|
|
2369
|
+
db.exec("DELETE FROM segment");
|
|
2427
2370
|
}
|
|
2428
2371
|
function generateSessionIndex(db, gapThreshold = DEFAULT_SESSION_GAP_THRESHOLD, onProgress) {
|
|
2429
2372
|
const countRow = db.prepare("SELECT COUNT(*) as count FROM message").get();
|
|
@@ -2457,9 +2400,9 @@ function generateSessionIndex(db, gapThreshold = DEFAULT_SESSION_GAP_THRESHOLD,
|
|
|
2457
2400
|
}
|
|
2458
2401
|
}
|
|
2459
2402
|
const insertSession = db.prepare(
|
|
2460
|
-
"INSERT INTO
|
|
2403
|
+
"INSERT INTO segment (start_ts, end_ts, message_count, is_manual, summary) VALUES (?, ?, ?, 0, NULL)"
|
|
2461
2404
|
);
|
|
2462
|
-
const insertContext = db.prepare("INSERT INTO message_context (message_id,
|
|
2405
|
+
const insertContext = db.prepare("INSERT INTO message_context (message_id, segment_id, topic_id) VALUES (?, ?, NULL)");
|
|
2463
2406
|
return db.transaction(() => {
|
|
2464
2407
|
let processed = 0;
|
|
2465
2408
|
const total = sessionMap.size;
|
|
@@ -2485,13 +2428,13 @@ function generateIncrementalSessionIndex(db, gapThreshold = DEFAULT_SESSION_GAP_
|
|
|
2485
2428
|
const allMessages = db.prepare("SELECT id, ts FROM message ORDER BY ts, id").all();
|
|
2486
2429
|
const newMessages = allMessages.filter((m) => !indexedIds.has(m.id));
|
|
2487
2430
|
if (newMessages.length === 0) return 0;
|
|
2488
|
-
const lastSession = hasTable(db, "
|
|
2431
|
+
const lastSession = hasTable(db, "segment") ? db.prepare("SELECT id, end_ts FROM segment ORDER BY end_ts DESC LIMIT 1").get() : void 0;
|
|
2489
2432
|
newMessages.sort((a, b) => a.ts - b.ts || a.id - b.id);
|
|
2490
2433
|
const insertSession = db.prepare(
|
|
2491
|
-
"INSERT INTO
|
|
2434
|
+
"INSERT INTO segment (start_ts, end_ts, message_count, is_manual, summary) VALUES (?, ?, ?, 0, NULL)"
|
|
2492
2435
|
);
|
|
2493
|
-
const insertContext = db.prepare("INSERT INTO message_context (message_id,
|
|
2494
|
-
const updateSession = db.prepare("UPDATE
|
|
2436
|
+
const insertContext = db.prepare("INSERT INTO message_context (message_id, segment_id, topic_id) VALUES (?, ?, NULL)");
|
|
2437
|
+
const updateSession = db.prepare("UPDATE segment SET end_ts = ?, message_count = message_count + ? WHERE id = ?");
|
|
2495
2438
|
return db.transaction(() => {
|
|
2496
2439
|
let newSessionCount = 0;
|
|
2497
2440
|
let currentSessionId = null;
|
|
@@ -2867,22 +2810,22 @@ function getSearchMessageContext(db, messageIds, contextBefore = 2, contextAfter
|
|
|
2867
2810
|
for (const messageId of messageIds) {
|
|
2868
2811
|
contextIds.add(messageId);
|
|
2869
2812
|
if (hasSessionData) {
|
|
2870
|
-
const sessionRow = db.prepare("SELECT
|
|
2813
|
+
const sessionRow = db.prepare("SELECT segment_id FROM message_context WHERE message_id = ?").get(messageId);
|
|
2871
2814
|
if (sessionRow) {
|
|
2872
2815
|
if (contextBefore > 0) {
|
|
2873
2816
|
const rows = db.prepare(
|
|
2874
2817
|
`SELECT mc.message_id as id FROM message_context mc
|
|
2875
|
-
WHERE mc.
|
|
2818
|
+
WHERE mc.segment_id = ? AND mc.message_id < ?
|
|
2876
2819
|
ORDER BY mc.message_id DESC LIMIT ?`
|
|
2877
|
-
).all(sessionRow.
|
|
2820
|
+
).all(sessionRow.segment_id, messageId, contextBefore);
|
|
2878
2821
|
rows.forEach((r) => contextIds.add(r.id));
|
|
2879
2822
|
}
|
|
2880
2823
|
if (contextAfter > 0) {
|
|
2881
2824
|
const rows = db.prepare(
|
|
2882
2825
|
`SELECT mc.message_id as id FROM message_context mc
|
|
2883
|
-
WHERE mc.
|
|
2826
|
+
WHERE mc.segment_id = ? AND mc.message_id > ?
|
|
2884
2827
|
ORDER BY mc.message_id ASC LIMIT ?`
|
|
2885
|
-
).all(sessionRow.
|
|
2828
|
+
).all(sessionRow.segment_id, messageId, contextAfter);
|
|
2886
2829
|
rows.forEach((r) => contextIds.add(r.id));
|
|
2887
2830
|
}
|
|
2888
2831
|
continue;
|
|
@@ -3229,17 +3172,17 @@ function filterMessagesWithContext(db, options = {}) {
|
|
|
3229
3172
|
pagination: { page, pageSize, totalBlocks, totalHits, hasMore }
|
|
3230
3173
|
};
|
|
3231
3174
|
}
|
|
3232
|
-
function getMultipleSessionsMessages(db,
|
|
3233
|
-
if (
|
|
3175
|
+
function getMultipleSessionsMessages(db, segmentIds, page = 1, pageSize = 50) {
|
|
3176
|
+
if (segmentIds.length === 0) {
|
|
3234
3177
|
return emptyResult(page, pageSize);
|
|
3235
3178
|
}
|
|
3236
3179
|
const sessionsSql = `
|
|
3237
3180
|
SELECT id, start_ts as startTs, end_ts as endTs, message_count as messageCount
|
|
3238
|
-
FROM
|
|
3239
|
-
WHERE id IN (${
|
|
3181
|
+
FROM segment
|
|
3182
|
+
WHERE id IN (${segmentIds.map(() => "?").join(",")})
|
|
3240
3183
|
ORDER BY start_ts ASC
|
|
3241
3184
|
`;
|
|
3242
|
-
const allSessions = db.prepare(sessionsSql).all(...
|
|
3185
|
+
const allSessions = db.prepare(sessionsSql).all(...segmentIds);
|
|
3243
3186
|
const totalBlocks = allSessions.length;
|
|
3244
3187
|
const startIdx = (page - 1) * pageSize;
|
|
3245
3188
|
const endIdx = Math.min(startIdx + pageSize, totalBlocks);
|
|
@@ -3262,7 +3205,7 @@ function getMultipleSessionsMessages(db, chatSessionIds, page = 1, pageSize = 50
|
|
|
3262
3205
|
JOIN member m ON msg.sender_id = m.id
|
|
3263
3206
|
LEFT JOIN message reply_msg ON msg.reply_to_message_id = reply_msg.platform_message_id
|
|
3264
3207
|
LEFT JOIN member reply_m ON reply_msg.sender_id = reply_m.id
|
|
3265
|
-
WHERE mc.
|
|
3208
|
+
WHERE mc.segment_id = ?
|
|
3266
3209
|
ORDER BY msg.ts ASC
|
|
3267
3210
|
`;
|
|
3268
3211
|
for (const session of pageSessions) {
|
|
@@ -3904,7 +3847,7 @@ function getRelationshipStats(db, filter, options) {
|
|
|
3904
3847
|
monthlyPerseverance: [],
|
|
3905
3848
|
perseveranceThreshold
|
|
3906
3849
|
};
|
|
3907
|
-
const sessionCount = db.prepare("SELECT COUNT(*) as count FROM
|
|
3850
|
+
const sessionCount = db.prepare("SELECT COUNT(*) as count FROM segment").get();
|
|
3908
3851
|
if (!sessionCount || sessionCount.count === 0) return emptyResult2;
|
|
3909
3852
|
const timeConditions = [];
|
|
3910
3853
|
const params = [];
|
|
@@ -3917,13 +3860,13 @@ function getRelationshipStats(db, filter, options) {
|
|
|
3917
3860
|
params.push(filter.endTs);
|
|
3918
3861
|
}
|
|
3919
3862
|
const whereClause = timeConditions.length > 0 ? `WHERE ${timeConditions.join(" AND ")}` : "";
|
|
3920
|
-
const
|
|
3921
|
-
`SELECT cs.id AS
|
|
3863
|
+
const segmentRows = db.prepare(
|
|
3864
|
+
`SELECT cs.id AS segment_id, cs.start_ts, cs.end_ts,
|
|
3922
3865
|
(SELECT m.sender_id FROM message_context mc JOIN message m ON m.id = mc.message_id
|
|
3923
|
-
WHERE mc.
|
|
3866
|
+
WHERE mc.segment_id = cs.id ORDER BY m.ts ASC, m.id ASC LIMIT 1) AS initiator_id,
|
|
3924
3867
|
(SELECT m.sender_id FROM message_context mc JOIN message m ON m.id = mc.message_id
|
|
3925
|
-
WHERE mc.
|
|
3926
|
-
FROM
|
|
3868
|
+
WHERE mc.segment_id = cs.id ORDER BY m.ts DESC, m.id DESC LIMIT 1) AS closer_id
|
|
3869
|
+
FROM segment cs ${whereClause} ORDER BY cs.start_ts ASC`
|
|
3927
3870
|
).all(...params);
|
|
3928
3871
|
const memberNames = /* @__PURE__ */ new Map();
|
|
3929
3872
|
const memberRows = db.prepare("SELECT id, COALESCE(group_nickname, account_name, platform_id) as name FROM member").all();
|
|
@@ -3934,7 +3877,7 @@ function getRelationshipStats(db, filter, options) {
|
|
|
3934
3877
|
const iceBreakMap = /* @__PURE__ */ new Map();
|
|
3935
3878
|
let totalIceBreaks = 0;
|
|
3936
3879
|
let prevEndTs = null;
|
|
3937
|
-
for (const row of
|
|
3880
|
+
for (const row of segmentRows) {
|
|
3938
3881
|
const month = toLocalMonth(row.start_ts);
|
|
3939
3882
|
if (!monthMap.has(month)) monthMap.set(month, { initiateMap: /* @__PURE__ */ new Map(), closeMap: /* @__PURE__ */ new Map(), totalSessions: 0 });
|
|
3940
3883
|
const ms = monthMap.get(month);
|
|
@@ -3983,12 +3926,12 @@ function getRelationshipStats(db, filter, options) {
|
|
|
3983
3926
|
iceBreakers.push({ month, memberId, name: memberNames.get(memberId) ?? `Unknown(${memberId})`, count });
|
|
3984
3927
|
}
|
|
3985
3928
|
}
|
|
3986
|
-
const
|
|
3987
|
-
const msgStats = queryMessageLevelStats(db,
|
|
3929
|
+
const segmentIdList = segmentRows.map((r) => r.segment_id);
|
|
3930
|
+
const msgStats = queryMessageLevelStats(db, segmentIdList, memberNames, perseveranceThreshold);
|
|
3988
3931
|
return {
|
|
3989
3932
|
months,
|
|
3990
3933
|
members,
|
|
3991
|
-
totalSessions:
|
|
3934
|
+
totalSessions: segmentRows.length,
|
|
3992
3935
|
hasSessionIndex: true,
|
|
3993
3936
|
iceBreakers,
|
|
3994
3937
|
totalIceBreaks,
|
|
@@ -3996,7 +3939,7 @@ function getRelationshipStats(db, filter, options) {
|
|
|
3996
3939
|
perseveranceThreshold
|
|
3997
3940
|
};
|
|
3998
3941
|
}
|
|
3999
|
-
function queryMessageLevelStats(db,
|
|
3942
|
+
function queryMessageLevelStats(db, segmentIds, memberNames, perseveranceThreshold) {
|
|
4000
3943
|
const empty = {
|
|
4001
3944
|
responseLatency: [],
|
|
4002
3945
|
perseverance: [],
|
|
@@ -4004,22 +3947,22 @@ function queryMessageLevelStats(db, sessionIds, memberNames, perseveranceThresho
|
|
|
4004
3947
|
monthlyResponseLatency: [],
|
|
4005
3948
|
monthlyPerseverance: []
|
|
4006
3949
|
};
|
|
4007
|
-
if (
|
|
3950
|
+
if (segmentIds.length === 0) return empty;
|
|
4008
3951
|
const BATCH_SIZE2 = 500;
|
|
4009
3952
|
const responseTotals = /* @__PURE__ */ new Map();
|
|
4010
3953
|
const dtTotals = /* @__PURE__ */ new Map();
|
|
4011
3954
|
const monthlyRespMap = /* @__PURE__ */ new Map();
|
|
4012
3955
|
const monthlyDtMap = /* @__PURE__ */ new Map();
|
|
4013
|
-
for (let i = 0; i <
|
|
4014
|
-
const batch =
|
|
3956
|
+
for (let i = 0; i < segmentIds.length; i += BATCH_SIZE2) {
|
|
3957
|
+
const batch = segmentIds.slice(i, i + BATCH_SIZE2);
|
|
4015
3958
|
const placeholders = batch.map(() => "?").join(",");
|
|
4016
3959
|
const latencyRows = db.prepare(
|
|
4017
3960
|
`WITH msg_lag AS (
|
|
4018
3961
|
SELECT m.sender_id, m.ts,
|
|
4019
|
-
LAG(m.sender_id) OVER (PARTITION BY mc.
|
|
4020
|
-
LAG(m.ts) OVER (PARTITION BY mc.
|
|
3962
|
+
LAG(m.sender_id) OVER (PARTITION BY mc.segment_id ORDER BY m.ts, m.id) AS prev_sender_id,
|
|
3963
|
+
LAG(m.ts) OVER (PARTITION BY mc.segment_id ORDER BY m.ts, m.id) AS prev_ts
|
|
4021
3964
|
FROM message_context mc JOIN message m ON m.id = mc.message_id
|
|
4022
|
-
WHERE mc.
|
|
3965
|
+
WHERE mc.segment_id IN (${placeholders}) AND m.type = 0
|
|
4023
3966
|
)
|
|
4024
3967
|
SELECT strftime('%Y-%m', datetime(ts, 'unixepoch', 'localtime')) AS month,
|
|
4025
3968
|
sender_id AS responder_id, SUM(ts - prev_ts) AS total_time, COUNT(*) AS response_count
|
|
@@ -4043,10 +3986,10 @@ function queryMessageLevelStats(db, sessionIds, memberNames, perseveranceThresho
|
|
|
4043
3986
|
const dtRows = db.prepare(
|
|
4044
3987
|
`WITH msg_lag AS (
|
|
4045
3988
|
SELECT m.sender_id, m.ts,
|
|
4046
|
-
LAG(m.sender_id) OVER (PARTITION BY mc.
|
|
4047
|
-
LAG(m.ts) OVER (PARTITION BY mc.
|
|
3989
|
+
LAG(m.sender_id) OVER (PARTITION BY mc.segment_id ORDER BY m.ts, m.id) AS prev_sender_id,
|
|
3990
|
+
LAG(m.ts) OVER (PARTITION BY mc.segment_id ORDER BY m.ts, m.id) AS prev_ts
|
|
4048
3991
|
FROM message_context mc JOIN message m ON m.id = mc.message_id
|
|
4049
|
-
WHERE mc.
|
|
3992
|
+
WHERE mc.segment_id IN (${placeholders}) AND m.type = 0
|
|
4050
3993
|
)
|
|
4051
3994
|
SELECT strftime('%Y-%m', datetime(ts, 'unixepoch', 'localtime')) AS month,
|
|
4052
3995
|
sender_id, COUNT(*) AS double_text_count
|
|
@@ -4258,125 +4201,6 @@ function getLanguagePreferenceAnalysis(db, params) {
|
|
|
4258
4201
|
return { members: memberProfiles, sharedWords, similarityScore };
|
|
4259
4202
|
}
|
|
4260
4203
|
|
|
4261
|
-
// ../../packages/core/src/schema/tables.ts
|
|
4262
|
-
var CURRENT_SCHEMA_VERSION = 5;
|
|
4263
|
-
var CHAT_DB_TABLES = `
|
|
4264
|
-
CREATE TABLE IF NOT EXISTS meta (
|
|
4265
|
-
name TEXT NOT NULL,
|
|
4266
|
-
platform TEXT NOT NULL,
|
|
4267
|
-
type TEXT NOT NULL,
|
|
4268
|
-
imported_at INTEGER NOT NULL,
|
|
4269
|
-
group_id TEXT,
|
|
4270
|
-
group_avatar TEXT,
|
|
4271
|
-
owner_id TEXT,
|
|
4272
|
-
schema_version INTEGER DEFAULT ${CURRENT_SCHEMA_VERSION},
|
|
4273
|
-
session_gap_threshold INTEGER
|
|
4274
|
-
);
|
|
4275
|
-
|
|
4276
|
-
CREATE TABLE IF NOT EXISTS member (
|
|
4277
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
4278
|
-
platform_id TEXT NOT NULL UNIQUE,
|
|
4279
|
-
account_name TEXT,
|
|
4280
|
-
group_nickname TEXT,
|
|
4281
|
-
aliases TEXT DEFAULT '[]',
|
|
4282
|
-
avatar TEXT,
|
|
4283
|
-
roles TEXT DEFAULT '[]'
|
|
4284
|
-
);
|
|
4285
|
-
|
|
4286
|
-
CREATE TABLE IF NOT EXISTS member_name_history (
|
|
4287
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
4288
|
-
member_id INTEGER NOT NULL,
|
|
4289
|
-
name_type TEXT NOT NULL,
|
|
4290
|
-
name TEXT NOT NULL,
|
|
4291
|
-
start_ts INTEGER NOT NULL,
|
|
4292
|
-
end_ts INTEGER,
|
|
4293
|
-
FOREIGN KEY(member_id) REFERENCES member(id)
|
|
4294
|
-
);
|
|
4295
|
-
|
|
4296
|
-
CREATE TABLE IF NOT EXISTS message (
|
|
4297
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
4298
|
-
sender_id INTEGER NOT NULL,
|
|
4299
|
-
sender_account_name TEXT,
|
|
4300
|
-
sender_group_nickname TEXT,
|
|
4301
|
-
ts INTEGER NOT NULL,
|
|
4302
|
-
type INTEGER NOT NULL,
|
|
4303
|
-
content TEXT,
|
|
4304
|
-
reply_to_message_id TEXT DEFAULT NULL,
|
|
4305
|
-
platform_message_id TEXT DEFAULT NULL,
|
|
4306
|
-
FOREIGN KEY(sender_id) REFERENCES member(id)
|
|
4307
|
-
);
|
|
4308
|
-
|
|
4309
|
-
CREATE TABLE IF NOT EXISTS chat_session (
|
|
4310
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
4311
|
-
start_ts INTEGER NOT NULL,
|
|
4312
|
-
end_ts INTEGER NOT NULL,
|
|
4313
|
-
message_count INTEGER DEFAULT 0,
|
|
4314
|
-
is_manual INTEGER DEFAULT 0,
|
|
4315
|
-
summary TEXT
|
|
4316
|
-
);
|
|
4317
|
-
|
|
4318
|
-
CREATE TABLE IF NOT EXISTS message_context (
|
|
4319
|
-
message_id INTEGER PRIMARY KEY,
|
|
4320
|
-
session_id INTEGER NOT NULL,
|
|
4321
|
-
topic_id INTEGER
|
|
4322
|
-
);
|
|
4323
|
-
`;
|
|
4324
|
-
var CHAT_DB_INDEXES = `
|
|
4325
|
-
CREATE INDEX IF NOT EXISTS idx_message_ts ON message(ts);
|
|
4326
|
-
CREATE INDEX IF NOT EXISTS idx_message_sender ON message(sender_id);
|
|
4327
|
-
CREATE INDEX IF NOT EXISTS idx_message_platform_id ON message(platform_message_id);
|
|
4328
|
-
CREATE INDEX IF NOT EXISTS idx_member_name_history_member_id ON member_name_history(member_id);
|
|
4329
|
-
CREATE INDEX IF NOT EXISTS idx_session_time ON chat_session(start_ts, end_ts);
|
|
4330
|
-
CREATE INDEX IF NOT EXISTS idx_context_session ON message_context(session_id);
|
|
4331
|
-
`;
|
|
4332
|
-
var CHAT_DB_SCHEMA = CHAT_DB_TABLES + CHAT_DB_INDEXES;
|
|
4333
|
-
var FTS_TABLE_SCHEMA = `
|
|
4334
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS message_fts USING fts5(
|
|
4335
|
-
content,
|
|
4336
|
-
content='',
|
|
4337
|
-
content_rowid=id
|
|
4338
|
-
);
|
|
4339
|
-
`;
|
|
4340
|
-
|
|
4341
|
-
// ../../packages/core/src/schema/migrations.ts
|
|
4342
|
-
function getSchemaVersion(db) {
|
|
4343
|
-
try {
|
|
4344
|
-
const tableInfo = db.pragma("table_info(meta)");
|
|
4345
|
-
const hasVersionColumn = tableInfo.some((col) => col.name === "schema_version");
|
|
4346
|
-
if (!hasVersionColumn) return 0;
|
|
4347
|
-
const result = db.prepare("SELECT schema_version FROM meta LIMIT 1").get();
|
|
4348
|
-
return result?.schema_version ?? 0;
|
|
4349
|
-
} catch {
|
|
4350
|
-
return 0;
|
|
4351
|
-
}
|
|
4352
|
-
}
|
|
4353
|
-
function setSchemaVersion(db, version) {
|
|
4354
|
-
const tableInfo = db.pragma("table_info(meta)");
|
|
4355
|
-
const hasVersionColumn = tableInfo.some((col) => col.name === "schema_version");
|
|
4356
|
-
if (!hasVersionColumn) {
|
|
4357
|
-
db.exec("ALTER TABLE meta ADD COLUMN schema_version INTEGER DEFAULT 0");
|
|
4358
|
-
}
|
|
4359
|
-
db.prepare("UPDATE meta SET schema_version = ?").run(version);
|
|
4360
|
-
}
|
|
4361
|
-
function needsMigration(db, targetVersion) {
|
|
4362
|
-
return getSchemaVersion(db) < targetVersion;
|
|
4363
|
-
}
|
|
4364
|
-
function runMigrations(db, migrationsList, forceRepair = false) {
|
|
4365
|
-
const currentVersion = getSchemaVersion(db);
|
|
4366
|
-
if (!forceRepair && currentVersion >= (migrationsList.at(-1)?.version ?? 0)) {
|
|
4367
|
-
return false;
|
|
4368
|
-
}
|
|
4369
|
-
const pending = forceRepair ? migrationsList : migrationsList.filter((m) => m.version > currentVersion);
|
|
4370
|
-
if (pending.length === 0) return false;
|
|
4371
|
-
db.transaction(() => {
|
|
4372
|
-
for (const migration of pending) {
|
|
4373
|
-
migration.up(db);
|
|
4374
|
-
setSchemaVersion(db, migration.version);
|
|
4375
|
-
}
|
|
4376
|
-
});
|
|
4377
|
-
return true;
|
|
4378
|
-
}
|
|
4379
|
-
|
|
4380
4204
|
// ../../packages/core/src/version.ts
|
|
4381
4205
|
function parseStableVersion(version) {
|
|
4382
4206
|
const normalized = version.trim().replace(/^v/i, "");
|
|
@@ -4410,6 +4234,218 @@ function isNewerStableVersion(latest, current) {
|
|
|
4410
4234
|
return currentVersion.prerelease;
|
|
4411
4235
|
}
|
|
4412
4236
|
|
|
4237
|
+
// ../../packages/core/src/chart/index.ts
|
|
4238
|
+
var ChartValidationError = class extends Error {
|
|
4239
|
+
constructor(message) {
|
|
4240
|
+
super(message);
|
|
4241
|
+
this.name = "ChartValidationError";
|
|
4242
|
+
}
|
|
4243
|
+
};
|
|
4244
|
+
var CHART_TYPES = /* @__PURE__ */ new Set(["bar", "line", "pie", "heatmap"]);
|
|
4245
|
+
function isRecord(value) {
|
|
4246
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4247
|
+
}
|
|
4248
|
+
function asFieldName(value, label) {
|
|
4249
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
4250
|
+
throw new ChartValidationError(`${label} must be a non-empty field name`);
|
|
4251
|
+
}
|
|
4252
|
+
return value;
|
|
4253
|
+
}
|
|
4254
|
+
function assertFieldExists(rows, field) {
|
|
4255
|
+
if (rows.length === 0) return;
|
|
4256
|
+
if (!Object.prototype.hasOwnProperty.call(rows[0], field)) {
|
|
4257
|
+
throw new ChartValidationError(`Field "${field}" does not exist in SQL result`);
|
|
4258
|
+
}
|
|
4259
|
+
}
|
|
4260
|
+
function toLabel(value) {
|
|
4261
|
+
if (value === null || value === void 0 || value === "") return "(empty)";
|
|
4262
|
+
return String(value);
|
|
4263
|
+
}
|
|
4264
|
+
function toNumber(value, field) {
|
|
4265
|
+
const num = typeof value === "number" ? value : Number(value);
|
|
4266
|
+
if (!Number.isFinite(num)) {
|
|
4267
|
+
throw new ChartValidationError(`Field "${field}" contains non-numeric value "${String(value)}"`);
|
|
4268
|
+
}
|
|
4269
|
+
return num;
|
|
4270
|
+
}
|
|
4271
|
+
function inferFieldType(values) {
|
|
4272
|
+
const present = values.filter((v) => v !== null && v !== void 0);
|
|
4273
|
+
if (present.length === 0) return "string";
|
|
4274
|
+
if (present.every((v) => typeof v === "number" && Number.isInteger(v))) return "integer";
|
|
4275
|
+
if (present.every(
|
|
4276
|
+
(v) => typeof v === "number" || typeof v === "string" && v.trim() !== "" && !Number.isNaN(Number(v))
|
|
4277
|
+
)) {
|
|
4278
|
+
return "number";
|
|
4279
|
+
}
|
|
4280
|
+
if (present.every((v) => typeof v === "boolean")) return "boolean";
|
|
4281
|
+
return "category";
|
|
4282
|
+
}
|
|
4283
|
+
function normalizeChartSpec(raw) {
|
|
4284
|
+
if (!isRecord(raw)) throw new ChartValidationError("chartSpec must be an object");
|
|
4285
|
+
if (raw.version !== 1) throw new ChartValidationError("chartSpec.version must be 1");
|
|
4286
|
+
if (typeof raw.type !== "string" || !CHART_TYPES.has(raw.type)) {
|
|
4287
|
+
throw new ChartValidationError("chartSpec.type must be one of: bar, line, pie, heatmap");
|
|
4288
|
+
}
|
|
4289
|
+
if (typeof raw.title !== "string" || raw.title.trim().length === 0) {
|
|
4290
|
+
throw new ChartValidationError("chartSpec.title must be a non-empty string");
|
|
4291
|
+
}
|
|
4292
|
+
if (!isRecord(raw.encoding)) throw new ChartValidationError("chartSpec.encoding must be an object");
|
|
4293
|
+
const spec = raw;
|
|
4294
|
+
switch (spec.type) {
|
|
4295
|
+
case "bar":
|
|
4296
|
+
case "line":
|
|
4297
|
+
asFieldName(spec.encoding.x, "encoding.x");
|
|
4298
|
+
asFieldName(spec.encoding.y, "encoding.y");
|
|
4299
|
+
break;
|
|
4300
|
+
case "pie":
|
|
4301
|
+
asFieldName(spec.encoding.label, "encoding.label");
|
|
4302
|
+
asFieldName(spec.encoding.value, "encoding.value");
|
|
4303
|
+
break;
|
|
4304
|
+
case "heatmap":
|
|
4305
|
+
asFieldName(spec.encoding.x, "encoding.x");
|
|
4306
|
+
asFieldName(spec.encoding.y, "encoding.y");
|
|
4307
|
+
asFieldName(spec.encoding.value, "encoding.value");
|
|
4308
|
+
break;
|
|
4309
|
+
}
|
|
4310
|
+
return {
|
|
4311
|
+
...spec,
|
|
4312
|
+
title: spec.title.trim()
|
|
4313
|
+
};
|
|
4314
|
+
}
|
|
4315
|
+
function inferChartDataset(rows, declaredFields) {
|
|
4316
|
+
const declared = new Map((declaredFields ?? []).map((field) => [field.name, field]));
|
|
4317
|
+
const columnNames = rows.length > 0 ? Object.keys(rows[0]) : [...declared.keys()];
|
|
4318
|
+
const columns = columnNames.map((name) => {
|
|
4319
|
+
const declaredField = declared.get(name);
|
|
4320
|
+
if (declaredField) return declaredField;
|
|
4321
|
+
return {
|
|
4322
|
+
name,
|
|
4323
|
+
type: inferFieldType(rows.map((row) => row[name]))
|
|
4324
|
+
};
|
|
4325
|
+
});
|
|
4326
|
+
return { columns, rows };
|
|
4327
|
+
}
|
|
4328
|
+
function aggregateByLabel(rows, labelField, valueField) {
|
|
4329
|
+
const labels = [];
|
|
4330
|
+
const indexByLabel = /* @__PURE__ */ new Map();
|
|
4331
|
+
const values = [];
|
|
4332
|
+
for (const row of rows) {
|
|
4333
|
+
const label = toLabel(row[labelField]);
|
|
4334
|
+
let index = indexByLabel.get(label);
|
|
4335
|
+
if (index === void 0) {
|
|
4336
|
+
index = labels.length;
|
|
4337
|
+
indexByLabel.set(label, index);
|
|
4338
|
+
labels.push(label);
|
|
4339
|
+
values.push(0);
|
|
4340
|
+
}
|
|
4341
|
+
values[index] += toNumber(row[valueField], valueField);
|
|
4342
|
+
}
|
|
4343
|
+
return { labels, values };
|
|
4344
|
+
}
|
|
4345
|
+
function buildLineData(rows, spec) {
|
|
4346
|
+
const xField = spec.encoding.x;
|
|
4347
|
+
const yField = spec.encoding.y;
|
|
4348
|
+
const seriesField = spec.encoding.series;
|
|
4349
|
+
if (!seriesField) return aggregateByLabel(rows, xField, yField);
|
|
4350
|
+
assertFieldExists(rows, seriesField);
|
|
4351
|
+
const labels = [];
|
|
4352
|
+
const labelIndex = /* @__PURE__ */ new Map();
|
|
4353
|
+
const seriesNames = [];
|
|
4354
|
+
const seriesIndex = /* @__PURE__ */ new Map();
|
|
4355
|
+
const matrix = [];
|
|
4356
|
+
for (const row of rows) {
|
|
4357
|
+
const label = toLabel(row[xField]);
|
|
4358
|
+
const seriesName = toLabel(row[seriesField]);
|
|
4359
|
+
let xIndex = labelIndex.get(label);
|
|
4360
|
+
if (xIndex === void 0) {
|
|
4361
|
+
xIndex = labels.length;
|
|
4362
|
+
labelIndex.set(label, xIndex);
|
|
4363
|
+
labels.push(label);
|
|
4364
|
+
for (const values of matrix) values.push(0);
|
|
4365
|
+
}
|
|
4366
|
+
let sIndex = seriesIndex.get(seriesName);
|
|
4367
|
+
if (sIndex === void 0) {
|
|
4368
|
+
sIndex = seriesNames.length;
|
|
4369
|
+
seriesIndex.set(seriesName, sIndex);
|
|
4370
|
+
seriesNames.push(seriesName);
|
|
4371
|
+
matrix.push(Array(labels.length).fill(0));
|
|
4372
|
+
}
|
|
4373
|
+
matrix[sIndex][xIndex] += toNumber(row[yField], yField);
|
|
4374
|
+
}
|
|
4375
|
+
const series = seriesNames.map((name, index) => ({ name, values: matrix[index] }));
|
|
4376
|
+
return {
|
|
4377
|
+
labels,
|
|
4378
|
+
values: series[0]?.values ?? [],
|
|
4379
|
+
series
|
|
4380
|
+
};
|
|
4381
|
+
}
|
|
4382
|
+
function buildHeatmapData(rows, spec) {
|
|
4383
|
+
const xField = spec.encoding.x;
|
|
4384
|
+
const yField = spec.encoding.y;
|
|
4385
|
+
const valueField = spec.encoding.value;
|
|
4386
|
+
const xLabels = [];
|
|
4387
|
+
const yLabels = [];
|
|
4388
|
+
const xIndex = /* @__PURE__ */ new Map();
|
|
4389
|
+
const yIndex = /* @__PURE__ */ new Map();
|
|
4390
|
+
const values = /* @__PURE__ */ new Map();
|
|
4391
|
+
for (const row of rows) {
|
|
4392
|
+
const xLabel = toLabel(row[xField]);
|
|
4393
|
+
const yLabel = toLabel(row[yField]);
|
|
4394
|
+
let xi = xIndex.get(xLabel);
|
|
4395
|
+
if (xi === void 0) {
|
|
4396
|
+
xi = xLabels.length;
|
|
4397
|
+
xIndex.set(xLabel, xi);
|
|
4398
|
+
xLabels.push(xLabel);
|
|
4399
|
+
}
|
|
4400
|
+
let yi = yIndex.get(yLabel);
|
|
4401
|
+
if (yi === void 0) {
|
|
4402
|
+
yi = yLabels.length;
|
|
4403
|
+
yIndex.set(yLabel, yi);
|
|
4404
|
+
yLabels.push(yLabel);
|
|
4405
|
+
}
|
|
4406
|
+
const key = `${xi}:${yi}`;
|
|
4407
|
+
values.set(key, (values.get(key) ?? 0) + toNumber(row[valueField], valueField));
|
|
4408
|
+
}
|
|
4409
|
+
const data = [];
|
|
4410
|
+
for (const [key, value] of values.entries()) {
|
|
4411
|
+
const [x, y] = key.split(":").map(Number);
|
|
4412
|
+
data.push([x, y, value]);
|
|
4413
|
+
}
|
|
4414
|
+
return { xLabels, yLabels, data };
|
|
4415
|
+
}
|
|
4416
|
+
function buildChartPayload(rows, rawSpec, options) {
|
|
4417
|
+
const spec = normalizeChartSpec(rawSpec);
|
|
4418
|
+
const dataset = inferChartDataset(rows, spec.fields);
|
|
4419
|
+
const requiredFields = /* @__PURE__ */ new Set();
|
|
4420
|
+
for (const field of Object.values(spec.encoding)) {
|
|
4421
|
+
if (typeof field === "string" && field) requiredFields.add(field);
|
|
4422
|
+
}
|
|
4423
|
+
for (const field of requiredFields) assertFieldExists(rows, field);
|
|
4424
|
+
let data;
|
|
4425
|
+
switch (spec.type) {
|
|
4426
|
+
case "bar":
|
|
4427
|
+
data = aggregateByLabel(rows, spec.encoding.x, spec.encoding.y);
|
|
4428
|
+
break;
|
|
4429
|
+
case "line":
|
|
4430
|
+
data = buildLineData(rows, spec);
|
|
4431
|
+
break;
|
|
4432
|
+
case "pie":
|
|
4433
|
+
data = aggregateByLabel(rows, spec.encoding.label, spec.encoding.value);
|
|
4434
|
+
break;
|
|
4435
|
+
case "heatmap":
|
|
4436
|
+
data = buildHeatmapData(rows, spec);
|
|
4437
|
+
break;
|
|
4438
|
+
}
|
|
4439
|
+
return {
|
|
4440
|
+
version: 1,
|
|
4441
|
+
spec,
|
|
4442
|
+
dataset,
|
|
4443
|
+
data,
|
|
4444
|
+
rowCount: rows.length,
|
|
4445
|
+
truncated: options?.truncated
|
|
4446
|
+
};
|
|
4447
|
+
}
|
|
4448
|
+
|
|
4413
4449
|
// ../../packages/core/src/nlp/pos-tags.ts
|
|
4414
4450
|
var POS_TAG_DEFINITIONS = [
|
|
4415
4451
|
{ tag: "n", name: "\u540D\u8BCD", description: "\u666E\u901A\u540D\u8BCD", meaningful: true },
|
|
@@ -5238,6 +5274,17 @@ function isValidWord(word, locale, minLength, enableStopwords, isStopwordFn) {
|
|
|
5238
5274
|
}
|
|
5239
5275
|
|
|
5240
5276
|
// ../../packages/core/src/ai/tool-catalog.ts
|
|
5277
|
+
var LEGACY_BUILTIN_TOOL_NAME_ALIASES = {
|
|
5278
|
+
search_sessions: "search_segments",
|
|
5279
|
+
get_session_messages: "get_segment_messages",
|
|
5280
|
+
get_session_summaries: "get_segment_summaries"
|
|
5281
|
+
};
|
|
5282
|
+
function normalizeBuiltinToolName(toolName) {
|
|
5283
|
+
return LEGACY_BUILTIN_TOOL_NAME_ALIASES[toolName] ?? toolName;
|
|
5284
|
+
}
|
|
5285
|
+
function normalizeBuiltinToolNames(toolNames) {
|
|
5286
|
+
return Array.from(new Set(toolNames.map(normalizeBuiltinToolName)));
|
|
5287
|
+
}
|
|
5241
5288
|
var BUILTIN_TOOL_CATALOG = [
|
|
5242
5289
|
// Core 工具
|
|
5243
5290
|
{ name: "get_chat_overview", category: "core" },
|
|
@@ -5245,17 +5292,20 @@ var BUILTIN_TOOL_CATALOG = [
|
|
|
5245
5292
|
{ name: "deep_search_messages", category: "core" },
|
|
5246
5293
|
{ name: "get_recent_messages", category: "core" },
|
|
5247
5294
|
{ name: "get_message_context", category: "core" },
|
|
5248
|
-
{ name: "
|
|
5249
|
-
{ name: "
|
|
5295
|
+
{ name: "search_segments", category: "core" },
|
|
5296
|
+
{ name: "get_segment_messages", category: "core" },
|
|
5250
5297
|
{ name: "get_members", category: "core" },
|
|
5298
|
+
{ name: "get_schema", category: "core" },
|
|
5251
5299
|
// Analysis 工具
|
|
5252
5300
|
{ name: "get_member_stats", category: "analysis" },
|
|
5253
5301
|
{ name: "get_time_stats", category: "analysis" },
|
|
5254
5302
|
{ name: "get_member_name_history", category: "analysis" },
|
|
5255
5303
|
{ name: "get_conversation_between", category: "analysis" },
|
|
5256
|
-
{ name: "
|
|
5304
|
+
{ name: "get_segment_summaries", category: "analysis" },
|
|
5257
5305
|
{ name: "response_time_analysis", category: "analysis" },
|
|
5258
5306
|
{ name: "keyword_frequency", category: "analysis" },
|
|
5307
|
+
{ name: "render_chart", category: "analysis" },
|
|
5308
|
+
{ name: "execute_sql", category: "analysis" },
|
|
5259
5309
|
// SQL Analysis 工具
|
|
5260
5310
|
{ name: "message_type_breakdown", category: "analysis" },
|
|
5261
5311
|
{ name: "peak_chat_hours_by_member", category: "analysis" },
|
|
@@ -5270,6 +5320,9 @@ var BUILTIN_TOOL_CATALOG = [
|
|
|
5270
5320
|
{ name: "unanswered_messages", category: "analysis" }
|
|
5271
5321
|
];
|
|
5272
5322
|
|
|
5323
|
+
// ../../packages/core/src/ai/chart-capability.ts
|
|
5324
|
+
var CHART_CAPABILITY_SKILL_ID = "chart_runtime";
|
|
5325
|
+
|
|
5273
5326
|
// ../../packages/core/src/ai/provider-registry.ts
|
|
5274
5327
|
var OPENAI = {
|
|
5275
5328
|
id: "openai",
|
|
@@ -6783,6 +6836,125 @@ function mergeMembers2(sources, collidingIds) {
|
|
|
6783
6836
|
return map;
|
|
6784
6837
|
}
|
|
6785
6838
|
|
|
6839
|
+
// ../../packages/core/src/schema/tables.ts
|
|
6840
|
+
var CURRENT_SCHEMA_VERSION = 6;
|
|
6841
|
+
var CHAT_DB_TABLES = `
|
|
6842
|
+
CREATE TABLE IF NOT EXISTS meta (
|
|
6843
|
+
name TEXT NOT NULL,
|
|
6844
|
+
platform TEXT NOT NULL,
|
|
6845
|
+
type TEXT NOT NULL,
|
|
6846
|
+
imported_at INTEGER NOT NULL,
|
|
6847
|
+
group_id TEXT,
|
|
6848
|
+
group_avatar TEXT,
|
|
6849
|
+
owner_id TEXT,
|
|
6850
|
+
schema_version INTEGER DEFAULT ${CURRENT_SCHEMA_VERSION},
|
|
6851
|
+
session_gap_threshold INTEGER
|
|
6852
|
+
);
|
|
6853
|
+
|
|
6854
|
+
CREATE TABLE IF NOT EXISTS member (
|
|
6855
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
6856
|
+
platform_id TEXT NOT NULL UNIQUE,
|
|
6857
|
+
account_name TEXT,
|
|
6858
|
+
group_nickname TEXT,
|
|
6859
|
+
aliases TEXT DEFAULT '[]',
|
|
6860
|
+
avatar TEXT,
|
|
6861
|
+
roles TEXT DEFAULT '[]'
|
|
6862
|
+
);
|
|
6863
|
+
|
|
6864
|
+
CREATE TABLE IF NOT EXISTS member_name_history (
|
|
6865
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
6866
|
+
member_id INTEGER NOT NULL,
|
|
6867
|
+
name_type TEXT NOT NULL,
|
|
6868
|
+
name TEXT NOT NULL,
|
|
6869
|
+
start_ts INTEGER NOT NULL,
|
|
6870
|
+
end_ts INTEGER,
|
|
6871
|
+
FOREIGN KEY(member_id) REFERENCES member(id)
|
|
6872
|
+
);
|
|
6873
|
+
|
|
6874
|
+
CREATE TABLE IF NOT EXISTS message (
|
|
6875
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
6876
|
+
sender_id INTEGER NOT NULL,
|
|
6877
|
+
sender_account_name TEXT,
|
|
6878
|
+
sender_group_nickname TEXT,
|
|
6879
|
+
ts INTEGER NOT NULL,
|
|
6880
|
+
type INTEGER NOT NULL,
|
|
6881
|
+
content TEXT,
|
|
6882
|
+
reply_to_message_id TEXT DEFAULT NULL,
|
|
6883
|
+
platform_message_id TEXT DEFAULT NULL,
|
|
6884
|
+
FOREIGN KEY(sender_id) REFERENCES member(id)
|
|
6885
|
+
);
|
|
6886
|
+
|
|
6887
|
+
CREATE TABLE IF NOT EXISTS segment (
|
|
6888
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
6889
|
+
start_ts INTEGER NOT NULL,
|
|
6890
|
+
end_ts INTEGER NOT NULL,
|
|
6891
|
+
message_count INTEGER DEFAULT 0,
|
|
6892
|
+
is_manual INTEGER DEFAULT 0,
|
|
6893
|
+
summary TEXT
|
|
6894
|
+
);
|
|
6895
|
+
|
|
6896
|
+
CREATE TABLE IF NOT EXISTS message_context (
|
|
6897
|
+
message_id INTEGER PRIMARY KEY,
|
|
6898
|
+
segment_id INTEGER NOT NULL,
|
|
6899
|
+
topic_id INTEGER
|
|
6900
|
+
);
|
|
6901
|
+
`;
|
|
6902
|
+
var CHAT_DB_INDEXES = `
|
|
6903
|
+
CREATE INDEX IF NOT EXISTS idx_message_ts ON message(ts);
|
|
6904
|
+
CREATE INDEX IF NOT EXISTS idx_message_sender ON message(sender_id);
|
|
6905
|
+
CREATE INDEX IF NOT EXISTS idx_message_platform_id ON message(platform_message_id);
|
|
6906
|
+
CREATE INDEX IF NOT EXISTS idx_member_name_history_member_id ON member_name_history(member_id);
|
|
6907
|
+
CREATE INDEX IF NOT EXISTS idx_segment_time ON segment(start_ts, end_ts);
|
|
6908
|
+
CREATE INDEX IF NOT EXISTS idx_context_segment ON message_context(segment_id);
|
|
6909
|
+
`;
|
|
6910
|
+
var CHAT_DB_SCHEMA = CHAT_DB_TABLES + CHAT_DB_INDEXES;
|
|
6911
|
+
var FTS_TABLE_SCHEMA = `
|
|
6912
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS message_fts USING fts5(
|
|
6913
|
+
content,
|
|
6914
|
+
content='',
|
|
6915
|
+
content_rowid=id
|
|
6916
|
+
);
|
|
6917
|
+
`;
|
|
6918
|
+
|
|
6919
|
+
// ../../packages/core/src/schema/migrations.ts
|
|
6920
|
+
function getSchemaVersion(db) {
|
|
6921
|
+
try {
|
|
6922
|
+
const tableInfo = db.pragma("table_info(meta)");
|
|
6923
|
+
const hasVersionColumn = tableInfo.some((col) => col.name === "schema_version");
|
|
6924
|
+
if (!hasVersionColumn) return 0;
|
|
6925
|
+
const result = db.prepare("SELECT schema_version FROM meta LIMIT 1").get();
|
|
6926
|
+
return result?.schema_version ?? 0;
|
|
6927
|
+
} catch {
|
|
6928
|
+
return 0;
|
|
6929
|
+
}
|
|
6930
|
+
}
|
|
6931
|
+
function setSchemaVersion(db, version) {
|
|
6932
|
+
const tableInfo = db.pragma("table_info(meta)");
|
|
6933
|
+
const hasVersionColumn = tableInfo.some((col) => col.name === "schema_version");
|
|
6934
|
+
if (!hasVersionColumn) {
|
|
6935
|
+
db.exec("ALTER TABLE meta ADD COLUMN schema_version INTEGER DEFAULT 0");
|
|
6936
|
+
}
|
|
6937
|
+
db.prepare("UPDATE meta SET schema_version = ?").run(version);
|
|
6938
|
+
}
|
|
6939
|
+
function needsMigration(db, targetVersion) {
|
|
6940
|
+
return getSchemaVersion(db) < targetVersion;
|
|
6941
|
+
}
|
|
6942
|
+
function runMigrations(db, migrationsList, forceRepair = false) {
|
|
6943
|
+
const currentVersion = getSchemaVersion(db);
|
|
6944
|
+
if (!forceRepair && currentVersion >= (migrationsList.at(-1)?.version ?? 0)) {
|
|
6945
|
+
return false;
|
|
6946
|
+
}
|
|
6947
|
+
const pending = forceRepair ? migrationsList : migrationsList.filter((m) => m.version > currentVersion);
|
|
6948
|
+
if (pending.length === 0) return false;
|
|
6949
|
+
db.transaction(() => {
|
|
6950
|
+
for (const migration of pending) {
|
|
6951
|
+
migration.up(db);
|
|
6952
|
+
setSchemaVersion(db, migration.version);
|
|
6953
|
+
}
|
|
6954
|
+
});
|
|
6955
|
+
return true;
|
|
6956
|
+
}
|
|
6957
|
+
|
|
6786
6958
|
// ../../packages/parser/src/index.ts
|
|
6787
6959
|
import * as fs24 from "fs";
|
|
6788
6960
|
import * as path20 from "path";
|
|
@@ -11989,17 +12161,17 @@ function writeParseResultToDb(db, meta, members, messages) {
|
|
|
11989
12161
|
// ../../packages/node-runtime/src/import/perf-logger.ts
|
|
11990
12162
|
var lastLogTime = Date.now();
|
|
11991
12163
|
|
|
11992
|
-
// ../../packages/node-runtime/src/ai/
|
|
11993
|
-
import
|
|
12164
|
+
// ../../packages/node-runtime/src/ai/chats.ts
|
|
12165
|
+
import Database from "better-sqlite3";
|
|
11994
12166
|
import * as fs28 from "fs";
|
|
11995
12167
|
import * as path23 from "path";
|
|
11996
12168
|
var DEFAULT_GENERAL_ID = "general_cn";
|
|
11997
12169
|
var defaultLogger = {
|
|
11998
12170
|
warn(_category, message, extra) {
|
|
11999
|
-
console.warn(`[AI
|
|
12171
|
+
console.warn(`[AI Chats] ${message}`, extra ?? "");
|
|
12000
12172
|
}
|
|
12001
12173
|
};
|
|
12002
|
-
var
|
|
12174
|
+
var AIChatManager = class {
|
|
12003
12175
|
db = null;
|
|
12004
12176
|
aiDataDir;
|
|
12005
12177
|
logger;
|
|
@@ -12019,13 +12191,14 @@ var AIConversationManager = class {
|
|
|
12019
12191
|
if (this.db) return this.db;
|
|
12020
12192
|
this.ensureDir(this.aiDataDir);
|
|
12021
12193
|
const dbPath = path23.join(this.aiDataDir, "conversations.db");
|
|
12022
|
-
this.db = this.nativeBinding ? new
|
|
12194
|
+
this.db = this.nativeBinding ? new Database(dbPath, { nativeBinding: this.nativeBinding }) : new Database(dbPath);
|
|
12023
12195
|
this.db.pragma("journal_mode = WAL");
|
|
12024
12196
|
this.db.exec(`
|
|
12025
|
-
CREATE TABLE IF NOT EXISTS
|
|
12197
|
+
CREATE TABLE IF NOT EXISTS ai_chat (
|
|
12026
12198
|
id TEXT PRIMARY KEY,
|
|
12027
12199
|
session_id TEXT NOT NULL,
|
|
12028
12200
|
title TEXT,
|
|
12201
|
+
assistant_id TEXT DEFAULT '${DEFAULT_GENERAL_ID}',
|
|
12029
12202
|
active_message_id TEXT,
|
|
12030
12203
|
created_at INTEGER NOT NULL,
|
|
12031
12204
|
updated_at INTEGER NOT NULL
|
|
@@ -12033,7 +12206,7 @@ var AIConversationManager = class {
|
|
|
12033
12206
|
|
|
12034
12207
|
CREATE TABLE IF NOT EXISTS ai_message (
|
|
12035
12208
|
id TEXT PRIMARY KEY,
|
|
12036
|
-
|
|
12209
|
+
ai_chat_id TEXT NOT NULL,
|
|
12037
12210
|
role TEXT NOT NULL,
|
|
12038
12211
|
content TEXT NOT NULL,
|
|
12039
12212
|
timestamp INTEGER NOT NULL,
|
|
@@ -12043,51 +12216,113 @@ var AIConversationManager = class {
|
|
|
12043
12216
|
parent_id TEXT,
|
|
12044
12217
|
sibling_group_id TEXT,
|
|
12045
12218
|
branch_index INTEGER DEFAULT 0,
|
|
12046
|
-
|
|
12219
|
+
debug_context TEXT,
|
|
12220
|
+
token_usage TEXT,
|
|
12221
|
+
FOREIGN KEY(ai_chat_id) REFERENCES ai_chat(id) ON DELETE CASCADE
|
|
12047
12222
|
);
|
|
12048
12223
|
|
|
12049
|
-
CREATE INDEX IF NOT EXISTS idx_ai_conversation_session ON ai_conversation(session_id);
|
|
12050
|
-
CREATE INDEX IF NOT EXISTS idx_ai_message_conversation ON ai_message(conversation_id);
|
|
12051
12224
|
`);
|
|
12052
12225
|
this.migrateDatabase(this.db);
|
|
12053
12226
|
return this.db;
|
|
12054
12227
|
}
|
|
12228
|
+
tableExists(db, tableName) {
|
|
12229
|
+
const row = db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?").get(tableName);
|
|
12230
|
+
return !!row;
|
|
12231
|
+
}
|
|
12232
|
+
getTableColumns(db, tableName) {
|
|
12233
|
+
const tableInfo = db.pragma(`table_info(${tableName})`);
|
|
12234
|
+
return tableInfo.map((col) => col.name);
|
|
12235
|
+
}
|
|
12236
|
+
ensureMessageMigrationColumns(db, tableName) {
|
|
12237
|
+
const messageColumns = this.getTableColumns(db, tableName);
|
|
12238
|
+
if (!messageColumns.includes("content_blocks")) {
|
|
12239
|
+
db.exec(`ALTER TABLE ${tableName} ADD COLUMN content_blocks TEXT`);
|
|
12240
|
+
}
|
|
12241
|
+
if (!messageColumns.includes("token_usage")) {
|
|
12242
|
+
db.exec(`ALTER TABLE ${tableName} ADD COLUMN token_usage TEXT`);
|
|
12243
|
+
}
|
|
12244
|
+
if (!messageColumns.includes("debug_context")) {
|
|
12245
|
+
db.exec(`ALTER TABLE ${tableName} ADD COLUMN debug_context TEXT`);
|
|
12246
|
+
}
|
|
12247
|
+
if (!messageColumns.includes("parent_id")) {
|
|
12248
|
+
db.exec(`ALTER TABLE ${tableName} ADD COLUMN parent_id TEXT`);
|
|
12249
|
+
}
|
|
12250
|
+
if (!messageColumns.includes("sibling_group_id")) {
|
|
12251
|
+
db.exec(`ALTER TABLE ${tableName} ADD COLUMN sibling_group_id TEXT`);
|
|
12252
|
+
}
|
|
12253
|
+
if (!messageColumns.includes("branch_index")) {
|
|
12254
|
+
db.exec(`ALTER TABLE ${tableName} ADD COLUMN branch_index INTEGER DEFAULT 0`);
|
|
12255
|
+
}
|
|
12256
|
+
}
|
|
12055
12257
|
migrateDatabase(db) {
|
|
12056
12258
|
try {
|
|
12057
|
-
const
|
|
12058
|
-
|
|
12059
|
-
|
|
12060
|
-
|
|
12061
|
-
|
|
12062
|
-
|
|
12063
|
-
|
|
12064
|
-
|
|
12065
|
-
|
|
12066
|
-
|
|
12067
|
-
|
|
12068
|
-
|
|
12069
|
-
|
|
12070
|
-
|
|
12071
|
-
|
|
12072
|
-
|
|
12073
|
-
|
|
12074
|
-
}
|
|
12075
|
-
if (!messageColumns.includes("branch_index")) {
|
|
12076
|
-
db.exec("ALTER TABLE ai_message ADD COLUMN branch_index INTEGER DEFAULT 0");
|
|
12259
|
+
const hasLegacyConversationTable = this.tableExists(db, "ai_conversation");
|
|
12260
|
+
if (hasLegacyConversationTable) {
|
|
12261
|
+
const convColumns = this.getTableColumns(db, "ai_conversation");
|
|
12262
|
+
if (!convColumns.includes("assistant_id")) {
|
|
12263
|
+
db.exec(`ALTER TABLE ai_conversation ADD COLUMN assistant_id TEXT DEFAULT '${DEFAULT_GENERAL_ID}'`);
|
|
12264
|
+
}
|
|
12265
|
+
if (!convColumns.includes("active_message_id")) {
|
|
12266
|
+
db.exec("ALTER TABLE ai_conversation ADD COLUMN active_message_id TEXT");
|
|
12267
|
+
}
|
|
12268
|
+
db.exec(`
|
|
12269
|
+
INSERT OR IGNORE INTO ai_chat (
|
|
12270
|
+
id, session_id, title, assistant_id, active_message_id, created_at, updated_at
|
|
12271
|
+
)
|
|
12272
|
+
SELECT id, session_id, title, COALESCE(assistant_id, '${DEFAULT_GENERAL_ID}'),
|
|
12273
|
+
active_message_id, created_at, updated_at
|
|
12274
|
+
FROM ai_conversation
|
|
12275
|
+
`);
|
|
12077
12276
|
}
|
|
12078
|
-
|
|
12079
|
-
const
|
|
12080
|
-
const
|
|
12081
|
-
|
|
12082
|
-
|
|
12277
|
+
this.ensureMessageMigrationColumns(db, "ai_message");
|
|
12278
|
+
const messageColumns = this.getTableColumns(db, "ai_message");
|
|
12279
|
+
const hadLegacyConversationId = messageColumns.includes("conversation_id");
|
|
12280
|
+
const needsMessageTreeBackfill = !messageColumns.includes("parent_id") || !messageColumns.includes("sibling_group_id") || !messageColumns.includes("branch_index") || hadLegacyConversationId;
|
|
12281
|
+
if (hadLegacyConversationId && !messageColumns.includes("ai_chat_id")) {
|
|
12282
|
+
db.exec(`
|
|
12283
|
+
DROP INDEX IF EXISTS idx_ai_message_conversation;
|
|
12284
|
+
ALTER TABLE ai_message RENAME TO ai_message_legacy;
|
|
12285
|
+
|
|
12286
|
+
CREATE TABLE ai_message (
|
|
12287
|
+
id TEXT PRIMARY KEY,
|
|
12288
|
+
ai_chat_id TEXT NOT NULL,
|
|
12289
|
+
role TEXT NOT NULL,
|
|
12290
|
+
content TEXT NOT NULL,
|
|
12291
|
+
timestamp INTEGER NOT NULL,
|
|
12292
|
+
data_keywords TEXT,
|
|
12293
|
+
data_message_count INTEGER,
|
|
12294
|
+
content_blocks TEXT,
|
|
12295
|
+
parent_id TEXT,
|
|
12296
|
+
sibling_group_id TEXT,
|
|
12297
|
+
branch_index INTEGER DEFAULT 0,
|
|
12298
|
+
debug_context TEXT,
|
|
12299
|
+
token_usage TEXT,
|
|
12300
|
+
FOREIGN KEY(ai_chat_id) REFERENCES ai_chat(id) ON DELETE CASCADE
|
|
12301
|
+
);
|
|
12302
|
+
|
|
12303
|
+
INSERT INTO ai_message (
|
|
12304
|
+
id, ai_chat_id, role, content, timestamp, data_keywords, data_message_count,
|
|
12305
|
+
content_blocks, parent_id, sibling_group_id, branch_index, debug_context, token_usage
|
|
12306
|
+
)
|
|
12307
|
+
SELECT id, conversation_id, role, content, timestamp, data_keywords, data_message_count,
|
|
12308
|
+
content_blocks, parent_id, sibling_group_id, branch_index, debug_context, token_usage
|
|
12309
|
+
FROM ai_message_legacy;
|
|
12310
|
+
|
|
12311
|
+
DROP TABLE ai_message_legacy;
|
|
12312
|
+
`);
|
|
12083
12313
|
}
|
|
12084
|
-
if (
|
|
12085
|
-
db.exec(
|
|
12314
|
+
if (hasLegacyConversationTable) {
|
|
12315
|
+
db.exec(`
|
|
12316
|
+
DROP INDEX IF EXISTS idx_ai_conversation_session;
|
|
12317
|
+
DROP TABLE ai_conversation;
|
|
12318
|
+
`);
|
|
12086
12319
|
}
|
|
12087
|
-
if (needsMessageTreeBackfill ||
|
|
12320
|
+
if (needsMessageTreeBackfill || this.hasUnbackfilledMessageTree(db)) {
|
|
12088
12321
|
this.backfillMessageTree(db);
|
|
12089
12322
|
}
|
|
12090
12323
|
db.exec(`
|
|
12324
|
+
CREATE INDEX IF NOT EXISTS idx_ai_chat_session ON ai_chat(session_id);
|
|
12325
|
+
CREATE INDEX IF NOT EXISTS idx_ai_message_ai_chat ON ai_message(ai_chat_id);
|
|
12091
12326
|
CREATE INDEX IF NOT EXISTS idx_ai_message_parent ON ai_message(parent_id);
|
|
12092
12327
|
CREATE INDEX IF NOT EXISTS idx_ai_message_sibling ON ai_message(sibling_group_id);
|
|
12093
12328
|
`);
|
|
@@ -12098,16 +12333,16 @@ var AIConversationManager = class {
|
|
|
12098
12333
|
hasUnbackfilledMessageTree(db) {
|
|
12099
12334
|
const row = db.prepare(
|
|
12100
12335
|
`SELECT 1
|
|
12101
|
-
FROM
|
|
12336
|
+
FROM ai_chat c
|
|
12102
12337
|
WHERE EXISTS (
|
|
12103
12338
|
SELECT 1 FROM ai_message m
|
|
12104
|
-
WHERE m.
|
|
12339
|
+
WHERE m.ai_chat_id = c.id
|
|
12105
12340
|
)
|
|
12106
12341
|
AND (
|
|
12107
12342
|
c.active_message_id IS NULL
|
|
12108
12343
|
OR EXISTS (
|
|
12109
12344
|
SELECT 1 FROM ai_message m
|
|
12110
|
-
WHERE m.
|
|
12345
|
+
WHERE m.ai_chat_id = c.id
|
|
12111
12346
|
AND (m.sibling_group_id IS NULL OR m.branch_index IS NULL)
|
|
12112
12347
|
)
|
|
12113
12348
|
)
|
|
@@ -12116,26 +12351,26 @@ var AIConversationManager = class {
|
|
|
12116
12351
|
return !!row;
|
|
12117
12352
|
}
|
|
12118
12353
|
backfillMessageTree(db) {
|
|
12119
|
-
const
|
|
12354
|
+
const aiChats = db.prepare("SELECT id FROM ai_chat").all();
|
|
12120
12355
|
const updateMessage = db.prepare(
|
|
12121
12356
|
"UPDATE ai_message SET parent_id = ?, sibling_group_id = COALESCE(sibling_group_id, ?), branch_index = COALESCE(branch_index, 0) WHERE id = ?"
|
|
12122
12357
|
);
|
|
12123
|
-
const
|
|
12358
|
+
const updateAIChat = db.prepare("UPDATE ai_chat SET active_message_id = ? WHERE id = ?");
|
|
12124
12359
|
const tx = db.transaction(() => {
|
|
12125
|
-
for (const
|
|
12360
|
+
for (const aiChat of aiChats) {
|
|
12126
12361
|
const messages = db.prepare(
|
|
12127
12362
|
`SELECT id, parent_id as parentId, sibling_group_id as siblingGroupId
|
|
12128
|
-
FROM ai_message WHERE
|
|
12129
|
-
).all(
|
|
12363
|
+
FROM ai_message WHERE ai_chat_id = ? ORDER BY timestamp ASC, id ASC`
|
|
12364
|
+
).all(aiChat.id);
|
|
12130
12365
|
let previousId = null;
|
|
12131
12366
|
for (const message of messages) {
|
|
12132
12367
|
const parentId = message.parentId === void 0 ? previousId : message.parentId ?? previousId;
|
|
12133
12368
|
updateMessage.run(parentId, message.siblingGroupId ?? message.id, message.id);
|
|
12134
12369
|
previousId = message.id;
|
|
12135
12370
|
}
|
|
12136
|
-
const
|
|
12137
|
-
if (!
|
|
12138
|
-
|
|
12371
|
+
const aiChatRow = db.prepare("SELECT active_message_id as activeMessageId FROM ai_chat WHERE id = ?").get(aiChat.id);
|
|
12372
|
+
if (!aiChatRow?.activeMessageId && previousId) {
|
|
12373
|
+
updateAIChat.run(previousId, aiChat.id);
|
|
12139
12374
|
}
|
|
12140
12375
|
}
|
|
12141
12376
|
});
|
|
@@ -12147,7 +12382,7 @@ var AIConversationManager = class {
|
|
|
12147
12382
|
parseMessageRow(row) {
|
|
12148
12383
|
return {
|
|
12149
12384
|
id: row.id,
|
|
12150
|
-
|
|
12385
|
+
aiChatId: row.aiChatId,
|
|
12151
12386
|
role: row.role,
|
|
12152
12387
|
content: row.content,
|
|
12153
12388
|
timestamp: row.timestamp,
|
|
@@ -12161,7 +12396,7 @@ var AIConversationManager = class {
|
|
|
12161
12396
|
getMessageRow(messageId) {
|
|
12162
12397
|
const db = this.getDb();
|
|
12163
12398
|
const row = db.prepare(
|
|
12164
|
-
`SELECT id,
|
|
12399
|
+
`SELECT id, ai_chat_id as aiChatId, role, content, timestamp,
|
|
12165
12400
|
parent_id as parentId, sibling_group_id as siblingGroupId, branch_index as branchIndex,
|
|
12166
12401
|
data_keywords as dataKeywords, data_message_count as dataMessageCount,
|
|
12167
12402
|
content_blocks as contentBlocks, token_usage as tokenUsage
|
|
@@ -12169,45 +12404,45 @@ var AIConversationManager = class {
|
|
|
12169
12404
|
).get(messageId);
|
|
12170
12405
|
return row ?? null;
|
|
12171
12406
|
}
|
|
12172
|
-
getActiveMessageId(
|
|
12407
|
+
getActiveMessageId(aiChatId) {
|
|
12173
12408
|
const db = this.getDb();
|
|
12174
|
-
const row = db.prepare("SELECT active_message_id as activeMessageId FROM
|
|
12409
|
+
const row = db.prepare("SELECT active_message_id as activeMessageId FROM ai_chat WHERE id = ?").get(aiChatId);
|
|
12175
12410
|
if (row?.activeMessageId) {
|
|
12176
12411
|
const activeExists = db.prepare("SELECT 1 FROM ai_message WHERE id = ?").get(row.activeMessageId);
|
|
12177
12412
|
if (activeExists) return row.activeMessageId;
|
|
12178
12413
|
}
|
|
12179
|
-
const fallback = db.prepare("SELECT id FROM ai_message WHERE
|
|
12414
|
+
const fallback = db.prepare("SELECT id FROM ai_message WHERE ai_chat_id = ? ORDER BY timestamp DESC, id DESC LIMIT 1").get(aiChatId);
|
|
12180
12415
|
if (fallback?.id) {
|
|
12181
|
-
db.prepare("UPDATE
|
|
12416
|
+
db.prepare("UPDATE ai_chat SET active_message_id = ? WHERE id = ?").run(fallback.id, aiChatId);
|
|
12182
12417
|
return fallback.id;
|
|
12183
12418
|
}
|
|
12184
12419
|
return null;
|
|
12185
12420
|
}
|
|
12186
|
-
getAllMessageRows(
|
|
12421
|
+
getAllMessageRows(aiChatId) {
|
|
12187
12422
|
return this.getDb().prepare(
|
|
12188
|
-
`SELECT id,
|
|
12423
|
+
`SELECT id, ai_chat_id as aiChatId, role, content, timestamp,
|
|
12189
12424
|
parent_id as parentId, sibling_group_id as siblingGroupId, branch_index as branchIndex,
|
|
12190
12425
|
data_keywords as dataKeywords, data_message_count as dataMessageCount,
|
|
12191
12426
|
content_blocks as contentBlocks, token_usage as tokenUsage
|
|
12192
|
-
FROM ai_message WHERE
|
|
12193
|
-
).all(
|
|
12427
|
+
FROM ai_message WHERE ai_chat_id = ? ORDER BY timestamp ASC, id ASC`
|
|
12428
|
+
).all(aiChatId);
|
|
12194
12429
|
}
|
|
12195
|
-
getActivePathRows(
|
|
12430
|
+
getActivePathRows(aiChatId, leafMessageId) {
|
|
12196
12431
|
if (leafMessageId === null) return [];
|
|
12197
|
-
const allRows = this.getAllMessageRows(
|
|
12432
|
+
const allRows = this.getAllMessageRows(aiChatId);
|
|
12198
12433
|
if (allRows.length === 0) return [];
|
|
12199
12434
|
const rowMap = new Map(allRows.map((row) => [row.id, row]));
|
|
12200
|
-
let currentId = leafMessageId ?? this.getActiveMessageId(
|
|
12201
|
-
const
|
|
12435
|
+
let currentId = leafMessageId ?? this.getActiveMessageId(aiChatId);
|
|
12436
|
+
const path36 = [];
|
|
12202
12437
|
const seen = /* @__PURE__ */ new Set();
|
|
12203
12438
|
while (currentId && !seen.has(currentId)) {
|
|
12204
12439
|
seen.add(currentId);
|
|
12205
12440
|
const row = rowMap.get(currentId);
|
|
12206
12441
|
if (!row) break;
|
|
12207
|
-
|
|
12442
|
+
path36.push(row);
|
|
12208
12443
|
currentId = row.parentId;
|
|
12209
12444
|
}
|
|
12210
|
-
return
|
|
12445
|
+
return path36.length > 0 ? path36.reverse() : allRows;
|
|
12211
12446
|
}
|
|
12212
12447
|
// ==================== 生命周期 ====================
|
|
12213
12448
|
close() {
|
|
@@ -12263,21 +12498,21 @@ var AIConversationManager = class {
|
|
|
12263
12498
|
}
|
|
12264
12499
|
}
|
|
12265
12500
|
// ==================== 对话管理 ====================
|
|
12266
|
-
|
|
12501
|
+
createAIChat(sessionId, title, assistantId) {
|
|
12267
12502
|
const db = this.getDb();
|
|
12268
12503
|
const now = Math.floor(Date.now() / 1e3);
|
|
12269
12504
|
const id = this.generateId("conv");
|
|
12270
12505
|
db.prepare(
|
|
12271
|
-
`INSERT INTO
|
|
12506
|
+
`INSERT INTO ai_chat (id, session_id, title, assistant_id, created_at, updated_at)
|
|
12272
12507
|
VALUES (?, ?, ?, ?, ?, ?)`
|
|
12273
12508
|
).run(id, sessionId, title || null, assistantId, now, now);
|
|
12274
12509
|
return { id, sessionId, title: title || null, assistantId, activeMessageId: null, createdAt: now, updatedAt: now };
|
|
12275
12510
|
}
|
|
12276
|
-
|
|
12511
|
+
getAIChatCountsBySession() {
|
|
12277
12512
|
const result = /* @__PURE__ */ new Map();
|
|
12278
12513
|
try {
|
|
12279
12514
|
const db = this.getDb();
|
|
12280
|
-
const rows = db.prepare("SELECT session_id, COUNT(*) as count FROM
|
|
12515
|
+
const rows = db.prepare("SELECT session_id, COUNT(*) as count FROM ai_chat GROUP BY session_id").all();
|
|
12281
12516
|
for (const row of rows) {
|
|
12282
12517
|
result.set(row.session_id, row.count);
|
|
12283
12518
|
}
|
|
@@ -12285,58 +12520,58 @@ var AIConversationManager = class {
|
|
|
12285
12520
|
}
|
|
12286
12521
|
return result;
|
|
12287
12522
|
}
|
|
12288
|
-
|
|
12523
|
+
getAIChats(sessionId) {
|
|
12289
12524
|
const db = this.getDb();
|
|
12290
12525
|
return db.prepare(
|
|
12291
12526
|
`SELECT id, session_id as sessionId, title, assistant_id as assistantId,
|
|
12292
12527
|
active_message_id as activeMessageId,
|
|
12293
12528
|
created_at as createdAt, updated_at as updatedAt
|
|
12294
|
-
FROM
|
|
12529
|
+
FROM ai_chat WHERE session_id = ? ORDER BY updated_at DESC`
|
|
12295
12530
|
).all(sessionId);
|
|
12296
12531
|
}
|
|
12297
|
-
|
|
12532
|
+
getAIChat(aiChatId) {
|
|
12298
12533
|
const db = this.getDb();
|
|
12299
12534
|
const row = db.prepare(
|
|
12300
12535
|
`SELECT id, session_id as sessionId, title, assistant_id as assistantId,
|
|
12301
12536
|
active_message_id as activeMessageId,
|
|
12302
12537
|
created_at as createdAt, updated_at as updatedAt
|
|
12303
|
-
FROM
|
|
12304
|
-
).get(
|
|
12538
|
+
FROM ai_chat WHERE id = ?`
|
|
12539
|
+
).get(aiChatId);
|
|
12305
12540
|
return row || null;
|
|
12306
12541
|
}
|
|
12307
|
-
|
|
12542
|
+
updateAIChatTitle(aiChatId, title) {
|
|
12308
12543
|
const db = this.getDb();
|
|
12309
12544
|
const now = Math.floor(Date.now() / 1e3);
|
|
12310
|
-
const result = db.prepare("UPDATE
|
|
12545
|
+
const result = db.prepare("UPDATE ai_chat SET title = ?, updated_at = ? WHERE id = ?").run(title, now, aiChatId);
|
|
12311
12546
|
return result.changes > 0;
|
|
12312
12547
|
}
|
|
12313
|
-
|
|
12548
|
+
deleteAIChat(aiChatId) {
|
|
12314
12549
|
const db = this.getDb();
|
|
12315
|
-
db.prepare("DELETE FROM ai_message WHERE
|
|
12316
|
-
const result = db.prepare("DELETE FROM
|
|
12550
|
+
db.prepare("DELETE FROM ai_message WHERE ai_chat_id = ?").run(aiChatId);
|
|
12551
|
+
const result = db.prepare("DELETE FROM ai_chat WHERE id = ?").run(aiChatId);
|
|
12317
12552
|
return result.changes > 0;
|
|
12318
12553
|
}
|
|
12319
12554
|
// ==================== 消息管理 ====================
|
|
12320
|
-
addMessage(
|
|
12555
|
+
addMessage(aiChatId, role, content, dataKeywords, dataMessageCount, contentBlocks, tokenUsage) {
|
|
12321
12556
|
const db = this.getDb();
|
|
12322
12557
|
const now = Math.floor(Date.now() / 1e3);
|
|
12323
12558
|
const id = this.generateId("msg");
|
|
12324
|
-
const parentId = this.getActiveMessageId(
|
|
12559
|
+
const parentId = this.getActiveMessageId(aiChatId);
|
|
12325
12560
|
const siblingGroupId = id;
|
|
12326
12561
|
const branchIndex = 0;
|
|
12327
|
-
const pendingDebug = role === "assistant" ? this.pendingDebugContextMap.get(
|
|
12562
|
+
const pendingDebug = role === "assistant" ? this.pendingDebugContextMap.get(aiChatId) : void 0;
|
|
12328
12563
|
if (pendingDebug) {
|
|
12329
|
-
this.pendingDebugContextMap.delete(
|
|
12564
|
+
this.pendingDebugContextMap.delete(aiChatId);
|
|
12330
12565
|
}
|
|
12331
12566
|
db.prepare(
|
|
12332
12567
|
`INSERT INTO ai_message (
|
|
12333
|
-
id,
|
|
12568
|
+
id, ai_chat_id, role, content, timestamp, data_keywords, data_message_count,
|
|
12334
12569
|
content_blocks, token_usage, debug_context, parent_id, sibling_group_id, branch_index
|
|
12335
12570
|
)
|
|
12336
12571
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
12337
12572
|
).run(
|
|
12338
12573
|
id,
|
|
12339
|
-
|
|
12574
|
+
aiChatId,
|
|
12340
12575
|
role,
|
|
12341
12576
|
content,
|
|
12342
12577
|
now,
|
|
@@ -12349,14 +12584,14 @@ var AIConversationManager = class {
|
|
|
12349
12584
|
siblingGroupId,
|
|
12350
12585
|
branchIndex
|
|
12351
12586
|
);
|
|
12352
|
-
db.prepare("UPDATE
|
|
12587
|
+
db.prepare("UPDATE ai_chat SET active_message_id = ?, updated_at = ? WHERE id = ?").run(
|
|
12353
12588
|
id,
|
|
12354
12589
|
now,
|
|
12355
|
-
|
|
12590
|
+
aiChatId
|
|
12356
12591
|
);
|
|
12357
12592
|
return {
|
|
12358
12593
|
id,
|
|
12359
|
-
|
|
12594
|
+
aiChatId,
|
|
12360
12595
|
role,
|
|
12361
12596
|
content,
|
|
12362
12597
|
timestamp: now,
|
|
@@ -12367,21 +12602,21 @@ var AIConversationManager = class {
|
|
|
12367
12602
|
tokenUsage
|
|
12368
12603
|
};
|
|
12369
12604
|
}
|
|
12370
|
-
getMessages(
|
|
12371
|
-
return this.getActivePathRows(
|
|
12605
|
+
getMessages(aiChatId) {
|
|
12606
|
+
return this.getActivePathRows(aiChatId).map((row) => this.parseMessageRow(row));
|
|
12372
12607
|
}
|
|
12373
12608
|
deleteMessage(messageId) {
|
|
12374
12609
|
const db = this.getDb();
|
|
12375
12610
|
const result = db.prepare("DELETE FROM ai_message WHERE id = ?").run(messageId);
|
|
12376
12611
|
return result.changes > 0;
|
|
12377
12612
|
}
|
|
12378
|
-
deleteMessagesFrom(
|
|
12613
|
+
deleteMessagesFrom(aiChatId, messageId) {
|
|
12379
12614
|
const db = this.getDb();
|
|
12380
12615
|
const target = this.getMessageRow(messageId);
|
|
12381
|
-
if (!target || target.
|
|
12382
|
-
throw new Error("Message not found in
|
|
12616
|
+
if (!target || target.aiChatId !== aiChatId) {
|
|
12617
|
+
throw new Error("Message not found in AI chat");
|
|
12383
12618
|
}
|
|
12384
|
-
const activePath = this.getActivePathRows(
|
|
12619
|
+
const activePath = this.getActivePathRows(aiChatId);
|
|
12385
12620
|
const targetIndex = activePath.findIndex((row) => row.id === messageId);
|
|
12386
12621
|
if (targetIndex < 0) {
|
|
12387
12622
|
throw new Error("Message not on active path");
|
|
@@ -12391,19 +12626,19 @@ var AIConversationManager = class {
|
|
|
12391
12626
|
db.prepare(`DELETE FROM ai_message WHERE id IN (${placeholders})`).run(...idsToDelete);
|
|
12392
12627
|
const newLeafId = targetIndex > 0 ? activePath[targetIndex - 1].id : null;
|
|
12393
12628
|
const now = Math.floor(Date.now() / 1e3);
|
|
12394
|
-
db.prepare("UPDATE
|
|
12629
|
+
db.prepare("UPDATE ai_chat SET active_message_id = ?, updated_at = ? WHERE id = ?").run(
|
|
12395
12630
|
newLeafId,
|
|
12396
12631
|
now,
|
|
12397
|
-
|
|
12632
|
+
aiChatId
|
|
12398
12633
|
);
|
|
12399
12634
|
}
|
|
12400
|
-
|
|
12635
|
+
forkAIChat(sourceAIChatId, upToMessageId, title) {
|
|
12401
12636
|
const db = this.getDb();
|
|
12402
|
-
const source = this.
|
|
12637
|
+
const source = this.getAIChat(sourceAIChatId);
|
|
12403
12638
|
if (!source) {
|
|
12404
|
-
throw new Error("Source
|
|
12639
|
+
throw new Error("Source AI chat not found");
|
|
12405
12640
|
}
|
|
12406
|
-
const activePath = this.getActivePathRows(
|
|
12641
|
+
const activePath = this.getActivePathRows(sourceAIChatId);
|
|
12407
12642
|
const cutIndex = activePath.findIndex((row) => row.id === upToMessageId);
|
|
12408
12643
|
if (cutIndex < 0) {
|
|
12409
12644
|
throw new Error("Message not on active path");
|
|
@@ -12413,7 +12648,7 @@ var AIConversationManager = class {
|
|
|
12413
12648
|
const newConvId = this.generateId("conv");
|
|
12414
12649
|
const forkTitle = title || `${source.title || "Untitled"} (fork)`;
|
|
12415
12650
|
db.prepare(
|
|
12416
|
-
`INSERT INTO
|
|
12651
|
+
`INSERT INTO ai_chat (id, session_id, title, assistant_id, active_message_id, created_at, updated_at)
|
|
12417
12652
|
VALUES (?, ?, ?, ?, NULL, ?, ?)`
|
|
12418
12653
|
).run(newConvId, source.sessionId, forkTitle, source.assistantId, now, now);
|
|
12419
12654
|
const idMap = /* @__PURE__ */ new Map();
|
|
@@ -12424,7 +12659,7 @@ var AIConversationManager = class {
|
|
|
12424
12659
|
const newParentId = row.parentId ? idMap.get(row.parentId) ?? null : null;
|
|
12425
12660
|
db.prepare(
|
|
12426
12661
|
`INSERT INTO ai_message (
|
|
12427
|
-
id,
|
|
12662
|
+
id, ai_chat_id, role, content, timestamp, data_keywords, data_message_count,
|
|
12428
12663
|
content_blocks, token_usage, debug_context, parent_id, sibling_group_id, branch_index
|
|
12429
12664
|
)
|
|
12430
12665
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, 0)`
|
|
@@ -12444,7 +12679,7 @@ var AIConversationManager = class {
|
|
|
12444
12679
|
lastNewId = newMsgId;
|
|
12445
12680
|
}
|
|
12446
12681
|
if (lastNewId) {
|
|
12447
|
-
db.prepare("UPDATE
|
|
12682
|
+
db.prepare("UPDATE ai_chat SET active_message_id = ? WHERE id = ?").run(lastNewId, newConvId);
|
|
12448
12683
|
}
|
|
12449
12684
|
return {
|
|
12450
12685
|
id: newConvId,
|
|
@@ -12461,46 +12696,46 @@ var AIConversationManager = class {
|
|
|
12461
12696
|
const result = db.prepare("UPDATE ai_message SET content = ? WHERE id = ?").run(newContent, messageId);
|
|
12462
12697
|
if (result.changes === 0) throw new Error("Message not found");
|
|
12463
12698
|
}
|
|
12464
|
-
deleteAndRelinkMessage(
|
|
12699
|
+
deleteAndRelinkMessage(aiChatId, messageId) {
|
|
12465
12700
|
const db = this.getDb();
|
|
12466
12701
|
const target = this.getMessageRow(messageId);
|
|
12467
|
-
if (!target || target.
|
|
12468
|
-
throw new Error("Message not found in
|
|
12702
|
+
if (!target || target.aiChatId !== aiChatId) {
|
|
12703
|
+
throw new Error("Message not found in AI chat");
|
|
12469
12704
|
}
|
|
12470
|
-
db.prepare("UPDATE ai_message SET parent_id = ? WHERE parent_id = ? AND
|
|
12705
|
+
db.prepare("UPDATE ai_message SET parent_id = ? WHERE parent_id = ? AND ai_chat_id = ?").run(
|
|
12471
12706
|
target.parentId,
|
|
12472
12707
|
messageId,
|
|
12473
|
-
|
|
12708
|
+
aiChatId
|
|
12474
12709
|
);
|
|
12475
|
-
const conv = this.
|
|
12710
|
+
const conv = this.getAIChat(aiChatId);
|
|
12476
12711
|
if (conv?.activeMessageId === messageId) {
|
|
12477
12712
|
const now = Math.floor(Date.now() / 1e3);
|
|
12478
|
-
db.prepare("UPDATE
|
|
12713
|
+
db.prepare("UPDATE ai_chat SET active_message_id = ?, updated_at = ? WHERE id = ?").run(
|
|
12479
12714
|
target.parentId,
|
|
12480
12715
|
now,
|
|
12481
|
-
|
|
12716
|
+
aiChatId
|
|
12482
12717
|
);
|
|
12483
12718
|
}
|
|
12484
12719
|
db.prepare("DELETE FROM ai_message WHERE id = ?").run(messageId);
|
|
12485
12720
|
}
|
|
12486
|
-
insertMessageAfter(
|
|
12721
|
+
insertMessageAfter(aiChatId, afterMessageId, role, content, contentBlocks, tokenUsage) {
|
|
12487
12722
|
const db = this.getDb();
|
|
12488
12723
|
const now = Math.floor(Date.now() / 1e3);
|
|
12489
12724
|
const id = this.generateId("msg");
|
|
12490
|
-
const pendingDebug = role === "assistant" ? this.pendingDebugContextMap.get(
|
|
12725
|
+
const pendingDebug = role === "assistant" ? this.pendingDebugContextMap.get(aiChatId) : void 0;
|
|
12491
12726
|
if (pendingDebug) {
|
|
12492
|
-
this.pendingDebugContextMap.delete(
|
|
12727
|
+
this.pendingDebugContextMap.delete(aiChatId);
|
|
12493
12728
|
}
|
|
12494
|
-
const childRow = db.prepare("SELECT id FROM ai_message WHERE parent_id = ? AND
|
|
12729
|
+
const childRow = db.prepare("SELECT id FROM ai_message WHERE parent_id = ? AND ai_chat_id = ? LIMIT 1").get(afterMessageId, aiChatId);
|
|
12495
12730
|
db.prepare(
|
|
12496
12731
|
`INSERT INTO ai_message (
|
|
12497
|
-
id,
|
|
12732
|
+
id, ai_chat_id, role, content, timestamp, data_keywords, data_message_count,
|
|
12498
12733
|
content_blocks, token_usage, debug_context, parent_id, sibling_group_id, branch_index
|
|
12499
12734
|
)
|
|
12500
12735
|
VALUES (?, ?, ?, ?, ?, NULL, NULL, ?, ?, ?, ?, ?, 0)`
|
|
12501
12736
|
).run(
|
|
12502
12737
|
id,
|
|
12503
|
-
|
|
12738
|
+
aiChatId,
|
|
12504
12739
|
role,
|
|
12505
12740
|
content,
|
|
12506
12741
|
now,
|
|
@@ -12512,17 +12747,17 @@ var AIConversationManager = class {
|
|
|
12512
12747
|
);
|
|
12513
12748
|
if (childRow) {
|
|
12514
12749
|
db.prepare("UPDATE ai_message SET parent_id = ? WHERE id = ?").run(id, childRow.id);
|
|
12515
|
-
db.prepare("UPDATE
|
|
12750
|
+
db.prepare("UPDATE ai_chat SET updated_at = ? WHERE id = ?").run(now, aiChatId);
|
|
12516
12751
|
} else {
|
|
12517
|
-
db.prepare("UPDATE
|
|
12752
|
+
db.prepare("UPDATE ai_chat SET active_message_id = ?, updated_at = ? WHERE id = ?").run(
|
|
12518
12753
|
id,
|
|
12519
12754
|
now,
|
|
12520
|
-
|
|
12755
|
+
aiChatId
|
|
12521
12756
|
);
|
|
12522
12757
|
}
|
|
12523
12758
|
return {
|
|
12524
12759
|
id,
|
|
12525
|
-
|
|
12760
|
+
aiChatId,
|
|
12526
12761
|
role,
|
|
12527
12762
|
content,
|
|
12528
12763
|
timestamp: now,
|
|
@@ -12531,8 +12766,8 @@ var AIConversationManager = class {
|
|
|
12531
12766
|
tokenUsage
|
|
12532
12767
|
};
|
|
12533
12768
|
}
|
|
12534
|
-
|
|
12535
|
-
const rows = this.getActivePathRows(
|
|
12769
|
+
getAIChatTokenUsage(aiChatId) {
|
|
12770
|
+
const rows = this.getActivePathRows(aiChatId);
|
|
12536
12771
|
const result = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
|
|
12537
12772
|
for (const row of rows) {
|
|
12538
12773
|
if (row.tokenUsage) {
|
|
@@ -12545,8 +12780,8 @@ var AIConversationManager = class {
|
|
|
12545
12780
|
return result;
|
|
12546
12781
|
}
|
|
12547
12782
|
// ==================== Debug context ====================
|
|
12548
|
-
setPendingDebugContext(
|
|
12549
|
-
this.pendingDebugContextMap.set(
|
|
12783
|
+
setPendingDebugContext(aiChatId, debugContext) {
|
|
12784
|
+
this.pendingDebugContextMap.set(aiChatId, debugContext);
|
|
12550
12785
|
}
|
|
12551
12786
|
setDebugContext(messageId, debugContext) {
|
|
12552
12787
|
const db = this.getDb();
|
|
@@ -12558,8 +12793,8 @@ var AIConversationManager = class {
|
|
|
12558
12793
|
return result.changes;
|
|
12559
12794
|
}
|
|
12560
12795
|
// ==================== Agent 专用 ====================
|
|
12561
|
-
getHistoryForAgent(
|
|
12562
|
-
const messages = this.getActivePathRows(
|
|
12796
|
+
getHistoryForAgent(aiChatId, maxMessages, leafMessageId) {
|
|
12797
|
+
const messages = this.getActivePathRows(aiChatId, leafMessageId).map((row) => this.parseMessageRow(row));
|
|
12563
12798
|
const validMessages = messages.filter(
|
|
12564
12799
|
(m) => (m.role === "user" || m.role === "assistant" || m.role === "summary") && m.content?.trim()
|
|
12565
12800
|
);
|
|
@@ -12577,8 +12812,8 @@ var AIConversationManager = class {
|
|
|
12577
12812
|
);
|
|
12578
12813
|
const bufferBoundary = metaBlock?.bufferBoundaryTimestamp;
|
|
12579
12814
|
if (!metaBlock) {
|
|
12580
|
-
this.logger.warn("
|
|
12581
|
-
|
|
12815
|
+
this.logger.warn("AIChats", "summary message missing summary_meta; agent context will be summary-only", {
|
|
12816
|
+
aiChatId,
|
|
12582
12817
|
messageId: summaryMsg.id
|
|
12583
12818
|
});
|
|
12584
12819
|
}
|
|
@@ -12601,7 +12836,7 @@ var AIConversationManager = class {
|
|
|
12601
12836
|
return result;
|
|
12602
12837
|
}
|
|
12603
12838
|
// ==================== Summary / 压缩专用 ====================
|
|
12604
|
-
addSummaryMessage(
|
|
12839
|
+
addSummaryMessage(aiChatId, content, meta) {
|
|
12605
12840
|
const contentBlocks = [
|
|
12606
12841
|
{
|
|
12607
12842
|
type: "summary_meta",
|
|
@@ -12609,28 +12844,28 @@ var AIConversationManager = class {
|
|
|
12609
12844
|
compressedMessageCount: meta.compressedMessageCount
|
|
12610
12845
|
}
|
|
12611
12846
|
];
|
|
12612
|
-
return this.addMessage(
|
|
12847
|
+
return this.addMessage(aiChatId, "summary", content, void 0, void 0, contentBlocks);
|
|
12613
12848
|
}
|
|
12614
|
-
getLatestSummary(
|
|
12615
|
-
const row = [...this.getActivePathRows(
|
|
12849
|
+
getLatestSummary(aiChatId) {
|
|
12850
|
+
const row = [...this.getActivePathRows(aiChatId)].reverse().find((message) => message.role === "summary");
|
|
12616
12851
|
return row ? this.parseMessageRow(row) : null;
|
|
12617
12852
|
}
|
|
12618
|
-
getMessagesAfterSummary(
|
|
12619
|
-
return this.getActivePathRows(
|
|
12853
|
+
getMessagesAfterSummary(aiChatId, summaryTimestamp) {
|
|
12854
|
+
return this.getActivePathRows(aiChatId).filter((row) => row.timestamp > summaryTimestamp && (row.role === "user" || row.role === "assistant")).map((row) => ({ role: row.role, content: row.content, timestamp: row.timestamp }));
|
|
12620
12855
|
}
|
|
12621
|
-
getAllUserAssistantMessages(
|
|
12622
|
-
return this.getActivePathRows(
|
|
12856
|
+
getAllUserAssistantMessages(aiChatId) {
|
|
12857
|
+
return this.getActivePathRows(aiChatId).filter((row) => row.role === "user" || row.role === "assistant").map((row) => ({ role: row.role, content: row.content, timestamp: row.timestamp }));
|
|
12623
12858
|
}
|
|
12624
|
-
getMessageCountAfterSummary(
|
|
12625
|
-
const summary = this.getLatestSummary(
|
|
12859
|
+
getMessageCountAfterSummary(aiChatId) {
|
|
12860
|
+
const summary = this.getLatestSummary(aiChatId);
|
|
12626
12861
|
if (!summary) {
|
|
12627
|
-
return this.getActivePathRows(
|
|
12862
|
+
return this.getActivePathRows(aiChatId).filter((row) => row.role === "user" || row.role === "assistant").length;
|
|
12628
12863
|
}
|
|
12629
12864
|
const metaBlock = summary.contentBlocks?.find(
|
|
12630
12865
|
(b) => b.type === "summary_meta"
|
|
12631
12866
|
);
|
|
12632
12867
|
const boundary = metaBlock?.bufferBoundaryTimestamp ?? summary.timestamp;
|
|
12633
|
-
return this.getActivePathRows(
|
|
12868
|
+
return this.getActivePathRows(aiChatId).filter(
|
|
12634
12869
|
(row) => row.timestamp >= boundary && (row.role === "user" || row.role === "assistant")
|
|
12635
12870
|
).length;
|
|
12636
12871
|
}
|
|
@@ -13098,7 +13333,7 @@ function parseAssistantFile(content, filePath) {
|
|
|
13098
13333
|
name,
|
|
13099
13334
|
systemPrompt: body.trim(),
|
|
13100
13335
|
presetQuestions: parseStringArray(fm.presetQuestions),
|
|
13101
|
-
allowedBuiltinTools: parseStringArray(fm.allowedBuiltinTools),
|
|
13336
|
+
allowedBuiltinTools: normalizeBuiltinToolNames(parseStringArray(fm.allowedBuiltinTools)),
|
|
13102
13337
|
builtinId: typeof fm.builtinId === "string" ? fm.builtinId : void 0,
|
|
13103
13338
|
applicableChatTypes: parseChatTypes(fm.applicableChatTypes),
|
|
13104
13339
|
supportedLocales: parseStringArray(fm.supportedLocales)
|
|
@@ -13115,7 +13350,7 @@ function serializeAssistant(config) {
|
|
|
13115
13350
|
if (config.builtinId) fm.builtinId = config.builtinId;
|
|
13116
13351
|
if (config.applicableChatTypes?.length) fm.applicableChatTypes = config.applicableChatTypes;
|
|
13117
13352
|
if (config.supportedLocales?.length) fm.supportedLocales = config.supportedLocales;
|
|
13118
|
-
if (config.allowedBuiltinTools?.length) fm.allowedBuiltinTools = config.allowedBuiltinTools;
|
|
13353
|
+
if (config.allowedBuiltinTools?.length) fm.allowedBuiltinTools = normalizeBuiltinToolNames(config.allowedBuiltinTools);
|
|
13119
13354
|
if (config.presetQuestions?.length) fm.presetQuestions = config.presetQuestions;
|
|
13120
13355
|
return matter.stringify(`
|
|
13121
13356
|
${config.systemPrompt}
|
|
@@ -13169,8 +13404,8 @@ var AssistantManager = class {
|
|
|
13169
13404
|
}
|
|
13170
13405
|
// ==================== Init ====================
|
|
13171
13406
|
init() {
|
|
13172
|
-
const { fs:
|
|
13173
|
-
|
|
13407
|
+
const { fs: fs40, assistantsDir } = this.deps;
|
|
13408
|
+
fs40.ensureDir(assistantsDir);
|
|
13174
13409
|
const generalCreated = this.ensureGeneralAssistants();
|
|
13175
13410
|
this.loadAll();
|
|
13176
13411
|
this.initialized = true;
|
|
@@ -13181,26 +13416,26 @@ var AssistantManager = class {
|
|
|
13181
13416
|
return { total: this.cache.size, generalCreated };
|
|
13182
13417
|
}
|
|
13183
13418
|
ensureGeneralAssistants() {
|
|
13184
|
-
const { fs:
|
|
13419
|
+
const { fs: fs40, assistantsDir } = this.deps;
|
|
13185
13420
|
let anyCreated = false;
|
|
13186
13421
|
for (const id of this.generalIds) {
|
|
13187
13422
|
const config = this.getBuiltinConfig(id);
|
|
13188
13423
|
if (!config) continue;
|
|
13189
|
-
const filePath =
|
|
13190
|
-
if (
|
|
13191
|
-
|
|
13424
|
+
const filePath = fs40.joinPath(assistantsDir, `${id}.md`);
|
|
13425
|
+
if (fs40.fileExists(filePath)) continue;
|
|
13426
|
+
fs40.writeFile(filePath, serializeAssistant({ ...config, builtinId: config.id }));
|
|
13192
13427
|
anyCreated = true;
|
|
13193
13428
|
}
|
|
13194
13429
|
return anyCreated;
|
|
13195
13430
|
}
|
|
13196
13431
|
loadAll() {
|
|
13197
|
-
const { fs:
|
|
13432
|
+
const { fs: fs40, assistantsDir } = this.deps;
|
|
13198
13433
|
this.cache.clear();
|
|
13199
|
-
const files =
|
|
13434
|
+
const files = fs40.listFiles(assistantsDir, ".md");
|
|
13200
13435
|
for (const file of files) {
|
|
13201
13436
|
try {
|
|
13202
|
-
const filePath =
|
|
13203
|
-
const content =
|
|
13437
|
+
const filePath = fs40.joinPath(assistantsDir, file);
|
|
13438
|
+
const content = fs40.readFile(filePath);
|
|
13204
13439
|
const config = parseAssistantFile(content, filePath);
|
|
13205
13440
|
if (config) {
|
|
13206
13441
|
this.cache.set(config.id, config);
|
|
@@ -13394,93 +13629,43 @@ function countMessagesTokens(messages, systemPrompt) {
|
|
|
13394
13629
|
// ../../packages/node-runtime/src/ai/skill-manager.ts
|
|
13395
13630
|
import * as fs30 from "fs";
|
|
13396
13631
|
import * as path27 from "path";
|
|
13397
|
-
|
|
13632
|
+
|
|
13633
|
+
// ../../packages/node-runtime/src/ai/skill-menu.ts
|
|
13398
13634
|
var MAX_SKILL_MENU_ITEMS = 15;
|
|
13399
|
-
var
|
|
13400
|
-
info: () => {
|
|
13401
|
-
},
|
|
13402
|
-
warn: () => {
|
|
13403
|
-
}
|
|
13404
|
-
};
|
|
13405
|
-
var SkillManager = class {
|
|
13406
|
-
skills = /* @__PURE__ */ new Map();
|
|
13407
|
-
initialized = false;
|
|
13408
|
-
skillsDir;
|
|
13409
|
-
logger;
|
|
13410
|
-
constructor(aiDataDir, logger) {
|
|
13411
|
-
this.skillsDir = path27.join(aiDataDir, SKILLS_DIR_NAME);
|
|
13412
|
-
this.logger = logger ?? defaultLogger2;
|
|
13413
|
-
}
|
|
13414
|
-
init() {
|
|
13415
|
-
this.loadAll();
|
|
13416
|
-
this.initialized = true;
|
|
13417
|
-
this.logger.info(`SkillManager initialized: ${this.skills.size} skills`);
|
|
13418
|
-
return { total: this.skills.size };
|
|
13419
|
-
}
|
|
13420
|
-
getSkillConfig(id) {
|
|
13421
|
-
this.ensureInitialized();
|
|
13422
|
-
return this.skills.get(id) ?? null;
|
|
13423
|
-
}
|
|
13424
|
-
getAllSkills() {
|
|
13425
|
-
this.ensureInitialized();
|
|
13426
|
-
return Array.from(this.skills.values()).map((def) => ({
|
|
13427
|
-
id: def.id,
|
|
13428
|
-
name: def.name,
|
|
13429
|
-
description: def.description,
|
|
13430
|
-
tags: def.tags,
|
|
13431
|
-
chatScope: def.chatScope,
|
|
13432
|
-
tools: def.tools,
|
|
13433
|
-
builtinId: def.builtinId
|
|
13434
|
-
}));
|
|
13435
|
-
}
|
|
13436
|
-
/**
|
|
13437
|
-
* 构建 AI 自选技能菜单文本
|
|
13438
|
-
* 只包含与当前 chatType + 助手工具权限兼容的技能
|
|
13439
|
-
*/
|
|
13440
|
-
getSkillMenu(chatType, allowedTools) {
|
|
13441
|
-
this.ensureInitialized();
|
|
13442
|
-
const compatible = Array.from(this.skills.values()).filter((skill) => {
|
|
13443
|
-
if (skill.chatScope !== "all" && skill.chatScope !== chatType) return false;
|
|
13444
|
-
if (skill.tools.length > 0 && allowedTools && allowedTools.length > 0) {
|
|
13445
|
-
const allCovered = skill.tools.every((t2) => allowedTools.includes(t2));
|
|
13446
|
-
if (!allCovered) return false;
|
|
13447
|
-
}
|
|
13448
|
-
return true;
|
|
13449
|
-
});
|
|
13450
|
-
if (compatible.length === 0) return null;
|
|
13451
|
-
const items = compatible.slice(0, MAX_SKILL_MENU_ITEMS);
|
|
13452
|
-
const lines = items.map((s) => `- ${s.id}: ${s.name} \u2014 ${s.description}`);
|
|
13453
|
-
return `## \u53EF\u7528\u6280\u80FD
|
|
13635
|
+
var SKILL_MENU_HEADER = `## \u53EF\u7528\u6280\u80FD
|
|
13454
13636
|
\u4EE5\u4E0B\u662F\u4F60\u53EF\u4EE5\u4F7F\u7528\u7684\u5206\u6790\u6280\u80FD\u3002\u5F53\u4F60\u5224\u65AD\u7528\u6237\u7684\u95EE\u9898\u9002\u5408\u4F7F\u7528\u67D0\u4E2A\u6280\u80FD\u65F6\uFF0C
|
|
13455
|
-
\u8BF7\u8C03\u7528 activate_skill \u5DE5\u5177\u6FC0\u6D3B\u5B83\uFF0C\u7136\u540E\u6309\u7167\u8FD4\u56DE\u7684\u6307\u5BFC\u5B8C\u6210\u4EFB\u52A1\u3002
|
|
13637
|
+
\u8BF7\u8C03\u7528 activate_skill \u5DE5\u5177\u6FC0\u6D3B\u5B83\uFF0C\u7136\u540E\u6309\u7167\u8FD4\u56DE\u7684\u6307\u5BFC\u5B8C\u6210\u4EFB\u52A1\u3002`;
|
|
13638
|
+
var SKILL_MENU_CLOSING = "\u5982\u679C\u7528\u6237\u7684\u95EE\u9898\u4E0D\u9700\u8981\u4F7F\u7528\u6280\u80FD\uFF0C\u76F4\u63A5\u56DE\u7B54\u5373\u53EF\u3002";
|
|
13639
|
+
var SKILL_MENU_CLOSING_BLOCK = `
|
|
13456
13640
|
|
|
13457
|
-
${
|
|
13641
|
+
${SKILL_MENU_CLOSING}`;
|
|
13642
|
+
function formatSkillMenuLine(item) {
|
|
13643
|
+
const guidanceSuffix = item.guidance ? `. ${item.guidance}` : "";
|
|
13644
|
+
return `- ${item.id}: ${item.name} \u2014 ${item.description}${guidanceSuffix}`;
|
|
13645
|
+
}
|
|
13646
|
+
function buildSkillMenuText(lines) {
|
|
13647
|
+
const visibleLines = normalizeSkillMenuLines(lines);
|
|
13648
|
+
if (visibleLines.length === 0) return null;
|
|
13649
|
+
return `${SKILL_MENU_HEADER}
|
|
13458
13650
|
|
|
13459
|
-
\
|
|
13460
|
-
|
|
13461
|
-
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
|
|
13465
|
-
|
|
13466
|
-
|
|
13467
|
-
|
|
13468
|
-
|
|
13469
|
-
|
|
13470
|
-
|
|
13471
|
-
try {
|
|
13472
|
-
const filePath = path27.join(this.skillsDir, file);
|
|
13473
|
-
const content = fs30.readFileSync(filePath, "utf-8");
|
|
13474
|
-
const def = parseSkillFile(content, filePath);
|
|
13475
|
-
if (def) {
|
|
13476
|
-
this.skills.set(def.id, def);
|
|
13477
|
-
}
|
|
13478
|
-
} catch (error) {
|
|
13479
|
-
this.logger.warn(`Failed to load skill: ${file}`, { error: String(error) });
|
|
13480
|
-
}
|
|
13481
|
-
}
|
|
13651
|
+
${visibleLines.join("\n")}
|
|
13652
|
+
|
|
13653
|
+
${SKILL_MENU_CLOSING}`;
|
|
13654
|
+
}
|
|
13655
|
+
function appendSkillMenuLines(baseMenu, lines) {
|
|
13656
|
+
const visibleLines = normalizeSkillMenuLines(lines);
|
|
13657
|
+
if (visibleLines.length === 0) return baseMenu ?? null;
|
|
13658
|
+
if (!baseMenu) return buildSkillMenuText(visibleLines);
|
|
13659
|
+
const insertion = `
|
|
13660
|
+
${visibleLines.join("\n")}`;
|
|
13661
|
+
if (!baseMenu.includes(SKILL_MENU_CLOSING_BLOCK)) {
|
|
13662
|
+
return `${baseMenu}${insertion}`;
|
|
13482
13663
|
}
|
|
13483
|
-
};
|
|
13664
|
+
return baseMenu.replace(SKILL_MENU_CLOSING_BLOCK, `${insertion}${SKILL_MENU_CLOSING_BLOCK}`);
|
|
13665
|
+
}
|
|
13666
|
+
function normalizeSkillMenuLines(lines) {
|
|
13667
|
+
return lines.map((line) => line.trim()).filter(Boolean);
|
|
13668
|
+
}
|
|
13484
13669
|
|
|
13485
13670
|
// ../../packages/node-runtime/src/ai/skill-manager-core.ts
|
|
13486
13671
|
function toSummary2(def) {
|
|
@@ -13511,7 +13696,6 @@ function simpleHash(content) {
|
|
|
13511
13696
|
}
|
|
13512
13697
|
return hash.toString(36);
|
|
13513
13698
|
}
|
|
13514
|
-
var MAX_SKILL_MENU_ITEMS2 = 15;
|
|
13515
13699
|
var SkillManagerCore = class {
|
|
13516
13700
|
deps;
|
|
13517
13701
|
builtinDefs = /* @__PURE__ */ new Map();
|
|
@@ -13537,21 +13721,21 @@ var SkillManagerCore = class {
|
|
|
13537
13721
|
}
|
|
13538
13722
|
// ==================== Init ====================
|
|
13539
13723
|
init() {
|
|
13540
|
-
const { fs:
|
|
13541
|
-
|
|
13724
|
+
const { fs: fs40, skillsDir } = this.deps;
|
|
13725
|
+
fs40.ensureDir(skillsDir);
|
|
13542
13726
|
this.loadAll();
|
|
13543
13727
|
this.initialized = true;
|
|
13544
13728
|
this.deps.logger?.info("SkillManager", "Initialized", { total: this.cache.size });
|
|
13545
13729
|
return { total: this.cache.size };
|
|
13546
13730
|
}
|
|
13547
13731
|
loadAll() {
|
|
13548
|
-
const { fs:
|
|
13732
|
+
const { fs: fs40, skillsDir } = this.deps;
|
|
13549
13733
|
this.cache.clear();
|
|
13550
|
-
const files =
|
|
13734
|
+
const files = fs40.listFiles(skillsDir, ".md");
|
|
13551
13735
|
for (const file of files) {
|
|
13552
13736
|
try {
|
|
13553
|
-
const filePath =
|
|
13554
|
-
const content =
|
|
13737
|
+
const filePath = fs40.joinPath(skillsDir, file);
|
|
13738
|
+
const content = fs40.readFile(filePath);
|
|
13555
13739
|
const def = parseSkillFile(content, filePath);
|
|
13556
13740
|
if (def) {
|
|
13557
13741
|
this.cache.set(def.id, def);
|
|
@@ -13665,21 +13849,14 @@ var SkillManagerCore = class {
|
|
|
13665
13849
|
this.ensureInitialized();
|
|
13666
13850
|
const compatible = Array.from(this.cache.values()).filter((skill) => {
|
|
13667
13851
|
if (skill.chatScope !== "all" && skill.chatScope !== chatType) return false;
|
|
13668
|
-
if (skill.tools.length > 0 && allowedTools
|
|
13852
|
+
if (skill.tools.length > 0 && allowedTools !== void 0) {
|
|
13669
13853
|
if (!skill.tools.every((t2) => allowedTools.includes(t2))) return false;
|
|
13670
13854
|
}
|
|
13671
13855
|
return true;
|
|
13672
13856
|
});
|
|
13673
13857
|
if (compatible.length === 0) return null;
|
|
13674
|
-
const items = compatible.slice(0,
|
|
13675
|
-
|
|
13676
|
-
return `## \u53EF\u7528\u6280\u80FD
|
|
13677
|
-
\u4EE5\u4E0B\u662F\u4F60\u53EF\u4EE5\u4F7F\u7528\u7684\u5206\u6790\u6280\u80FD\u3002\u5F53\u4F60\u5224\u65AD\u7528\u6237\u7684\u95EE\u9898\u9002\u5408\u4F7F\u7528\u67D0\u4E2A\u6280\u80FD\u65F6\uFF0C
|
|
13678
|
-
\u8BF7\u8C03\u7528 activate_skill \u5DE5\u5177\u6FC0\u6D3B\u5B83\uFF0C\u7136\u540E\u6309\u7167\u8FD4\u56DE\u7684\u6307\u5BFC\u5B8C\u6210\u4EFB\u52A1\u3002
|
|
13679
|
-
|
|
13680
|
-
${lines.join("\n")}
|
|
13681
|
-
|
|
13682
|
-
\u5982\u679C\u7528\u6237\u7684\u95EE\u9898\u4E0D\u9700\u8981\u4F7F\u7528\u6280\u80FD\uFF0C\u76F4\u63A5\u56DE\u7B54\u5373\u53EF\u3002`;
|
|
13858
|
+
const items = compatible.slice(0, MAX_SKILL_MENU_ITEMS);
|
|
13859
|
+
return buildSkillMenuText(items.map(formatSkillMenuLine));
|
|
13683
13860
|
}
|
|
13684
13861
|
// ==================== Internal ====================
|
|
13685
13862
|
findByBuiltinId(builtinId) {
|
|
@@ -13709,6 +13886,80 @@ ${lines.join("\n")}
|
|
|
13709
13886
|
}
|
|
13710
13887
|
};
|
|
13711
13888
|
|
|
13889
|
+
// ../../packages/node-runtime/src/ai/skill-manager.ts
|
|
13890
|
+
var SKILLS_DIR_NAME = "skills";
|
|
13891
|
+
var defaultLogger2 = {
|
|
13892
|
+
info: () => {
|
|
13893
|
+
},
|
|
13894
|
+
warn: () => {
|
|
13895
|
+
}
|
|
13896
|
+
};
|
|
13897
|
+
var nodeFs = {
|
|
13898
|
+
ensureDir(dir) {
|
|
13899
|
+
fs30.mkdirSync(dir, { recursive: true });
|
|
13900
|
+
},
|
|
13901
|
+
listFiles(dir, ext) {
|
|
13902
|
+
if (!fs30.existsSync(dir)) return [];
|
|
13903
|
+
return fs30.readdirSync(dir).filter((file) => file.endsWith(ext));
|
|
13904
|
+
},
|
|
13905
|
+
readFile(filePath) {
|
|
13906
|
+
return fs30.readFileSync(filePath, "utf-8");
|
|
13907
|
+
},
|
|
13908
|
+
writeFile(filePath, content) {
|
|
13909
|
+
fs30.writeFileSync(filePath, content, "utf-8");
|
|
13910
|
+
},
|
|
13911
|
+
deleteFile(filePath) {
|
|
13912
|
+
fs30.unlinkSync(filePath);
|
|
13913
|
+
},
|
|
13914
|
+
fileExists(filePath) {
|
|
13915
|
+
return fs30.existsSync(filePath);
|
|
13916
|
+
},
|
|
13917
|
+
joinPath(...parts) {
|
|
13918
|
+
return path27.join(...parts);
|
|
13919
|
+
}
|
|
13920
|
+
};
|
|
13921
|
+
var SkillManager = class {
|
|
13922
|
+
core;
|
|
13923
|
+
logger;
|
|
13924
|
+
constructor(aiDataDir, logger) {
|
|
13925
|
+
this.logger = logger ?? defaultLogger2;
|
|
13926
|
+
this.core = new SkillManagerCore({
|
|
13927
|
+
fs: nodeFs,
|
|
13928
|
+
skillsDir: path27.join(aiDataDir, SKILLS_DIR_NAME),
|
|
13929
|
+
builtinRawSkills: [],
|
|
13930
|
+
logger: {
|
|
13931
|
+
info: () => {
|
|
13932
|
+
},
|
|
13933
|
+
warn: (_category, message, data) => this.logger.warn(message, toLoggerExtra(data)),
|
|
13934
|
+
error: (_category, message, data) => this.logger.warn(message, toLoggerExtra(data))
|
|
13935
|
+
}
|
|
13936
|
+
});
|
|
13937
|
+
}
|
|
13938
|
+
init() {
|
|
13939
|
+
const result = this.core.init();
|
|
13940
|
+
this.logger.info(`SkillManager initialized: ${result.total} skills`);
|
|
13941
|
+
return result;
|
|
13942
|
+
}
|
|
13943
|
+
getSkillConfig(id) {
|
|
13944
|
+
return this.core.getSkillConfig(id);
|
|
13945
|
+
}
|
|
13946
|
+
getAllSkills() {
|
|
13947
|
+
return this.core.getAllSkills();
|
|
13948
|
+
}
|
|
13949
|
+
/**
|
|
13950
|
+
* 构建 AI 自选技能菜单文本
|
|
13951
|
+
* 只包含与当前 chatType + 助手工具权限兼容的技能
|
|
13952
|
+
*/
|
|
13953
|
+
getSkillMenu(chatType, allowedTools) {
|
|
13954
|
+
return this.core.getSkillMenu(chatType, allowedTools);
|
|
13955
|
+
}
|
|
13956
|
+
};
|
|
13957
|
+
function toLoggerExtra(data) {
|
|
13958
|
+
if (data === void 0) return void 0;
|
|
13959
|
+
if (data && typeof data === "object" && !Array.isArray(data)) return data;
|
|
13960
|
+
return { data };
|
|
13961
|
+
}
|
|
13962
|
+
|
|
13712
13963
|
// ../../packages/node-runtime/src/ai/activate-skill-tool.ts
|
|
13713
13964
|
function createActivateSkillTool(options) {
|
|
13714
13965
|
const { chatType, allowedTools, coreToolNames, getSkillConfig, locale = "zh-CN" } = options;
|
|
@@ -13744,7 +13995,7 @@ function createActivateSkillTool(options) {
|
|
|
13744
13995
|
details: { skillId, found: true, applicable: false }
|
|
13745
13996
|
};
|
|
13746
13997
|
}
|
|
13747
|
-
if (skill.tools.length > 0 && allowedTools
|
|
13998
|
+
if (skill.tools.length > 0 && allowedTools !== void 0) {
|
|
13748
13999
|
const missing = skill.tools.filter((t2) => !(coreToolNames?.has(t2) ?? false) && !allowedTools.includes(t2));
|
|
13749
14000
|
if (missing.length > 0) {
|
|
13750
14001
|
const msg = isZh ? `\u5F53\u524D\u52A9\u624B\u7F3A\u5C11\u8BE5\u6280\u80FD\u6240\u9700\u7684\u5DE5\u5177\uFF1A${missing.join(", ")}` : `Current assistant lacks tools required by this skill: ${missing.join(", ")}`;
|
|
@@ -13763,6 +14014,175 @@ function createActivateSkillTool(options) {
|
|
|
13763
14014
|
};
|
|
13764
14015
|
}
|
|
13765
14016
|
|
|
14017
|
+
// ../../packages/node-runtime/src/ai/chart-runtime.ts
|
|
14018
|
+
var CHART_CAPABILITY_CORE_TOOLS = ["get_schema"];
|
|
14019
|
+
var CHART_CAPABILITY_ANALYSIS_TOOLS = ["render_chart"];
|
|
14020
|
+
var RAW_SQL_TOOL_NAMES = /* @__PURE__ */ new Set(["execute_sql"]);
|
|
14021
|
+
function getChartCapabilityAllowedBuiltinTools(allowedTools) {
|
|
14022
|
+
const baseTools = (allowedTools ?? []).filter((toolName) => !RAW_SQL_TOOL_NAMES.has(toolName));
|
|
14023
|
+
return Array.from(/* @__PURE__ */ new Set([...baseTools, ...CHART_CAPABILITY_ANALYSIS_TOOLS]));
|
|
14024
|
+
}
|
|
14025
|
+
function getAllowedBuiltinToolsForChartAutoSkill(allowedTools) {
|
|
14026
|
+
if (!allowedTools) return void 0;
|
|
14027
|
+
if (allowedTools.length === 0) return [];
|
|
14028
|
+
return Array.from(/* @__PURE__ */ new Set([...allowedTools, ...CHART_CAPABILITY_ANALYSIS_TOOLS]));
|
|
14029
|
+
}
|
|
14030
|
+
function shouldUseChartCapabilityForMessage(message) {
|
|
14031
|
+
const normalized = message.trim().toLowerCase();
|
|
14032
|
+
if (!normalized) return false;
|
|
14033
|
+
return /(?:画|绘制|生成|做|出|展示).{0,8}(?:图|图表)|(?:图表|可视化|饼图|柱状图|条形图|折线图|热力图|趋势图|占比图|分布图|chart|charts|plot|visuali[sz]e|visuali[sz]ation|pie chart|bar chart|line chart|heatmap)/i.test(
|
|
14034
|
+
normalized
|
|
14035
|
+
);
|
|
14036
|
+
}
|
|
14037
|
+
function resolveChartRuntimeForRequest(options) {
|
|
14038
|
+
const locale = options.locale ?? "zh-CN";
|
|
14039
|
+
const isExplicitChartSkill = options.skillId === CHART_CAPABILITY_SKILL_ID;
|
|
14040
|
+
const isAutoChartSkill = options.enableAutoDetection === true && !options.skillId && shouldUseChartCapabilityForMessage(options.userMessage ?? "");
|
|
14041
|
+
if (!isExplicitChartSkill && !isAutoChartSkill) {
|
|
14042
|
+
return { isChartCapability: false };
|
|
14043
|
+
}
|
|
14044
|
+
return {
|
|
14045
|
+
isChartCapability: true,
|
|
14046
|
+
skillDef: { ...getChartCapabilitySkill(locale), chatScope: "all" },
|
|
14047
|
+
allowedBuiltinTools: getChartCapabilityAllowedBuiltinTools(options.assistantAllowedTools)
|
|
14048
|
+
};
|
|
14049
|
+
}
|
|
14050
|
+
function getChartCapabilitySkill(locale = "zh-CN") {
|
|
14051
|
+
const isZh = locale.startsWith("zh");
|
|
14052
|
+
return {
|
|
14053
|
+
id: CHART_CAPABILITY_SKILL_ID,
|
|
14054
|
+
name: isZh ? "\u7ED8\u56FE\u52A9\u624B" : "Chart Assistant",
|
|
14055
|
+
description: isZh ? "\u6309\u672C\u8F6E\u95EE\u9898\u751F\u6210\u7075\u6D3B\u7684\u804A\u5929\u6570\u636E\u56FE\u8868" : "Generate flexible charts for this chat question",
|
|
14056
|
+
tags: [isZh ? "\u56FE\u8868" : "chart"],
|
|
14057
|
+
chatScope: "all",
|
|
14058
|
+
tools: ["render_chart", "get_schema"],
|
|
14059
|
+
prompt: isZh ? ZH_PROMPT : EN_PROMPT,
|
|
14060
|
+
builtinId: CHART_CAPABILITY_SKILL_ID
|
|
14061
|
+
};
|
|
14062
|
+
}
|
|
14063
|
+
function getChartMenuLine(locale) {
|
|
14064
|
+
const skill = getChartCapabilitySkill(locale);
|
|
14065
|
+
const isZh = locale.startsWith("zh");
|
|
14066
|
+
const guidance = isZh ? "\u7528\u6237\u660E\u786E\u8981\u6C42\u56FE\u8868\u3001\u753B\u56FE\u3001\u5360\u6BD4\u3001\u8D8B\u52BF\u3001\u5206\u5E03\u3001\u997C\u56FE\u3001\u67F1\u72B6\u56FE\u3001\u6298\u7EBF\u56FE\u6216\u70ED\u529B\u56FE\u65F6\u4F18\u5148\u6FC0\u6D3B\uFF1B\u4E0D\u8981\u8F93\u51FA Python/JS \u7ED8\u56FE\u4EE3\u7801" : "Activate first when the user explicitly asks for charts, visualization, ratios, trends, distributions, pie, bar, line, or heatmap charts; do not output Python/JS chart code";
|
|
14067
|
+
return formatSkillMenuLine({
|
|
14068
|
+
id: skill.id,
|
|
14069
|
+
name: skill.name,
|
|
14070
|
+
description: skill.description,
|
|
14071
|
+
guidance
|
|
14072
|
+
});
|
|
14073
|
+
}
|
|
14074
|
+
function buildSkillMenuWithBuiltinChart(baseMenu, locale = "zh-CN", allowedTools) {
|
|
14075
|
+
if (allowedTools && !allowedTools.includes(CHART_CAPABILITY_ANALYSIS_TOOLS[0])) return baseMenu ?? null;
|
|
14076
|
+
if (baseMenu?.includes(CHART_CAPABILITY_SKILL_ID)) return baseMenu;
|
|
14077
|
+
const chartLine = getChartMenuLine(locale);
|
|
14078
|
+
return appendSkillMenuLines(baseMenu, [chartLine]) ?? "";
|
|
14079
|
+
}
|
|
14080
|
+
function getSkillConfigWithBuiltinChart(id, locale = "zh-CN", getSkillConfig) {
|
|
14081
|
+
if (id === CHART_CAPABILITY_SKILL_ID) return getChartCapabilitySkill(locale);
|
|
14082
|
+
return getSkillConfig(id);
|
|
14083
|
+
}
|
|
14084
|
+
var ZH_PROMPT = `\u4F60\u662F ChatLab \u7ED8\u56FE\u52A9\u624B\u3002\u672C\u8F6E\u7528\u6237\u5E0C\u671B\u4F60\u5728\u56DE\u7B54\u91CC\u81EA\u7136\u5D4C\u5165\u4E00\u5F20\u6216\u591A\u5F20\u56FE\u8868\u3002
|
|
14085
|
+
|
|
14086
|
+
\u4F60\u5FC5\u987B\u901A\u8FC7 render_chart \u5DE5\u5177\u751F\u6210\u56FE\u8868\u3002\u4E0D\u8981\u8F93\u51FA HTML\u3001JavaScript\u3001SVG\u3001Canvas\u3001ECharts option \u6216\u4EFB\u4F55\u6E32\u67D3\u4EE3\u7801\u3002
|
|
14087
|
+
|
|
14088
|
+
\u786C\u6027\u89C4\u5219\uFF1A
|
|
14089
|
+
1. \u7B2C\u4E00\u6B21\u5199 SQL \u524D\u5FC5\u987B\u5148\u8C03\u7528 get_schema\u3002\u7981\u6B62\u731C\u6D4B\u8868\u540D\u3001\u5B57\u6BB5\u540D\u6216\u65F6\u95F4\u5B57\u6BB5\u3002
|
|
14090
|
+
2. \u201C\u6700\u8FD1\u201D\u201C\u5230\u73B0\u5728\u201D\u201C\u5230\u6700\u8FD1\u201D\u5FC5\u987B\u7528\u6570\u636E\u4E2D\u7684 MAX(ts) \u6216\u7B49\u4EF7\u5B57\u6BB5\u786E\u5B9A\u7ED3\u675F\u65E5\u671F\uFF1B\u4E0D\u8981\u624B\u7B97\u6216\u81C6\u6D4B\u65E5\u671F\u3002
|
|
14091
|
+
3. ChatLab \u7684 message.ts \u662F\u79D2\u7EA7 Unix \u65F6\u95F4\u6233\uFF0C\u4F7F\u7528 date(ts, 'unixepoch', 'localtime')\uFF1B\u7981\u6B62\u5199 ts/1000\u3002
|
|
14092
|
+
4. \u201C\u6700\u8FD1\u7684 N \u4EBA/\u6210\u5458\u201D\u5FC5\u987B\u5148\u7528\u6570\u636E\u5B9A\u4E49\u5E76\u7B5B\u9009\u51FA N \u4E2A\u6210\u5458\uFF0C\u518D\u53EA\u7EDF\u8BA1\u8FD9\u4E9B\u6210\u5458\u3002
|
|
14093
|
+
5. \u6298\u7EBF\u56FE\u6709\u591A\u6761\u7EBF\u65F6\uFF0C\u6BCF\u6761\u7EBF\u5FC5\u987B\u6709\u660E\u786E series \u5B57\u6BB5\u542B\u4E49\uFF1B\u6309\u65E5\u671F\u7EDF\u8BA1\u65F6\u5E94\u8865\u9F50\u65E5\u671F \xD7 series \u7684 0 \u503C\uFF0C\u907F\u514D\u7F3A\u5931\u65E5\u671F\u5BFC\u81F4\u6298\u7EBF\u65AD\u88C2\u6216\u8BEF\u8FDE\u3002
|
|
14094
|
+
6. \u5DE5\u5177\u5931\u8D25\u3001SQL \u4FEE\u6B63\u3001schema \u63A2\u7D22\u8FC7\u7A0B\u4E0D\u8981\u5199\u8FDB\u6700\u7EC8\u56DE\u7B54\uFF1B\u6700\u7EC8\u53EA\u4FDD\u7559\u56FE\u8868\u548C\u7B80\u77ED\u7ED3\u8BBA\u3002
|
|
14095
|
+
7. \u56FE\u8868\u89E3\u91CA\u53EA\u80FD\u63CF\u8FF0\u6570\u636E\u76F4\u63A5\u652F\u6301\u7684\u8D8B\u52BF\u3001\u5CF0\u503C\u3001\u4F4E\u8C37\u3001\u5DEE\u5F02\u548C\u540C\u6B65\u6027\uFF0C\u7981\u6B62\u5938\u5F20\u62DF\u4EBA\u5316\u6216\u65E0\u6CD5\u4ECE\u56FE\u4E2D\u9A8C\u8BC1\u7684\u5173\u7CFB\u5224\u65AD\u3002
|
|
14096
|
+
|
|
14097
|
+
\u5DE5\u4F5C\u6D41\u7A0B\uFF1A
|
|
14098
|
+
1. \u8C03\u7528 get_schema\u3002
|
|
14099
|
+
2. \u6839\u636E schema \u548C\u7528\u6237\u8981\u6C42\u786E\u5B9A\u7EDF\u8BA1\u5BF9\u8C61\u3001\u65F6\u95F4\u8303\u56F4\u3001\u7EF4\u5EA6\u3001\u6307\u6807\u548C\u56FE\u8868\u7C7B\u578B\u3002
|
|
14100
|
+
3. \u5FC5\u8981\u65F6\u7528\u53EA\u8BFB SQL \u5728 render_chart \u4E2D\u5B8C\u6210\u6210\u5458\u7B5B\u9009\u3001\u65F6\u95F4\u8303\u56F4\u786E\u8BA4\u3001\u805A\u5408\u548C\u8865\u96F6\u3002
|
|
14101
|
+
4. \u8C03\u7528 render_chart\uFF0C\u63D0\u4EA4\u53EA\u8BFB SQL \u548C ChartSpec v1\u3002
|
|
14102
|
+
5. \u56FE\u8868\u751F\u6210\u540E\uFF0C\u7528 1-3 \u53E5\u7B80\u6D01\u6587\u5B57\u89E3\u91CA\u7ED3\u8BBA\u3002\u7528\u6237\u8981\u6C42\u591A\u5F20\u56FE\u65F6\uFF0C\u53EF\u4EE5\u591A\u6B21\u8C03\u7528 render_chart\u3002
|
|
14103
|
+
|
|
14104
|
+
\u5E38\u7528\u8BED\u3001\u53E3\u5934\u7985\u3001\u9AD8\u9891\u77ED\u53E5\u7C7B\u56FE\u8868\u5FC5\u987B\u6392\u9664\u975E\u771F\u4EBA\u6587\u672C\uFF1A\u53D1\u9001\u8005\u4E3A\u7CFB\u7EDF\u6D88\u606F\u3001\u5A92\u4F53\u5360\u4F4D\uFF08\u5982 [\u8868\u60C5\u5305]\u3001[\u56FE\u7247]\u3001[\u8BED\u97F3]\u3001[\u89C6\u9891]\u3001[\u6587\u4EF6]\u3001[\u94FE\u63A5]\u3001[\u7EA2\u5305]\u3001[\u8F6C\u8D26]\uFF09\u4EE5\u53CA\u64A4\u56DE/\u5220\u9664\u63D0\u793A\u90FD\u4E0D\u80FD\u8FDB\u5165\u7EDF\u8BA1\u3002
|
|
14105
|
+
|
|
14106
|
+
ChartSpec v1 \u652F\u6301\uFF1A
|
|
14107
|
+
- bar: encoding.x + encoding.y
|
|
14108
|
+
- line: encoding.x + encoding.y\uFF0C\u53EF\u9009 encoding.series \u8868\u793A\u6BCF\u6761\u7EBF\u7684\u542B\u4E49
|
|
14109
|
+
- pie: encoding.label + encoding.value
|
|
14110
|
+
- heatmap: encoding.x + encoding.y + encoding.value
|
|
14111
|
+
|
|
14112
|
+
ChartSpec \u793A\u4F8B\uFF1A
|
|
14113
|
+
{
|
|
14114
|
+
"version": 1,
|
|
14115
|
+
"type": "line",
|
|
14116
|
+
"title": "\u6700\u8FD1 30 \u5929\u6210\u5458\u53D1\u8A00\u8D8B\u52BF",
|
|
14117
|
+
"encoding": { "x": "day", "y": "msg_count", "series": "member_name" },
|
|
14118
|
+
"unit": "\u6761"
|
|
14119
|
+
}
|
|
14120
|
+
|
|
14121
|
+
\u7528\u6237\u660E\u786E\u8981\u6C42\u56FE\u8868\u65F6\u5FC5\u987B\u5C1D\u8BD5\u751F\u6210\u3002\u7528\u6237\u6CA1\u6709\u660E\u786E\u8981\u6C42\u65F6\uFF0C\u53EA\u6709\u6392\u540D\u3001\u8D8B\u52BF\u3001\u5206\u5E03\u3001\u5360\u6BD4\u6216\u4E8C\u7EF4\u5BC6\u5EA6\u660E\u663E\u66F4\u6E05\u695A\u65F6\u624D\u4E3B\u52A8\u751F\u6210\uFF0C\u4E14\u9ED8\u8BA4\u6700\u591A\u4E00\u5F20\u3002`;
|
|
14122
|
+
var EN_PROMPT = `You are the ChatLab Chart Assistant. In this turn, the user wants one or more charts embedded naturally in the answer.
|
|
14123
|
+
|
|
14124
|
+
You must generate charts through the render_chart tool. Do not output HTML, JavaScript, SVG, Canvas, ECharts options, or rendering code.
|
|
14125
|
+
|
|
14126
|
+
Hard rules:
|
|
14127
|
+
1. Always call get_schema before writing the first SQL query. Do not guess table names, field names, or timestamp fields.
|
|
14128
|
+
2. For "latest", "until now", or "through the latest date", derive the end date from MAX(ts) or the equivalent timestamp field in the data. Do not hand-calculate or assume dates.
|
|
14129
|
+
3. ChatLab message.ts is a Unix timestamp in seconds. Use date(ts, 'unixepoch', 'localtime'); never write ts/1000.
|
|
14130
|
+
4. For "latest N members" or "recent N people", first define and select those N members from the data, then count only those members.
|
|
14131
|
+
5. For multi-series line charts, every line must have an explicit series field. For daily counts, fill the date x series grid with zero values so missing days do not break or mislead the line.
|
|
14132
|
+
6. Do not include failed SQL attempts, schema exploration, or retry reasoning in the final answer. Final answer should contain only the chart and a short conclusion.
|
|
14133
|
+
7. Explain only trends, peaks, lows, differences, and synchrony directly supported by chart data. Do not make exaggerated personality or relationship claims.
|
|
14134
|
+
|
|
14135
|
+
Workflow:
|
|
14136
|
+
1. Call get_schema.
|
|
14137
|
+
2. Derive the target members, time range, dimensions, metrics, and chart type from schema and the user request.
|
|
14138
|
+
3. When needed, use read-only SQL inside render_chart to select members, determine time range, aggregate data, and fill zero rows.
|
|
14139
|
+
4. Call render_chart with read-only SQL and ChartSpec v1.
|
|
14140
|
+
5. After the chart is generated, explain the key finding in 1-3 concise sentences. If the user asks for multiple charts, call render_chart multiple times.
|
|
14141
|
+
|
|
14142
|
+
For catchphrase, common phrase, or frequent short-text charts, exclude non-human text from the SQL: system-message senders, media placeholders such as [Sticker], [Image], [Photo], [Voice], [Video], [File], [Link], and recall/deletion notices must not be counted.
|
|
14143
|
+
|
|
14144
|
+
ChartSpec v1 supports:
|
|
14145
|
+
- bar: encoding.x + encoding.y
|
|
14146
|
+
- line: encoding.x + encoding.y, optional encoding.series for the meaning of each line
|
|
14147
|
+
- pie: encoding.label + encoding.value
|
|
14148
|
+
- heatmap: encoding.x + encoding.y + encoding.value
|
|
14149
|
+
|
|
14150
|
+
ChartSpec example:
|
|
14151
|
+
{
|
|
14152
|
+
"version": 1,
|
|
14153
|
+
"type": "line",
|
|
14154
|
+
"title": "Member message trend in the last 30 days",
|
|
14155
|
+
"encoding": { "x": "day", "y": "msg_count", "series": "member_name" },
|
|
14156
|
+
"unit": "messages"
|
|
14157
|
+
}
|
|
14158
|
+
|
|
14159
|
+
When the user explicitly asks for charts, you must try to generate them. If the user does not explicitly ask, add at most one chart only when ranking, trend, distribution, ratio, or two-dimensional density is clearly easier to understand visually.`;
|
|
14160
|
+
|
|
14161
|
+
// ../../packages/node-runtime/src/ai/chart-schema-gate.ts
|
|
14162
|
+
var CHART_SCHEMA_REQUIRED_MESSAGE = "Error: Call get_schema before render_chart. Do not guess table names, fields, or timestamp units.";
|
|
14163
|
+
function createChartSchemaGateState() {
|
|
14164
|
+
return { schemaSeen: false };
|
|
14165
|
+
}
|
|
14166
|
+
function wrapWithChartSchemaGate(tool, state) {
|
|
14167
|
+
const originalExecute = tool.execute;
|
|
14168
|
+
return {
|
|
14169
|
+
...tool,
|
|
14170
|
+
execute: async (toolCallId, params, signal, onUpdate) => {
|
|
14171
|
+
if (tool.name === "render_chart" && !state.schemaSeen) {
|
|
14172
|
+
return {
|
|
14173
|
+
content: [{ type: "text", text: CHART_SCHEMA_REQUIRED_MESSAGE }],
|
|
14174
|
+
details: null
|
|
14175
|
+
};
|
|
14176
|
+
}
|
|
14177
|
+
const result = await originalExecute(toolCallId, params, signal, onUpdate);
|
|
14178
|
+
if (tool.name === "get_schema") {
|
|
14179
|
+
state.schemaSeen = true;
|
|
14180
|
+
}
|
|
14181
|
+
return result;
|
|
14182
|
+
}
|
|
14183
|
+
};
|
|
14184
|
+
}
|
|
14185
|
+
|
|
13766
14186
|
// ../../packages/node-runtime/src/ai/compression/compressor.ts
|
|
13767
14187
|
var DEFAULT_CONTEXT_WINDOW = 128e3;
|
|
13768
14188
|
var INITIAL_COMPRESSION_PROMPT = `You are a context compression assistant. Compress the conversation below into a structured summary.
|
|
@@ -13806,23 +14226,23 @@ var defaultLogger3 = {
|
|
|
13806
14226
|
error: () => {
|
|
13807
14227
|
}
|
|
13808
14228
|
};
|
|
13809
|
-
async function checkAndCompress(
|
|
14229
|
+
async function checkAndCompress(aiChatId, config, systemPrompt, llmAdapter, convManager, logger = defaultLogger3) {
|
|
13810
14230
|
if (!config.enabled) {
|
|
13811
14231
|
return { compressed: false, reason: "skipped_disabled" };
|
|
13812
14232
|
}
|
|
13813
14233
|
try {
|
|
13814
14234
|
const contextWindow = llmAdapter.contextWindow || DEFAULT_CONTEXT_WINDOW;
|
|
13815
14235
|
const thresholdTokens = Math.floor(contextWindow * (config.tokenThresholdPercent / 100) * 0.95);
|
|
13816
|
-
const summary = convManager.getLatestSummary(
|
|
14236
|
+
const summary = convManager.getLatestSummary(aiChatId);
|
|
13817
14237
|
let messages;
|
|
13818
14238
|
if (summary) {
|
|
13819
14239
|
const metaBlock = summary.contentBlocks?.find(
|
|
13820
14240
|
(b) => b.type === "summary_meta"
|
|
13821
14241
|
);
|
|
13822
14242
|
const boundary = metaBlock?.bufferBoundaryTimestamp ?? summary.timestamp;
|
|
13823
|
-
messages = convManager.getMessagesAfterSummary(
|
|
14243
|
+
messages = convManager.getMessagesAfterSummary(aiChatId, boundary - 1);
|
|
13824
14244
|
} else {
|
|
13825
|
-
messages = convManager.getAllUserAssistantMessages(
|
|
14245
|
+
messages = convManager.getAllUserAssistantMessages(aiChatId);
|
|
13826
14246
|
}
|
|
13827
14247
|
const historyForTokenCount = [];
|
|
13828
14248
|
if (summary) {
|
|
@@ -13833,7 +14253,7 @@ async function checkAndCompress(conversationId, config, systemPrompt, llmAdapter
|
|
|
13833
14253
|
}
|
|
13834
14254
|
const currentTokens = countMessagesTokens(historyForTokenCount, systemPrompt);
|
|
13835
14255
|
logger.info("Compression", `Token check: ${currentTokens} / ${thresholdTokens} (${contextWindow} window)`, {
|
|
13836
|
-
|
|
14256
|
+
aiChatId,
|
|
13837
14257
|
messageCount: messages.length,
|
|
13838
14258
|
hasSummary: !!summary
|
|
13839
14259
|
});
|
|
@@ -13857,7 +14277,7 @@ async function checkAndCompress(conversationId, config, systemPrompt, llmAdapter
|
|
|
13857
14277
|
summaryText = forceTruncate(compressInput, targetTokens);
|
|
13858
14278
|
}
|
|
13859
14279
|
const bufferBoundary = bufferMessages.length > 0 ? bufferMessages[0].timestamp : messagesToCompress[messagesToCompress.length - 1].timestamp + 1;
|
|
13860
|
-
convManager.addSummaryMessage(
|
|
14280
|
+
convManager.addSummaryMessage(aiChatId, summaryText, {
|
|
13861
14281
|
bufferBoundaryTimestamp: bufferBoundary,
|
|
13862
14282
|
compressedMessageCount: messagesToCompress.length
|
|
13863
14283
|
});
|
|
@@ -14542,6 +14962,11 @@ import {
|
|
|
14542
14962
|
streamSimple as defaultStreamSimple,
|
|
14543
14963
|
clampThinkingLevel
|
|
14544
14964
|
} from "@earendil-works/pi-ai";
|
|
14965
|
+
|
|
14966
|
+
// ../../packages/node-runtime/src/ai/agent/constants.ts
|
|
14967
|
+
var DEFAULT_MAX_TOOL_ROUNDS = 10;
|
|
14968
|
+
|
|
14969
|
+
// ../../packages/node-runtime/src/ai/agent/core.ts
|
|
14545
14970
|
function createEmptyPiUsage() {
|
|
14546
14971
|
return {
|
|
14547
14972
|
input: 0,
|
|
@@ -14584,7 +15009,7 @@ async function runAgentCore(options) {
|
|
|
14584
15009
|
tools,
|
|
14585
15010
|
history,
|
|
14586
15011
|
userMessage,
|
|
14587
|
-
maxToolRounds =
|
|
15012
|
+
maxToolRounds = DEFAULT_MAX_TOOL_ROUNDS,
|
|
14588
15013
|
abortSignal,
|
|
14589
15014
|
steerMessage = "Please provide your final answer based on the information gathered.",
|
|
14590
15015
|
onEvent,
|
|
@@ -15073,40 +15498,40 @@ var zh_CN_default = {
|
|
|
15073
15498
|
context_size: "\u4E0A\u4E0B\u6587\u5927\u5C0F\uFF0C\u5373\u83B7\u53D6\u524D\u540E\u5404\u591A\u5C11\u6761\u6D88\u606F\uFF0C\u9ED8\u8BA4 20"
|
|
15074
15499
|
}
|
|
15075
15500
|
},
|
|
15076
|
-
|
|
15077
|
-
desc: "\u641C\u7D22\u804A\u5929\
|
|
15501
|
+
search_segments: {
|
|
15502
|
+
desc: "\u641C\u7D22\u804A\u5929\u6BB5\u843D\uFF08\u5BF9\u8BDD\u6BB5\u843D\uFF09\u3002\u6BB5\u843D\u662F\u6839\u636E\u6D88\u606F\u65F6\u95F4\u95F4\u9694\u81EA\u52A8\u5207\u5206\u7684\u5BF9\u8BDD\u5355\u5143\u3002\u9002\u7528\u4E8E\u67E5\u627E\u7279\u5B9A\u8BDD\u9898\u7684\u8BA8\u8BBA\u3001\u4E86\u89E3\u67D0\u4E2A\u65F6\u95F4\u6BB5\u5185\u53D1\u751F\u4E86\u51E0\u6B21\u5BF9\u8BDD\u7B49\u573A\u666F\u3002\u8FD4\u56DE\u5339\u914D\u7684\u6BB5\u843D\u5217\u8868\u53CA\u6BCF\u4E2A\u6BB5\u843D\u7684\u524D5\u6761\u6D88\u606F\u9884\u89C8\u3002",
|
|
15078
15503
|
params: {
|
|
15079
|
-
keywords: "\u53EF\u9009\u7684\u641C\u7D22\u5173\u952E\u8BCD\u5217\u8868\uFF0C\u53EA\u8FD4\u56DE\u5305\u542B\u8FD9\u4E9B\u5173\u952E\u8BCD\u7684\
|
|
15080
|
-
limit: "\u8FD4\u56DE\
|
|
15081
|
-
year: "\u6307\u5B9A\u5E74\u4EFD\u7B5B\u9009\
|
|
15082
|
-
month: "\u6307\u5B9A\u6708\u4EFD\u7B5B\u9009\
|
|
15083
|
-
day: "\u6307\u5B9A\u65E5\u671F\u7B5B\u9009\
|
|
15504
|
+
keywords: "\u53EF\u9009\u7684\u641C\u7D22\u5173\u952E\u8BCD\u5217\u8868\uFF0C\u53EA\u8FD4\u56DE\u5305\u542B\u8FD9\u4E9B\u5173\u952E\u8BCD\u7684\u6BB5\u843D\uFF08OR \u903B\u8F91\u5339\u914D\uFF09",
|
|
15505
|
+
limit: "\u8FD4\u56DE\u6BB5\u843D\u6570\u91CF\u9650\u5236\uFF0C\u9ED8\u8BA4 20",
|
|
15506
|
+
year: "\u6307\u5B9A\u5E74\u4EFD\u7B5B\u9009\u6BB5\u843D\uFF0C\u5982 2024",
|
|
15507
|
+
month: "\u6307\u5B9A\u6708\u4EFD\u7B5B\u9009\u6BB5\u843D\uFF081-12\uFF09\uFF0C\u9700\u914D\u5408 year \u4F7F\u7528",
|
|
15508
|
+
day: "\u6307\u5B9A\u65E5\u671F\u7B5B\u9009\u6BB5\u843D\uFF081-31\uFF09\uFF0C\u9700\u914D\u5408 year \u548C month \u4F7F\u7528",
|
|
15084
15509
|
start_time: '\u5F00\u59CB\u65F6\u95F4\uFF0C\u683C\u5F0F "YYYY-MM-DD HH:mm"\uFF0C\u5982 "2024-03-15 14:00"',
|
|
15085
15510
|
end_time: '\u7ED3\u675F\u65F6\u95F4\uFF0C\u683C\u5F0F "YYYY-MM-DD HH:mm"\uFF0C\u5982 "2024-03-15 18:30"'
|
|
15086
15511
|
}
|
|
15087
15512
|
},
|
|
15088
|
-
|
|
15089
|
-
desc: "\u83B7\u53D6\u6307\u5B9A\
|
|
15513
|
+
get_segment_messages: {
|
|
15514
|
+
desc: "\u83B7\u53D6\u6307\u5B9A\u6BB5\u843D\u7684\u5B8C\u6574\u6D88\u606F\u5217\u8868\u3002\u7528\u4E8E\u5728 search_segments \u627E\u5230\u76F8\u5173\u6BB5\u843D\u540E\uFF0C\u83B7\u53D6\u8BE5\u6BB5\u843D\u7684\u5B8C\u6574\u4E0A\u4E0B\u6587\u3002\u8FD4\u56DE\u6BB5\u843D\u7684\u6240\u6709\u6D88\u606F\u53CA\u53C2\u4E0E\u8005\u4FE1\u606F\u3002",
|
|
15090
15515
|
params: {
|
|
15091
|
-
|
|
15092
|
-
limit: "\u8FD4\u56DE\u6D88\u606F\u6570\u91CF\u9650\u5236\uFF0C\u9ED8\u8BA4 1000\u3002\u5BF9\u4E8E\u8D85\u957F\
|
|
15516
|
+
segment_id: "\u6BB5\u843D ID\uFF0C\u53EF\u4EE5\u4ECE search_segments \u7684\u8FD4\u56DE\u7ED3\u679C\u4E2D\u83B7\u53D6",
|
|
15517
|
+
limit: "\u8FD4\u56DE\u6D88\u606F\u6570\u91CF\u9650\u5236\uFF0C\u9ED8\u8BA4 1000\u3002\u5BF9\u4E8E\u8D85\u957F\u6BB5\u843D\u53EF\u4EE5\u9650\u5236\u8FD4\u56DE\u6570\u91CF\u4EE5\u8282\u7701 token"
|
|
15093
15518
|
}
|
|
15094
15519
|
},
|
|
15095
|
-
|
|
15096
|
-
desc: `\u83B7\u53D6\
|
|
15520
|
+
get_segment_summaries: {
|
|
15521
|
+
desc: `\u83B7\u53D6\u6BB5\u843D\u6458\u8981\u5217\u8868\uFF0C\u5FEB\u901F\u4E86\u89E3\u7FA4\u804A\u5386\u53F2\u8BA8\u8BBA\u7684\u4E3B\u9898\u3002
|
|
15097
15522
|
|
|
15098
15523
|
\u9002\u7528\u573A\u666F\uFF1A
|
|
15099
15524
|
1. \u4E86\u89E3\u7FA4\u91CC\u6700\u8FD1\u5728\u804A\u4EC0\u4E48\u8BDD\u9898
|
|
15100
15525
|
2. \u6309\u5173\u952E\u8BCD\u641C\u7D22\u8BA8\u8BBA\u8FC7\u7684\u8BDD\u9898
|
|
15101
15526
|
3. \u6982\u89C8\u6027\u95EE\u9898\u5982"\u7FA4\u91CC\u6709\u6CA1\u6709\u8BA8\u8BBA\u8FC7\u65C5\u6E38"
|
|
15102
15527
|
|
|
15103
|
-
\u8FD4\u56DE\u7684\u6458\u8981\u662F\u5BF9\u6BCF\u4E2A\
|
|
15528
|
+
\u8FD4\u56DE\u7684\u6458\u8981\u662F\u5BF9\u6BCF\u4E2A\u6BB5\u843D\u7684\u7B80\u77ED\u603B\u7ED3\uFF0C\u53EF\u4EE5\u5E2E\u52A9\u5FEB\u901F\u5B9A\u4F4D\u611F\u5174\u8DA3\u7684\u6BB5\u843D\uFF0C\u7136\u540E\u7528 get_segment_messages \u83B7\u53D6\u8BE6\u60C5\u3002`,
|
|
15104
15529
|
params: {
|
|
15105
15530
|
keywords: "\u5728\u6458\u8981\u4E2D\u641C\u7D22\u7684\u5173\u952E\u8BCD\u5217\u8868\uFF08OR \u903B\u8F91\u5339\u914D\uFF09",
|
|
15106
|
-
limit: "\u8FD4\u56DE\
|
|
15107
|
-
year: "\u6307\u5B9A\u5E74\u4EFD\u7B5B\u9009\
|
|
15108
|
-
month: "\u6307\u5B9A\u6708\u4EFD\u7B5B\u9009\
|
|
15109
|
-
day: "\u6307\u5B9A\u65E5\u671F\u7B5B\u9009\
|
|
15531
|
+
limit: "\u8FD4\u56DE\u6BB5\u843D\u6570\u91CF\u9650\u5236\uFF0C\u9ED8\u8BA4 20",
|
|
15532
|
+
year: "\u6307\u5B9A\u5E74\u4EFD\u7B5B\u9009\u6BB5\u843D",
|
|
15533
|
+
month: "\u6307\u5B9A\u6708\u4EFD\u7B5B\u9009\u6BB5\u843D\uFF081-12\uFF09",
|
|
15534
|
+
day: "\u6307\u5B9A\u65E5\u671F\u7B5B\u9009\u6BB5\u843D\uFF081-31\uFF09",
|
|
15110
15535
|
start_time: '\u5F00\u59CB\u65F6\u95F4\uFF0C\u683C\u5F0F "YYYY-MM-DD HH:mm"',
|
|
15111
15536
|
end_time: '\u7ED3\u675F\u65F6\u95F4\uFF0C\u683C\u5F0F "YYYY-MM-DD HH:mm"'
|
|
15112
15537
|
}
|
|
@@ -15193,14 +15618,14 @@ var zh_CN_default = {
|
|
|
15193
15618
|
fallback: "\u8BE5\u65F6\u95F4\u8303\u56F4\u5185\u6CA1\u6709\u6D88\u606F\u8BB0\u5F55"
|
|
15194
15619
|
},
|
|
15195
15620
|
conversation_initiator_stats: {
|
|
15196
|
-
desc: "\u7EDF\u8BA1\u6BCF\u4E2A\u6210\u5458\u53D1\u8D77\
|
|
15621
|
+
desc: "\u7EDF\u8BA1\u6BCF\u4E2A\u6210\u5458\u53D1\u8D77\u6BB5\u843D\uFF08\u4F5C\u4E3A\u6BB5\u843D\u9996\u6761\u6D88\u606F\u7684\u53D1\u9001\u8005\uFF09\u7684\u6B21\u6570\uFF0C\u627E\u51FA\u8C01\u6700\u5E38\u5F00\u542F\u8BDD\u9898\u3002\u9700\u8981\u5DF2\u751F\u6210\u6BB5\u843D\u7D22\u5F15\u3002",
|
|
15197
15622
|
params: {
|
|
15198
15623
|
days: "\u7EDF\u8BA1\u6700\u8FD1\u591A\u5C11\u5929\u7684\u6570\u636E",
|
|
15199
15624
|
limit: "\u8FD4\u56DE\u524D\u591A\u5C11\u540D"
|
|
15200
15625
|
},
|
|
15201
15626
|
rowTemplate: "{name}\uFF1A\u53D1\u8D77 {initiated_count} \u6B21\u8BDD\u9898",
|
|
15202
15627
|
summaryTemplate: "\u8BDD\u9898\u53D1\u8D77\u8005 Top {rowCount}\uFF1A",
|
|
15203
|
-
fallback: "\u8BE5\u65F6\u95F4\u8303\u56F4\u5185\u6CA1\u6709\
|
|
15628
|
+
fallback: "\u8BE5\u65F6\u95F4\u8303\u56F4\u5185\u6CA1\u6709\u6BB5\u843D\u8BB0\u5F55\uFF0C\u53EF\u80FD\u9700\u8981\u5148\u751F\u6210\u6BB5\u843D\u7D22\u5F15"
|
|
15204
15629
|
},
|
|
15205
15630
|
activity_heatmap: {
|
|
15206
15631
|
desc: "\u8FD4\u56DE \u661F\u671F\xD7\u5C0F\u65F6 \u7684\u6D88\u606F\u6570\u77E9\u9635\uFF0C\u9002\u5408\u751F\u6210\u6D3B\u8DC3\u5EA6\u70ED\u529B\u56FE\u3002weekday: 0=\u5468\u65E5, 1=\u5468\u4E00, ..., 6=\u5468\u516D\u3002",
|
|
@@ -15222,6 +15647,19 @@ var zh_CN_default = {
|
|
|
15222
15647
|
days: "\u7EDF\u8BA1\u6700\u8FD1\u591A\u5C11\u5929\u7684\u6570\u636E",
|
|
15223
15648
|
top_n: "\u8FD4\u56DE\u524D\u591A\u5C11\u4E2A\u5173\u952E\u8BCD"
|
|
15224
15649
|
}
|
|
15650
|
+
},
|
|
15651
|
+
get_schema: {
|
|
15652
|
+
desc: "\u67E5\u770B\u804A\u5929\u6570\u636E\u5E93\u8868\u7ED3\u6784\u3002\u7ED8\u56FE\u6216\u81EA\u5B9A\u4E49 SQL \u524D\u5E94\u5148\u7528\u5B83\u786E\u8BA4\u8868\u540D\u548C\u5B57\u6BB5\u540D\u3002",
|
|
15653
|
+
params: {}
|
|
15654
|
+
},
|
|
15655
|
+
render_chart: {
|
|
15656
|
+
desc: "\u6839\u636E\u53EA\u8BFB SQL \u548C ChartSpec v1 \u751F\u6210 ChatLab \u539F\u751F\u56FE\u8868\u3002\u652F\u6301 bar\u3001line\u3001pie\u3001heatmap\u3002\u7981\u6B62\u8F93\u51FA HTML\u3001JavaScript\u3001SVG\u3001ECharts option \u6216\u6E32\u67D3\u4EE3\u7801\u3002",
|
|
15657
|
+
params: {
|
|
15658
|
+
sql: "\u53EA\u8BFB SELECT \u6216 WITH SELECT SQL\u3002\u5FC5\u987B\u8FD4\u56DE ChartSpec encoding \u4E2D\u5F15\u7528\u7684\u5B57\u6BB5\u3002",
|
|
15659
|
+
params: "SQL \u547D\u540D\u53C2\u6570\u5BF9\u8C61\uFF1B\u4E0D\u9700\u8981\u53C2\u6570\u65F6\u4F20\u7A7A\u5BF9\u8C61\u3002",
|
|
15660
|
+
chartSpec: "ChartSpec v1\uFF0C\u5305\u542B version\u3001type\u3001title\u3001encoding\u3002",
|
|
15661
|
+
maxRows: "\u56FE\u8868\u67E5\u8BE2\u6700\u5927\u884C\u6570\uFF0C\u9ED8\u8BA4 1000\u3002"
|
|
15662
|
+
}
|
|
15225
15663
|
}
|
|
15226
15664
|
},
|
|
15227
15665
|
agent: {
|
|
@@ -15291,10 +15729,10 @@ var zh_CN_default = {
|
|
|
15291
15729
|
rawErrorLabel: "\u539F\u59CB\u9519\u8BEF"
|
|
15292
15730
|
},
|
|
15293
15731
|
summary: {
|
|
15294
|
-
|
|
15732
|
+
segmentNotFound: "\u6BB5\u843D\u4E0D\u5B58\u5728\u6216\u6570\u636E\u5E93\u6253\u5F00\u5931\u8D25",
|
|
15295
15733
|
tooFewMessages: "\u6D88\u606F\u6570\u91CF\u5C11\u4E8E{{count}}\u6761\uFF0C\u65E0\u9700\u751F\u6210\u6458\u8981",
|
|
15296
15734
|
tooFewValidMessages: "\u6709\u6548\u6D88\u606F\u6570\u91CF\u5C11\u4E8E{{count}}\u6761\uFF0C\u65E0\u9700\u751F\u6210\u6458\u8981",
|
|
15297
|
-
|
|
15735
|
+
segmentNotExist: "\u6BB5\u843D\u4E0D\u5B58\u5728",
|
|
15298
15736
|
messagesTooFew: "\u6D88\u606F\u592A\u5C11",
|
|
15299
15737
|
validMessagesTooFew: "\u6709\u6548\u6D88\u606F\u592A\u5C11",
|
|
15300
15738
|
systemPromptDirect: "\u4F60\u662F\u4E00\u4E2A\u5BF9\u8BDD\u6458\u8981\u4E13\u5BB6\uFF0C\u64C5\u957F\u7528\u7B80\u6D01\u7684\u8BED\u8A00\u603B\u7ED3\u5BF9\u8BDD\u5185\u5BB9\u3002",
|
|
@@ -15394,40 +15832,40 @@ var en_US_default = {
|
|
|
15394
15832
|
context_size: "Context size, i.e. how many messages before and after to retrieve, default 20"
|
|
15395
15833
|
}
|
|
15396
15834
|
},
|
|
15397
|
-
|
|
15398
|
-
desc: "Search chat
|
|
15835
|
+
search_segments: {
|
|
15836
|
+
desc: "Search chat segments (conversation segments). Segments are conversation units automatically split by message time intervals. Suitable for finding discussions on specific topics or understanding how many conversations occurred in a time period. Returns matching segments with a 5-message preview each.",
|
|
15399
15837
|
params: {
|
|
15400
|
-
keywords: "Optional keyword list, only returns
|
|
15838
|
+
keywords: "Optional keyword list, only returns segments containing these keywords (OR logic)",
|
|
15401
15839
|
limit: "Session count limit, default 20",
|
|
15402
|
-
year: "Filter
|
|
15403
|
-
month: "Filter
|
|
15404
|
-
day: "Filter
|
|
15840
|
+
year: "Filter segments by year, e.g. 2024",
|
|
15841
|
+
month: "Filter segments by month (1-12), use with year",
|
|
15842
|
+
day: "Filter segments by day (1-31), use with year and month",
|
|
15405
15843
|
start_time: 'Start time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 14:00"',
|
|
15406
15844
|
end_time: 'End time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 18:30"'
|
|
15407
15845
|
}
|
|
15408
15846
|
},
|
|
15409
|
-
|
|
15410
|
-
desc: "Get the complete message list for a specific
|
|
15847
|
+
get_segment_messages: {
|
|
15848
|
+
desc: "Get the complete message list for a specific segment. Used to get full context after finding a relevant segment via search_segments. Returns all messages and participant information.",
|
|
15411
15849
|
params: {
|
|
15412
|
-
|
|
15413
|
-
limit: "Message count limit, default 1000. Can be limited for very long
|
|
15850
|
+
segment_id: "Segment ID, can be obtained from search_segments results",
|
|
15851
|
+
limit: "Message count limit, default 1000. Can be limited for very long segments to save tokens"
|
|
15414
15852
|
}
|
|
15415
15853
|
},
|
|
15416
|
-
|
|
15417
|
-
desc: `Get
|
|
15854
|
+
get_segment_summaries: {
|
|
15855
|
+
desc: `Get segment summary list to quickly understand discussion topics in chat history.
|
|
15418
15856
|
|
|
15419
15857
|
Use cases:
|
|
15420
15858
|
1. Understand what topics have been discussed recently
|
|
15421
15859
|
2. Search for discussed topics by keyword
|
|
15422
15860
|
3. Overview questions like "has the group discussed travel"
|
|
15423
15861
|
|
|
15424
|
-
Returned summaries are brief descriptions of each
|
|
15862
|
+
Returned summaries are brief descriptions of each segment, helping quickly locate segments of interest. Use get_segment_messages for details.`,
|
|
15425
15863
|
params: {
|
|
15426
15864
|
keywords: "Keyword list to search within summaries (OR logic)",
|
|
15427
15865
|
limit: "Session count limit, default 20",
|
|
15428
|
-
year: "Filter
|
|
15429
|
-
month: "Filter
|
|
15430
|
-
day: "Filter
|
|
15866
|
+
year: "Filter segments by year",
|
|
15867
|
+
month: "Filter segments by month (1-12)",
|
|
15868
|
+
day: "Filter segments by day (1-31)",
|
|
15431
15869
|
start_time: 'Start time, format "YYYY-MM-DD HH:mm"',
|
|
15432
15870
|
end_time: 'End time, format "YYYY-MM-DD HH:mm"'
|
|
15433
15871
|
}
|
|
@@ -15515,14 +15953,14 @@ Returned summaries are brief descriptions of each session, helping quickly locat
|
|
|
15515
15953
|
fallback: "No messages in this time range"
|
|
15516
15954
|
},
|
|
15517
15955
|
conversation_initiator_stats: {
|
|
15518
|
-
desc: "Count how many times each member initiated a conversation (was the first sender in a
|
|
15956
|
+
desc: "Count how many times each member initiated a conversation (was the first sender in a segment). Requires segment index to be generated.",
|
|
15519
15957
|
params: {
|
|
15520
15958
|
days: "Number of recent days to analyze",
|
|
15521
15959
|
limit: "Number of top members to return"
|
|
15522
15960
|
},
|
|
15523
15961
|
rowTemplate: "{name}: initiated {initiated_count} topics",
|
|
15524
15962
|
summaryTemplate: "Topic initiator Top {rowCount}:",
|
|
15525
|
-
fallback: "No
|
|
15963
|
+
fallback: "No segment records in this time range. Session index may need to be generated first."
|
|
15526
15964
|
},
|
|
15527
15965
|
activity_heatmap: {
|
|
15528
15966
|
desc: "Return a weekday \xD7 hour message count matrix for generating activity heatmaps. weekday: 0=Sun, 1=Mon, ..., 6=Sat.",
|
|
@@ -15544,6 +15982,19 @@ Returned summaries are brief descriptions of each session, helping quickly locat
|
|
|
15544
15982
|
days: "Number of recent days to analyze",
|
|
15545
15983
|
top_n: "Number of top keywords to return"
|
|
15546
15984
|
}
|
|
15985
|
+
},
|
|
15986
|
+
get_schema: {
|
|
15987
|
+
desc: "Inspect the chat database schema. Use it before charting or custom SQL when table or field names are uncertain.",
|
|
15988
|
+
params: {}
|
|
15989
|
+
},
|
|
15990
|
+
render_chart: {
|
|
15991
|
+
desc: "Generate a native ChatLab chart from read-only SQL and ChartSpec v1. Supports bar, line, pie, and heatmap. Do not output HTML, JavaScript, SVG, ECharts options, or rendering code.",
|
|
15992
|
+
params: {
|
|
15993
|
+
sql: "Read-only SELECT or WITH SELECT SQL. It must return fields referenced by ChartSpec encoding.",
|
|
15994
|
+
params: "Named SQL parameters. Use an empty object when no parameters are needed.",
|
|
15995
|
+
chartSpec: "ChartSpec v1 with version, type, title, and encoding.",
|
|
15996
|
+
maxRows: "Maximum chart query rows. Default 1000."
|
|
15997
|
+
}
|
|
15547
15998
|
}
|
|
15548
15999
|
},
|
|
15549
16000
|
// ===== AI Agent system prompts =====
|
|
@@ -15610,10 +16061,10 @@ Your task is to help users understand and analyze their private chat data.
|
|
|
15610
16061
|
rawErrorLabel: "Raw error"
|
|
15611
16062
|
},
|
|
15612
16063
|
summary: {
|
|
15613
|
-
|
|
16064
|
+
segmentNotFound: "Session not found or database could not be opened",
|
|
15614
16065
|
tooFewMessages: "Message count less than {{count}}, no need to generate summary",
|
|
15615
16066
|
tooFewValidMessages: "Valid message count less than {{count}}, no need to generate summary",
|
|
15616
|
-
|
|
16067
|
+
segmentNotExist: "Session not found",
|
|
15617
16068
|
messagesTooFew: "Too few messages",
|
|
15618
16069
|
validMessagesTooFew: "Too few valid messages",
|
|
15619
16070
|
systemPromptDirect: "You are a conversation summarization expert. Summarize conversations concisely.",
|
|
@@ -15713,40 +16164,40 @@ var ja_JP_default = {
|
|
|
15713
16164
|
context_size: "\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u30B5\u30A4\u30BA\u3002\u524D\u5F8C\u305D\u308C\u305E\u308C\u4F55\u4EF6\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u53D6\u5F97\u3059\u308B\u304B\u3002\u30C7\u30D5\u30A9\u30EB\u30C8 20"
|
|
15714
16165
|
}
|
|
15715
16166
|
},
|
|
15716
|
-
|
|
15717
|
-
desc: "\u30C1\u30E3\u30C3\u30C8\u30BB\
|
|
16167
|
+
search_segments: {
|
|
16168
|
+
desc: "\u30C1\u30E3\u30C3\u30C8\u30BB\u30B0\u30E1\u30F3\u30C8\uFF08\u4F1A\u8A71\u30BB\u30B0\u30E1\u30F3\u30C8\uFF09\u3092\u691C\u7D22\u3059\u308B\u3002\u30BB\u30B0\u30E1\u30F3\u30C8\u306F\u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u6642\u9593\u9593\u9694\u306B\u57FA\u3065\u3044\u3066\u81EA\u52D5\u5206\u5272\u3055\u308C\u305F\u4F1A\u8A71\u5358\u4F4D\u3067\u3042\u308B\u3002\u7279\u5B9A\u30C8\u30D4\u30C3\u30AF\u306E\u8B70\u8AD6\u3092\u898B\u3064\u3051\u305F\u308A\u3001\u3042\u308B\u671F\u9593\u5185\u306E\u4F1A\u8A71\u56DE\u6570\u3092\u628A\u63E1\u3059\u308B\u306E\u306B\u9069\u3057\u3066\u3044\u308B\u3002\u30DE\u30C3\u30C1\u3057\u305F\u30BB\u30B0\u30E1\u30F3\u30C8\u30EA\u30B9\u30C8\u3068\u5404\u30BB\u30B0\u30E1\u30F3\u30C8\u306E\u6700\u521D\u306E5\u4EF6\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u30D7\u30EC\u30D3\u30E5\u30FC\u3092\u8FD4\u5374\u3059\u308B\u3002",
|
|
15718
16169
|
params: {
|
|
15719
|
-
keywords: "\u4EFB\u610F\u306E\u691C\u7D22\u30AD\u30FC\u30EF\u30FC\u30C9\u30EA\u30B9\u30C8\u3002\u3053\u308C\u3089\u306E\u30AD\u30FC\u30EF\u30FC\u30C9\u3092\u542B\u3080\u30BB\
|
|
15720
|
-
limit: "\u8FD4\u5374\u30BB\
|
|
15721
|
-
year: "\u6307\u5B9A\u5E74\u306E\u30BB\
|
|
15722
|
-
month: "\u6307\u5B9A\u6708\u306E\u30BB\
|
|
15723
|
-
day: "\u6307\u5B9A\u65E5\u306E\u30BB\
|
|
16170
|
+
keywords: "\u4EFB\u610F\u306E\u691C\u7D22\u30AD\u30FC\u30EF\u30FC\u30C9\u30EA\u30B9\u30C8\u3002\u3053\u308C\u3089\u306E\u30AD\u30FC\u30EF\u30FC\u30C9\u3092\u542B\u3080\u30BB\u30B0\u30E1\u30F3\u30C8\u306E\u307F\u8FD4\u5374\u3059\u308B\uFF08OR \u30ED\u30B8\u30C3\u30AF\u30DE\u30C3\u30C1\uFF09",
|
|
16171
|
+
limit: "\u8FD4\u5374\u30BB\u30B0\u30E1\u30F3\u30C8\u6570\u306E\u4E0A\u9650\u3002\u30C7\u30D5\u30A9\u30EB\u30C8 20",
|
|
16172
|
+
year: "\u6307\u5B9A\u5E74\u306E\u30BB\u30B0\u30E1\u30F3\u30C8\u3092\u30D5\u30A3\u30EB\u30BF\u30EA\u30F3\u30B0\uFF08\u4F8B\uFF1A2024\uFF09",
|
|
16173
|
+
month: "\u6307\u5B9A\u6708\u306E\u30BB\u30B0\u30E1\u30F3\u30C8\u3092\u30D5\u30A3\u30EB\u30BF\u30EA\u30F3\u30B0\uFF081-12\uFF09\u3002year \u3068\u4F75\u7528\u3059\u308B\u5FC5\u8981\u304C\u3042\u308B",
|
|
16174
|
+
day: "\u6307\u5B9A\u65E5\u306E\u30BB\u30B0\u30E1\u30F3\u30C8\u3092\u30D5\u30A3\u30EB\u30BF\u30EA\u30F3\u30B0\uFF081-31\uFF09\u3002year \u3068 month \u3068\u4F75\u7528\u3059\u308B\u5FC5\u8981\u304C\u3042\u308B",
|
|
15724
16175
|
start_time: '\u958B\u59CB\u6642\u523B\u3002\u5F62\u5F0F "YYYY-MM-DD HH:mm"\uFF08\u4F8B\uFF1A"2024-03-15 14:00"\uFF09',
|
|
15725
16176
|
end_time: '\u7D42\u4E86\u6642\u523B\u3002\u5F62\u5F0F "YYYY-MM-DD HH:mm"\uFF08\u4F8B\uFF1A"2024-03-15 18:30"\uFF09'
|
|
15726
16177
|
}
|
|
15727
16178
|
},
|
|
15728
|
-
|
|
15729
|
-
desc: "\u6307\u5B9A\u30BB\
|
|
16179
|
+
get_segment_messages: {
|
|
16180
|
+
desc: "\u6307\u5B9A\u30BB\u30B0\u30E1\u30F3\u30C8\u306E\u5B8C\u5168\u306A\u30E1\u30C3\u30BB\u30FC\u30B8\u30EA\u30B9\u30C8\u3092\u53D6\u5F97\u3059\u308B\u3002search_segments \u3067\u95A2\u9023\u30BB\u30B0\u30E1\u30F3\u30C8\u3092\u898B\u3064\u3051\u305F\u5F8C\u3001\u305D\u306E\u30BB\u30B0\u30E1\u30F3\u30C8\u306E\u5B8C\u5168\u306A\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u3092\u53D6\u5F97\u3059\u308B\u305F\u3081\u306B\u4F7F\u7528\u3059\u308B\u3002\u30BB\u30B0\u30E1\u30F3\u30C8\u306E\u5168\u30E1\u30C3\u30BB\u30FC\u30B8\u3068\u53C2\u52A0\u8005\u60C5\u5831\u3092\u8FD4\u5374\u3059\u308B\u3002",
|
|
15730
16181
|
params: {
|
|
15731
|
-
|
|
15732
|
-
limit: "\u8FD4\u5374\u30E1\u30C3\u30BB\u30FC\u30B8\u6570\u306E\u4E0A\u9650\u3002\u30C7\u30D5\u30A9\u30EB\u30C8 1000\u3002\u975E\u5E38\u306B\u9577\u3044\u30BB\
|
|
16182
|
+
segment_id: "\u30BB\u30B0\u30E1\u30F3\u30C8 ID\u3002search_segments \u306E\u8FD4\u5374\u7D50\u679C\u304B\u3089\u53D6\u5F97\u3067\u304D\u308B",
|
|
16183
|
+
limit: "\u8FD4\u5374\u30E1\u30C3\u30BB\u30FC\u30B8\u6570\u306E\u4E0A\u9650\u3002\u30C7\u30D5\u30A9\u30EB\u30C8 1000\u3002\u975E\u5E38\u306B\u9577\u3044\u30BB\u30B0\u30E1\u30F3\u30C8\u3067\u306F Token \u7BC0\u7D04\u306E\u305F\u3081\u4EF6\u6570\u3092\u5236\u9650\u3067\u304D\u308B"
|
|
15733
16184
|
}
|
|
15734
16185
|
},
|
|
15735
|
-
|
|
15736
|
-
desc: `\u30BB\
|
|
16186
|
+
get_segment_summaries: {
|
|
16187
|
+
desc: `\u30BB\u30B0\u30E1\u30F3\u30C8\u8981\u7D04\u30EA\u30B9\u30C8\u3092\u53D6\u5F97\u3057\u3001\u30B0\u30EB\u30FC\u30D7\u30C1\u30E3\u30C3\u30C8\u306E\u904E\u53BB\u306E\u8B70\u8AD6\u30C8\u30D4\u30C3\u30AF\u3092\u3059\u3070\u3084\u304F\u628A\u63E1\u3059\u308B\u3002
|
|
15737
16188
|
|
|
15738
16189
|
\u9069\u7528\u30B7\u30FC\u30F3\uFF1A
|
|
15739
16190
|
1. \u30B0\u30EB\u30FC\u30D7\u3067\u6700\u8FD1\u4F55\u304C\u8A71\u984C\u306B\u306A\u3063\u3066\u3044\u305F\u304B\u77E5\u308A\u305F\u3044
|
|
15740
16191
|
2. \u30AD\u30FC\u30EF\u30FC\u30C9\u3067\u904E\u53BB\u306B\u8B70\u8AD6\u3055\u308C\u305F\u30C8\u30D4\u30C3\u30AF\u3092\u691C\u7D22
|
|
15741
16192
|
3. \u300C\u30B0\u30EB\u30FC\u30D7\u3067\u65C5\u884C\u306B\u3064\u3044\u3066\u8A71\u3057\u305F\u3053\u3068\u3042\u308B\uFF1F\u300D\u306A\u3069\u306E\u6982\u8981\u7684\u306A\u8CEA\u554F
|
|
15742
16193
|
|
|
15743
|
-
\u8FD4\u5374\u3055\u308C\u308B\u8981\u7D04\u306F\u5404\u30BB\
|
|
16194
|
+
\u8FD4\u5374\u3055\u308C\u308B\u8981\u7D04\u306F\u5404\u30BB\u30B0\u30E1\u30F3\u30C8\u306E\u77ED\u3044\u6982\u8981\u3067\u3042\u308A\u3001\u8208\u5473\u306E\u3042\u308B\u30BB\u30B0\u30E1\u30F3\u30C8\u3092\u3059\u3070\u3084\u304F\u7279\u5B9A\u3057\u3001get_segment_messages \u3067\u8A73\u7D30\u3092\u53D6\u5F97\u3067\u304D\u308B\u3002`,
|
|
15744
16195
|
params: {
|
|
15745
16196
|
keywords: "\u8981\u7D04\u5185\u3067\u691C\u7D22\u3059\u308B\u30AD\u30FC\u30EF\u30FC\u30C9\u30EA\u30B9\u30C8\uFF08OR \u30ED\u30B8\u30C3\u30AF\u30DE\u30C3\u30C1\uFF09",
|
|
15746
|
-
limit: "\u8FD4\u5374\u30BB\
|
|
15747
|
-
year: "\u6307\u5B9A\u5E74\u306E\u30BB\
|
|
15748
|
-
month: "\u6307\u5B9A\u6708\u306E\u30BB\
|
|
15749
|
-
day: "\u6307\u5B9A\u65E5\u306E\u30BB\
|
|
16197
|
+
limit: "\u8FD4\u5374\u30BB\u30B0\u30E1\u30F3\u30C8\u6570\u306E\u4E0A\u9650\u3002\u30C7\u30D5\u30A9\u30EB\u30C8 20",
|
|
16198
|
+
year: "\u6307\u5B9A\u5E74\u306E\u30BB\u30B0\u30E1\u30F3\u30C8\u3092\u30D5\u30A3\u30EB\u30BF\u30EA\u30F3\u30B0",
|
|
16199
|
+
month: "\u6307\u5B9A\u6708\u306E\u30BB\u30B0\u30E1\u30F3\u30C8\u3092\u30D5\u30A3\u30EB\u30BF\u30EA\u30F3\u30B0\uFF081-12\uFF09",
|
|
16200
|
+
day: "\u6307\u5B9A\u65E5\u306E\u30BB\u30B0\u30E1\u30F3\u30C8\u3092\u30D5\u30A3\u30EB\u30BF\u30EA\u30F3\u30B0\uFF081-31\uFF09",
|
|
15750
16201
|
start_time: '\u958B\u59CB\u6642\u523B\u3002\u5F62\u5F0F "YYYY-MM-DD HH:mm"',
|
|
15751
16202
|
end_time: '\u7D42\u4E86\u6642\u523B\u3002\u5F62\u5F0F "YYYY-MM-DD HH:mm"'
|
|
15752
16203
|
}
|
|
@@ -15833,14 +16284,14 @@ var ja_JP_default = {
|
|
|
15833
16284
|
fallback: "\u3053\u306E\u671F\u9593\u306B\u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u8A18\u9332\u304C\u3042\u308A\u307E\u305B\u3093"
|
|
15834
16285
|
},
|
|
15835
16286
|
conversation_initiator_stats: {
|
|
15836
|
-
desc: "\u5404\u30E1\u30F3\u30D0\u30FC\u304C\u4F1A\u8A71\u3092\u958B\u59CB\u3057\u305F\u56DE\u6570\uFF08\u30BB\
|
|
16287
|
+
desc: "\u5404\u30E1\u30F3\u30D0\u30FC\u304C\u4F1A\u8A71\u3092\u958B\u59CB\u3057\u305F\u56DE\u6570\uFF08\u30BB\u30B0\u30E1\u30F3\u30C8\u306E\u6700\u521D\u306E\u767A\u8A00\u8005\uFF09\u3092\u96C6\u8A08\u3057\u3001\u8AB0\u304C\u6700\u3082\u8A71\u984C\u3092\u5207\u308A\u51FA\u3059\u304B\u3092\u767A\u898B\u3059\u308B\u3002\u30BB\u30B0\u30E1\u30F3\u30C8\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u306E\u751F\u6210\u304C\u5FC5\u8981\u3002",
|
|
15837
16288
|
params: {
|
|
15838
16289
|
days: "\u76F4\u8FD1\u4F55\u65E5\u9593\u306E\u30C7\u30FC\u30BF\u3092\u96C6\u8A08\u3059\u308B\u304B",
|
|
15839
16290
|
limit: "\u4E0A\u4F4D\u4F55\u540D\u3092\u8FD4\u5374\u3059\u308B\u304B"
|
|
15840
16291
|
},
|
|
15841
16292
|
rowTemplate: "{name}\uFF1A{initiated_count} \u56DE\u8A71\u984C\u3092\u958B\u59CB",
|
|
15842
16293
|
summaryTemplate: "\u8A71\u984C\u958B\u59CB\u8005 Top {rowCount}\uFF1A",
|
|
15843
|
-
fallback: "\u3053\u306E\u671F\u9593\u306B\u30BB\
|
|
16294
|
+
fallback: "\u3053\u306E\u671F\u9593\u306B\u30BB\u30B0\u30E1\u30F3\u30C8\u8A18\u9332\u304C\u3042\u308A\u307E\u305B\u3093\u3002\u5148\u306B\u30BB\u30B0\u30E1\u30F3\u30C8\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u3092\u751F\u6210\u3059\u308B\u5FC5\u8981\u304C\u3042\u308B\u304B\u3082\u3057\u308C\u307E\u305B\u3093"
|
|
15844
16295
|
},
|
|
15845
16296
|
activity_heatmap: {
|
|
15846
16297
|
desc: "\u66DC\u65E5\xD7\u6642\u9593\u5E2F\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u6570\u30DE\u30C8\u30EA\u30C3\u30AF\u30B9\u3092\u8FD4\u5374\u3059\u308B\u3002\u6D3B\u6027\u5EA6\u30D2\u30FC\u30C8\u30DE\u30C3\u30D7\u306E\u751F\u6210\u306B\u9069\u3057\u3066\u3044\u308B\u3002weekday: 0=\u65E5\u66DC, 1=\u6708\u66DC, ..., 6=\u571F\u66DC\u3002",
|
|
@@ -15862,6 +16313,19 @@ var ja_JP_default = {
|
|
|
15862
16313
|
days: "\u76F4\u8FD1\u4F55\u65E5\u9593\u306E\u30C7\u30FC\u30BF\u3092\u96C6\u8A08\u3059\u308B\u304B",
|
|
15863
16314
|
top_n: "\u4E0A\u4F4D\u4F55\u500B\u306E\u30AD\u30FC\u30EF\u30FC\u30C9\u3092\u8FD4\u5374\u3059\u308B\u304B"
|
|
15864
16315
|
}
|
|
16316
|
+
},
|
|
16317
|
+
get_schema: {
|
|
16318
|
+
desc: "\u30C1\u30E3\u30C3\u30C8\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u30B9\u30AD\u30FC\u30DE\u3092\u78BA\u8A8D\u3057\u307E\u3059\u3002\u30C1\u30E3\u30FC\u30C8\u4F5C\u6210\u3084\u30AB\u30B9\u30BF\u30E0 SQL \u306E\u524D\u306B\u30C6\u30FC\u30D6\u30EB\u540D\u3068\u30D5\u30A3\u30FC\u30EB\u30C9\u540D\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
16319
|
+
params: {}
|
|
16320
|
+
},
|
|
16321
|
+
render_chart: {
|
|
16322
|
+
desc: "\u8AAD\u307F\u53D6\u308A\u5C02\u7528 SQL \u3068 ChartSpec v1 \u304B\u3089 ChatLab \u30CD\u30A4\u30C6\u30A3\u30D6\u30C1\u30E3\u30FC\u30C8\u3092\u751F\u6210\u3057\u307E\u3059\u3002bar\u3001line\u3001pie\u3001heatmap \u3092\u30B5\u30DD\u30FC\u30C8\u3057\u307E\u3059\u3002HTML\u3001JavaScript\u3001SVG\u3001ECharts option\u3001\u63CF\u753B\u30B3\u30FC\u30C9\u306F\u51FA\u529B\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002",
|
|
16323
|
+
params: {
|
|
16324
|
+
sql: "\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u306E SELECT \u307E\u305F\u306F WITH SELECT SQL\u3002ChartSpec encoding \u3067\u53C2\u7167\u3059\u308B\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u8FD4\u3059\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002",
|
|
16325
|
+
params: "SQL \u306E\u540D\u524D\u4ED8\u304D\u30D1\u30E9\u30E1\u30FC\u30BF\u3002\u4E0D\u8981\u306A\u5834\u5408\u306F\u7A7A\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3092\u6E21\u3057\u307E\u3059\u3002",
|
|
16326
|
+
chartSpec: "version\u3001type\u3001title\u3001encoding \u3092\u542B\u3080 ChartSpec v1\u3002",
|
|
16327
|
+
maxRows: "\u30C1\u30E3\u30FC\u30C8\u30AF\u30A8\u30EA\u306E\u6700\u5927\u884C\u6570\u3002\u30C7\u30D5\u30A9\u30EB\u30C8\u306F 1000\u3002"
|
|
16328
|
+
}
|
|
15865
16329
|
}
|
|
15866
16330
|
},
|
|
15867
16331
|
agent: {
|
|
@@ -15929,10 +16393,10 @@ var ja_JP_default = {
|
|
|
15929
16393
|
rawErrorLabel: "\u5143\u306E\u30A8\u30E9\u30FC"
|
|
15930
16394
|
},
|
|
15931
16395
|
summary: {
|
|
15932
|
-
|
|
16396
|
+
segmentNotFound: "\u30BB\u30B0\u30E1\u30F3\u30C8\u304C\u5B58\u5728\u3057\u306A\u3044\u304B\u3001\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u958B\u3051\u307E\u305B\u3093\u3067\u3057\u305F",
|
|
15933
16397
|
tooFewMessages: "\u30E1\u30C3\u30BB\u30FC\u30B8\u6570\u304C{{count}}\u4EF6\u672A\u6E80\u306E\u305F\u3081\u3001\u8981\u7D04\u306E\u751F\u6210\u306F\u4E0D\u8981\u3067\u3059",
|
|
15934
16398
|
tooFewValidMessages: "\u6709\u52B9\u306A\u30E1\u30C3\u30BB\u30FC\u30B8\u6570\u304C{{count}}\u4EF6\u672A\u6E80\u306E\u305F\u3081\u3001\u8981\u7D04\u306E\u751F\u6210\u306F\u4E0D\u8981\u3067\u3059",
|
|
15935
|
-
|
|
16399
|
+
segmentNotExist: "\u30BB\u30B0\u30E1\u30F3\u30C8\u304C\u5B58\u5728\u3057\u307E\u305B\u3093",
|
|
15936
16400
|
messagesTooFew: "\u30E1\u30C3\u30BB\u30FC\u30B8\u304C\u5C11\u306A\u3059\u304E\u307E\u3059",
|
|
15937
16401
|
validMessagesTooFew: "\u6709\u52B9\u306A\u30E1\u30C3\u30BB\u30FC\u30B8\u304C\u5C11\u306A\u3059\u304E\u307E\u3059",
|
|
15938
16402
|
systemPromptDirect: "\u3042\u306A\u305F\u306F\u4F1A\u8A71\u8981\u7D04\u306E\u5C02\u9580\u5BB6\u3067\u3042\u308A\u3001\u7C21\u6F54\u306A\u8A00\u8449\u3067\u4F1A\u8A71\u5185\u5BB9\u3092\u8981\u7D04\u3059\u308B\u3053\u3068\u306B\u9577\u3051\u3066\u3044\u308B\u3002",
|
|
@@ -16032,7 +16496,7 @@ var zh_TW_default = {
|
|
|
16032
16496
|
context_size: "\u4E0A\u4E0B\u6587\u5927\u5C0F\uFF0C\u5373\u53D6\u5F97\u524D\u5F8C\u5404\u591A\u5C11\u689D\u8A0A\u606F\uFF0C\u9810\u8A2D 20"
|
|
16033
16497
|
}
|
|
16034
16498
|
},
|
|
16035
|
-
|
|
16499
|
+
search_segments: {
|
|
16036
16500
|
desc: "\u641C\u5C0B\u804A\u5929\u6703\u8A71\uFF08\u5C0D\u8A71\u6BB5\u843D\uFF09\u3002\u6703\u8A71\u662F\u6839\u64DA\u8A0A\u606F\u6642\u9593\u9593\u9694\u81EA\u52D5\u5207\u5206\u7684\u5C0D\u8A71\u55AE\u5143\u3002\u9069\u7528\u65BC\u67E5\u627E\u7279\u5B9A\u8A71\u984C\u7684\u8A0E\u8AD6\u3001\u4E86\u89E3\u67D0\u500B\u6642\u9593\u6BB5\u5167\u767C\u751F\u4E86\u5E7E\u6B21\u5C0D\u8A71\u7B49\u5834\u666F\u3002\u56DE\u50B3\u5339\u914D\u7684\u6703\u8A71\u6E05\u55AE\u53CA\u6BCF\u500B\u6703\u8A71\u7684\u524D5\u689D\u8A0A\u606F\u9810\u89BD\u3002",
|
|
16037
16501
|
params: {
|
|
16038
16502
|
keywords: "\u53EF\u9078\u7684\u641C\u5C0B\u95DC\u9375\u8A5E\u6E05\u55AE\uFF0C\u53EA\u56DE\u50B3\u5305\u542B\u9019\u4E9B\u95DC\u9375\u8A5E\u7684\u6703\u8A71\uFF08OR \u908F\u8F2F\u5339\u914D\uFF09",
|
|
@@ -16044,22 +16508,22 @@ var zh_TW_default = {
|
|
|
16044
16508
|
end_time: '\u7D50\u675F\u6642\u9593\uFF0C\u683C\u5F0F "YYYY-MM-DD HH:mm"\uFF0C\u5982 "2024-03-15 18:30"'
|
|
16045
16509
|
}
|
|
16046
16510
|
},
|
|
16047
|
-
|
|
16048
|
-
desc: "\u53D6\u5F97\u6307\u5B9A\u6703\u8A71\u7684\u5B8C\u6574\u8A0A\u606F\u6E05\u55AE\u3002\u7528\u65BC\u5728
|
|
16511
|
+
get_segment_messages: {
|
|
16512
|
+
desc: "\u53D6\u5F97\u6307\u5B9A\u6703\u8A71\u7684\u5B8C\u6574\u8A0A\u606F\u6E05\u55AE\u3002\u7528\u65BC\u5728 search_segments \u627E\u5230\u76F8\u95DC\u6703\u8A71\u5F8C\uFF0C\u53D6\u5F97\u8A72\u6703\u8A71\u7684\u5B8C\u6574\u4E0A\u4E0B\u6587\u3002\u56DE\u50B3\u6703\u8A71\u7684\u6240\u6709\u8A0A\u606F\u53CA\u53C3\u8207\u8005\u8CC7\u8A0A\u3002",
|
|
16049
16513
|
params: {
|
|
16050
|
-
|
|
16514
|
+
segment_id: "\u6703\u8A71 ID\uFF0C\u53EF\u4EE5\u5F9E search_segments \u7684\u56DE\u50B3\u7D50\u679C\u4E2D\u53D6\u5F97",
|
|
16051
16515
|
limit: "\u56DE\u50B3\u8A0A\u606F\u6578\u91CF\u9650\u5236\uFF0C\u9810\u8A2D 1000\u3002\u5C0D\u65BC\u8D85\u9577\u6703\u8A71\u53EF\u4EE5\u9650\u5236\u56DE\u50B3\u6578\u91CF\u4EE5\u7BC0\u7701 token"
|
|
16052
16516
|
}
|
|
16053
16517
|
},
|
|
16054
|
-
|
|
16055
|
-
desc: `\u53D6\u5F97\
|
|
16518
|
+
get_segment_summaries: {
|
|
16519
|
+
desc: `\u53D6\u5F97\u6BB5\u843D\u6458\u8981\u6E05\u55AE\uFF0C\u5FEB\u901F\u4E86\u89E3\u7FA4\u804A\u6B77\u53F2\u8A0E\u8AD6\u7684\u4E3B\u984C\u3002
|
|
16056
16520
|
|
|
16057
16521
|
\u9069\u7528\u5834\u666F\uFF1A
|
|
16058
16522
|
1. \u4E86\u89E3\u7FA4\u88E1\u6700\u8FD1\u5728\u804A\u4EC0\u9EBC\u8A71\u984C
|
|
16059
16523
|
2. \u6309\u95DC\u9375\u8A5E\u641C\u5C0B\u8A0E\u8AD6\u904E\u7684\u8A71\u984C
|
|
16060
16524
|
3. \u6982\u89BD\u6027\u554F\u984C\u5982\u300C\u7FA4\u88E1\u6709\u6C92\u6709\u8A0E\u8AD6\u904E\u65C5\u904A\u300D
|
|
16061
16525
|
|
|
16062
|
-
\u56DE\u50B3\u7684\u6458\u8981\u662F\u5C0D\u6BCF\u500B\u6703\u8A71\u7684\u7C21\u77ED\u7E3D\u7D50\uFF0C\u53EF\u4EE5\u5E6B\u52A9\u5FEB\u901F\u5B9A\u4F4D\u611F\u8208\u8DA3\u7684\u6703\u8A71\uFF0C\u7136\u5F8C\u7528
|
|
16526
|
+
\u56DE\u50B3\u7684\u6458\u8981\u662F\u5C0D\u6BCF\u500B\u6703\u8A71\u7684\u7C21\u77ED\u7E3D\u7D50\uFF0C\u53EF\u4EE5\u5E6B\u52A9\u5FEB\u901F\u5B9A\u4F4D\u611F\u8208\u8DA3\u7684\u6703\u8A71\uFF0C\u7136\u5F8C\u7528 get_segment_messages \u53D6\u5F97\u8A73\u60C5\u3002`,
|
|
16063
16527
|
params: {
|
|
16064
16528
|
keywords: "\u5728\u6458\u8981\u4E2D\u641C\u5C0B\u7684\u95DC\u9375\u8A5E\u6E05\u55AE\uFF08OR \u908F\u8F2F\u5339\u914D\uFF09",
|
|
16065
16529
|
limit: "\u56DE\u50B3\u6703\u8A71\u6578\u91CF\u9650\u5236\uFF0C\u9810\u8A2D 20",
|
|
@@ -16181,6 +16645,19 @@ var zh_TW_default = {
|
|
|
16181
16645
|
days: "\u7D71\u8A08\u6700\u8FD1\u591A\u5C11\u5929\u7684\u8CC7\u6599",
|
|
16182
16646
|
top_n: "\u56DE\u50B3\u524D\u591A\u5C11\u500B\u95DC\u9375\u8A5E"
|
|
16183
16647
|
}
|
|
16648
|
+
},
|
|
16649
|
+
get_schema: {
|
|
16650
|
+
desc: "\u67E5\u770B\u804A\u5929\u8CC7\u6599\u5EAB\u8868\u7D50\u69CB\u3002\u7E6A\u5716\u6216\u81EA\u8A02 SQL \u524D\u61C9\u5148\u7528\u5B83\u78BA\u8A8D\u8868\u540D\u548C\u6B04\u4F4D\u540D\u3002",
|
|
16651
|
+
params: {}
|
|
16652
|
+
},
|
|
16653
|
+
render_chart: {
|
|
16654
|
+
desc: "\u6839\u64DA\u552F\u8B80 SQL \u548C ChartSpec v1 \u751F\u6210 ChatLab \u539F\u751F\u5716\u8868\u3002\u652F\u63F4 bar\u3001line\u3001pie\u3001heatmap\u3002\u7981\u6B62\u8F38\u51FA HTML\u3001JavaScript\u3001SVG\u3001ECharts option \u6216\u6E32\u67D3\u7A0B\u5F0F\u78BC\u3002",
|
|
16655
|
+
params: {
|
|
16656
|
+
sql: "\u552F\u8B80 SELECT \u6216 WITH SELECT SQL\u3002\u5FC5\u9808\u8FD4\u56DE ChartSpec encoding \u4E2D\u5F15\u7528\u7684\u6B04\u4F4D\u3002",
|
|
16657
|
+
params: "SQL \u547D\u540D\u53C3\u6578\u7269\u4EF6\uFF1B\u4E0D\u9700\u8981\u53C3\u6578\u6642\u50B3\u7A7A\u7269\u4EF6\u3002",
|
|
16658
|
+
chartSpec: "ChartSpec v1\uFF0C\u5305\u542B version\u3001type\u3001title\u3001encoding\u3002",
|
|
16659
|
+
maxRows: "\u5716\u8868\u67E5\u8A62\u6700\u5927\u884C\u6578\uFF0C\u9810\u8A2D 1000\u3002"
|
|
16660
|
+
}
|
|
16184
16661
|
}
|
|
16185
16662
|
},
|
|
16186
16663
|
agent: {
|
|
@@ -16248,10 +16725,10 @@ var zh_TW_default = {
|
|
|
16248
16725
|
rawErrorLabel: "\u539F\u59CB\u932F\u8AA4"
|
|
16249
16726
|
},
|
|
16250
16727
|
summary: {
|
|
16251
|
-
|
|
16728
|
+
segmentNotFound: "\u6703\u8A71\u4E0D\u5B58\u5728\u6216\u8CC7\u6599\u5EAB\u958B\u555F\u5931\u6557",
|
|
16252
16729
|
tooFewMessages: "\u8A0A\u606F\u6578\u91CF\u5C11\u65BC {{count}} \u689D\uFF0C\u7121\u9700\u7522\u751F\u6458\u8981",
|
|
16253
16730
|
tooFewValidMessages: "\u6709\u6548\u8A0A\u606F\u6578\u91CF\u5C11\u65BC {{count}} \u689D\uFF0C\u7121\u9700\u7522\u751F\u6458\u8981",
|
|
16254
|
-
|
|
16731
|
+
segmentNotExist: "\u627E\u4E0D\u5230\u6703\u8A71",
|
|
16255
16732
|
messagesTooFew: "\u8A0A\u606F\u592A\u5C11",
|
|
16256
16733
|
validMessagesTooFew: "\u6709\u6548\u8A0A\u606F\u592A\u5C11",
|
|
16257
16734
|
systemPromptDirect: "\u4F60\u662F\u4E00\u500B\u5C0D\u8A71\u6458\u8981\u5C08\u5BB6\uFF0C\u64C5\u9577\u7528\u7C21\u6F54\u7684\u8A9E\u8A00\u7E3D\u7D50\u5C0D\u8A71\u5167\u5BB9\u3002",
|
|
@@ -16266,9 +16743,9 @@ var localeMap = {
|
|
|
16266
16743
|
"ja-JP": ja_JP_default,
|
|
16267
16744
|
"zh-TW": zh_TW_default
|
|
16268
16745
|
};
|
|
16269
|
-
function getNestedValue(obj,
|
|
16746
|
+
function getNestedValue(obj, path36) {
|
|
16270
16747
|
let current = obj;
|
|
16271
|
-
for (const segment2 of
|
|
16748
|
+
for (const segment2 of path36.split(".")) {
|
|
16272
16749
|
if (current == null || typeof current !== "object") return void 0;
|
|
16273
16750
|
current = current[segment2];
|
|
16274
16751
|
}
|
|
@@ -16464,15 +16941,15 @@ function postProcessSummary(summary, lengthLimit) {
|
|
|
16464
16941
|
}
|
|
16465
16942
|
return result;
|
|
16466
16943
|
}
|
|
16467
|
-
async function generateSessionSummary(deps,
|
|
16944
|
+
async function generateSessionSummary(deps, segmentId, options = {}) {
|
|
16468
16945
|
const { locale = "zh-CN", forceRegenerate = false, strategy = "standard" } = options;
|
|
16469
16946
|
const log = deps.logger;
|
|
16470
16947
|
try {
|
|
16471
16948
|
if (!forceRegenerate) {
|
|
16472
|
-
const existing = deps.getSummary(
|
|
16949
|
+
const existing = deps.getSummary(segmentId);
|
|
16473
16950
|
if (existing) return { success: true, summary: existing };
|
|
16474
16951
|
}
|
|
16475
|
-
const rawMessages = deps.loadMessages(
|
|
16952
|
+
const rawMessages = deps.loadMessages(segmentId);
|
|
16476
16953
|
if (!rawMessages) {
|
|
16477
16954
|
return { success: false, error: deps.t("summary.sessionNotFound") };
|
|
16478
16955
|
}
|
|
@@ -16489,7 +16966,7 @@ async function generateSessionSummary(deps, chatSessionId, options = {}) {
|
|
|
16489
16966
|
const content = formatMessages(validMessages);
|
|
16490
16967
|
log?.info(
|
|
16491
16968
|
"Summary",
|
|
16492
|
-
`Generating summary: sessionId=${
|
|
16969
|
+
`Generating summary: sessionId=${segmentId}, strategy=${strategy}, raw=${rawMessages.length}, valid=${validMessages.length}, chars=${content.length}`
|
|
16493
16970
|
);
|
|
16494
16971
|
let summary;
|
|
16495
16972
|
if (content.length <= SEGMENT_THRESHOLD) {
|
|
@@ -16524,7 +17001,7 @@ async function generateSessionSummary(deps, chatSessionId, options = {}) {
|
|
|
16524
17001
|
}
|
|
16525
17002
|
}
|
|
16526
17003
|
summary = postProcessSummary(summary, lengthLimit);
|
|
16527
|
-
deps.saveSummary(
|
|
17004
|
+
deps.saveSummary(segmentId, summary);
|
|
16528
17005
|
log?.info("Summary", `Summary generated: "${summary.slice(0, 50)}..."`);
|
|
16529
17006
|
return { success: true, summary };
|
|
16530
17007
|
} catch (error) {
|
|
@@ -16532,9 +17009,9 @@ async function generateSessionSummary(deps, chatSessionId, options = {}) {
|
|
|
16532
17009
|
return { success: false, error: error instanceof Error ? error.message : String(error) };
|
|
16533
17010
|
}
|
|
16534
17011
|
}
|
|
16535
|
-
function checkSessionsCanGenerateSummary(deps,
|
|
17012
|
+
function checkSessionsCanGenerateSummary(deps, segmentIds) {
|
|
16536
17013
|
const results = /* @__PURE__ */ new Map();
|
|
16537
|
-
for (const id of
|
|
17014
|
+
for (const id of segmentIds) {
|
|
16538
17015
|
const messages = deps.loadMessages(id);
|
|
16539
17016
|
if (!messages) {
|
|
16540
17017
|
results.set(id, { canGenerate: false, reason: deps.t("summary.sessionNotExist") });
|
|
@@ -16845,7 +17322,7 @@ function getNoopLogger() {
|
|
|
16845
17322
|
var _logger = getNoopLogger();
|
|
16846
17323
|
|
|
16847
17324
|
// ../../packages/node-runtime/src/ai/rag/chunking/session.ts
|
|
16848
|
-
import
|
|
17325
|
+
import Database2 from "better-sqlite3";
|
|
16849
17326
|
var _logger2 = getNoopLogger();
|
|
16850
17327
|
|
|
16851
17328
|
// ../../packages/node-runtime/src/ai/rag/embedding/openai-compatible.ts
|
|
@@ -16855,7 +17332,7 @@ var _logger3 = getNoopLogger();
|
|
|
16855
17332
|
var _logger4 = getNoopLogger();
|
|
16856
17333
|
|
|
16857
17334
|
// ../../packages/node-runtime/src/ai/rag/store/sqlite.ts
|
|
16858
|
-
import
|
|
17335
|
+
import Database3 from "better-sqlite3";
|
|
16859
17336
|
var _logger5 = getNoopLogger();
|
|
16860
17337
|
|
|
16861
17338
|
// ../../packages/node-runtime/src/ai/rag/store/memory.ts
|
|
@@ -17380,7 +17857,216 @@ function expandHome(filePath) {
|
|
|
17380
17857
|
return filePath;
|
|
17381
17858
|
}
|
|
17382
17859
|
|
|
17860
|
+
// ../../packages/node-runtime/src/data-dir-compat.ts
|
|
17861
|
+
import fs34 from "fs";
|
|
17862
|
+
import path31 from "path";
|
|
17863
|
+
var DataDirCompatibilityError = class extends Error {
|
|
17864
|
+
code;
|
|
17865
|
+
userDataDir;
|
|
17866
|
+
metaPath;
|
|
17867
|
+
currentVersion;
|
|
17868
|
+
minRuntimeVersion;
|
|
17869
|
+
statusCode = 409;
|
|
17870
|
+
constructor(code, message, options) {
|
|
17871
|
+
super(message, { cause: options.cause });
|
|
17872
|
+
this.name = "DataDirCompatibilityError";
|
|
17873
|
+
this.code = code;
|
|
17874
|
+
this.userDataDir = options.userDataDir;
|
|
17875
|
+
this.metaPath = options.metaPath;
|
|
17876
|
+
this.currentVersion = options.currentVersion;
|
|
17877
|
+
this.minRuntimeVersion = options.minRuntimeVersion;
|
|
17878
|
+
}
|
|
17879
|
+
};
|
|
17880
|
+
function readDataDirCompatibilityMeta(userDataDir) {
|
|
17881
|
+
const metaPath = getMetaPath(userDataDir);
|
|
17882
|
+
if (!fs34.existsSync(metaPath)) return null;
|
|
17883
|
+
let parsed;
|
|
17884
|
+
try {
|
|
17885
|
+
parsed = JSON.parse(fs34.readFileSync(metaPath, "utf-8"));
|
|
17886
|
+
} catch (error) {
|
|
17887
|
+
throw createInvalidMetaError(userDataDir, metaPath, "Invalid data directory compatibility meta JSON.", error);
|
|
17888
|
+
}
|
|
17889
|
+
return validateDataDirCompatibilityMeta(parsed, userDataDir, metaPath);
|
|
17890
|
+
}
|
|
17891
|
+
function assertDataDirCompatible(pathProvider, runtime, options = {}) {
|
|
17892
|
+
const userDataDir = pathProvider.getUserDataDir();
|
|
17893
|
+
const meta = readDataDirCompatibilityMeta(userDataDir);
|
|
17894
|
+
if (!meta) return;
|
|
17895
|
+
if (!isStableSemver(runtime.version)) {
|
|
17896
|
+
throw new DataDirCompatibilityError(
|
|
17897
|
+
"DATA_DIR_REQUIRES_NEWER_RUNTIME",
|
|
17898
|
+
`ChatLab data directory compatibility check requires a stable runtime version; current version is ${runtime.version}.`,
|
|
17899
|
+
{
|
|
17900
|
+
userDataDir,
|
|
17901
|
+
metaPath: getMetaPath(userDataDir),
|
|
17902
|
+
currentVersion: runtime.version,
|
|
17903
|
+
minRuntimeVersion: meta.minRuntimeVersion
|
|
17904
|
+
}
|
|
17905
|
+
);
|
|
17906
|
+
}
|
|
17907
|
+
if (compareStableSemver(runtime.version, meta.minRuntimeVersion) < 0) {
|
|
17908
|
+
const env = options.env ?? process.env;
|
|
17909
|
+
if (env.CHATLAB_ALLOW_INCOMPATIBLE_DATA_DIR === "1") {
|
|
17910
|
+
const warn = options.warn ?? console.warn;
|
|
17911
|
+
warn(
|
|
17912
|
+
[
|
|
17913
|
+
"CHATLAB_ALLOW_INCOMPATIBLE_DATA_DIR=1 is set. ChatLab will bypass the data directory runtime version gate.",
|
|
17914
|
+
`Current runtime ${runtime.kind}@${runtime.version} is below required version ${meta.minRuntimeVersion}.`,
|
|
17915
|
+
`Data directory: ${userDataDir}. Continuing may risk data corruption.`
|
|
17916
|
+
].join(" ")
|
|
17917
|
+
);
|
|
17918
|
+
return;
|
|
17919
|
+
}
|
|
17920
|
+
throw new DataDirCompatibilityError(
|
|
17921
|
+
"DATA_DIR_REQUIRES_NEWER_RUNTIME",
|
|
17922
|
+
`ChatLab data directory requires runtime version ${meta.minRuntimeVersion} or newer; current version is ${runtime.version}.`,
|
|
17923
|
+
{
|
|
17924
|
+
userDataDir,
|
|
17925
|
+
metaPath: getMetaPath(userDataDir),
|
|
17926
|
+
currentVersion: runtime.version,
|
|
17927
|
+
minRuntimeVersion: meta.minRuntimeVersion
|
|
17928
|
+
}
|
|
17929
|
+
);
|
|
17930
|
+
}
|
|
17931
|
+
}
|
|
17932
|
+
function raiseDataDirMinRuntimeVersion(pathProvider, input) {
|
|
17933
|
+
const userDataDir = pathProvider.getUserDataDir();
|
|
17934
|
+
const metaPath = getMetaPath(userDataDir);
|
|
17935
|
+
assertStableVersion(input.minRuntimeVersion, userDataDir, metaPath, "Invalid minRuntimeVersion.");
|
|
17936
|
+
assertStableVersion(input.runtime.version, userDataDir, metaPath, "Invalid runtime version.");
|
|
17937
|
+
if (!isRuntimeKind(input.runtime.kind)) {
|
|
17938
|
+
throw createInvalidMetaError(userDataDir, metaPath, "Invalid runtime kind.");
|
|
17939
|
+
}
|
|
17940
|
+
if (!isNonEmptyString(input.module) || !isNonEmptyString(input.reason)) {
|
|
17941
|
+
throw createInvalidMetaError(userDataDir, metaPath, "Invalid compatibility raise metadata.");
|
|
17942
|
+
}
|
|
17943
|
+
if (!Number.isInteger(input.dataCompatibilityVersion) || input.dataCompatibilityVersion < 0) {
|
|
17944
|
+
throw createInvalidMetaError(userDataDir, metaPath, "Invalid dataCompatibilityVersion.");
|
|
17945
|
+
}
|
|
17946
|
+
const existing = readDataDirCompatibilityMeta(userDataDir);
|
|
17947
|
+
const minRuntimeVersion = existing && compareStableSemver(existing.minRuntimeVersion, input.minRuntimeVersion) > 0 ? existing.minRuntimeVersion : input.minRuntimeVersion;
|
|
17948
|
+
const dataCompatibilityVersion = Math.max(existing?.dataCompatibilityVersion ?? 0, input.dataCompatibilityVersion);
|
|
17949
|
+
const reasons = mergeReasons(existing?.reasons ?? [], input.reason);
|
|
17950
|
+
const now = input.now ?? (() => Math.floor(Date.now() / 1e3));
|
|
17951
|
+
const nextMeta = {
|
|
17952
|
+
formatVersion: 1,
|
|
17953
|
+
minRuntimeVersion,
|
|
17954
|
+
dataCompatibilityVersion,
|
|
17955
|
+
reasons,
|
|
17956
|
+
updatedBy: {
|
|
17957
|
+
runtime: input.runtime.kind,
|
|
17958
|
+
module: input.module,
|
|
17959
|
+
version: input.runtime.version
|
|
17960
|
+
},
|
|
17961
|
+
updatedAt: now()
|
|
17962
|
+
};
|
|
17963
|
+
writeMetaAtomic(userDataDir, metaPath, nextMeta);
|
|
17964
|
+
return nextMeta;
|
|
17965
|
+
}
|
|
17966
|
+
function getMetaPath(userDataDir) {
|
|
17967
|
+
return path31.join(userDataDir, ".chatlab-meta.json");
|
|
17968
|
+
}
|
|
17969
|
+
function validateDataDirCompatibilityMeta(value, userDataDir, metaPath) {
|
|
17970
|
+
if (!isRecord2(value)) {
|
|
17971
|
+
throw createInvalidMetaError(userDataDir, metaPath, "Data directory compatibility meta must be an object.");
|
|
17972
|
+
}
|
|
17973
|
+
if (value.formatVersion !== 1) {
|
|
17974
|
+
throw createInvalidMetaError(userDataDir, metaPath, "Unsupported data directory compatibility meta format.");
|
|
17975
|
+
}
|
|
17976
|
+
const minRuntimeVersion = value.minRuntimeVersion;
|
|
17977
|
+
const dataCompatibilityVersion = value.dataCompatibilityVersion;
|
|
17978
|
+
const reasons = value.reasons;
|
|
17979
|
+
const updatedBy = value.updatedBy;
|
|
17980
|
+
const updatedAt = value.updatedAt;
|
|
17981
|
+
if (!isStableSemver(minRuntimeVersion) || typeof dataCompatibilityVersion !== "number" || !Number.isInteger(dataCompatibilityVersion) || dataCompatibilityVersion < 0 || !Array.isArray(reasons) || !reasons.every(isNonEmptyString) || !isRecord2(updatedBy) || !isRuntimeKind(updatedBy.runtime) || !isNonEmptyString(updatedBy.module) || !isStableSemver(updatedBy.version) || typeof updatedAt !== "number" || !Number.isInteger(updatedAt) || updatedAt < 0) {
|
|
17982
|
+
throw createInvalidMetaError(userDataDir, metaPath, "Invalid data directory compatibility meta fields.");
|
|
17983
|
+
}
|
|
17984
|
+
return {
|
|
17985
|
+
formatVersion: 1,
|
|
17986
|
+
minRuntimeVersion,
|
|
17987
|
+
dataCompatibilityVersion,
|
|
17988
|
+
reasons: [...reasons],
|
|
17989
|
+
updatedBy: {
|
|
17990
|
+
runtime: updatedBy.runtime,
|
|
17991
|
+
module: updatedBy.module,
|
|
17992
|
+
version: updatedBy.version
|
|
17993
|
+
},
|
|
17994
|
+
updatedAt
|
|
17995
|
+
};
|
|
17996
|
+
}
|
|
17997
|
+
function createInvalidMetaError(userDataDir, metaPath, message, cause) {
|
|
17998
|
+
return new DataDirCompatibilityError("DATA_DIR_COMPATIBILITY_META_INVALID", message, {
|
|
17999
|
+
userDataDir,
|
|
18000
|
+
metaPath,
|
|
18001
|
+
cause
|
|
18002
|
+
});
|
|
18003
|
+
}
|
|
18004
|
+
function assertStableVersion(version, userDataDir, metaPath, message) {
|
|
18005
|
+
if (!isStableSemver(version)) {
|
|
18006
|
+
throw createInvalidMetaError(userDataDir, metaPath, message);
|
|
18007
|
+
}
|
|
18008
|
+
}
|
|
18009
|
+
function isStableSemver(version) {
|
|
18010
|
+
return typeof version === "string" && /^\d+\.\d+\.\d+$/.test(version);
|
|
18011
|
+
}
|
|
18012
|
+
function compareStableSemver(left, right) {
|
|
18013
|
+
const leftParts = left.split(".").map(Number);
|
|
18014
|
+
const rightParts = right.split(".").map(Number);
|
|
18015
|
+
for (let i = 0; i < 3; i += 1) {
|
|
18016
|
+
if (leftParts[i] > rightParts[i]) return 1;
|
|
18017
|
+
if (leftParts[i] < rightParts[i]) return -1;
|
|
18018
|
+
}
|
|
18019
|
+
return 0;
|
|
18020
|
+
}
|
|
18021
|
+
function mergeReasons(existing, next) {
|
|
18022
|
+
return [.../* @__PURE__ */ new Set([...existing, next])];
|
|
18023
|
+
}
|
|
18024
|
+
function writeMetaAtomic(userDataDir, metaPath, meta) {
|
|
18025
|
+
fs34.mkdirSync(userDataDir, { recursive: true });
|
|
18026
|
+
const tempPath = path31.join(userDataDir, `.chatlab-meta.json.${process.pid}.${Date.now()}.tmp`);
|
|
18027
|
+
try {
|
|
18028
|
+
fs34.writeFileSync(tempPath, `${JSON.stringify(meta, null, 2)}
|
|
18029
|
+
`, "utf-8");
|
|
18030
|
+
fs34.renameSync(tempPath, metaPath);
|
|
18031
|
+
} catch (error) {
|
|
18032
|
+
try {
|
|
18033
|
+
if (fs34.existsSync(tempPath)) fs34.unlinkSync(tempPath);
|
|
18034
|
+
} catch {
|
|
18035
|
+
}
|
|
18036
|
+
throw error;
|
|
18037
|
+
}
|
|
18038
|
+
}
|
|
18039
|
+
function isRecord2(value) {
|
|
18040
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18041
|
+
}
|
|
18042
|
+
function isNonEmptyString(value) {
|
|
18043
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
18044
|
+
}
|
|
18045
|
+
function isRuntimeKind(value) {
|
|
18046
|
+
return value === "cli" || value === "desktop" || value === "mcp" || value === "unknown";
|
|
18047
|
+
}
|
|
18048
|
+
|
|
17383
18049
|
// ../../packages/node-runtime/src/migrations/chat-db-migrations.ts
|
|
18050
|
+
var CHAT_DB_COMPATIBILITY_RAISES = [
|
|
18051
|
+
{
|
|
18052
|
+
migrationVersion: 6,
|
|
18053
|
+
minRuntimeVersion: "0.25.1",
|
|
18054
|
+
dataCompatibilityVersion: 1,
|
|
18055
|
+
reason: "segment-schema",
|
|
18056
|
+
module: "chat-db-migration"
|
|
18057
|
+
}
|
|
18058
|
+
];
|
|
18059
|
+
function raiseChatDbCompatibilityGate(pathProvider, runtime) {
|
|
18060
|
+
for (const compatibilityRaise of CHAT_DB_COMPATIBILITY_RAISES) {
|
|
18061
|
+
raiseDataDirMinRuntimeVersion(pathProvider, {
|
|
18062
|
+
minRuntimeVersion: compatibilityRaise.minRuntimeVersion,
|
|
18063
|
+
dataCompatibilityVersion: compatibilityRaise.dataCompatibilityVersion,
|
|
18064
|
+
reason: compatibilityRaise.reason,
|
|
18065
|
+
runtime,
|
|
18066
|
+
module: compatibilityRaise.module
|
|
18067
|
+
});
|
|
18068
|
+
}
|
|
18069
|
+
}
|
|
17384
18070
|
function getChatDbMigrations(deps) {
|
|
17385
18071
|
const hasColumn2 = (db, tableName, columnName) => {
|
|
17386
18072
|
const tableInfo = db.pragma(`table_info(${tableName})`);
|
|
@@ -17555,13 +18241,120 @@ function getChatDbMigrations(deps) {
|
|
|
17555
18241
|
db.exec("CREATE INDEX IF NOT EXISTS idx_session_time ON chat_session(start_ts, end_ts)");
|
|
17556
18242
|
db.exec("CREATE INDEX IF NOT EXISTS idx_context_session ON message_context(session_id)");
|
|
17557
18243
|
}
|
|
18244
|
+
},
|
|
18245
|
+
{
|
|
18246
|
+
version: 6,
|
|
18247
|
+
description: "Rename chat_session index tables to segment terminology",
|
|
18248
|
+
up: (db) => {
|
|
18249
|
+
const hasTable2 = (tableName) => {
|
|
18250
|
+
const row = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name = ?").get(tableName);
|
|
18251
|
+
return !!row;
|
|
18252
|
+
};
|
|
18253
|
+
db.exec(`
|
|
18254
|
+
DROP INDEX IF EXISTS idx_session_time;
|
|
18255
|
+
DROP INDEX IF EXISTS idx_context_session;
|
|
18256
|
+
`);
|
|
18257
|
+
const hasLegacyChatSession = hasTable2("chat_session");
|
|
18258
|
+
const hasSegment = hasTable2("segment");
|
|
18259
|
+
if (hasLegacyChatSession && !hasSegment) {
|
|
18260
|
+
db.exec("ALTER TABLE chat_session RENAME TO segment");
|
|
18261
|
+
} else if (hasLegacyChatSession && hasSegment) {
|
|
18262
|
+
db.exec(`
|
|
18263
|
+
INSERT OR IGNORE INTO segment (id, start_ts, end_ts, message_count, is_manual, summary)
|
|
18264
|
+
SELECT id, start_ts, end_ts, message_count, is_manual, summary
|
|
18265
|
+
FROM chat_session;
|
|
18266
|
+
DROP TABLE chat_session;
|
|
18267
|
+
`);
|
|
18268
|
+
}
|
|
18269
|
+
if (hasTable2("message_context") && hasColumn2(db, "message_context", "session_id")) {
|
|
18270
|
+
db.exec("ALTER TABLE message_context RENAME COLUMN session_id TO segment_id");
|
|
18271
|
+
}
|
|
18272
|
+
db.exec(`
|
|
18273
|
+
CREATE TABLE IF NOT EXISTS segment (
|
|
18274
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
18275
|
+
start_ts INTEGER NOT NULL,
|
|
18276
|
+
end_ts INTEGER NOT NULL,
|
|
18277
|
+
message_count INTEGER DEFAULT 0,
|
|
18278
|
+
is_manual INTEGER DEFAULT 0,
|
|
18279
|
+
summary TEXT
|
|
18280
|
+
);
|
|
18281
|
+
|
|
18282
|
+
CREATE TABLE IF NOT EXISTS message_context (
|
|
18283
|
+
message_id INTEGER PRIMARY KEY,
|
|
18284
|
+
segment_id INTEGER NOT NULL,
|
|
18285
|
+
topic_id INTEGER
|
|
18286
|
+
);
|
|
18287
|
+
|
|
18288
|
+
CREATE INDEX IF NOT EXISTS idx_segment_time ON segment(start_ts, end_ts);
|
|
18289
|
+
CREATE INDEX IF NOT EXISTS idx_context_segment ON message_context(segment_id);
|
|
18290
|
+
`);
|
|
18291
|
+
}
|
|
17558
18292
|
}
|
|
17559
18293
|
];
|
|
17560
18294
|
}
|
|
17561
18295
|
|
|
17562
18296
|
// ../../packages/node-runtime/src/database-manager.ts
|
|
17563
|
-
import * as
|
|
17564
|
-
import * as
|
|
18297
|
+
import * as fs35 from "fs";
|
|
18298
|
+
import * as path32 from "path";
|
|
18299
|
+
|
|
18300
|
+
// ../../packages/node-runtime/src/better-sqlite3-adapter.ts
|
|
18301
|
+
import Database4 from "better-sqlite3";
|
|
18302
|
+
var BetterSqlitePreparedStatement = class {
|
|
18303
|
+
constructor(stmt) {
|
|
18304
|
+
this.stmt = stmt;
|
|
18305
|
+
this.readonly = stmt.readonly;
|
|
18306
|
+
}
|
|
18307
|
+
stmt;
|
|
18308
|
+
readonly;
|
|
18309
|
+
get(...params) {
|
|
18310
|
+
return this.stmt.get(...params);
|
|
18311
|
+
}
|
|
18312
|
+
all(...params) {
|
|
18313
|
+
return this.stmt.all(...params);
|
|
18314
|
+
}
|
|
18315
|
+
run(...params) {
|
|
18316
|
+
const result = this.stmt.run(...params);
|
|
18317
|
+
return {
|
|
18318
|
+
changes: result.changes,
|
|
18319
|
+
lastInsertRowid: result.lastInsertRowid
|
|
18320
|
+
};
|
|
18321
|
+
}
|
|
18322
|
+
};
|
|
18323
|
+
var BetterSqliteAdapter = class {
|
|
18324
|
+
constructor(db) {
|
|
18325
|
+
this.db = db;
|
|
18326
|
+
this.readonly = db.readonly;
|
|
18327
|
+
}
|
|
18328
|
+
db;
|
|
18329
|
+
readonly;
|
|
18330
|
+
exec(sql) {
|
|
18331
|
+
this.db.exec(sql);
|
|
18332
|
+
}
|
|
18333
|
+
prepare(sql) {
|
|
18334
|
+
return new BetterSqlitePreparedStatement(this.db.prepare(sql));
|
|
18335
|
+
}
|
|
18336
|
+
transaction(fn) {
|
|
18337
|
+
return this.db.transaction(fn)();
|
|
18338
|
+
}
|
|
18339
|
+
pragma(pragma) {
|
|
18340
|
+
return this.db.pragma(pragma);
|
|
18341
|
+
}
|
|
18342
|
+
close() {
|
|
18343
|
+
this.db.close();
|
|
18344
|
+
}
|
|
18345
|
+
};
|
|
18346
|
+
function openBetterSqliteDatabase(filePath, options) {
|
|
18347
|
+
const db = new Database4(filePath, {
|
|
18348
|
+
readonly: options?.readonly ?? false,
|
|
18349
|
+
nativeBinding: options?.nativeBinding
|
|
18350
|
+
});
|
|
18351
|
+
if (!options?.readonly) {
|
|
18352
|
+
db.pragma("journal_mode = WAL");
|
|
18353
|
+
}
|
|
18354
|
+
return new BetterSqliteAdapter(db);
|
|
18355
|
+
}
|
|
18356
|
+
|
|
18357
|
+
// ../../packages/node-runtime/src/database-manager.ts
|
|
17565
18358
|
function createMigrationDeps(overrides) {
|
|
17566
18359
|
return {
|
|
17567
18360
|
tokenizeForFts,
|
|
@@ -17569,25 +18362,32 @@ function createMigrationDeps(overrides) {
|
|
|
17569
18362
|
};
|
|
17570
18363
|
}
|
|
17571
18364
|
var DatabaseManager = class {
|
|
17572
|
-
constructor(pathProvider, options) {
|
|
18365
|
+
constructor(pathProvider, options = {}) {
|
|
17573
18366
|
this.pathProvider = pathProvider;
|
|
18367
|
+
if (!options.runtime && !options.allowMissingRuntimeForTests) {
|
|
18368
|
+
throw new Error("DatabaseManager runtime identity is required for data directory compatibility checks.");
|
|
18369
|
+
}
|
|
17574
18370
|
this.nativeBinding = options?.nativeBinding;
|
|
17575
18371
|
this.migrationDeps = createMigrationDeps(options?.migrationDeps);
|
|
18372
|
+
this.runtime = options?.runtime ?? null;
|
|
17576
18373
|
}
|
|
17577
18374
|
pathProvider;
|
|
17578
18375
|
cache = /* @__PURE__ */ new Map();
|
|
17579
18376
|
nativeBinding;
|
|
17580
18377
|
migrationDeps;
|
|
18378
|
+
runtime;
|
|
17581
18379
|
/**
|
|
17582
18380
|
* Open a session DB (read-only by default, cached).
|
|
17583
18381
|
*/
|
|
17584
18382
|
open(sessionId, options) {
|
|
18383
|
+
this.assertCompatible();
|
|
17585
18384
|
if (this.cache.has(sessionId)) {
|
|
17586
18385
|
return this.cache.get(sessionId);
|
|
17587
18386
|
}
|
|
17588
18387
|
const dbPath = this.getDbPath(sessionId);
|
|
17589
|
-
if (!
|
|
18388
|
+
if (!fs35.existsSync(dbPath)) return null;
|
|
17590
18389
|
this.migrateIfNeeded(dbPath);
|
|
18390
|
+
this.assertCompatible();
|
|
17591
18391
|
const adapter = openBetterSqliteDatabase(dbPath, {
|
|
17592
18392
|
readonly: options?.readonly ?? true,
|
|
17593
18393
|
nativeBinding: this.nativeBinding
|
|
@@ -17601,7 +18401,9 @@ var DatabaseManager = class {
|
|
|
17601
18401
|
nativeBinding: this.nativeBinding
|
|
17602
18402
|
});
|
|
17603
18403
|
try {
|
|
17604
|
-
if (!isChatSessionDb(readonlyAdapter)
|
|
18404
|
+
if (!isChatSessionDb(readonlyAdapter)) return;
|
|
18405
|
+
this.raiseCompatibilityGateIfNeeded(getSchemaVersion(readonlyAdapter));
|
|
18406
|
+
if (!needsMigration(readonlyAdapter, CURRENT_SCHEMA_VERSION)) return;
|
|
17605
18407
|
} finally {
|
|
17606
18408
|
readonlyAdapter.close();
|
|
17607
18409
|
}
|
|
@@ -17611,7 +18413,7 @@ var DatabaseManager = class {
|
|
|
17611
18413
|
});
|
|
17612
18414
|
try {
|
|
17613
18415
|
const migrations = getChatDbMigrations(this.migrationDeps);
|
|
17614
|
-
runMigrations(adapter, migrations);
|
|
18416
|
+
this.runMigrations(adapter, migrations);
|
|
17615
18417
|
} finally {
|
|
17616
18418
|
adapter.close();
|
|
17617
18419
|
}
|
|
@@ -17621,6 +18423,7 @@ var DatabaseManager = class {
|
|
|
17621
18423
|
* Falls back to `open(id, { readonly: false })` if migration is unnecessary.
|
|
17622
18424
|
*/
|
|
17623
18425
|
openWritable(sessionId) {
|
|
18426
|
+
this.assertCompatible();
|
|
17624
18427
|
const existing = this.cache.get(sessionId);
|
|
17625
18428
|
if (existing && !existing.readonly) return existing;
|
|
17626
18429
|
if (existing) {
|
|
@@ -17628,14 +18431,17 @@ var DatabaseManager = class {
|
|
|
17628
18431
|
this.cache.delete(sessionId);
|
|
17629
18432
|
}
|
|
17630
18433
|
const dbPath = this.getDbPath(sessionId);
|
|
17631
|
-
if (!
|
|
18434
|
+
if (!fs35.existsSync(dbPath)) return null;
|
|
17632
18435
|
const adapter = openBetterSqliteDatabase(dbPath, {
|
|
17633
18436
|
readonly: false,
|
|
17634
18437
|
nativeBinding: this.nativeBinding
|
|
17635
18438
|
});
|
|
17636
18439
|
if (needsMigration(adapter, CURRENT_SCHEMA_VERSION)) {
|
|
17637
18440
|
const migrations = getChatDbMigrations(this.migrationDeps);
|
|
17638
|
-
runMigrations(adapter, migrations);
|
|
18441
|
+
this.runMigrations(adapter, migrations);
|
|
18442
|
+
this.assertCompatible();
|
|
18443
|
+
} else {
|
|
18444
|
+
this.raiseCompatibilityGateIfNeeded(getSchemaVersion(adapter));
|
|
17639
18445
|
}
|
|
17640
18446
|
this.cache.set(sessionId, adapter);
|
|
17641
18447
|
return adapter;
|
|
@@ -17663,9 +18469,10 @@ var DatabaseManager = class {
|
|
|
17663
18469
|
* 列举数据库目录下的所有聊天会话 ID
|
|
17664
18470
|
*/
|
|
17665
18471
|
listSessionIds() {
|
|
18472
|
+
this.assertCompatible();
|
|
17666
18473
|
const dbDir = this.pathProvider.getDatabaseDir();
|
|
17667
|
-
if (!
|
|
17668
|
-
return
|
|
18474
|
+
if (!fs35.existsSync(dbDir)) return [];
|
|
18475
|
+
return fs35.readdirSync(dbDir).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", "")).filter((id) => {
|
|
17669
18476
|
const db = this.open(id);
|
|
17670
18477
|
if (!db) return false;
|
|
17671
18478
|
return isChatSessionDb(db);
|
|
@@ -17675,9 +18482,70 @@ var DatabaseManager = class {
|
|
|
17675
18482
|
* 获取数据库文件路径
|
|
17676
18483
|
*/
|
|
17677
18484
|
getDbPath(sessionId) {
|
|
17678
|
-
return
|
|
18485
|
+
return path32.join(this.pathProvider.getDatabaseDir(), `${sessionId}.db`);
|
|
18486
|
+
}
|
|
18487
|
+
openRawSessionDatabase(sessionId, options = {}) {
|
|
18488
|
+
this.assertCompatible();
|
|
18489
|
+
const dbPath = this.getDbPath(sessionId);
|
|
18490
|
+
if (!options.create && !fs35.existsSync(dbPath)) {
|
|
18491
|
+
throw new Error(`Session database not found: ${sessionId}`);
|
|
18492
|
+
}
|
|
18493
|
+
if (!options.readonly) {
|
|
18494
|
+
this.close(sessionId);
|
|
18495
|
+
fs35.mkdirSync(path32.dirname(dbPath), { recursive: true });
|
|
18496
|
+
}
|
|
18497
|
+
const adapter = openBetterSqliteDatabase(dbPath, {
|
|
18498
|
+
readonly: options.readonly ?? false,
|
|
18499
|
+
nativeBinding: this.nativeBinding
|
|
18500
|
+
});
|
|
18501
|
+
if (options.initializeChatTables) {
|
|
18502
|
+
adapter.exec(CHAT_DB_TABLES);
|
|
18503
|
+
}
|
|
18504
|
+
return adapter;
|
|
18505
|
+
}
|
|
18506
|
+
deleteSessionDatabaseFiles(sessionId) {
|
|
18507
|
+
this.close(sessionId);
|
|
18508
|
+
const dbPath = this.getDbPath(sessionId);
|
|
18509
|
+
for (const suffix of ["", "-wal", "-shm"]) {
|
|
18510
|
+
try {
|
|
18511
|
+
const filePath = dbPath + suffix;
|
|
18512
|
+
if (fs35.existsSync(filePath)) fs35.unlinkSync(filePath);
|
|
18513
|
+
} catch {
|
|
18514
|
+
}
|
|
18515
|
+
}
|
|
18516
|
+
}
|
|
18517
|
+
raiseCurrentChatDbCompatibilityGate() {
|
|
18518
|
+
if (!this.runtime) return;
|
|
18519
|
+
raiseChatDbCompatibilityGate(this.pathProvider, this.runtime);
|
|
18520
|
+
}
|
|
18521
|
+
assertCompatible() {
|
|
18522
|
+
if (!this.runtime) return;
|
|
18523
|
+
assertDataDirCompatible(this.pathProvider, this.runtime);
|
|
18524
|
+
}
|
|
18525
|
+
runMigrations(adapter, migrations) {
|
|
18526
|
+
const beforeVersion = getSchemaVersion(adapter);
|
|
18527
|
+
const migrated = runMigrations(adapter, migrations);
|
|
18528
|
+
if (!migrated || !this.runtime) return;
|
|
18529
|
+
const afterVersion = getSchemaVersion(adapter);
|
|
18530
|
+
if (shouldRaiseCompatibilityGate(beforeVersion, afterVersion)) {
|
|
18531
|
+
this.raiseCurrentChatDbCompatibilityGate();
|
|
18532
|
+
}
|
|
18533
|
+
}
|
|
18534
|
+
raiseCompatibilityGateIfNeeded(schemaVersion) {
|
|
18535
|
+
if (!this.runtime) return;
|
|
18536
|
+
if (shouldRepairCompatibilityGate(schemaVersion)) {
|
|
18537
|
+
this.raiseCurrentChatDbCompatibilityGate();
|
|
18538
|
+
}
|
|
17679
18539
|
}
|
|
17680
18540
|
};
|
|
18541
|
+
function shouldRaiseCompatibilityGate(beforeVersion, afterVersion) {
|
|
18542
|
+
return CHAT_DB_COMPATIBILITY_RAISES.some(
|
|
18543
|
+
(compatibilityRaise) => beforeVersion < compatibilityRaise.migrationVersion && afterVersion >= compatibilityRaise.migrationVersion
|
|
18544
|
+
);
|
|
18545
|
+
}
|
|
18546
|
+
function shouldRepairCompatibilityGate(schemaVersion) {
|
|
18547
|
+
return CHAT_DB_COMPATIBILITY_RAISES.some((compatibilityRaise) => schemaVersion >= compatibilityRaise.migrationVersion);
|
|
18548
|
+
}
|
|
17681
18549
|
|
|
17682
18550
|
// ../../packages/node-runtime/src/jieba-nlp-provider.ts
|
|
17683
18551
|
function createJiebaNlpProvider(dictType = "default") {
|
|
@@ -17723,7 +18591,7 @@ function exportFilterResultToMarkdown(params, deps, writer) {
|
|
|
17723
18591
|
} else {
|
|
17724
18592
|
writer.write(`- Mode: session filter
|
|
17725
18593
|
`);
|
|
17726
|
-
writer.write(`- Selected sessions: ${params.
|
|
18594
|
+
writer.write(`- Selected sessions: ${params.segmentIds?.length || 0}
|
|
17727
18595
|
`);
|
|
17728
18596
|
}
|
|
17729
18597
|
writer.write("\n");
|
|
@@ -17881,7 +18749,7 @@ function exportConditionMode(db, params, writer, progress) {
|
|
|
17881
18749
|
return { totalMessages, blockIndex };
|
|
17882
18750
|
}
|
|
17883
18751
|
function exportSessionMode(db, params, writer, progress) {
|
|
17884
|
-
if (!params.
|
|
18752
|
+
if (!params.segmentIds || params.segmentIds.length === 0) {
|
|
17885
18753
|
writer.write(`## Statistics
|
|
17886
18754
|
|
|
17887
18755
|
- No sessions selected
|
|
@@ -17892,17 +18760,17 @@ function exportSessionMode(db, params, writer, progress) {
|
|
|
17892
18760
|
progress?.({
|
|
17893
18761
|
stage: "preparing",
|
|
17894
18762
|
currentBlock: 0,
|
|
17895
|
-
totalBlocks: params.
|
|
18763
|
+
totalBlocks: params.segmentIds.length,
|
|
17896
18764
|
percentage: 10,
|
|
17897
|
-
message: `Preparing to export ${params.
|
|
18765
|
+
message: `Preparing to export ${params.segmentIds.length} sessions...`
|
|
17898
18766
|
});
|
|
17899
18767
|
const sessionsSql = `
|
|
17900
18768
|
SELECT id, start_ts as startTs, end_ts as endTs
|
|
17901
|
-
FROM
|
|
17902
|
-
WHERE id IN (${params.
|
|
18769
|
+
FROM segment
|
|
18770
|
+
WHERE id IN (${params.segmentIds.map(() => "?").join(",")})
|
|
17903
18771
|
ORDER BY start_ts ASC
|
|
17904
18772
|
`;
|
|
17905
|
-
const sessions = db.prepare(sessionsSql).all(...params.
|
|
18773
|
+
const sessions = db.prepare(sessionsSql).all(...params.segmentIds);
|
|
17906
18774
|
const totalBlocks = sessions.length;
|
|
17907
18775
|
writer.write(`## Statistics
|
|
17908
18776
|
|
|
@@ -17920,7 +18788,7 @@ function exportSessionMode(db, params, writer, progress) {
|
|
|
17920
18788
|
FROM message_context mc
|
|
17921
18789
|
JOIN message msg ON msg.id = mc.message_id
|
|
17922
18790
|
JOIN member m ON msg.sender_id = m.id
|
|
17923
|
-
WHERE mc.
|
|
18791
|
+
WHERE mc.segment_id = ?
|
|
17924
18792
|
ORDER BY msg.ts ASC
|
|
17925
18793
|
`;
|
|
17926
18794
|
let totalMessages = 0;
|
|
@@ -17953,8 +18821,8 @@ function exportSessionMode(db, params, writer, progress) {
|
|
|
17953
18821
|
}
|
|
17954
18822
|
|
|
17955
18823
|
// ../../packages/node-runtime/src/preferences.ts
|
|
17956
|
-
import * as
|
|
17957
|
-
import * as
|
|
18824
|
+
import * as fs36 from "fs";
|
|
18825
|
+
import * as path33 from "path";
|
|
17958
18826
|
var DEFAULTS = {
|
|
17959
18827
|
pinnedSessionIds: [],
|
|
17960
18828
|
aiPreprocessConfig: {
|
|
@@ -17996,13 +18864,13 @@ var PreferencesManager = class {
|
|
|
17996
18864
|
filePath;
|
|
17997
18865
|
cache = null;
|
|
17998
18866
|
constructor(systemDir) {
|
|
17999
|
-
this.filePath =
|
|
18867
|
+
this.filePath = path33.join(systemDir, "preferences.json");
|
|
18000
18868
|
}
|
|
18001
18869
|
load() {
|
|
18002
18870
|
if (this.cache) return this.cache;
|
|
18003
18871
|
try {
|
|
18004
|
-
if (
|
|
18005
|
-
const raw =
|
|
18872
|
+
if (fs36.existsSync(this.filePath)) {
|
|
18873
|
+
const raw = fs36.readFileSync(this.filePath, "utf-8");
|
|
18006
18874
|
const parsed = JSON.parse(raw);
|
|
18007
18875
|
const migrated = this.migrateLegacyDesensitizeRules(parsed, raw);
|
|
18008
18876
|
this.cache = this.mergeDefaults(migrated.preferences);
|
|
@@ -18114,21 +18982,21 @@ var PreferencesManager = class {
|
|
|
18114
18982
|
};
|
|
18115
18983
|
}
|
|
18116
18984
|
backupLegacyPreferences(rawContent) {
|
|
18117
|
-
const backupDir =
|
|
18118
|
-
if (!
|
|
18119
|
-
|
|
18985
|
+
const backupDir = path33.join(path33.dirname(this.filePath), "backups");
|
|
18986
|
+
if (!fs36.existsSync(backupDir)) {
|
|
18987
|
+
fs36.mkdirSync(backupDir, { recursive: true });
|
|
18120
18988
|
}
|
|
18121
18989
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
18122
|
-
const backupPath =
|
|
18123
|
-
|
|
18990
|
+
const backupPath = path33.join(backupDir, `preferences-pre-desensitize-groups-${timestamp}.json`);
|
|
18991
|
+
fs36.writeFileSync(backupPath, rawContent, "utf-8");
|
|
18124
18992
|
console.info(`[Preferences] Backed up legacy desensitize rules to ${backupPath}`);
|
|
18125
18993
|
}
|
|
18126
18994
|
writePreferences(preferences) {
|
|
18127
|
-
const dir =
|
|
18128
|
-
if (!
|
|
18129
|
-
|
|
18995
|
+
const dir = path33.dirname(this.filePath);
|
|
18996
|
+
if (!fs36.existsSync(dir)) {
|
|
18997
|
+
fs36.mkdirSync(dir, { recursive: true });
|
|
18130
18998
|
}
|
|
18131
|
-
|
|
18999
|
+
fs36.writeFileSync(this.filePath, JSON.stringify(preferences, null, 2), "utf-8");
|
|
18132
19000
|
}
|
|
18133
19001
|
/**
|
|
18134
19002
|
* Deep merge: arrays are replaced (not concatenated), objects are merged.
|
|
@@ -18248,8 +19116,8 @@ function* serializeChatLabToJsonl(data) {
|
|
|
18248
19116
|
}
|
|
18249
19117
|
|
|
18250
19118
|
// ../../packages/node-runtime/src/merger/temp-db.ts
|
|
18251
|
-
import * as
|
|
18252
|
-
import * as
|
|
19119
|
+
import * as fs37 from "fs";
|
|
19120
|
+
import * as path34 from "path";
|
|
18253
19121
|
var TEMP_DB_SCHEMA = `
|
|
18254
19122
|
CREATE TABLE IF NOT EXISTS meta (
|
|
18255
19123
|
name TEXT NOT NULL,
|
|
@@ -18494,21 +19362,21 @@ function exportSessionToJson(db) {
|
|
|
18494
19362
|
}
|
|
18495
19363
|
function deleteTempDatabase(dbPath) {
|
|
18496
19364
|
try {
|
|
18497
|
-
if (
|
|
19365
|
+
if (fs37.existsSync(dbPath)) fs37.unlinkSync(dbPath);
|
|
18498
19366
|
const walPath = dbPath + "-wal";
|
|
18499
19367
|
const shmPath = dbPath + "-shm";
|
|
18500
|
-
if (
|
|
18501
|
-
if (
|
|
19368
|
+
if (fs37.existsSync(walPath)) fs37.unlinkSync(walPath);
|
|
19369
|
+
if (fs37.existsSync(shmPath)) fs37.unlinkSync(shmPath);
|
|
18502
19370
|
} catch {
|
|
18503
19371
|
}
|
|
18504
19372
|
}
|
|
18505
19373
|
function cleanupTempDatabases(tempDir) {
|
|
18506
19374
|
try {
|
|
18507
|
-
if (!
|
|
18508
|
-
const files =
|
|
19375
|
+
if (!fs37.existsSync(tempDir)) return;
|
|
19376
|
+
const files = fs37.readdirSync(tempDir);
|
|
18509
19377
|
for (const file of files) {
|
|
18510
19378
|
if (file.startsWith("merge_") && file.endsWith(".db")) {
|
|
18511
|
-
deleteTempDatabase(
|
|
19379
|
+
deleteTempDatabase(path34.join(tempDir, file));
|
|
18512
19380
|
}
|
|
18513
19381
|
}
|
|
18514
19382
|
} catch {
|
|
@@ -18669,16 +19537,16 @@ __export(summary_service_exports, {
|
|
|
18669
19537
|
function buildSummaryDeps(db, llmConfig, deps) {
|
|
18670
19538
|
const piModel = deps.buildPiModel(llmConfig);
|
|
18671
19539
|
return {
|
|
18672
|
-
loadMessages(
|
|
18673
|
-
const data =
|
|
19540
|
+
loadMessages(segmentId, limit = 500) {
|
|
19541
|
+
const data = getSegmentMessages(db, segmentId, limit);
|
|
18674
19542
|
if (!data) return null;
|
|
18675
19543
|
return data.messages.map((m) => ({ senderName: m.senderName, content: m.content }));
|
|
18676
19544
|
},
|
|
18677
|
-
saveSummary(
|
|
18678
|
-
|
|
19545
|
+
saveSummary(segmentId, summary) {
|
|
19546
|
+
saveSegmentSummary(db, segmentId, summary);
|
|
18679
19547
|
},
|
|
18680
|
-
getSummary(
|
|
18681
|
-
return
|
|
19548
|
+
getSummary(segmentId) {
|
|
19549
|
+
return getSegmentSummary(db, segmentId);
|
|
18682
19550
|
},
|
|
18683
19551
|
async llmComplete(systemPrompt, userPrompt, options) {
|
|
18684
19552
|
const result = await completeSimple4(
|
|
@@ -18694,14 +19562,14 @@ function buildSummaryDeps(db, llmConfig, deps) {
|
|
|
18694
19562
|
t: (key) => key
|
|
18695
19563
|
};
|
|
18696
19564
|
}
|
|
18697
|
-
async function generateSummary(adapter, sessionId,
|
|
19565
|
+
async function generateSummary(adapter, sessionId, segmentId, serviceDeps, options) {
|
|
18698
19566
|
const llmConfig = serviceDeps.getLlmConfig();
|
|
18699
19567
|
if (!llmConfig) {
|
|
18700
19568
|
return { success: false, error: "No LLM configuration available" };
|
|
18701
19569
|
}
|
|
18702
19570
|
const db = adapter.ensureWritable(sessionId);
|
|
18703
19571
|
const deps = buildSummaryDeps(db, llmConfig, serviceDeps);
|
|
18704
|
-
return generateSessionSummary(deps,
|
|
19572
|
+
return generateSessionSummary(deps, segmentId, options);
|
|
18705
19573
|
}
|
|
18706
19574
|
async function generateAllSummaries(adapter, sessionId, serviceDeps, options) {
|
|
18707
19575
|
const llmConfig = serviceDeps.getLlmConfig();
|
|
@@ -18720,17 +19588,17 @@ async function generateAllSummaries(adapter, sessionId, serviceDeps, options) {
|
|
|
18720
19588
|
}
|
|
18721
19589
|
return { success, failed, total: chatSessions.length };
|
|
18722
19590
|
}
|
|
18723
|
-
function checkCanGenerate(adapter, sessionId,
|
|
19591
|
+
function checkCanGenerate(adapter, sessionId, segmentIds) {
|
|
18724
19592
|
const db = adapter.ensureReadonly(sessionId);
|
|
18725
19593
|
const deps = {
|
|
18726
|
-
loadMessages(
|
|
18727
|
-
const data =
|
|
19594
|
+
loadMessages(segmentId, limit = 500) {
|
|
19595
|
+
const data = getSegmentMessages(db, segmentId, limit);
|
|
18728
19596
|
if (!data) return null;
|
|
18729
19597
|
return data.messages.map((m) => ({ senderName: m.senderName, content: m.content }));
|
|
18730
19598
|
},
|
|
18731
19599
|
t: (key) => key
|
|
18732
19600
|
};
|
|
18733
|
-
const resultMap = checkSessionsCanGenerateSummary(deps,
|
|
19601
|
+
const resultMap = checkSessionsCanGenerateSummary(deps, segmentIds);
|
|
18734
19602
|
const result = {};
|
|
18735
19603
|
for (const [id, info] of resultMap) {
|
|
18736
19604
|
result[id] = info;
|
|
@@ -18764,7 +19632,7 @@ function exportMarkdown(adapter, params) {
|
|
|
18764
19632
|
}
|
|
18765
19633
|
|
|
18766
19634
|
// ../../packages/node-runtime/src/services/adapters/database-manager-adapter.ts
|
|
18767
|
-
import * as
|
|
19635
|
+
import * as fs38 from "fs";
|
|
18768
19636
|
function createDatabaseManagerAdapter(dbManager) {
|
|
18769
19637
|
return {
|
|
18770
19638
|
listSessionIds: () => dbManager.listSessionIds(),
|
|
@@ -18775,8 +19643,8 @@ function createDatabaseManagerAdapter(dbManager) {
|
|
|
18775
19643
|
deleteSessionFile(sessionId) {
|
|
18776
19644
|
dbManager.close(sessionId);
|
|
18777
19645
|
const dbPath = dbManager.getDbPath(sessionId);
|
|
18778
|
-
if (!
|
|
18779
|
-
|
|
19646
|
+
if (!fs38.existsSync(dbPath)) return false;
|
|
19647
|
+
fs38.unlinkSync(dbPath);
|
|
18780
19648
|
return true;
|
|
18781
19649
|
},
|
|
18782
19650
|
ensureReadonly(sessionId) {
|
|
@@ -18797,8 +19665,8 @@ function createDatabaseManagerAdapter(dbManager) {
|
|
|
18797
19665
|
}
|
|
18798
19666
|
|
|
18799
19667
|
// ../../packages/node-runtime/src/services/merge-cache.ts
|
|
18800
|
-
import * as
|
|
18801
|
-
import * as
|
|
19668
|
+
import * as fs39 from "fs";
|
|
19669
|
+
import * as path35 from "path";
|
|
18802
19670
|
import * as crypto from "crypto";
|
|
18803
19671
|
var MergeSessionCache = class {
|
|
18804
19672
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -18807,15 +19675,15 @@ var MergeSessionCache = class {
|
|
|
18807
19675
|
constructor(pathProvider, options) {
|
|
18808
19676
|
this.tempDir = pathProvider.getTempDir();
|
|
18809
19677
|
this.nativeBinding = options?.nativeBinding;
|
|
18810
|
-
if (!
|
|
18811
|
-
|
|
19678
|
+
if (!fs39.existsSync(this.tempDir)) {
|
|
19679
|
+
fs39.mkdirSync(this.tempDir, { recursive: true });
|
|
18812
19680
|
}
|
|
18813
19681
|
}
|
|
18814
19682
|
generateTempDbPath(filename) {
|
|
18815
19683
|
const ts = Date.now();
|
|
18816
19684
|
const rand = Math.random().toString(36).slice(2, 8);
|
|
18817
19685
|
const safeName = filename.replace(/[/\\?%*:|"<>]/g, "_").slice(0, 40);
|
|
18818
|
-
return
|
|
19686
|
+
return path35.join(this.tempDir, `merge_${safeName}_${ts}_${rand}.db`);
|
|
18819
19687
|
}
|
|
18820
19688
|
/** Store a parsed file's temp DB and return a handle for subsequent requests. */
|
|
18821
19689
|
store(filename, tempDbPath) {
|
|
@@ -18826,7 +19694,7 @@ var MergeSessionCache = class {
|
|
|
18826
19694
|
/** Open a TempDbReader for a given handle. Caller must close the reader. */
|
|
18827
19695
|
openReader(handle) {
|
|
18828
19696
|
const entry = this.cache.get(handle);
|
|
18829
|
-
if (!entry || !
|
|
19697
|
+
if (!entry || !fs39.existsSync(entry.tempDbPath)) return null;
|
|
18830
19698
|
const adapter = openBetterSqliteDatabase(entry.tempDbPath, {
|
|
18831
19699
|
readonly: true,
|
|
18832
19700
|
nativeBinding: this.nativeBinding
|
|
@@ -18879,7 +19747,6 @@ export {
|
|
|
18879
19747
|
writeAuthProfile,
|
|
18880
19748
|
MigrationRunner,
|
|
18881
19749
|
ALL_MIGRATIONS,
|
|
18882
|
-
openBetterSqliteDatabase,
|
|
18883
19750
|
writeParseResultToDb,
|
|
18884
19751
|
getTimeRange,
|
|
18885
19752
|
getAvailableYears,
|
|
@@ -18896,9 +19763,9 @@ export {
|
|
|
18896
19763
|
getSessionOverview,
|
|
18897
19764
|
getDatabaseSchema,
|
|
18898
19765
|
getChatOverview,
|
|
18899
|
-
|
|
18900
|
-
|
|
18901
|
-
|
|
19766
|
+
searchSegments,
|
|
19767
|
+
getSegmentMessages,
|
|
19768
|
+
getSegmentSummaries,
|
|
18902
19769
|
generateSessionIndex,
|
|
18903
19770
|
generateIncrementalSessionIndex,
|
|
18904
19771
|
queryMessages,
|
|
@@ -18925,7 +19792,9 @@ export {
|
|
|
18925
19792
|
getRelationshipStats,
|
|
18926
19793
|
getLanguagePreferenceAnalysis,
|
|
18927
19794
|
isNewerStableVersion,
|
|
19795
|
+
buildChartPayload,
|
|
18928
19796
|
POS_TAG_DEFINITIONS,
|
|
19797
|
+
normalizeBuiltinToolNames,
|
|
18929
19798
|
BUILTIN_TOOL_CATALOG,
|
|
18930
19799
|
BUILTIN_PROVIDERS,
|
|
18931
19800
|
BUILTIN_MODELS,
|
|
@@ -18933,7 +19802,6 @@ export {
|
|
|
18933
19802
|
stripAvatarFields,
|
|
18934
19803
|
generateMessageKey,
|
|
18935
19804
|
buildMemberIdMap,
|
|
18936
|
-
CHAT_DB_TABLES,
|
|
18937
19805
|
CHAT_DB_SCHEMA,
|
|
18938
19806
|
FTS_TABLE_SCHEMA,
|
|
18939
19807
|
detectFormat,
|
|
@@ -18960,17 +19828,26 @@ export {
|
|
|
18960
19828
|
formatAIError,
|
|
18961
19829
|
parseAssistantFile,
|
|
18962
19830
|
AssistantManager,
|
|
18963
|
-
|
|
19831
|
+
AIChatManager,
|
|
18964
19832
|
initTokenizer,
|
|
18965
19833
|
countMessagesTokens,
|
|
18966
|
-
SkillManager,
|
|
18967
19834
|
SkillManagerCore,
|
|
19835
|
+
SkillManager,
|
|
18968
19836
|
createActivateSkillTool,
|
|
19837
|
+
CHART_CAPABILITY_CORE_TOOLS,
|
|
19838
|
+
getAllowedBuiltinToolsForChartAutoSkill,
|
|
19839
|
+
resolveChartRuntimeForRequest,
|
|
19840
|
+
getChartCapabilitySkill,
|
|
19841
|
+
buildSkillMenuWithBuiltinChart,
|
|
19842
|
+
getSkillConfigWithBuiltinChart,
|
|
19843
|
+
createChartSchemaGateState,
|
|
19844
|
+
wrapWithChartSchemaGate,
|
|
18969
19845
|
checkAndCompress,
|
|
18970
19846
|
createCompressionLlmAdapter,
|
|
18971
19847
|
getDefaultRulesForLocale,
|
|
18972
19848
|
mergeRulesForLocale,
|
|
18973
19849
|
applyPreprocessingPipeline,
|
|
19850
|
+
DEFAULT_MAX_TOOL_ROUNDS,
|
|
18974
19851
|
runAgentCore,
|
|
18975
19852
|
AgentEventHandler,
|
|
18976
19853
|
buildSystemPrompt,
|
|
@@ -18989,6 +19866,8 @@ export {
|
|
|
18989
19866
|
applyPendingNodeDataDirMigrationIfNeeded,
|
|
18990
19867
|
NodePathProvider,
|
|
18991
19868
|
getDefaultNodeUserDataDir,
|
|
19869
|
+
DataDirCompatibilityError,
|
|
19870
|
+
assertDataDirCompatible,
|
|
18992
19871
|
DatabaseManager,
|
|
18993
19872
|
createJiebaNlpProvider,
|
|
18994
19873
|
PreferencesManager,
|
|
@@ -19005,4 +19884,4 @@ export {
|
|
|
19005
19884
|
createDatabaseManagerAdapter,
|
|
19006
19885
|
MergeSessionCache
|
|
19007
19886
|
};
|
|
19008
|
-
//# sourceMappingURL=chunk-
|
|
19887
|
+
//# sourceMappingURL=chunk-7VG6QGQ2.mjs.map
|