chatlab-cli 0.25.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat-command-ZP4WJVWC.mjs +304 -0
- package/dist/chat-command-ZP4WJVWC.mjs.map +1 -0
- package/dist/{chunk-CIBTUWAE.mjs → chunk-6G7AIF7I.mjs} +38 -8
- package/dist/chunk-6G7AIF7I.mjs.map +1 -0
- package/dist/chunk-ILGSSXOG.mjs +549 -0
- package/dist/chunk-ILGSSXOG.mjs.map +1 -0
- package/dist/{chunk-E65ABM3C.mjs → chunk-IRZRIHIT.mjs} +100 -63
- package/dist/chunk-IRZRIHIT.mjs.map +1 -0
- package/dist/{chunk-4OMV4VNH.mjs → chunk-QY67NN65.mjs} +1900 -729
- package/dist/chunk-QY67NN65.mjs.map +1 -0
- package/dist/{chunk-FSHVDWI2.mjs → chunk-SJIOPSMM.mjs} +116 -569
- package/dist/chunk-SJIOPSMM.mjs.map +1 -0
- package/dist/{chunk-GNT5G74Z.mjs → chunk-TC74HESZ.mjs} +59 -33
- package/dist/chunk-TC74HESZ.mjs.map +1 -0
- package/dist/chunk-UB4XBM4R.mjs +40 -0
- package/dist/chunk-UB4XBM4R.mjs.map +1 -0
- package/dist/{chunk-TCPXAX3F.mjs → chunk-WXC6RZCX.mjs} +17 -25
- package/dist/chunk-WXC6RZCX.mjs.map +1 -0
- package/dist/cli.mjs +3 -2
- package/dist/{http-PMNZ42EN.mjs → http-J3IOFFIA.mjs} +8 -6
- package/dist/{import-OP7R4CYY.mjs → import-POYG5LOX.mjs} +4 -4
- package/dist/index.mjs +10 -8
- package/dist/{mcp-ABXNFUJO.mjs → mcp-7HH7UMXT.mjs} +11 -6
- package/dist/mcp-7HH7UMXT.mjs.map +1 -0
- package/dist/{stream-import-L6RJHH4L.mjs → stream-import-O3H3FGV2.mjs} +3 -3
- package/dist-web/assets/{DebugToolsPanel-DaSNc1o-.css → DebugToolsPanel-CrqULdXp.css} +1 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-BTJxEma5.js +182 -0
- package/dist-web/assets/{EChartWordcloud-CzhfrEF_.js → EChartWordcloud-B_YisOW5.js} +1 -1
- package/dist-web/assets/{MessageExportModal-BAJKWX4y.js → MessageExportModal-C7NgEL8T.js} +1 -1
- package/dist-web/assets/{electron-CZt36wW5.js → electron-B3DFm1cC.js} +1 -1
- package/dist-web/assets/electron-BMM4Nfty.js +1 -0
- package/dist-web/assets/{fetch-qoGEVjNg.js → fetch-ArMjdMcy.js} +1 -1
- package/dist-web/assets/fetch-BFtuJaa1.js +1 -0
- package/dist-web/assets/{fetch-yWwp067l.js → fetch-BGfaAqO9.js} +1 -1
- package/dist-web/assets/{fetch-DD1EGRKV.js → fetch-BaJDB31c.js} +1 -1
- package/dist-web/assets/{fetch-JzVEwamn.js → fetch-BjDJgdN0.js} +1 -1
- package/dist-web/assets/{fetch-GMkMBzBS.js → fetch-C5CLcpQW.js} +1 -1
- package/dist-web/assets/{fetch-DXfZysDf.js → fetch-DQZvdHnG.js} +1 -1
- package/dist-web/assets/{fetch-D4p9vj1A.js → fetch-Dhfbt1BQ.js} +3 -3
- package/dist-web/assets/fetch-DnEP0uyF.js +1 -0
- package/dist-web/assets/{fetch-CgBIWyAo.js → fetch-SYrb-sZe.js} +1 -1
- package/dist-web/assets/index-CWfkrx37.js +173 -0
- package/dist-web/assets/index-D3N4NDFx.css +1 -0
- package/dist-web/assets/{index-O0PG26_v.js → index-D7_ch4zf.js} +1 -1
- package/dist-web/assets/{index-BrS_VrIY.js → index-DK9LEEzT.js} +1 -1
- package/dist-web/assets/index-DqDa_on9.js +9 -0
- package/dist-web/assets/{index-Cvlw0RLu.js → index-DrN1G9bl.js} +2 -2
- package/dist-web/assets/{index-DvWI6Yqa.js → index-MdYeovYo.js} +4 -4
- package/dist-web/assets/{vendor-nuxt-ui-C_8CsH6e.js → vendor-nuxt-ui-Zy8txNdC.js} +1 -1
- package/dist-web/assets/{vendor-reka-ui-CIMXwvEp.js → vendor-reka-ui-mMvma1EP.js} +1 -1
- package/dist-web/assets/{web-4rtrAcLu.js → web-zEXsvoZW.js} +1 -1
- package/dist-web/index.html +4 -4
- package/package.json +1 -1
- package/dist/chunk-4OMV4VNH.mjs.map +0 -1
- package/dist/chunk-CIBTUWAE.mjs.map +0 -1
- package/dist/chunk-E65ABM3C.mjs.map +0 -1
- package/dist/chunk-FSHVDWI2.mjs.map +0 -1
- package/dist/chunk-GNT5G74Z.mjs.map +0 -1
- package/dist/chunk-TCPXAX3F.mjs.map +0 -1
- package/dist/mcp-ABXNFUJO.mjs.map +0 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-BUwpIerl.js +0 -161
- package/dist-web/assets/electron-CwERrTWp.js +0 -1
- package/dist-web/assets/fetch-BxFAkm7O.js +0 -1
- package/dist-web/assets/fetch-DO8lty7_.js +0 -1
- package/dist-web/assets/index-C1t-kzfo.css +0 -1
- package/dist-web/assets/index-DABpUm3J.js +0 -9
- package/dist-web/assets/index-OsjX5hXw.js +0 -173
- /package/dist/{http-PMNZ42EN.mjs.map → http-J3IOFFIA.mjs.map} +0 -0
- /package/dist/{import-OP7R4CYY.mjs.map → import-POYG5LOX.mjs.map} +0 -0
- /package/dist/{stream-import-L6RJHH4L.mjs.map → stream-import-O3H3FGV2.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) {
|
|
@@ -2215,6 +2158,7 @@ function getChatOverview(db, topN = 10) {
|
|
|
2215
2158
|
if (!meta) return null;
|
|
2216
2159
|
const overview = getSessionOverview(db);
|
|
2217
2160
|
const members = getMemberActivity(db);
|
|
2161
|
+
const summaryCount = getSummaryCount(db);
|
|
2218
2162
|
const topMembers = members.slice(0, topN).map((m) => ({
|
|
2219
2163
|
id: m.memberId,
|
|
2220
2164
|
name: m.name,
|
|
@@ -2228,14 +2172,15 @@ function getChatOverview(db, topN = 10) {
|
|
|
2228
2172
|
totalMembers: overview.totalMembers,
|
|
2229
2173
|
firstMessageTs: overview.firstMessageTs,
|
|
2230
2174
|
lastMessageTs: overview.lastMessageTs,
|
|
2231
|
-
topMembers
|
|
2175
|
+
topMembers,
|
|
2176
|
+
summaryCount
|
|
2232
2177
|
};
|
|
2233
2178
|
}
|
|
2234
|
-
function
|
|
2235
|
-
if (!hasTable(db, "
|
|
2179
|
+
function searchSegments(db, keywords, timeFilter, limit = 20, previewCount = 5, ftsMatchExpression) {
|
|
2180
|
+
if (!hasTable(db, "segment")) return [];
|
|
2236
2181
|
let sessionSql = `
|
|
2237
2182
|
SELECT cs.id, cs.start_ts as startTs, cs.end_ts as endTs, cs.message_count as messageCount
|
|
2238
|
-
FROM
|
|
2183
|
+
FROM segment cs WHERE 1=1
|
|
2239
2184
|
`;
|
|
2240
2185
|
const params = [];
|
|
2241
2186
|
if (timeFilter?.startTs !== void 0) {
|
|
@@ -2250,7 +2195,7 @@ function searchSessions(db, keywords, timeFilter, limit = 20, previewCount = 5,
|
|
|
2250
2195
|
if (ftsMatchExpression) {
|
|
2251
2196
|
sessionSql += `
|
|
2252
2197
|
AND cs.id IN (
|
|
2253
|
-
SELECT DISTINCT mc.
|
|
2198
|
+
SELECT DISTINCT mc.segment_id FROM message_context mc
|
|
2254
2199
|
WHERE mc.message_id IN (SELECT rowid FROM message_fts WHERE content MATCH ?)
|
|
2255
2200
|
)
|
|
2256
2201
|
`;
|
|
@@ -2259,7 +2204,7 @@ function searchSessions(db, keywords, timeFilter, limit = 20, previewCount = 5,
|
|
|
2259
2204
|
const keywordConditions = keywords.map(() => "m.content LIKE ?").join(" OR ");
|
|
2260
2205
|
sessionSql += `
|
|
2261
2206
|
AND cs.id IN (
|
|
2262
|
-
SELECT DISTINCT mc.
|
|
2207
|
+
SELECT DISTINCT mc.segment_id FROM message_context mc
|
|
2263
2208
|
JOIN message m ON m.id = mc.message_id
|
|
2264
2209
|
WHERE (${keywordConditions})
|
|
2265
2210
|
)
|
|
@@ -2280,7 +2225,7 @@ function searchSessions(db, keywords, timeFilter, limit = 20, previewCount = 5,
|
|
|
2280
2225
|
FROM message_context mc
|
|
2281
2226
|
JOIN message m ON m.id = mc.message_id
|
|
2282
2227
|
JOIN member mb ON mb.id = m.sender_id
|
|
2283
|
-
WHERE mc.
|
|
2228
|
+
WHERE mc.segment_id = ? ORDER BY m.ts ASC LIMIT ?
|
|
2284
2229
|
`;
|
|
2285
2230
|
return sessions.map((session) => {
|
|
2286
2231
|
const previewMessages = db.prepare(previewSql).all(session.id, previewCount);
|
|
@@ -2294,12 +2239,12 @@ function searchSessions(db, keywords, timeFilter, limit = 20, previewCount = 5,
|
|
|
2294
2239
|
};
|
|
2295
2240
|
});
|
|
2296
2241
|
}
|
|
2297
|
-
function
|
|
2298
|
-
if (!hasTable(db, "
|
|
2242
|
+
function getSegmentMessages(db, segmentId, limit = 500) {
|
|
2243
|
+
if (!hasTable(db, "segment")) return null;
|
|
2299
2244
|
const session = db.prepare(
|
|
2300
2245
|
`SELECT id, start_ts as startTs, end_ts as endTs, message_count as messageCount
|
|
2301
|
-
FROM
|
|
2302
|
-
).get(
|
|
2246
|
+
FROM segment WHERE id = ?`
|
|
2247
|
+
).get(segmentId);
|
|
2303
2248
|
if (!session) return null;
|
|
2304
2249
|
const messages = db.prepare(
|
|
2305
2250
|
`SELECT m.id, mb.id as senderId,
|
|
@@ -2309,14 +2254,14 @@ function getSessionMessages(db, chatSessionId, limit = 500) {
|
|
|
2309
2254
|
FROM message_context mc
|
|
2310
2255
|
JOIN message m ON m.id = mc.message_id
|
|
2311
2256
|
JOIN member mb ON mb.id = m.sender_id
|
|
2312
|
-
WHERE mc.
|
|
2313
|
-
).all(
|
|
2257
|
+
WHERE mc.segment_id = ? ORDER BY m.ts ASC LIMIT ?`
|
|
2258
|
+
).all(segmentId, limit);
|
|
2314
2259
|
const participantsSet = /* @__PURE__ */ new Set();
|
|
2315
2260
|
for (const msg of messages) {
|
|
2316
2261
|
participantsSet.add(msg.senderName);
|
|
2317
2262
|
}
|
|
2318
2263
|
return {
|
|
2319
|
-
|
|
2264
|
+
segmentId: session.id,
|
|
2320
2265
|
startTs: session.startTs,
|
|
2321
2266
|
endTs: session.endTs,
|
|
2322
2267
|
messageCount: session.messageCount,
|
|
@@ -2325,13 +2270,13 @@ function getSessionMessages(db, chatSessionId, limit = 500) {
|
|
|
2325
2270
|
messages
|
|
2326
2271
|
};
|
|
2327
2272
|
}
|
|
2328
|
-
function
|
|
2329
|
-
if (!hasTable(db, "
|
|
2273
|
+
function getSegmentSummaries(db, options) {
|
|
2274
|
+
if (!hasTable(db, "segment")) return [];
|
|
2330
2275
|
const { limit = 50, timeFilter } = options ?? {};
|
|
2331
2276
|
let sql = `
|
|
2332
2277
|
SELECT cs.id, cs.start_ts as startTs, cs.end_ts as endTs,
|
|
2333
2278
|
cs.message_count as messageCount, cs.summary
|
|
2334
|
-
FROM
|
|
2279
|
+
FROM segment cs
|
|
2335
2280
|
WHERE cs.summary IS NOT NULL AND cs.summary != ''
|
|
2336
2281
|
`;
|
|
2337
2282
|
const params = [];
|
|
@@ -2351,7 +2296,7 @@ function getSessionSummaries(db, options) {
|
|
|
2351
2296
|
FROM message_context mc
|
|
2352
2297
|
JOIN message m ON m.id = mc.message_id
|
|
2353
2298
|
JOIN member mb ON mb.id = m.sender_id
|
|
2354
|
-
WHERE mc.
|
|
2299
|
+
WHERE mc.segment_id = ? LIMIT 10
|
|
2355
2300
|
`;
|
|
2356
2301
|
return sessions.map((session) => {
|
|
2357
2302
|
const participants = db.prepare(participantsSql).all(session.id);
|
|
@@ -2368,9 +2313,9 @@ function getSessionSummaries(db, options) {
|
|
|
2368
2313
|
var DEFAULT_SESSION_GAP_THRESHOLD = 1800;
|
|
2369
2314
|
function getSessionIndexStats(db) {
|
|
2370
2315
|
let sessionCount = 0;
|
|
2371
|
-
if (hasTable(db, "
|
|
2316
|
+
if (hasTable(db, "segment")) {
|
|
2372
2317
|
try {
|
|
2373
|
-
const row = db.prepare("SELECT COUNT(*) as count FROM
|
|
2318
|
+
const row = db.prepare("SELECT COUNT(*) as count FROM segment").get();
|
|
2374
2319
|
sessionCount = row?.count ?? 0;
|
|
2375
2320
|
} catch {
|
|
2376
2321
|
}
|
|
@@ -2386,7 +2331,7 @@ function getSessionIndexStats(db) {
|
|
|
2386
2331
|
return { sessionCount, hasIndex: sessionCount > 0, gapThreshold };
|
|
2387
2332
|
}
|
|
2388
2333
|
function getChatSessionList(db) {
|
|
2389
|
-
if (!hasTable(db, "
|
|
2334
|
+
if (!hasTable(db, "segment")) return [];
|
|
2390
2335
|
try {
|
|
2391
2336
|
return db.prepare(
|
|
2392
2337
|
`SELECT
|
|
@@ -2396,24 +2341,24 @@ function getChatSessionList(db) {
|
|
|
2396
2341
|
cs.message_count as messageCount,
|
|
2397
2342
|
cs.summary,
|
|
2398
2343
|
(SELECT mc.message_id FROM message_context mc
|
|
2399
|
-
WHERE mc.
|
|
2400
|
-
FROM
|
|
2344
|
+
WHERE mc.segment_id = cs.id ORDER BY mc.message_id LIMIT 1) as firstMessageId
|
|
2345
|
+
FROM segment cs
|
|
2401
2346
|
ORDER BY cs.start_ts ASC`
|
|
2402
2347
|
).all();
|
|
2403
2348
|
} catch {
|
|
2404
2349
|
return [];
|
|
2405
2350
|
}
|
|
2406
2351
|
}
|
|
2407
|
-
function
|
|
2352
|
+
function getSegmentSummary(db, segmentId) {
|
|
2408
2353
|
try {
|
|
2409
|
-
const row = db.prepare("SELECT summary FROM
|
|
2354
|
+
const row = db.prepare("SELECT summary FROM segment WHERE id = ?").get(segmentId);
|
|
2410
2355
|
return row?.summary ?? null;
|
|
2411
2356
|
} catch {
|
|
2412
2357
|
return null;
|
|
2413
2358
|
}
|
|
2414
2359
|
}
|
|
2415
|
-
function
|
|
2416
|
-
db.prepare("UPDATE
|
|
2360
|
+
function saveSegmentSummary(db, segmentId, summary) {
|
|
2361
|
+
db.prepare("UPDATE segment SET summary = ? WHERE id = ?").run(summary, segmentId);
|
|
2417
2362
|
}
|
|
2418
2363
|
function updateSessionOwnerId(db, ownerId) {
|
|
2419
2364
|
db.prepare("UPDATE meta SET owner_id = ?").run(ownerId);
|
|
@@ -2423,7 +2368,7 @@ function renameSession(db, newName) {
|
|
|
2423
2368
|
}
|
|
2424
2369
|
function clearSessionIndex(db) {
|
|
2425
2370
|
db.exec("DELETE FROM message_context");
|
|
2426
|
-
db.exec("DELETE FROM
|
|
2371
|
+
db.exec("DELETE FROM segment");
|
|
2427
2372
|
}
|
|
2428
2373
|
function generateSessionIndex(db, gapThreshold = DEFAULT_SESSION_GAP_THRESHOLD, onProgress) {
|
|
2429
2374
|
const countRow = db.prepare("SELECT COUNT(*) as count FROM message").get();
|
|
@@ -2457,9 +2402,9 @@ function generateSessionIndex(db, gapThreshold = DEFAULT_SESSION_GAP_THRESHOLD,
|
|
|
2457
2402
|
}
|
|
2458
2403
|
}
|
|
2459
2404
|
const insertSession = db.prepare(
|
|
2460
|
-
"INSERT INTO
|
|
2405
|
+
"INSERT INTO segment (start_ts, end_ts, message_count, is_manual, summary) VALUES (?, ?, ?, 0, NULL)"
|
|
2461
2406
|
);
|
|
2462
|
-
const insertContext = db.prepare("INSERT INTO message_context (message_id,
|
|
2407
|
+
const insertContext = db.prepare("INSERT INTO message_context (message_id, segment_id, topic_id) VALUES (?, ?, NULL)");
|
|
2463
2408
|
return db.transaction(() => {
|
|
2464
2409
|
let processed = 0;
|
|
2465
2410
|
const total = sessionMap.size;
|
|
@@ -2485,13 +2430,13 @@ function generateIncrementalSessionIndex(db, gapThreshold = DEFAULT_SESSION_GAP_
|
|
|
2485
2430
|
const allMessages = db.prepare("SELECT id, ts FROM message ORDER BY ts, id").all();
|
|
2486
2431
|
const newMessages = allMessages.filter((m) => !indexedIds.has(m.id));
|
|
2487
2432
|
if (newMessages.length === 0) return 0;
|
|
2488
|
-
const lastSession = hasTable(db, "
|
|
2433
|
+
const lastSession = hasTable(db, "segment") ? db.prepare("SELECT id, end_ts FROM segment ORDER BY end_ts DESC LIMIT 1").get() : void 0;
|
|
2489
2434
|
newMessages.sort((a, b) => a.ts - b.ts || a.id - b.id);
|
|
2490
2435
|
const insertSession = db.prepare(
|
|
2491
|
-
"INSERT INTO
|
|
2436
|
+
"INSERT INTO segment (start_ts, end_ts, message_count, is_manual, summary) VALUES (?, ?, ?, 0, NULL)"
|
|
2492
2437
|
);
|
|
2493
|
-
const insertContext = db.prepare("INSERT INTO message_context (message_id,
|
|
2494
|
-
const updateSession = db.prepare("UPDATE
|
|
2438
|
+
const insertContext = db.prepare("INSERT INTO message_context (message_id, segment_id, topic_id) VALUES (?, ?, NULL)");
|
|
2439
|
+
const updateSession = db.prepare("UPDATE segment SET end_ts = ?, message_count = message_count + ? WHERE id = ?");
|
|
2495
2440
|
return db.transaction(() => {
|
|
2496
2441
|
let newSessionCount = 0;
|
|
2497
2442
|
let currentSessionId = null;
|
|
@@ -2867,22 +2812,22 @@ function getSearchMessageContext(db, messageIds, contextBefore = 2, contextAfter
|
|
|
2867
2812
|
for (const messageId of messageIds) {
|
|
2868
2813
|
contextIds.add(messageId);
|
|
2869
2814
|
if (hasSessionData) {
|
|
2870
|
-
const sessionRow = db.prepare("SELECT
|
|
2815
|
+
const sessionRow = db.prepare("SELECT segment_id FROM message_context WHERE message_id = ?").get(messageId);
|
|
2871
2816
|
if (sessionRow) {
|
|
2872
2817
|
if (contextBefore > 0) {
|
|
2873
2818
|
const rows = db.prepare(
|
|
2874
2819
|
`SELECT mc.message_id as id FROM message_context mc
|
|
2875
|
-
WHERE mc.
|
|
2820
|
+
WHERE mc.segment_id = ? AND mc.message_id < ?
|
|
2876
2821
|
ORDER BY mc.message_id DESC LIMIT ?`
|
|
2877
|
-
).all(sessionRow.
|
|
2822
|
+
).all(sessionRow.segment_id, messageId, contextBefore);
|
|
2878
2823
|
rows.forEach((r) => contextIds.add(r.id));
|
|
2879
2824
|
}
|
|
2880
2825
|
if (contextAfter > 0) {
|
|
2881
2826
|
const rows = db.prepare(
|
|
2882
2827
|
`SELECT mc.message_id as id FROM message_context mc
|
|
2883
|
-
WHERE mc.
|
|
2828
|
+
WHERE mc.segment_id = ? AND mc.message_id > ?
|
|
2884
2829
|
ORDER BY mc.message_id ASC LIMIT ?`
|
|
2885
|
-
).all(sessionRow.
|
|
2830
|
+
).all(sessionRow.segment_id, messageId, contextAfter);
|
|
2886
2831
|
rows.forEach((r) => contextIds.add(r.id));
|
|
2887
2832
|
}
|
|
2888
2833
|
continue;
|
|
@@ -3229,17 +3174,17 @@ function filterMessagesWithContext(db, options = {}) {
|
|
|
3229
3174
|
pagination: { page, pageSize, totalBlocks, totalHits, hasMore }
|
|
3230
3175
|
};
|
|
3231
3176
|
}
|
|
3232
|
-
function getMultipleSessionsMessages(db,
|
|
3233
|
-
if (
|
|
3177
|
+
function getMultipleSessionsMessages(db, segmentIds, page = 1, pageSize = 50) {
|
|
3178
|
+
if (segmentIds.length === 0) {
|
|
3234
3179
|
return emptyResult(page, pageSize);
|
|
3235
3180
|
}
|
|
3236
3181
|
const sessionsSql = `
|
|
3237
3182
|
SELECT id, start_ts as startTs, end_ts as endTs, message_count as messageCount
|
|
3238
|
-
FROM
|
|
3239
|
-
WHERE id IN (${
|
|
3183
|
+
FROM segment
|
|
3184
|
+
WHERE id IN (${segmentIds.map(() => "?").join(",")})
|
|
3240
3185
|
ORDER BY start_ts ASC
|
|
3241
3186
|
`;
|
|
3242
|
-
const allSessions = db.prepare(sessionsSql).all(...
|
|
3187
|
+
const allSessions = db.prepare(sessionsSql).all(...segmentIds);
|
|
3243
3188
|
const totalBlocks = allSessions.length;
|
|
3244
3189
|
const startIdx = (page - 1) * pageSize;
|
|
3245
3190
|
const endIdx = Math.min(startIdx + pageSize, totalBlocks);
|
|
@@ -3262,7 +3207,7 @@ function getMultipleSessionsMessages(db, chatSessionIds, page = 1, pageSize = 50
|
|
|
3262
3207
|
JOIN member m ON msg.sender_id = m.id
|
|
3263
3208
|
LEFT JOIN message reply_msg ON msg.reply_to_message_id = reply_msg.platform_message_id
|
|
3264
3209
|
LEFT JOIN member reply_m ON reply_msg.sender_id = reply_m.id
|
|
3265
|
-
WHERE mc.
|
|
3210
|
+
WHERE mc.segment_id = ?
|
|
3266
3211
|
ORDER BY msg.ts ASC
|
|
3267
3212
|
`;
|
|
3268
3213
|
for (const session of pageSessions) {
|
|
@@ -3904,7 +3849,7 @@ function getRelationshipStats(db, filter, options) {
|
|
|
3904
3849
|
monthlyPerseverance: [],
|
|
3905
3850
|
perseveranceThreshold
|
|
3906
3851
|
};
|
|
3907
|
-
const sessionCount = db.prepare("SELECT COUNT(*) as count FROM
|
|
3852
|
+
const sessionCount = db.prepare("SELECT COUNT(*) as count FROM segment").get();
|
|
3908
3853
|
if (!sessionCount || sessionCount.count === 0) return emptyResult2;
|
|
3909
3854
|
const timeConditions = [];
|
|
3910
3855
|
const params = [];
|
|
@@ -3917,13 +3862,13 @@ function getRelationshipStats(db, filter, options) {
|
|
|
3917
3862
|
params.push(filter.endTs);
|
|
3918
3863
|
}
|
|
3919
3864
|
const whereClause = timeConditions.length > 0 ? `WHERE ${timeConditions.join(" AND ")}` : "";
|
|
3920
|
-
const
|
|
3921
|
-
`SELECT cs.id AS
|
|
3865
|
+
const segmentRows = db.prepare(
|
|
3866
|
+
`SELECT cs.id AS segment_id, cs.start_ts, cs.end_ts,
|
|
3922
3867
|
(SELECT m.sender_id FROM message_context mc JOIN message m ON m.id = mc.message_id
|
|
3923
|
-
WHERE mc.
|
|
3868
|
+
WHERE mc.segment_id = cs.id ORDER BY m.ts ASC, m.id ASC LIMIT 1) AS initiator_id,
|
|
3924
3869
|
(SELECT m.sender_id FROM message_context mc JOIN message m ON m.id = mc.message_id
|
|
3925
|
-
WHERE mc.
|
|
3926
|
-
FROM
|
|
3870
|
+
WHERE mc.segment_id = cs.id ORDER BY m.ts DESC, m.id DESC LIMIT 1) AS closer_id
|
|
3871
|
+
FROM segment cs ${whereClause} ORDER BY cs.start_ts ASC`
|
|
3927
3872
|
).all(...params);
|
|
3928
3873
|
const memberNames = /* @__PURE__ */ new Map();
|
|
3929
3874
|
const memberRows = db.prepare("SELECT id, COALESCE(group_nickname, account_name, platform_id) as name FROM member").all();
|
|
@@ -3934,7 +3879,7 @@ function getRelationshipStats(db, filter, options) {
|
|
|
3934
3879
|
const iceBreakMap = /* @__PURE__ */ new Map();
|
|
3935
3880
|
let totalIceBreaks = 0;
|
|
3936
3881
|
let prevEndTs = null;
|
|
3937
|
-
for (const row of
|
|
3882
|
+
for (const row of segmentRows) {
|
|
3938
3883
|
const month = toLocalMonth(row.start_ts);
|
|
3939
3884
|
if (!monthMap.has(month)) monthMap.set(month, { initiateMap: /* @__PURE__ */ new Map(), closeMap: /* @__PURE__ */ new Map(), totalSessions: 0 });
|
|
3940
3885
|
const ms = monthMap.get(month);
|
|
@@ -3983,12 +3928,12 @@ function getRelationshipStats(db, filter, options) {
|
|
|
3983
3928
|
iceBreakers.push({ month, memberId, name: memberNames.get(memberId) ?? `Unknown(${memberId})`, count });
|
|
3984
3929
|
}
|
|
3985
3930
|
}
|
|
3986
|
-
const
|
|
3987
|
-
const msgStats = queryMessageLevelStats(db,
|
|
3931
|
+
const segmentIdList = segmentRows.map((r) => r.segment_id);
|
|
3932
|
+
const msgStats = queryMessageLevelStats(db, segmentIdList, memberNames, perseveranceThreshold);
|
|
3988
3933
|
return {
|
|
3989
3934
|
months,
|
|
3990
3935
|
members,
|
|
3991
|
-
totalSessions:
|
|
3936
|
+
totalSessions: segmentRows.length,
|
|
3992
3937
|
hasSessionIndex: true,
|
|
3993
3938
|
iceBreakers,
|
|
3994
3939
|
totalIceBreaks,
|
|
@@ -3996,7 +3941,7 @@ function getRelationshipStats(db, filter, options) {
|
|
|
3996
3941
|
perseveranceThreshold
|
|
3997
3942
|
};
|
|
3998
3943
|
}
|
|
3999
|
-
function queryMessageLevelStats(db,
|
|
3944
|
+
function queryMessageLevelStats(db, segmentIds, memberNames, perseveranceThreshold) {
|
|
4000
3945
|
const empty = {
|
|
4001
3946
|
responseLatency: [],
|
|
4002
3947
|
perseverance: [],
|
|
@@ -4004,22 +3949,22 @@ function queryMessageLevelStats(db, sessionIds, memberNames, perseveranceThresho
|
|
|
4004
3949
|
monthlyResponseLatency: [],
|
|
4005
3950
|
monthlyPerseverance: []
|
|
4006
3951
|
};
|
|
4007
|
-
if (
|
|
3952
|
+
if (segmentIds.length === 0) return empty;
|
|
4008
3953
|
const BATCH_SIZE2 = 500;
|
|
4009
3954
|
const responseTotals = /* @__PURE__ */ new Map();
|
|
4010
3955
|
const dtTotals = /* @__PURE__ */ new Map();
|
|
4011
3956
|
const monthlyRespMap = /* @__PURE__ */ new Map();
|
|
4012
3957
|
const monthlyDtMap = /* @__PURE__ */ new Map();
|
|
4013
|
-
for (let i = 0; i <
|
|
4014
|
-
const batch =
|
|
3958
|
+
for (let i = 0; i < segmentIds.length; i += BATCH_SIZE2) {
|
|
3959
|
+
const batch = segmentIds.slice(i, i + BATCH_SIZE2);
|
|
4015
3960
|
const placeholders = batch.map(() => "?").join(",");
|
|
4016
3961
|
const latencyRows = db.prepare(
|
|
4017
3962
|
`WITH msg_lag AS (
|
|
4018
3963
|
SELECT m.sender_id, m.ts,
|
|
4019
|
-
LAG(m.sender_id) OVER (PARTITION BY mc.
|
|
4020
|
-
LAG(m.ts) OVER (PARTITION BY mc.
|
|
3964
|
+
LAG(m.sender_id) OVER (PARTITION BY mc.segment_id ORDER BY m.ts, m.id) AS prev_sender_id,
|
|
3965
|
+
LAG(m.ts) OVER (PARTITION BY mc.segment_id ORDER BY m.ts, m.id) AS prev_ts
|
|
4021
3966
|
FROM message_context mc JOIN message m ON m.id = mc.message_id
|
|
4022
|
-
WHERE mc.
|
|
3967
|
+
WHERE mc.segment_id IN (${placeholders}) AND m.type = 0
|
|
4023
3968
|
)
|
|
4024
3969
|
SELECT strftime('%Y-%m', datetime(ts, 'unixepoch', 'localtime')) AS month,
|
|
4025
3970
|
sender_id AS responder_id, SUM(ts - prev_ts) AS total_time, COUNT(*) AS response_count
|
|
@@ -4043,10 +3988,10 @@ function queryMessageLevelStats(db, sessionIds, memberNames, perseveranceThresho
|
|
|
4043
3988
|
const dtRows = db.prepare(
|
|
4044
3989
|
`WITH msg_lag AS (
|
|
4045
3990
|
SELECT m.sender_id, m.ts,
|
|
4046
|
-
LAG(m.sender_id) OVER (PARTITION BY mc.
|
|
4047
|
-
LAG(m.ts) OVER (PARTITION BY mc.
|
|
3991
|
+
LAG(m.sender_id) OVER (PARTITION BY mc.segment_id ORDER BY m.ts, m.id) AS prev_sender_id,
|
|
3992
|
+
LAG(m.ts) OVER (PARTITION BY mc.segment_id ORDER BY m.ts, m.id) AS prev_ts
|
|
4048
3993
|
FROM message_context mc JOIN message m ON m.id = mc.message_id
|
|
4049
|
-
WHERE mc.
|
|
3994
|
+
WHERE mc.segment_id IN (${placeholders}) AND m.type = 0
|
|
4050
3995
|
)
|
|
4051
3996
|
SELECT strftime('%Y-%m', datetime(ts, 'unixepoch', 'localtime')) AS month,
|
|
4052
3997
|
sender_id, COUNT(*) AS double_text_count
|
|
@@ -4258,125 +4203,6 @@ function getLanguagePreferenceAnalysis(db, params) {
|
|
|
4258
4203
|
return { members: memberProfiles, sharedWords, similarityScore };
|
|
4259
4204
|
}
|
|
4260
4205
|
|
|
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
4206
|
// ../../packages/core/src/version.ts
|
|
4381
4207
|
function parseStableVersion(version) {
|
|
4382
4208
|
const normalized = version.trim().replace(/^v/i, "");
|
|
@@ -5450,6 +5276,17 @@ function isValidWord(word, locale, minLength, enableStopwords, isStopwordFn) {
|
|
|
5450
5276
|
}
|
|
5451
5277
|
|
|
5452
5278
|
// ../../packages/core/src/ai/tool-catalog.ts
|
|
5279
|
+
var LEGACY_BUILTIN_TOOL_NAME_ALIASES = {
|
|
5280
|
+
search_sessions: "search_segments",
|
|
5281
|
+
get_session_messages: "get_segment_messages",
|
|
5282
|
+
get_session_summaries: "get_segment_summaries"
|
|
5283
|
+
};
|
|
5284
|
+
function normalizeBuiltinToolName(toolName) {
|
|
5285
|
+
return LEGACY_BUILTIN_TOOL_NAME_ALIASES[toolName] ?? toolName;
|
|
5286
|
+
}
|
|
5287
|
+
function normalizeBuiltinToolNames(toolNames) {
|
|
5288
|
+
return Array.from(new Set(toolNames.map(normalizeBuiltinToolName)));
|
|
5289
|
+
}
|
|
5453
5290
|
var BUILTIN_TOOL_CATALOG = [
|
|
5454
5291
|
// Core 工具
|
|
5455
5292
|
{ name: "get_chat_overview", category: "core" },
|
|
@@ -5457,8 +5294,8 @@ var BUILTIN_TOOL_CATALOG = [
|
|
|
5457
5294
|
{ name: "deep_search_messages", category: "core" },
|
|
5458
5295
|
{ name: "get_recent_messages", category: "core" },
|
|
5459
5296
|
{ name: "get_message_context", category: "core" },
|
|
5460
|
-
{ name: "
|
|
5461
|
-
{ name: "
|
|
5297
|
+
{ name: "search_segments", category: "core" },
|
|
5298
|
+
{ name: "get_segment_messages", category: "core" },
|
|
5462
5299
|
{ name: "get_members", category: "core" },
|
|
5463
5300
|
{ name: "get_schema", category: "core" },
|
|
5464
5301
|
// Analysis 工具
|
|
@@ -5466,7 +5303,7 @@ var BUILTIN_TOOL_CATALOG = [
|
|
|
5466
5303
|
{ name: "get_time_stats", category: "analysis" },
|
|
5467
5304
|
{ name: "get_member_name_history", category: "analysis" },
|
|
5468
5305
|
{ name: "get_conversation_between", category: "analysis" },
|
|
5469
|
-
{ name: "
|
|
5306
|
+
{ name: "get_segment_summaries", category: "analysis" },
|
|
5470
5307
|
{ name: "response_time_analysis", category: "analysis" },
|
|
5471
5308
|
{ name: "keyword_frequency", category: "analysis" },
|
|
5472
5309
|
{ name: "render_chart", category: "analysis" },
|
|
@@ -7001,76 +6838,195 @@ function mergeMembers2(sources, collidingIds) {
|
|
|
7001
6838
|
return map;
|
|
7002
6839
|
}
|
|
7003
6840
|
|
|
7004
|
-
// ../../packages/
|
|
7005
|
-
|
|
7006
|
-
|
|
6841
|
+
// ../../packages/core/src/schema/tables.ts
|
|
6842
|
+
var CURRENT_SCHEMA_VERSION = 6;
|
|
6843
|
+
var CHAT_DB_TABLES = `
|
|
6844
|
+
CREATE TABLE IF NOT EXISTS meta (
|
|
6845
|
+
name TEXT NOT NULL,
|
|
6846
|
+
platform TEXT NOT NULL,
|
|
6847
|
+
type TEXT NOT NULL,
|
|
6848
|
+
imported_at INTEGER NOT NULL,
|
|
6849
|
+
group_id TEXT,
|
|
6850
|
+
group_avatar TEXT,
|
|
6851
|
+
owner_id TEXT,
|
|
6852
|
+
schema_version INTEGER DEFAULT ${CURRENT_SCHEMA_VERSION},
|
|
6853
|
+
session_gap_threshold INTEGER
|
|
6854
|
+
);
|
|
7007
6855
|
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
|
|
7061
|
-
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
|
|
7065
|
-
|
|
7066
|
-
|
|
7067
|
-
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
6856
|
+
CREATE TABLE IF NOT EXISTS member (
|
|
6857
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
6858
|
+
platform_id TEXT NOT NULL UNIQUE,
|
|
6859
|
+
account_name TEXT,
|
|
6860
|
+
group_nickname TEXT,
|
|
6861
|
+
aliases TEXT DEFAULT '[]',
|
|
6862
|
+
avatar TEXT,
|
|
6863
|
+
roles TEXT DEFAULT '[]'
|
|
6864
|
+
);
|
|
6865
|
+
|
|
6866
|
+
CREATE TABLE IF NOT EXISTS member_name_history (
|
|
6867
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
6868
|
+
member_id INTEGER NOT NULL,
|
|
6869
|
+
name_type TEXT NOT NULL,
|
|
6870
|
+
name TEXT NOT NULL,
|
|
6871
|
+
start_ts INTEGER NOT NULL,
|
|
6872
|
+
end_ts INTEGER,
|
|
6873
|
+
FOREIGN KEY(member_id) REFERENCES member(id)
|
|
6874
|
+
);
|
|
6875
|
+
|
|
6876
|
+
CREATE TABLE IF NOT EXISTS message (
|
|
6877
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
6878
|
+
sender_id INTEGER NOT NULL,
|
|
6879
|
+
sender_account_name TEXT,
|
|
6880
|
+
sender_group_nickname TEXT,
|
|
6881
|
+
ts INTEGER NOT NULL,
|
|
6882
|
+
type INTEGER NOT NULL,
|
|
6883
|
+
content TEXT,
|
|
6884
|
+
reply_to_message_id TEXT DEFAULT NULL,
|
|
6885
|
+
platform_message_id TEXT DEFAULT NULL,
|
|
6886
|
+
FOREIGN KEY(sender_id) REFERENCES member(id)
|
|
6887
|
+
);
|
|
6888
|
+
|
|
6889
|
+
CREATE TABLE IF NOT EXISTS segment (
|
|
6890
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
6891
|
+
start_ts INTEGER NOT NULL,
|
|
6892
|
+
end_ts INTEGER NOT NULL,
|
|
6893
|
+
message_count INTEGER DEFAULT 0,
|
|
6894
|
+
is_manual INTEGER DEFAULT 0,
|
|
6895
|
+
summary TEXT
|
|
6896
|
+
);
|
|
6897
|
+
|
|
6898
|
+
CREATE TABLE IF NOT EXISTS message_context (
|
|
6899
|
+
message_id INTEGER PRIMARY KEY,
|
|
6900
|
+
segment_id INTEGER NOT NULL,
|
|
6901
|
+
topic_id INTEGER
|
|
6902
|
+
);
|
|
6903
|
+
`;
|
|
6904
|
+
var CHAT_DB_INDEXES = `
|
|
6905
|
+
CREATE INDEX IF NOT EXISTS idx_message_ts ON message(ts);
|
|
6906
|
+
CREATE INDEX IF NOT EXISTS idx_message_sender ON message(sender_id);
|
|
6907
|
+
CREATE INDEX IF NOT EXISTS idx_message_platform_id ON message(platform_message_id);
|
|
6908
|
+
CREATE INDEX IF NOT EXISTS idx_member_name_history_member_id ON member_name_history(member_id);
|
|
6909
|
+
CREATE INDEX IF NOT EXISTS idx_segment_time ON segment(start_ts, end_ts);
|
|
6910
|
+
CREATE INDEX IF NOT EXISTS idx_context_segment ON message_context(segment_id);
|
|
6911
|
+
`;
|
|
6912
|
+
var CHAT_DB_SCHEMA = CHAT_DB_TABLES + CHAT_DB_INDEXES;
|
|
6913
|
+
var FTS_TABLE_SCHEMA = `
|
|
6914
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS message_fts USING fts5(
|
|
6915
|
+
content,
|
|
6916
|
+
content='',
|
|
6917
|
+
content_rowid=id
|
|
6918
|
+
);
|
|
6919
|
+
`;
|
|
6920
|
+
|
|
6921
|
+
// ../../packages/core/src/schema/migrations.ts
|
|
6922
|
+
function getSchemaVersion(db) {
|
|
6923
|
+
try {
|
|
6924
|
+
const tableInfo = db.pragma("table_info(meta)");
|
|
6925
|
+
const hasVersionColumn = tableInfo.some((col) => col.name === "schema_version");
|
|
6926
|
+
if (!hasVersionColumn) return 0;
|
|
6927
|
+
const result = db.prepare("SELECT schema_version FROM meta LIMIT 1").get();
|
|
6928
|
+
return result?.schema_version ?? 0;
|
|
6929
|
+
} catch {
|
|
6930
|
+
return 0;
|
|
6931
|
+
}
|
|
6932
|
+
}
|
|
6933
|
+
function setSchemaVersion(db, version) {
|
|
6934
|
+
const tableInfo = db.pragma("table_info(meta)");
|
|
6935
|
+
const hasVersionColumn = tableInfo.some((col) => col.name === "schema_version");
|
|
6936
|
+
if (!hasVersionColumn) {
|
|
6937
|
+
db.exec("ALTER TABLE meta ADD COLUMN schema_version INTEGER DEFAULT 0");
|
|
6938
|
+
}
|
|
6939
|
+
db.prepare("UPDATE meta SET schema_version = ?").run(version);
|
|
6940
|
+
}
|
|
6941
|
+
function needsMigration(db, targetVersion) {
|
|
6942
|
+
return getSchemaVersion(db) < targetVersion;
|
|
6943
|
+
}
|
|
6944
|
+
function runMigrations(db, migrationsList, forceRepair = false) {
|
|
6945
|
+
const currentVersion = getSchemaVersion(db);
|
|
6946
|
+
if (!forceRepair && currentVersion >= (migrationsList.at(-1)?.version ?? 0)) {
|
|
6947
|
+
return false;
|
|
6948
|
+
}
|
|
6949
|
+
const pending = forceRepair ? migrationsList : migrationsList.filter((m) => m.version > currentVersion);
|
|
6950
|
+
if (pending.length === 0) return false;
|
|
6951
|
+
db.transaction(() => {
|
|
6952
|
+
for (const migration of pending) {
|
|
6953
|
+
migration.up(db);
|
|
6954
|
+
setSchemaVersion(db, migration.version);
|
|
6955
|
+
}
|
|
6956
|
+
});
|
|
6957
|
+
return true;
|
|
6958
|
+
}
|
|
6959
|
+
|
|
6960
|
+
// ../../packages/parser/src/index.ts
|
|
6961
|
+
import * as fs24 from "fs";
|
|
6962
|
+
import * as path20 from "path";
|
|
6963
|
+
|
|
6964
|
+
// ../../packages/parser/src/sniffer.ts
|
|
6965
|
+
import * as fs9 from "fs";
|
|
6966
|
+
import * as path9 from "path";
|
|
6967
|
+
var HEAD_SIZE = 64 * 1024;
|
|
6968
|
+
function readFileHead(filePath, size = HEAD_SIZE) {
|
|
6969
|
+
const fd = fs9.openSync(filePath, "r");
|
|
6970
|
+
const buffer = Buffer.alloc(size);
|
|
6971
|
+
const bytesRead = fs9.readSync(fd, buffer, 0, size, 0);
|
|
6972
|
+
fs9.closeSync(fd);
|
|
6973
|
+
return buffer.slice(0, bytesRead).toString("utf-8");
|
|
6974
|
+
}
|
|
6975
|
+
function getExtension(filePath) {
|
|
6976
|
+
return path9.extname(filePath).toLowerCase();
|
|
6977
|
+
}
|
|
6978
|
+
function matchHeadSignatures(headContent, patterns) {
|
|
6979
|
+
return patterns.some((pattern) => pattern.test(headContent));
|
|
6980
|
+
}
|
|
6981
|
+
function matchFilenameSignatures(filePath, patterns) {
|
|
6982
|
+
const filename = path9.basename(filePath);
|
|
6983
|
+
return patterns.some((pattern) => pattern.test(filename));
|
|
6984
|
+
}
|
|
6985
|
+
function matchRequiredFields(headContent, fields) {
|
|
6986
|
+
return fields.every((field) => {
|
|
6987
|
+
const pattern = new RegExp(`"${field.replace(".", '"\\s*:\\s*.*"')}"\\s*:`);
|
|
6988
|
+
return pattern.test(headContent) || headContent.includes(`"${field}"`);
|
|
6989
|
+
});
|
|
6990
|
+
}
|
|
6991
|
+
var FormatSniffer = class {
|
|
6992
|
+
formats = [];
|
|
6993
|
+
/**
|
|
6994
|
+
* 注册格式模块
|
|
6995
|
+
*/
|
|
6996
|
+
register(module) {
|
|
6997
|
+
this.formats.push(module);
|
|
6998
|
+
this.formats.sort((a, b) => a.feature.priority - b.feature.priority);
|
|
6999
|
+
}
|
|
7000
|
+
/**
|
|
7001
|
+
* 批量注册格式模块
|
|
7002
|
+
*/
|
|
7003
|
+
registerAll(modules) {
|
|
7004
|
+
for (const module of modules) {
|
|
7005
|
+
this.register(module);
|
|
7006
|
+
}
|
|
7007
|
+
}
|
|
7008
|
+
/**
|
|
7009
|
+
* 嗅探文件格式
|
|
7010
|
+
* @param filePath 文件路径
|
|
7011
|
+
* @returns 匹配的格式特征,如果无法识别则返回 null
|
|
7012
|
+
*/
|
|
7013
|
+
sniff(filePath) {
|
|
7014
|
+
const ext = getExtension(filePath);
|
|
7015
|
+
const headContent = readFileHead(filePath);
|
|
7016
|
+
for (const { feature: feature14 } of this.formats) {
|
|
7017
|
+
if (this.matchFeature(feature14, ext, headContent, filePath)) {
|
|
7018
|
+
return feature14;
|
|
7019
|
+
}
|
|
7020
|
+
}
|
|
7021
|
+
return null;
|
|
7022
|
+
}
|
|
7023
|
+
/**
|
|
7024
|
+
* 获取文件对应的解析器
|
|
7025
|
+
* @param filePath 文件路径
|
|
7026
|
+
* @returns 匹配的解析器,如果无法识别则返回 null
|
|
7027
|
+
*/
|
|
7028
|
+
getParser(filePath) {
|
|
7029
|
+
const ext = getExtension(filePath);
|
|
7074
7030
|
const headContent = readFileHead(filePath);
|
|
7075
7031
|
for (const { feature: feature14, parser: parser9 } of this.formats) {
|
|
7076
7032
|
if (this.matchFeature(feature14, ext, headContent, filePath)) {
|
|
@@ -11825,6 +11781,10 @@ function isDuplicate(msg, existingPlatformMsgIds, existingKeys) {
|
|
|
11825
11781
|
existingKeys.add(key);
|
|
11826
11782
|
return false;
|
|
11827
11783
|
}
|
|
11784
|
+
function normalizeTimestamp(timestamp) {
|
|
11785
|
+
const value = typeof timestamp === "string" && timestamp.trim() !== "" ? Number(timestamp) : timestamp;
|
|
11786
|
+
return typeof value === "number" && value > 0 && Number.isFinite(value) ? value : null;
|
|
11787
|
+
}
|
|
11828
11788
|
async function analyzeIncrementalImport(sessionId, filePath, deps) {
|
|
11829
11789
|
const formatFeature = detectFormat(filePath);
|
|
11830
11790
|
if (!formatFeature) {
|
|
@@ -11852,7 +11812,9 @@ async function analyzeIncrementalImport(sessionId, filePath, deps) {
|
|
|
11852
11812
|
onMessageBatch: (batch) => {
|
|
11853
11813
|
for (const msg of batch) {
|
|
11854
11814
|
totalInFile++;
|
|
11855
|
-
|
|
11815
|
+
const timestamp = normalizeTimestamp(msg.timestamp);
|
|
11816
|
+
if (timestamp === null) continue;
|
|
11817
|
+
if (isDuplicate({ ...msg, timestamp }, existingPlatformMsgIds, existingKeys)) {
|
|
11856
11818
|
duplicateCount++;
|
|
11857
11819
|
} else {
|
|
11858
11820
|
newMessageCount++;
|
|
@@ -11975,11 +11937,12 @@ async function incrementalImport(sessionId, filePath, deps, options) {
|
|
|
11975
11937
|
trackError2(processedCount, "MISSING_TIMESTAMP", "timestamp field is missing");
|
|
11976
11938
|
continue;
|
|
11977
11939
|
}
|
|
11978
|
-
|
|
11940
|
+
const timestamp = normalizeTimestamp(msg.timestamp);
|
|
11941
|
+
if (timestamp === null) {
|
|
11979
11942
|
trackError2(processedCount, "INVALID_TIMESTAMP", `timestamp value: ${msg.timestamp}`);
|
|
11980
11943
|
continue;
|
|
11981
11944
|
}
|
|
11982
|
-
if (isDuplicate(msg, existingPlatformMsgIds, existingKeys)) {
|
|
11945
|
+
if (isDuplicate({ ...msg, timestamp }, existingPlatformMsgIds, existingKeys)) {
|
|
11983
11946
|
duplicateCount++;
|
|
11984
11947
|
continue;
|
|
11985
11948
|
}
|
|
@@ -12003,7 +11966,7 @@ async function incrementalImport(sessionId, filePath, deps, options) {
|
|
|
12003
11966
|
memberId,
|
|
12004
11967
|
msg.senderAccountName || null,
|
|
12005
11968
|
msg.senderGroupNickname || null,
|
|
12006
|
-
|
|
11969
|
+
timestamp,
|
|
12007
11970
|
msg.type,
|
|
12008
11971
|
msg.content || null,
|
|
12009
11972
|
msg.replyToMessageId || null,
|
|
@@ -12207,17 +12170,17 @@ function writeParseResultToDb(db, meta, members, messages) {
|
|
|
12207
12170
|
// ../../packages/node-runtime/src/import/perf-logger.ts
|
|
12208
12171
|
var lastLogTime = Date.now();
|
|
12209
12172
|
|
|
12210
|
-
// ../../packages/node-runtime/src/ai/
|
|
12211
|
-
import
|
|
12173
|
+
// ../../packages/node-runtime/src/ai/chats.ts
|
|
12174
|
+
import Database from "better-sqlite3";
|
|
12212
12175
|
import * as fs28 from "fs";
|
|
12213
12176
|
import * as path23 from "path";
|
|
12214
12177
|
var DEFAULT_GENERAL_ID = "general_cn";
|
|
12215
12178
|
var defaultLogger = {
|
|
12216
12179
|
warn(_category, message, extra) {
|
|
12217
|
-
console.warn(`[AI
|
|
12180
|
+
console.warn(`[AI Chats] ${message}`, extra ?? "");
|
|
12218
12181
|
}
|
|
12219
12182
|
};
|
|
12220
|
-
var
|
|
12183
|
+
var AIChatManager = class {
|
|
12221
12184
|
db = null;
|
|
12222
12185
|
aiDataDir;
|
|
12223
12186
|
logger;
|
|
@@ -12237,13 +12200,14 @@ var AIConversationManager = class {
|
|
|
12237
12200
|
if (this.db) return this.db;
|
|
12238
12201
|
this.ensureDir(this.aiDataDir);
|
|
12239
12202
|
const dbPath = path23.join(this.aiDataDir, "conversations.db");
|
|
12240
|
-
this.db = this.nativeBinding ? new
|
|
12203
|
+
this.db = this.nativeBinding ? new Database(dbPath, { nativeBinding: this.nativeBinding }) : new Database(dbPath);
|
|
12241
12204
|
this.db.pragma("journal_mode = WAL");
|
|
12242
12205
|
this.db.exec(`
|
|
12243
|
-
CREATE TABLE IF NOT EXISTS
|
|
12206
|
+
CREATE TABLE IF NOT EXISTS ai_chat (
|
|
12244
12207
|
id TEXT PRIMARY KEY,
|
|
12245
12208
|
session_id TEXT NOT NULL,
|
|
12246
12209
|
title TEXT,
|
|
12210
|
+
assistant_id TEXT DEFAULT '${DEFAULT_GENERAL_ID}',
|
|
12247
12211
|
active_message_id TEXT,
|
|
12248
12212
|
created_at INTEGER NOT NULL,
|
|
12249
12213
|
updated_at INTEGER NOT NULL
|
|
@@ -12251,7 +12215,7 @@ var AIConversationManager = class {
|
|
|
12251
12215
|
|
|
12252
12216
|
CREATE TABLE IF NOT EXISTS ai_message (
|
|
12253
12217
|
id TEXT PRIMARY KEY,
|
|
12254
|
-
|
|
12218
|
+
ai_chat_id TEXT NOT NULL,
|
|
12255
12219
|
role TEXT NOT NULL,
|
|
12256
12220
|
content TEXT NOT NULL,
|
|
12257
12221
|
timestamp INTEGER NOT NULL,
|
|
@@ -12261,51 +12225,113 @@ var AIConversationManager = class {
|
|
|
12261
12225
|
parent_id TEXT,
|
|
12262
12226
|
sibling_group_id TEXT,
|
|
12263
12227
|
branch_index INTEGER DEFAULT 0,
|
|
12264
|
-
|
|
12228
|
+
debug_context TEXT,
|
|
12229
|
+
token_usage TEXT,
|
|
12230
|
+
FOREIGN KEY(ai_chat_id) REFERENCES ai_chat(id) ON DELETE CASCADE
|
|
12265
12231
|
);
|
|
12266
12232
|
|
|
12267
|
-
CREATE INDEX IF NOT EXISTS idx_ai_conversation_session ON ai_conversation(session_id);
|
|
12268
|
-
CREATE INDEX IF NOT EXISTS idx_ai_message_conversation ON ai_message(conversation_id);
|
|
12269
12233
|
`);
|
|
12270
12234
|
this.migrateDatabase(this.db);
|
|
12271
12235
|
return this.db;
|
|
12272
12236
|
}
|
|
12237
|
+
tableExists(db, tableName) {
|
|
12238
|
+
const row = db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?").get(tableName);
|
|
12239
|
+
return !!row;
|
|
12240
|
+
}
|
|
12241
|
+
getTableColumns(db, tableName) {
|
|
12242
|
+
const tableInfo = db.pragma(`table_info(${tableName})`);
|
|
12243
|
+
return tableInfo.map((col) => col.name);
|
|
12244
|
+
}
|
|
12245
|
+
ensureMessageMigrationColumns(db, tableName) {
|
|
12246
|
+
const messageColumns = this.getTableColumns(db, tableName);
|
|
12247
|
+
if (!messageColumns.includes("content_blocks")) {
|
|
12248
|
+
db.exec(`ALTER TABLE ${tableName} ADD COLUMN content_blocks TEXT`);
|
|
12249
|
+
}
|
|
12250
|
+
if (!messageColumns.includes("token_usage")) {
|
|
12251
|
+
db.exec(`ALTER TABLE ${tableName} ADD COLUMN token_usage TEXT`);
|
|
12252
|
+
}
|
|
12253
|
+
if (!messageColumns.includes("debug_context")) {
|
|
12254
|
+
db.exec(`ALTER TABLE ${tableName} ADD COLUMN debug_context TEXT`);
|
|
12255
|
+
}
|
|
12256
|
+
if (!messageColumns.includes("parent_id")) {
|
|
12257
|
+
db.exec(`ALTER TABLE ${tableName} ADD COLUMN parent_id TEXT`);
|
|
12258
|
+
}
|
|
12259
|
+
if (!messageColumns.includes("sibling_group_id")) {
|
|
12260
|
+
db.exec(`ALTER TABLE ${tableName} ADD COLUMN sibling_group_id TEXT`);
|
|
12261
|
+
}
|
|
12262
|
+
if (!messageColumns.includes("branch_index")) {
|
|
12263
|
+
db.exec(`ALTER TABLE ${tableName} ADD COLUMN branch_index INTEGER DEFAULT 0`);
|
|
12264
|
+
}
|
|
12265
|
+
}
|
|
12273
12266
|
migrateDatabase(db) {
|
|
12274
12267
|
try {
|
|
12275
|
-
const
|
|
12276
|
-
|
|
12277
|
-
|
|
12278
|
-
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
|
|
12284
|
-
|
|
12285
|
-
|
|
12286
|
-
|
|
12287
|
-
|
|
12288
|
-
|
|
12289
|
-
|
|
12290
|
-
|
|
12291
|
-
|
|
12292
|
-
}
|
|
12293
|
-
if (!messageColumns.includes("branch_index")) {
|
|
12294
|
-
db.exec("ALTER TABLE ai_message ADD COLUMN branch_index INTEGER DEFAULT 0");
|
|
12268
|
+
const hasLegacyConversationTable = this.tableExists(db, "ai_conversation");
|
|
12269
|
+
if (hasLegacyConversationTable) {
|
|
12270
|
+
const convColumns = this.getTableColumns(db, "ai_conversation");
|
|
12271
|
+
if (!convColumns.includes("assistant_id")) {
|
|
12272
|
+
db.exec(`ALTER TABLE ai_conversation ADD COLUMN assistant_id TEXT DEFAULT '${DEFAULT_GENERAL_ID}'`);
|
|
12273
|
+
}
|
|
12274
|
+
if (!convColumns.includes("active_message_id")) {
|
|
12275
|
+
db.exec("ALTER TABLE ai_conversation ADD COLUMN active_message_id TEXT");
|
|
12276
|
+
}
|
|
12277
|
+
db.exec(`
|
|
12278
|
+
INSERT OR IGNORE INTO ai_chat (
|
|
12279
|
+
id, session_id, title, assistant_id, active_message_id, created_at, updated_at
|
|
12280
|
+
)
|
|
12281
|
+
SELECT id, session_id, title, COALESCE(assistant_id, '${DEFAULT_GENERAL_ID}'),
|
|
12282
|
+
active_message_id, created_at, updated_at
|
|
12283
|
+
FROM ai_conversation
|
|
12284
|
+
`);
|
|
12295
12285
|
}
|
|
12296
|
-
|
|
12297
|
-
const
|
|
12298
|
-
const
|
|
12299
|
-
|
|
12300
|
-
|
|
12286
|
+
this.ensureMessageMigrationColumns(db, "ai_message");
|
|
12287
|
+
const messageColumns = this.getTableColumns(db, "ai_message");
|
|
12288
|
+
const hadLegacyConversationId = messageColumns.includes("conversation_id");
|
|
12289
|
+
const needsMessageTreeBackfill = !messageColumns.includes("parent_id") || !messageColumns.includes("sibling_group_id") || !messageColumns.includes("branch_index") || hadLegacyConversationId;
|
|
12290
|
+
if (hadLegacyConversationId && !messageColumns.includes("ai_chat_id")) {
|
|
12291
|
+
db.exec(`
|
|
12292
|
+
DROP INDEX IF EXISTS idx_ai_message_conversation;
|
|
12293
|
+
ALTER TABLE ai_message RENAME TO ai_message_legacy;
|
|
12294
|
+
|
|
12295
|
+
CREATE TABLE ai_message (
|
|
12296
|
+
id TEXT PRIMARY KEY,
|
|
12297
|
+
ai_chat_id TEXT NOT NULL,
|
|
12298
|
+
role TEXT NOT NULL,
|
|
12299
|
+
content TEXT NOT NULL,
|
|
12300
|
+
timestamp INTEGER NOT NULL,
|
|
12301
|
+
data_keywords TEXT,
|
|
12302
|
+
data_message_count INTEGER,
|
|
12303
|
+
content_blocks TEXT,
|
|
12304
|
+
parent_id TEXT,
|
|
12305
|
+
sibling_group_id TEXT,
|
|
12306
|
+
branch_index INTEGER DEFAULT 0,
|
|
12307
|
+
debug_context TEXT,
|
|
12308
|
+
token_usage TEXT,
|
|
12309
|
+
FOREIGN KEY(ai_chat_id) REFERENCES ai_chat(id) ON DELETE CASCADE
|
|
12310
|
+
);
|
|
12311
|
+
|
|
12312
|
+
INSERT INTO ai_message (
|
|
12313
|
+
id, ai_chat_id, role, content, timestamp, data_keywords, data_message_count,
|
|
12314
|
+
content_blocks, parent_id, sibling_group_id, branch_index, debug_context, token_usage
|
|
12315
|
+
)
|
|
12316
|
+
SELECT id, conversation_id, role, content, timestamp, data_keywords, data_message_count,
|
|
12317
|
+
content_blocks, parent_id, sibling_group_id, branch_index, debug_context, token_usage
|
|
12318
|
+
FROM ai_message_legacy;
|
|
12319
|
+
|
|
12320
|
+
DROP TABLE ai_message_legacy;
|
|
12321
|
+
`);
|
|
12301
12322
|
}
|
|
12302
|
-
if (
|
|
12303
|
-
db.exec(
|
|
12323
|
+
if (hasLegacyConversationTable) {
|
|
12324
|
+
db.exec(`
|
|
12325
|
+
DROP INDEX IF EXISTS idx_ai_conversation_session;
|
|
12326
|
+
DROP TABLE ai_conversation;
|
|
12327
|
+
`);
|
|
12304
12328
|
}
|
|
12305
|
-
if (needsMessageTreeBackfill ||
|
|
12329
|
+
if (needsMessageTreeBackfill || this.hasUnbackfilledMessageTree(db)) {
|
|
12306
12330
|
this.backfillMessageTree(db);
|
|
12307
12331
|
}
|
|
12308
12332
|
db.exec(`
|
|
12333
|
+
CREATE INDEX IF NOT EXISTS idx_ai_chat_session ON ai_chat(session_id);
|
|
12334
|
+
CREATE INDEX IF NOT EXISTS idx_ai_message_ai_chat ON ai_message(ai_chat_id);
|
|
12309
12335
|
CREATE INDEX IF NOT EXISTS idx_ai_message_parent ON ai_message(parent_id);
|
|
12310
12336
|
CREATE INDEX IF NOT EXISTS idx_ai_message_sibling ON ai_message(sibling_group_id);
|
|
12311
12337
|
`);
|
|
@@ -12316,16 +12342,16 @@ var AIConversationManager = class {
|
|
|
12316
12342
|
hasUnbackfilledMessageTree(db) {
|
|
12317
12343
|
const row = db.prepare(
|
|
12318
12344
|
`SELECT 1
|
|
12319
|
-
FROM
|
|
12345
|
+
FROM ai_chat c
|
|
12320
12346
|
WHERE EXISTS (
|
|
12321
12347
|
SELECT 1 FROM ai_message m
|
|
12322
|
-
WHERE m.
|
|
12348
|
+
WHERE m.ai_chat_id = c.id
|
|
12323
12349
|
)
|
|
12324
12350
|
AND (
|
|
12325
12351
|
c.active_message_id IS NULL
|
|
12326
12352
|
OR EXISTS (
|
|
12327
12353
|
SELECT 1 FROM ai_message m
|
|
12328
|
-
WHERE m.
|
|
12354
|
+
WHERE m.ai_chat_id = c.id
|
|
12329
12355
|
AND (m.sibling_group_id IS NULL OR m.branch_index IS NULL)
|
|
12330
12356
|
)
|
|
12331
12357
|
)
|
|
@@ -12334,26 +12360,26 @@ var AIConversationManager = class {
|
|
|
12334
12360
|
return !!row;
|
|
12335
12361
|
}
|
|
12336
12362
|
backfillMessageTree(db) {
|
|
12337
|
-
const
|
|
12363
|
+
const aiChats = db.prepare("SELECT id FROM ai_chat").all();
|
|
12338
12364
|
const updateMessage = db.prepare(
|
|
12339
12365
|
"UPDATE ai_message SET parent_id = ?, sibling_group_id = COALESCE(sibling_group_id, ?), branch_index = COALESCE(branch_index, 0) WHERE id = ?"
|
|
12340
12366
|
);
|
|
12341
|
-
const
|
|
12367
|
+
const updateAIChat = db.prepare("UPDATE ai_chat SET active_message_id = ? WHERE id = ?");
|
|
12342
12368
|
const tx = db.transaction(() => {
|
|
12343
|
-
for (const
|
|
12369
|
+
for (const aiChat of aiChats) {
|
|
12344
12370
|
const messages = db.prepare(
|
|
12345
12371
|
`SELECT id, parent_id as parentId, sibling_group_id as siblingGroupId
|
|
12346
|
-
FROM ai_message WHERE
|
|
12347
|
-
).all(
|
|
12372
|
+
FROM ai_message WHERE ai_chat_id = ? ORDER BY timestamp ASC, id ASC`
|
|
12373
|
+
).all(aiChat.id);
|
|
12348
12374
|
let previousId = null;
|
|
12349
12375
|
for (const message of messages) {
|
|
12350
12376
|
const parentId = message.parentId === void 0 ? previousId : message.parentId ?? previousId;
|
|
12351
12377
|
updateMessage.run(parentId, message.siblingGroupId ?? message.id, message.id);
|
|
12352
12378
|
previousId = message.id;
|
|
12353
12379
|
}
|
|
12354
|
-
const
|
|
12355
|
-
if (!
|
|
12356
|
-
|
|
12380
|
+
const aiChatRow = db.prepare("SELECT active_message_id as activeMessageId FROM ai_chat WHERE id = ?").get(aiChat.id);
|
|
12381
|
+
if (!aiChatRow?.activeMessageId && previousId) {
|
|
12382
|
+
updateAIChat.run(previousId, aiChat.id);
|
|
12357
12383
|
}
|
|
12358
12384
|
}
|
|
12359
12385
|
});
|
|
@@ -12365,7 +12391,7 @@ var AIConversationManager = class {
|
|
|
12365
12391
|
parseMessageRow(row) {
|
|
12366
12392
|
return {
|
|
12367
12393
|
id: row.id,
|
|
12368
|
-
|
|
12394
|
+
aiChatId: row.aiChatId,
|
|
12369
12395
|
role: row.role,
|
|
12370
12396
|
content: row.content,
|
|
12371
12397
|
timestamp: row.timestamp,
|
|
@@ -12379,7 +12405,7 @@ var AIConversationManager = class {
|
|
|
12379
12405
|
getMessageRow(messageId) {
|
|
12380
12406
|
const db = this.getDb();
|
|
12381
12407
|
const row = db.prepare(
|
|
12382
|
-
`SELECT id,
|
|
12408
|
+
`SELECT id, ai_chat_id as aiChatId, role, content, timestamp,
|
|
12383
12409
|
parent_id as parentId, sibling_group_id as siblingGroupId, branch_index as branchIndex,
|
|
12384
12410
|
data_keywords as dataKeywords, data_message_count as dataMessageCount,
|
|
12385
12411
|
content_blocks as contentBlocks, token_usage as tokenUsage
|
|
@@ -12387,45 +12413,45 @@ var AIConversationManager = class {
|
|
|
12387
12413
|
).get(messageId);
|
|
12388
12414
|
return row ?? null;
|
|
12389
12415
|
}
|
|
12390
|
-
getActiveMessageId(
|
|
12416
|
+
getActiveMessageId(aiChatId) {
|
|
12391
12417
|
const db = this.getDb();
|
|
12392
|
-
const row = db.prepare("SELECT active_message_id as activeMessageId FROM
|
|
12418
|
+
const row = db.prepare("SELECT active_message_id as activeMessageId FROM ai_chat WHERE id = ?").get(aiChatId);
|
|
12393
12419
|
if (row?.activeMessageId) {
|
|
12394
12420
|
const activeExists = db.prepare("SELECT 1 FROM ai_message WHERE id = ?").get(row.activeMessageId);
|
|
12395
12421
|
if (activeExists) return row.activeMessageId;
|
|
12396
12422
|
}
|
|
12397
|
-
const fallback = db.prepare("SELECT id FROM ai_message WHERE
|
|
12423
|
+
const fallback = db.prepare("SELECT id FROM ai_message WHERE ai_chat_id = ? ORDER BY timestamp DESC, id DESC LIMIT 1").get(aiChatId);
|
|
12398
12424
|
if (fallback?.id) {
|
|
12399
|
-
db.prepare("UPDATE
|
|
12425
|
+
db.prepare("UPDATE ai_chat SET active_message_id = ? WHERE id = ?").run(fallback.id, aiChatId);
|
|
12400
12426
|
return fallback.id;
|
|
12401
12427
|
}
|
|
12402
12428
|
return null;
|
|
12403
12429
|
}
|
|
12404
|
-
getAllMessageRows(
|
|
12430
|
+
getAllMessageRows(aiChatId) {
|
|
12405
12431
|
return this.getDb().prepare(
|
|
12406
|
-
`SELECT id,
|
|
12432
|
+
`SELECT id, ai_chat_id as aiChatId, role, content, timestamp,
|
|
12407
12433
|
parent_id as parentId, sibling_group_id as siblingGroupId, branch_index as branchIndex,
|
|
12408
12434
|
data_keywords as dataKeywords, data_message_count as dataMessageCount,
|
|
12409
12435
|
content_blocks as contentBlocks, token_usage as tokenUsage
|
|
12410
|
-
FROM ai_message WHERE
|
|
12411
|
-
).all(
|
|
12436
|
+
FROM ai_message WHERE ai_chat_id = ? ORDER BY timestamp ASC, id ASC`
|
|
12437
|
+
).all(aiChatId);
|
|
12412
12438
|
}
|
|
12413
|
-
getActivePathRows(
|
|
12439
|
+
getActivePathRows(aiChatId, leafMessageId) {
|
|
12414
12440
|
if (leafMessageId === null) return [];
|
|
12415
|
-
const allRows = this.getAllMessageRows(
|
|
12441
|
+
const allRows = this.getAllMessageRows(aiChatId);
|
|
12416
12442
|
if (allRows.length === 0) return [];
|
|
12417
12443
|
const rowMap = new Map(allRows.map((row) => [row.id, row]));
|
|
12418
|
-
let currentId = leafMessageId ?? this.getActiveMessageId(
|
|
12419
|
-
const
|
|
12444
|
+
let currentId = leafMessageId ?? this.getActiveMessageId(aiChatId);
|
|
12445
|
+
const path36 = [];
|
|
12420
12446
|
const seen = /* @__PURE__ */ new Set();
|
|
12421
12447
|
while (currentId && !seen.has(currentId)) {
|
|
12422
12448
|
seen.add(currentId);
|
|
12423
12449
|
const row = rowMap.get(currentId);
|
|
12424
12450
|
if (!row) break;
|
|
12425
|
-
|
|
12451
|
+
path36.push(row);
|
|
12426
12452
|
currentId = row.parentId;
|
|
12427
12453
|
}
|
|
12428
|
-
return
|
|
12454
|
+
return path36.length > 0 ? path36.reverse() : allRows;
|
|
12429
12455
|
}
|
|
12430
12456
|
// ==================== 生命周期 ====================
|
|
12431
12457
|
close() {
|
|
@@ -12481,21 +12507,21 @@ var AIConversationManager = class {
|
|
|
12481
12507
|
}
|
|
12482
12508
|
}
|
|
12483
12509
|
// ==================== 对话管理 ====================
|
|
12484
|
-
|
|
12510
|
+
createAIChat(sessionId, title, assistantId) {
|
|
12485
12511
|
const db = this.getDb();
|
|
12486
12512
|
const now = Math.floor(Date.now() / 1e3);
|
|
12487
12513
|
const id = this.generateId("conv");
|
|
12488
12514
|
db.prepare(
|
|
12489
|
-
`INSERT INTO
|
|
12515
|
+
`INSERT INTO ai_chat (id, session_id, title, assistant_id, created_at, updated_at)
|
|
12490
12516
|
VALUES (?, ?, ?, ?, ?, ?)`
|
|
12491
12517
|
).run(id, sessionId, title || null, assistantId, now, now);
|
|
12492
12518
|
return { id, sessionId, title: title || null, assistantId, activeMessageId: null, createdAt: now, updatedAt: now };
|
|
12493
12519
|
}
|
|
12494
|
-
|
|
12520
|
+
getAIChatCountsBySession() {
|
|
12495
12521
|
const result = /* @__PURE__ */ new Map();
|
|
12496
12522
|
try {
|
|
12497
12523
|
const db = this.getDb();
|
|
12498
|
-
const rows = db.prepare("SELECT session_id, COUNT(*) as count FROM
|
|
12524
|
+
const rows = db.prepare("SELECT session_id, COUNT(*) as count FROM ai_chat GROUP BY session_id").all();
|
|
12499
12525
|
for (const row of rows) {
|
|
12500
12526
|
result.set(row.session_id, row.count);
|
|
12501
12527
|
}
|
|
@@ -12503,58 +12529,58 @@ var AIConversationManager = class {
|
|
|
12503
12529
|
}
|
|
12504
12530
|
return result;
|
|
12505
12531
|
}
|
|
12506
|
-
|
|
12532
|
+
getAIChats(sessionId) {
|
|
12507
12533
|
const db = this.getDb();
|
|
12508
12534
|
return db.prepare(
|
|
12509
12535
|
`SELECT id, session_id as sessionId, title, assistant_id as assistantId,
|
|
12510
12536
|
active_message_id as activeMessageId,
|
|
12511
12537
|
created_at as createdAt, updated_at as updatedAt
|
|
12512
|
-
FROM
|
|
12538
|
+
FROM ai_chat WHERE session_id = ? ORDER BY updated_at DESC`
|
|
12513
12539
|
).all(sessionId);
|
|
12514
12540
|
}
|
|
12515
|
-
|
|
12541
|
+
getAIChat(aiChatId) {
|
|
12516
12542
|
const db = this.getDb();
|
|
12517
12543
|
const row = db.prepare(
|
|
12518
12544
|
`SELECT id, session_id as sessionId, title, assistant_id as assistantId,
|
|
12519
12545
|
active_message_id as activeMessageId,
|
|
12520
12546
|
created_at as createdAt, updated_at as updatedAt
|
|
12521
|
-
FROM
|
|
12522
|
-
).get(
|
|
12547
|
+
FROM ai_chat WHERE id = ?`
|
|
12548
|
+
).get(aiChatId);
|
|
12523
12549
|
return row || null;
|
|
12524
12550
|
}
|
|
12525
|
-
|
|
12551
|
+
updateAIChatTitle(aiChatId, title) {
|
|
12526
12552
|
const db = this.getDb();
|
|
12527
12553
|
const now = Math.floor(Date.now() / 1e3);
|
|
12528
|
-
const result = db.prepare("UPDATE
|
|
12554
|
+
const result = db.prepare("UPDATE ai_chat SET title = ?, updated_at = ? WHERE id = ?").run(title, now, aiChatId);
|
|
12529
12555
|
return result.changes > 0;
|
|
12530
12556
|
}
|
|
12531
|
-
|
|
12557
|
+
deleteAIChat(aiChatId) {
|
|
12532
12558
|
const db = this.getDb();
|
|
12533
|
-
db.prepare("DELETE FROM ai_message WHERE
|
|
12534
|
-
const result = db.prepare("DELETE FROM
|
|
12559
|
+
db.prepare("DELETE FROM ai_message WHERE ai_chat_id = ?").run(aiChatId);
|
|
12560
|
+
const result = db.prepare("DELETE FROM ai_chat WHERE id = ?").run(aiChatId);
|
|
12535
12561
|
return result.changes > 0;
|
|
12536
12562
|
}
|
|
12537
12563
|
// ==================== 消息管理 ====================
|
|
12538
|
-
addMessage(
|
|
12564
|
+
addMessage(aiChatId, role, content, dataKeywords, dataMessageCount, contentBlocks, tokenUsage) {
|
|
12539
12565
|
const db = this.getDb();
|
|
12540
12566
|
const now = Math.floor(Date.now() / 1e3);
|
|
12541
12567
|
const id = this.generateId("msg");
|
|
12542
|
-
const parentId = this.getActiveMessageId(
|
|
12568
|
+
const parentId = this.getActiveMessageId(aiChatId);
|
|
12543
12569
|
const siblingGroupId = id;
|
|
12544
12570
|
const branchIndex = 0;
|
|
12545
|
-
const pendingDebug = role === "assistant" ? this.pendingDebugContextMap.get(
|
|
12571
|
+
const pendingDebug = role === "assistant" ? this.pendingDebugContextMap.get(aiChatId) : void 0;
|
|
12546
12572
|
if (pendingDebug) {
|
|
12547
|
-
this.pendingDebugContextMap.delete(
|
|
12573
|
+
this.pendingDebugContextMap.delete(aiChatId);
|
|
12548
12574
|
}
|
|
12549
12575
|
db.prepare(
|
|
12550
12576
|
`INSERT INTO ai_message (
|
|
12551
|
-
id,
|
|
12577
|
+
id, ai_chat_id, role, content, timestamp, data_keywords, data_message_count,
|
|
12552
12578
|
content_blocks, token_usage, debug_context, parent_id, sibling_group_id, branch_index
|
|
12553
12579
|
)
|
|
12554
12580
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
12555
12581
|
).run(
|
|
12556
12582
|
id,
|
|
12557
|
-
|
|
12583
|
+
aiChatId,
|
|
12558
12584
|
role,
|
|
12559
12585
|
content,
|
|
12560
12586
|
now,
|
|
@@ -12567,14 +12593,10 @@ var AIConversationManager = class {
|
|
|
12567
12593
|
siblingGroupId,
|
|
12568
12594
|
branchIndex
|
|
12569
12595
|
);
|
|
12570
|
-
db.prepare("UPDATE
|
|
12571
|
-
id,
|
|
12572
|
-
now,
|
|
12573
|
-
conversationId
|
|
12574
|
-
);
|
|
12596
|
+
db.prepare("UPDATE ai_chat SET active_message_id = ?, updated_at = ? WHERE id = ?").run(id, now, aiChatId);
|
|
12575
12597
|
return {
|
|
12576
12598
|
id,
|
|
12577
|
-
|
|
12599
|
+
aiChatId,
|
|
12578
12600
|
role,
|
|
12579
12601
|
content,
|
|
12580
12602
|
timestamp: now,
|
|
@@ -12585,21 +12607,21 @@ var AIConversationManager = class {
|
|
|
12585
12607
|
tokenUsage
|
|
12586
12608
|
};
|
|
12587
12609
|
}
|
|
12588
|
-
getMessages(
|
|
12589
|
-
return this.getActivePathRows(
|
|
12610
|
+
getMessages(aiChatId) {
|
|
12611
|
+
return this.getActivePathRows(aiChatId).map((row) => this.parseMessageRow(row));
|
|
12590
12612
|
}
|
|
12591
12613
|
deleteMessage(messageId) {
|
|
12592
12614
|
const db = this.getDb();
|
|
12593
12615
|
const result = db.prepare("DELETE FROM ai_message WHERE id = ?").run(messageId);
|
|
12594
12616
|
return result.changes > 0;
|
|
12595
12617
|
}
|
|
12596
|
-
deleteMessagesFrom(
|
|
12618
|
+
deleteMessagesFrom(aiChatId, messageId) {
|
|
12597
12619
|
const db = this.getDb();
|
|
12598
12620
|
const target = this.getMessageRow(messageId);
|
|
12599
|
-
if (!target || target.
|
|
12600
|
-
throw new Error("Message not found in
|
|
12621
|
+
if (!target || target.aiChatId !== aiChatId) {
|
|
12622
|
+
throw new Error("Message not found in AI chat");
|
|
12601
12623
|
}
|
|
12602
|
-
const activePath = this.getActivePathRows(
|
|
12624
|
+
const activePath = this.getActivePathRows(aiChatId);
|
|
12603
12625
|
const targetIndex = activePath.findIndex((row) => row.id === messageId);
|
|
12604
12626
|
if (targetIndex < 0) {
|
|
12605
12627
|
throw new Error("Message not on active path");
|
|
@@ -12609,19 +12631,15 @@ var AIConversationManager = class {
|
|
|
12609
12631
|
db.prepare(`DELETE FROM ai_message WHERE id IN (${placeholders})`).run(...idsToDelete);
|
|
12610
12632
|
const newLeafId = targetIndex > 0 ? activePath[targetIndex - 1].id : null;
|
|
12611
12633
|
const now = Math.floor(Date.now() / 1e3);
|
|
12612
|
-
db.prepare("UPDATE
|
|
12613
|
-
newLeafId,
|
|
12614
|
-
now,
|
|
12615
|
-
conversationId
|
|
12616
|
-
);
|
|
12634
|
+
db.prepare("UPDATE ai_chat SET active_message_id = ?, updated_at = ? WHERE id = ?").run(newLeafId, now, aiChatId);
|
|
12617
12635
|
}
|
|
12618
|
-
|
|
12636
|
+
forkAIChat(sourceAIChatId, upToMessageId, title) {
|
|
12619
12637
|
const db = this.getDb();
|
|
12620
|
-
const source = this.
|
|
12638
|
+
const source = this.getAIChat(sourceAIChatId);
|
|
12621
12639
|
if (!source) {
|
|
12622
|
-
throw new Error("Source
|
|
12640
|
+
throw new Error("Source AI chat not found");
|
|
12623
12641
|
}
|
|
12624
|
-
const activePath = this.getActivePathRows(
|
|
12642
|
+
const activePath = this.getActivePathRows(sourceAIChatId);
|
|
12625
12643
|
const cutIndex = activePath.findIndex((row) => row.id === upToMessageId);
|
|
12626
12644
|
if (cutIndex < 0) {
|
|
12627
12645
|
throw new Error("Message not on active path");
|
|
@@ -12631,7 +12649,7 @@ var AIConversationManager = class {
|
|
|
12631
12649
|
const newConvId = this.generateId("conv");
|
|
12632
12650
|
const forkTitle = title || `${source.title || "Untitled"} (fork)`;
|
|
12633
12651
|
db.prepare(
|
|
12634
|
-
`INSERT INTO
|
|
12652
|
+
`INSERT INTO ai_chat (id, session_id, title, assistant_id, active_message_id, created_at, updated_at)
|
|
12635
12653
|
VALUES (?, ?, ?, ?, NULL, ?, ?)`
|
|
12636
12654
|
).run(newConvId, source.sessionId, forkTitle, source.assistantId, now, now);
|
|
12637
12655
|
const idMap = /* @__PURE__ */ new Map();
|
|
@@ -12642,7 +12660,7 @@ var AIConversationManager = class {
|
|
|
12642
12660
|
const newParentId = row.parentId ? idMap.get(row.parentId) ?? null : null;
|
|
12643
12661
|
db.prepare(
|
|
12644
12662
|
`INSERT INTO ai_message (
|
|
12645
|
-
id,
|
|
12663
|
+
id, ai_chat_id, role, content, timestamp, data_keywords, data_message_count,
|
|
12646
12664
|
content_blocks, token_usage, debug_context, parent_id, sibling_group_id, branch_index
|
|
12647
12665
|
)
|
|
12648
12666
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, 0)`
|
|
@@ -12662,7 +12680,7 @@ var AIConversationManager = class {
|
|
|
12662
12680
|
lastNewId = newMsgId;
|
|
12663
12681
|
}
|
|
12664
12682
|
if (lastNewId) {
|
|
12665
|
-
db.prepare("UPDATE
|
|
12683
|
+
db.prepare("UPDATE ai_chat SET active_message_id = ? WHERE id = ?").run(lastNewId, newConvId);
|
|
12666
12684
|
}
|
|
12667
12685
|
return {
|
|
12668
12686
|
id: newConvId,
|
|
@@ -12679,46 +12697,46 @@ var AIConversationManager = class {
|
|
|
12679
12697
|
const result = db.prepare("UPDATE ai_message SET content = ? WHERE id = ?").run(newContent, messageId);
|
|
12680
12698
|
if (result.changes === 0) throw new Error("Message not found");
|
|
12681
12699
|
}
|
|
12682
|
-
deleteAndRelinkMessage(
|
|
12700
|
+
deleteAndRelinkMessage(aiChatId, messageId) {
|
|
12683
12701
|
const db = this.getDb();
|
|
12684
12702
|
const target = this.getMessageRow(messageId);
|
|
12685
|
-
if (!target || target.
|
|
12686
|
-
throw new Error("Message not found in
|
|
12703
|
+
if (!target || target.aiChatId !== aiChatId) {
|
|
12704
|
+
throw new Error("Message not found in AI chat");
|
|
12687
12705
|
}
|
|
12688
|
-
db.prepare("UPDATE ai_message SET parent_id = ? WHERE parent_id = ? AND
|
|
12706
|
+
db.prepare("UPDATE ai_message SET parent_id = ? WHERE parent_id = ? AND ai_chat_id = ?").run(
|
|
12689
12707
|
target.parentId,
|
|
12690
12708
|
messageId,
|
|
12691
|
-
|
|
12709
|
+
aiChatId
|
|
12692
12710
|
);
|
|
12693
|
-
const conv = this.
|
|
12711
|
+
const conv = this.getAIChat(aiChatId);
|
|
12694
12712
|
if (conv?.activeMessageId === messageId) {
|
|
12695
12713
|
const now = Math.floor(Date.now() / 1e3);
|
|
12696
|
-
db.prepare("UPDATE
|
|
12714
|
+
db.prepare("UPDATE ai_chat SET active_message_id = ?, updated_at = ? WHERE id = ?").run(
|
|
12697
12715
|
target.parentId,
|
|
12698
12716
|
now,
|
|
12699
|
-
|
|
12717
|
+
aiChatId
|
|
12700
12718
|
);
|
|
12701
12719
|
}
|
|
12702
12720
|
db.prepare("DELETE FROM ai_message WHERE id = ?").run(messageId);
|
|
12703
12721
|
}
|
|
12704
|
-
insertMessageAfter(
|
|
12722
|
+
insertMessageAfter(aiChatId, afterMessageId, role, content, contentBlocks, tokenUsage) {
|
|
12705
12723
|
const db = this.getDb();
|
|
12706
12724
|
const now = Math.floor(Date.now() / 1e3);
|
|
12707
12725
|
const id = this.generateId("msg");
|
|
12708
|
-
const pendingDebug = role === "assistant" ? this.pendingDebugContextMap.get(
|
|
12726
|
+
const pendingDebug = role === "assistant" ? this.pendingDebugContextMap.get(aiChatId) : void 0;
|
|
12709
12727
|
if (pendingDebug) {
|
|
12710
|
-
this.pendingDebugContextMap.delete(
|
|
12728
|
+
this.pendingDebugContextMap.delete(aiChatId);
|
|
12711
12729
|
}
|
|
12712
|
-
const childRow = db.prepare("SELECT id FROM ai_message WHERE parent_id = ? AND
|
|
12730
|
+
const childRow = db.prepare("SELECT id FROM ai_message WHERE parent_id = ? AND ai_chat_id = ? LIMIT 1").get(afterMessageId, aiChatId);
|
|
12713
12731
|
db.prepare(
|
|
12714
12732
|
`INSERT INTO ai_message (
|
|
12715
|
-
id,
|
|
12733
|
+
id, ai_chat_id, role, content, timestamp, data_keywords, data_message_count,
|
|
12716
12734
|
content_blocks, token_usage, debug_context, parent_id, sibling_group_id, branch_index
|
|
12717
12735
|
)
|
|
12718
12736
|
VALUES (?, ?, ?, ?, ?, NULL, NULL, ?, ?, ?, ?, ?, 0)`
|
|
12719
12737
|
).run(
|
|
12720
12738
|
id,
|
|
12721
|
-
|
|
12739
|
+
aiChatId,
|
|
12722
12740
|
role,
|
|
12723
12741
|
content,
|
|
12724
12742
|
now,
|
|
@@ -12730,17 +12748,13 @@ var AIConversationManager = class {
|
|
|
12730
12748
|
);
|
|
12731
12749
|
if (childRow) {
|
|
12732
12750
|
db.prepare("UPDATE ai_message SET parent_id = ? WHERE id = ?").run(id, childRow.id);
|
|
12733
|
-
db.prepare("UPDATE
|
|
12751
|
+
db.prepare("UPDATE ai_chat SET updated_at = ? WHERE id = ?").run(now, aiChatId);
|
|
12734
12752
|
} else {
|
|
12735
|
-
db.prepare("UPDATE
|
|
12736
|
-
id,
|
|
12737
|
-
now,
|
|
12738
|
-
conversationId
|
|
12739
|
-
);
|
|
12753
|
+
db.prepare("UPDATE ai_chat SET active_message_id = ?, updated_at = ? WHERE id = ?").run(id, now, aiChatId);
|
|
12740
12754
|
}
|
|
12741
12755
|
return {
|
|
12742
12756
|
id,
|
|
12743
|
-
|
|
12757
|
+
aiChatId,
|
|
12744
12758
|
role,
|
|
12745
12759
|
content,
|
|
12746
12760
|
timestamp: now,
|
|
@@ -12749,8 +12763,8 @@ var AIConversationManager = class {
|
|
|
12749
12763
|
tokenUsage
|
|
12750
12764
|
};
|
|
12751
12765
|
}
|
|
12752
|
-
|
|
12753
|
-
const rows = this.getActivePathRows(
|
|
12766
|
+
getAIChatTokenUsage(aiChatId) {
|
|
12767
|
+
const rows = this.getActivePathRows(aiChatId);
|
|
12754
12768
|
const result = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
|
|
12755
12769
|
for (const row of rows) {
|
|
12756
12770
|
if (row.tokenUsage) {
|
|
@@ -12763,8 +12777,8 @@ var AIConversationManager = class {
|
|
|
12763
12777
|
return result;
|
|
12764
12778
|
}
|
|
12765
12779
|
// ==================== Debug context ====================
|
|
12766
|
-
setPendingDebugContext(
|
|
12767
|
-
this.pendingDebugContextMap.set(
|
|
12780
|
+
setPendingDebugContext(aiChatId, debugContext) {
|
|
12781
|
+
this.pendingDebugContextMap.set(aiChatId, debugContext);
|
|
12768
12782
|
}
|
|
12769
12783
|
setDebugContext(messageId, debugContext) {
|
|
12770
12784
|
const db = this.getDb();
|
|
@@ -12776,8 +12790,8 @@ var AIConversationManager = class {
|
|
|
12776
12790
|
return result.changes;
|
|
12777
12791
|
}
|
|
12778
12792
|
// ==================== Agent 专用 ====================
|
|
12779
|
-
getHistoryForAgent(
|
|
12780
|
-
const messages = this.getActivePathRows(
|
|
12793
|
+
getHistoryForAgent(aiChatId, maxMessages, leafMessageId) {
|
|
12794
|
+
const messages = this.getActivePathRows(aiChatId, leafMessageId).map((row) => this.parseMessageRow(row));
|
|
12781
12795
|
const validMessages = messages.filter(
|
|
12782
12796
|
(m) => (m.role === "user" || m.role === "assistant" || m.role === "summary") && m.content?.trim()
|
|
12783
12797
|
);
|
|
@@ -12795,8 +12809,8 @@ var AIConversationManager = class {
|
|
|
12795
12809
|
);
|
|
12796
12810
|
const bufferBoundary = metaBlock?.bufferBoundaryTimestamp;
|
|
12797
12811
|
if (!metaBlock) {
|
|
12798
|
-
this.logger.warn("
|
|
12799
|
-
|
|
12812
|
+
this.logger.warn("AIChats", "summary message missing summary_meta; agent context will be summary-only", {
|
|
12813
|
+
aiChatId,
|
|
12800
12814
|
messageId: summaryMsg.id
|
|
12801
12815
|
});
|
|
12802
12816
|
}
|
|
@@ -12819,7 +12833,7 @@ var AIConversationManager = class {
|
|
|
12819
12833
|
return result;
|
|
12820
12834
|
}
|
|
12821
12835
|
// ==================== Summary / 压缩专用 ====================
|
|
12822
|
-
addSummaryMessage(
|
|
12836
|
+
addSummaryMessage(aiChatId, content, meta) {
|
|
12823
12837
|
const contentBlocks = [
|
|
12824
12838
|
{
|
|
12825
12839
|
type: "summary_meta",
|
|
@@ -12827,28 +12841,28 @@ var AIConversationManager = class {
|
|
|
12827
12841
|
compressedMessageCount: meta.compressedMessageCount
|
|
12828
12842
|
}
|
|
12829
12843
|
];
|
|
12830
|
-
return this.addMessage(
|
|
12844
|
+
return this.addMessage(aiChatId, "summary", content, void 0, void 0, contentBlocks);
|
|
12831
12845
|
}
|
|
12832
|
-
getLatestSummary(
|
|
12833
|
-
const row = [...this.getActivePathRows(
|
|
12846
|
+
getLatestSummary(aiChatId) {
|
|
12847
|
+
const row = [...this.getActivePathRows(aiChatId)].reverse().find((message) => message.role === "summary");
|
|
12834
12848
|
return row ? this.parseMessageRow(row) : null;
|
|
12835
12849
|
}
|
|
12836
|
-
getMessagesAfterSummary(
|
|
12837
|
-
return this.getActivePathRows(
|
|
12850
|
+
getMessagesAfterSummary(aiChatId, summaryTimestamp) {
|
|
12851
|
+
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 }));
|
|
12838
12852
|
}
|
|
12839
|
-
getAllUserAssistantMessages(
|
|
12840
|
-
return this.getActivePathRows(
|
|
12853
|
+
getAllUserAssistantMessages(aiChatId) {
|
|
12854
|
+
return this.getActivePathRows(aiChatId).filter((row) => row.role === "user" || row.role === "assistant").map((row) => ({ role: row.role, content: row.content, timestamp: row.timestamp }));
|
|
12841
12855
|
}
|
|
12842
|
-
getMessageCountAfterSummary(
|
|
12843
|
-
const summary = this.getLatestSummary(
|
|
12856
|
+
getMessageCountAfterSummary(aiChatId) {
|
|
12857
|
+
const summary = this.getLatestSummary(aiChatId);
|
|
12844
12858
|
if (!summary) {
|
|
12845
|
-
return this.getActivePathRows(
|
|
12859
|
+
return this.getActivePathRows(aiChatId).filter((row) => row.role === "user" || row.role === "assistant").length;
|
|
12846
12860
|
}
|
|
12847
12861
|
const metaBlock = summary.contentBlocks?.find(
|
|
12848
12862
|
(b) => b.type === "summary_meta"
|
|
12849
12863
|
);
|
|
12850
12864
|
const boundary = metaBlock?.bufferBoundaryTimestamp ?? summary.timestamp;
|
|
12851
|
-
return this.getActivePathRows(
|
|
12865
|
+
return this.getActivePathRows(aiChatId).filter(
|
|
12852
12866
|
(row) => row.timestamp >= boundary && (row.role === "user" || row.role === "assistant")
|
|
12853
12867
|
).length;
|
|
12854
12868
|
}
|
|
@@ -13316,7 +13330,7 @@ function parseAssistantFile(content, filePath) {
|
|
|
13316
13330
|
name,
|
|
13317
13331
|
systemPrompt: body.trim(),
|
|
13318
13332
|
presetQuestions: parseStringArray(fm.presetQuestions),
|
|
13319
|
-
allowedBuiltinTools: parseStringArray(fm.allowedBuiltinTools),
|
|
13333
|
+
allowedBuiltinTools: normalizeBuiltinToolNames(parseStringArray(fm.allowedBuiltinTools)),
|
|
13320
13334
|
builtinId: typeof fm.builtinId === "string" ? fm.builtinId : void 0,
|
|
13321
13335
|
applicableChatTypes: parseChatTypes(fm.applicableChatTypes),
|
|
13322
13336
|
supportedLocales: parseStringArray(fm.supportedLocales)
|
|
@@ -13333,7 +13347,7 @@ function serializeAssistant(config) {
|
|
|
13333
13347
|
if (config.builtinId) fm.builtinId = config.builtinId;
|
|
13334
13348
|
if (config.applicableChatTypes?.length) fm.applicableChatTypes = config.applicableChatTypes;
|
|
13335
13349
|
if (config.supportedLocales?.length) fm.supportedLocales = config.supportedLocales;
|
|
13336
|
-
if (config.allowedBuiltinTools?.length) fm.allowedBuiltinTools = config.allowedBuiltinTools;
|
|
13350
|
+
if (config.allowedBuiltinTools?.length) fm.allowedBuiltinTools = normalizeBuiltinToolNames(config.allowedBuiltinTools);
|
|
13337
13351
|
if (config.presetQuestions?.length) fm.presetQuestions = config.presetQuestions;
|
|
13338
13352
|
return matter.stringify(`
|
|
13339
13353
|
${config.systemPrompt}
|
|
@@ -13387,8 +13401,8 @@ var AssistantManager = class {
|
|
|
13387
13401
|
}
|
|
13388
13402
|
// ==================== Init ====================
|
|
13389
13403
|
init() {
|
|
13390
|
-
const { fs:
|
|
13391
|
-
|
|
13404
|
+
const { fs: fs40, assistantsDir } = this.deps;
|
|
13405
|
+
fs40.ensureDir(assistantsDir);
|
|
13392
13406
|
const generalCreated = this.ensureGeneralAssistants();
|
|
13393
13407
|
this.loadAll();
|
|
13394
13408
|
this.initialized = true;
|
|
@@ -13399,26 +13413,26 @@ var AssistantManager = class {
|
|
|
13399
13413
|
return { total: this.cache.size, generalCreated };
|
|
13400
13414
|
}
|
|
13401
13415
|
ensureGeneralAssistants() {
|
|
13402
|
-
const { fs:
|
|
13416
|
+
const { fs: fs40, assistantsDir } = this.deps;
|
|
13403
13417
|
let anyCreated = false;
|
|
13404
13418
|
for (const id of this.generalIds) {
|
|
13405
13419
|
const config = this.getBuiltinConfig(id);
|
|
13406
13420
|
if (!config) continue;
|
|
13407
|
-
const filePath =
|
|
13408
|
-
if (
|
|
13409
|
-
|
|
13421
|
+
const filePath = fs40.joinPath(assistantsDir, `${id}.md`);
|
|
13422
|
+
if (fs40.fileExists(filePath)) continue;
|
|
13423
|
+
fs40.writeFile(filePath, serializeAssistant({ ...config, builtinId: config.id }));
|
|
13410
13424
|
anyCreated = true;
|
|
13411
13425
|
}
|
|
13412
13426
|
return anyCreated;
|
|
13413
13427
|
}
|
|
13414
13428
|
loadAll() {
|
|
13415
|
-
const { fs:
|
|
13429
|
+
const { fs: fs40, assistantsDir } = this.deps;
|
|
13416
13430
|
this.cache.clear();
|
|
13417
|
-
const files =
|
|
13431
|
+
const files = fs40.listFiles(assistantsDir, ".md");
|
|
13418
13432
|
for (const file of files) {
|
|
13419
13433
|
try {
|
|
13420
|
-
const filePath =
|
|
13421
|
-
const content =
|
|
13434
|
+
const filePath = fs40.joinPath(assistantsDir, file);
|
|
13435
|
+
const content = fs40.readFile(filePath);
|
|
13422
13436
|
const config = parseAssistantFile(content, filePath);
|
|
13423
13437
|
if (config) {
|
|
13424
13438
|
this.cache.set(config.id, config);
|
|
@@ -13704,21 +13718,21 @@ var SkillManagerCore = class {
|
|
|
13704
13718
|
}
|
|
13705
13719
|
// ==================== Init ====================
|
|
13706
13720
|
init() {
|
|
13707
|
-
const { fs:
|
|
13708
|
-
|
|
13721
|
+
const { fs: fs40, skillsDir } = this.deps;
|
|
13722
|
+
fs40.ensureDir(skillsDir);
|
|
13709
13723
|
this.loadAll();
|
|
13710
13724
|
this.initialized = true;
|
|
13711
13725
|
this.deps.logger?.info("SkillManager", "Initialized", { total: this.cache.size });
|
|
13712
13726
|
return { total: this.cache.size };
|
|
13713
13727
|
}
|
|
13714
13728
|
loadAll() {
|
|
13715
|
-
const { fs:
|
|
13729
|
+
const { fs: fs40, skillsDir } = this.deps;
|
|
13716
13730
|
this.cache.clear();
|
|
13717
|
-
const files =
|
|
13731
|
+
const files = fs40.listFiles(skillsDir, ".md");
|
|
13718
13732
|
for (const file of files) {
|
|
13719
13733
|
try {
|
|
13720
|
-
const filePath =
|
|
13721
|
-
const content =
|
|
13734
|
+
const filePath = fs40.joinPath(skillsDir, file);
|
|
13735
|
+
const content = fs40.readFile(filePath);
|
|
13722
13736
|
const def = parseSkillFile(content, filePath);
|
|
13723
13737
|
if (def) {
|
|
13724
13738
|
this.cache.set(def.id, def);
|
|
@@ -14017,10 +14031,38 @@ function shouldUseChartCapabilityForMessage(message) {
|
|
|
14017
14031
|
normalized
|
|
14018
14032
|
);
|
|
14019
14033
|
}
|
|
14034
|
+
function shouldOfferChartCapabilityForAnalyticalMessage(message) {
|
|
14035
|
+
const normalized = message.trim().toLowerCase();
|
|
14036
|
+
if (!normalized) return false;
|
|
14037
|
+
if (shouldUseChartCapabilityForMessage(normalized)) return true;
|
|
14038
|
+
return /(?:趋势|变化|走势|排名|排行|前\s*\d+|top\s*\d*|最多|最少|高频|分布|占比|比例|构成|份额|活跃度|热度|按.{0,8}统计|统计.{0,8}按|trend|ranking|rank|top\s*\d*|distribution|ratio|share|percentage|breakdown)/i.test(
|
|
14039
|
+
normalized
|
|
14040
|
+
);
|
|
14041
|
+
}
|
|
14042
|
+
function getChartPlannerCapabilityForMessage(options) {
|
|
14043
|
+
const availableToolSet = new Set(options.availableTools);
|
|
14044
|
+
if (!availableToolSet.has("get_schema") || !availableToolSet.has("render_chart")) {
|
|
14045
|
+
return null;
|
|
14046
|
+
}
|
|
14047
|
+
const chartAutoMode = options.chartAutoMode ?? "suggest";
|
|
14048
|
+
const shouldOffer = chartAutoMode === "explicit" ? shouldUseChartCapabilityForMessage(options.userMessage) : shouldOfferChartCapabilityForAnalyticalMessage(options.userMessage);
|
|
14049
|
+
if (!shouldOffer) {
|
|
14050
|
+
return null;
|
|
14051
|
+
}
|
|
14052
|
+
const isZh = (options.locale ?? "zh-CN").startsWith("zh");
|
|
14053
|
+
return {
|
|
14054
|
+
id: "chart_generation",
|
|
14055
|
+
label: isZh ? "\u56FE\u8868\u751F\u6210" : "Chart generation",
|
|
14056
|
+
tools: ["get_schema", "render_chart"],
|
|
14057
|
+
guidance: isZh ? "\u7528\u6237\u660E\u786E\u8981\u6C42\u56FE\u8868\uFF0C\u6216\u8D8B\u52BF\u3001\u6392\u540D\u3001\u5206\u5E03\u3001\u5360\u6BD4\u7B49\u5206\u6790\u7528\u56FE\u66F4\u6E05\u695A\u65F6\uFF0C\u53EF\u4EE5\u5728\u8BA1\u5212\u4E2D\u52A0\u5165\u6700\u591A\u4E00\u5F20\u56FE\u8868\u6B65\u9AA4\uFF1B\u5FC5\u987B\u5148\u7528 get_schema \u786E\u8BA4 schema\uFF0C\u518D\u7528 render_chart \u751F\u6210\u56FE\u8868\uFF1B\u4E0D\u8981\u8F93\u51FA\u7ED8\u56FE\u4EE3\u7801\u3002" : "When the user explicitly asks for charts, or when trends, rankings, distributions, or ratios are clearer visually, you may add at most one chart step to the plan; call get_schema before render_chart; do not output chart-rendering code."
|
|
14058
|
+
};
|
|
14059
|
+
}
|
|
14020
14060
|
function resolveChartRuntimeForRequest(options) {
|
|
14021
14061
|
const locale = options.locale ?? "zh-CN";
|
|
14022
14062
|
const isExplicitChartSkill = options.skillId === CHART_CAPABILITY_SKILL_ID;
|
|
14023
|
-
const
|
|
14063
|
+
const allowAnalyticalAutoDetection = options.chartAutoMode !== void 0 ? options.chartAutoMode === "aggressive" : options.enableAnalyticalAutoDetection === true;
|
|
14064
|
+
const shouldAutoDetectChart = shouldUseChartCapabilityForMessage(options.userMessage ?? "") || allowAnalyticalAutoDetection && shouldOfferChartCapabilityForAnalyticalMessage(options.userMessage ?? "");
|
|
14065
|
+
const isAutoChartSkill = options.enableAutoDetection === true && !options.skillId && shouldAutoDetectChart;
|
|
14024
14066
|
if (!isExplicitChartSkill && !isAutoChartSkill) {
|
|
14025
14067
|
return { isChartCapability: false };
|
|
14026
14068
|
}
|
|
@@ -14066,23 +14108,28 @@ function getSkillConfigWithBuiltinChart(id, locale = "zh-CN", getSkillConfig) {
|
|
|
14066
14108
|
}
|
|
14067
14109
|
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
|
|
14068
14110
|
|
|
14069
|
-
\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
|
|
14111
|
+
\u4F60\u5FC5\u987B\u901A\u8FC7 render_chart \u5DE5\u5177\u751F\u6210\u56FE\u8868\u3002\u4E0D\u8981\u8F93\u51FA HTML\u3001JavaScript\u3001SVG\u3001Canvas\u3001ECharts option\u3001Markdown \u56FE\u7247\u94FE\u63A5\uFF08\u5982 \uFF09\u6216\u4EFB\u4F55\u6E32\u67D3\u4EE3\u7801\u3002
|
|
14070
14112
|
|
|
14071
14113
|
\u786C\u6027\u89C4\u5219\uFF1A
|
|
14072
14114
|
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
|
|
14073
|
-
2. \u201C\u6700\u8FD1\u201D\u201C\
|
|
14115
|
+
2. \u201C\u6700\u8FD1\u201D\u201C\u8FC7\u53BB N \u5929/\u5E74\u201D\u7B49\u76F8\u5BF9\u65F6\u95F4\u4EE5\u7CFB\u7EDF\u63D0\u793A\u4E2D\u7684\u771F\u5B9E\u5F53\u524D\u65E5\u671F\u4E3A\u57FA\u51C6\uFF1B\u5982\u679C\u542F\u52A8\u4E0A\u4E0B\u6587\u663E\u793A\u6570\u636E\u5E93\u8986\u76D6\u4E0D\u8DB3\uFF0C\u53EA\u5206\u6790\u7528\u6237\u65F6\u95F4\u8303\u56F4\u4E0E\u6570\u636E\u5E93\u8986\u76D6\u8303\u56F4\u7684\u4EA4\u96C6\u5E76\u8BF4\u660E\u7F3A\u53E3\u3002
|
|
14074
14116
|
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
|
|
14075
14117
|
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
|
|
14076
14118
|
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
|
|
14077
|
-
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
|
|
14078
|
-
7. \
|
|
14119
|
+
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\u539F\u751F\u56FE\u8868\u548C\u7B80\u77ED\u7ED3\u8BBA\uFF0C\u7981\u6B62\u7528 chart1.png\u3001chart2.png \u7B49\u6587\u4EF6\u540D\u5F15\u7528\u56FE\u8868\u3002
|
|
14120
|
+
7. \u8C03\u7528 render_chart \u65F6\uFF0CChatLab \u4F1A\u7ACB\u5373\u5728\u8BE5\u4F4D\u7F6E\u63D2\u5165\u539F\u751F\u56FE\u8868\uFF1B\u9700\u8981\u56FE\u8868\u5C31\u76F4\u63A5\u8C03\u7528\u5DE5\u5177\uFF0C\u4E0D\u8981\u5199 SQL \u6CE8\u91CA\u3001Markdown \u56FE\u7247\u6216\u201C\u5DF2\u751F\u6210\u56FE\u8868/\u89C1\u4E0A\u56FE\u201D\u8FD9\u7C7B\u6587\u672C\u5360\u4F4D\u3002
|
|
14121
|
+
8. \u7528\u6237\u8981\u6C42\u591A\u5F20\u56FE\u65F6\uFF0C\u56FE\u8868\u5E94\u5206\u6563\u51FA\u73B0\u5728\u76F8\u5173\u603B\u7ED3\u6216\u89E3\u91CA\u9644\u8FD1\uFF1B\u4E0D\u8981\u628A\u6240\u6709\u56FE\u96C6\u4E2D\u751F\u6210\u540E\u518D\u5728\u6700\u540E\u7528\u6587\u5B57\u5F15\u7528\u3002
|
|
14122
|
+
9. \u4E3A\u56FE\u8868\u51C6\u5907\u6570\u636E\u65F6\uFF0C\u4F18\u5148\u8C03\u7528\u9AD8\u5C42\u5DE5\u5177\uFF08\u5982 get_time_stats\u3001member_stats\uFF09\u800C\u975E\u81EA\u5DF1\u5199 SQL\uFF1B\u53EA\u6709\u9AD8\u5C42\u5DE5\u5177\u65E0\u6CD5\u8986\u76D6\u6240\u9700\u7B5B\u9009\u6216\u805A\u5408\u65F6\u624D\u7528 sql\u3002render_chart \u4E0D\u8981\u7528\u4E8E\u5143\u6570\u636E\u63A2\u6D4B\u3001\u6807\u91CF\u67E5\u8BE2\u3001\u5355\u884C\u65E5\u671F\u5B57\u7B26\u4E32\u6216\u7EAF\u8BF4\u660E\u6027\u7ED3\u679C\u3002
|
|
14123
|
+
10. render_chart \u7684\u5DE5\u5177\u7ED3\u679C\u4F1A\u5305\u542B\u6570\u636E\u9884\u89C8\uFF08Data preview\uFF09\uFF1B\u7528\u5B83\u5206\u6790\u5CF0\u503C\u3001\u4F4E\u8C37\u548C\u5DEE\u5F02\uFF0C\u4E0D\u8981\u4E3A\u4E86\u8BFB\u53D6\u6570\u503C\u91CD\u590D\u751F\u6210\u7B49\u4EF7\u56FE\u8868\u3002
|
|
14124
|
+
11. \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
|
|
14079
14125
|
|
|
14080
14126
|
\u5DE5\u4F5C\u6D41\u7A0B\uFF1A
|
|
14081
14127
|
1. \u8C03\u7528 get_schema\u3002
|
|
14082
|
-
2. \u6839\u636E schema
|
|
14083
|
-
3. \
|
|
14084
|
-
4. \
|
|
14085
|
-
5. \
|
|
14128
|
+
2. \u6839\u636E schema\u3001\u7528\u6237\u8981\u6C42\u3001\u7CFB\u7EDF\u5F53\u524D\u65E5\u671F\u548C\u542F\u52A8\u4E0A\u4E0B\u6587\u786E\u5B9A\u7EDF\u8BA1\u5BF9\u8C61\u3001\u65F6\u95F4\u8303\u56F4\u3001\u7EF4\u5EA6\u3001\u6307\u6807\u548C\u56FE\u8868\u7C7B\u578B\u3002
|
|
14129
|
+
3. \u5982\u9700\u8C03\u67E5\u4E8B\u5B9E\u3001\u5EFA\u7ACB\u8BDD\u9898\u5730\u56FE\u3001\u7B5B\u9009\u6210\u5458\u6216\u786E\u8BA4\u7EDF\u8BA1\u53E3\u5F84\uFF0C\u5148\u7528\u53EF\u7528\u7684\u666E\u901A\u5206\u6790\u5DE5\u5177\u5B8C\u6210\uFF1B\u4E0D\u8981\u4E3A\u4E86\u8C03\u67E5\u800C\u751F\u6210\u4E34\u65F6\u56FE\u8868\u3002
|
|
14130
|
+
4. \u51C6\u5907\u56FE\u8868\u6570\u636E\u2014\u2014\u5148\u95EE\u81EA\u5DF1\uFF1A\u54EA\u4E2A\u53EF\u7528\u7684\u9AD8\u5C42\u5DE5\u5177\u80FD\u76F4\u63A5\u63D0\u4F9B\u8FD9\u5F20\u56FE\u6240\u9700\u7684\u6570\u636E\uFF1Fget_time_stats \u80FD\u7ED9\u65F6\u95F4\u5206\u5E03\u3001member_stats \u80FD\u7ED9\u6210\u5458\u6392\u540D\uFF1B\u80FD\u7528\u5C31\u8C03\u7528\uFF0C\u5C06 data \u6570\u7EC4\u4F5C\u4E3A rows \u4F20\u5165 render_chart\u3002\u53EA\u6709\u5728\u9AD8\u5C42\u5DE5\u5177\u65E0\u6CD5\u8986\u76D6\u6240\u9700\u7B5B\u9009\u6216\u805A\u5408\u65F6\uFF0C\u624D\u7F16\u5199 SQL\u3002
|
|
14131
|
+
5. \u5728\u5E0C\u671B\u56FE\u8868\u51FA\u73B0\u7684\u4F4D\u7F6E\u8C03\u7528 render_chart\uFF0C\u63D0\u4EA4\u6570\u636E\uFF08rows \u6216 sql\uFF09\u548C ChartSpec v1\u3002
|
|
14132
|
+
6. \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\uFF0C\u5E76\u628A\u6BCF\u5F20\u56FE\u653E\u5728\u6700\u76F8\u5173\u7684\u6BB5\u843D\u9644\u8FD1\u3002
|
|
14086
14133
|
|
|
14087
14134
|
\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
|
|
14088
14135
|
|
|
@@ -14104,23 +14151,28 @@ ChartSpec \u793A\u4F8B\uFF1A
|
|
|
14104
14151
|
\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`;
|
|
14105
14152
|
var EN_PROMPT = `You are the ChatLab Chart Assistant. In this turn, the user wants one or more charts embedded naturally in the answer.
|
|
14106
14153
|
|
|
14107
|
-
You must generate charts through the render_chart tool. Do not output HTML, JavaScript, SVG, Canvas, ECharts options, or rendering code.
|
|
14154
|
+
You must generate charts through the render_chart tool. Do not output HTML, JavaScript, SVG, Canvas, ECharts options, Markdown image links such as , or rendering code.
|
|
14108
14155
|
|
|
14109
14156
|
Hard rules:
|
|
14110
14157
|
1. Always call get_schema before writing the first SQL query. Do not guess table names, field names, or timestamp fields.
|
|
14111
|
-
2. For
|
|
14158
|
+
2. For relative ranges like "recent" or "past N days/years", use the real current date from the system prompt as the baseline. If startup context shows incomplete database coverage, analyze only the intersection between the requested range and database coverage, and state the gap.
|
|
14112
14159
|
3. ChatLab message.ts is a Unix timestamp in seconds. Use date(ts, 'unixepoch', 'localtime'); never write ts/1000.
|
|
14113
14160
|
4. For "latest N members" or "recent N people", first define and select those N members from the data, then count only those members.
|
|
14114
14161
|
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.
|
|
14115
|
-
6. Do not include failed SQL attempts, schema exploration, or retry reasoning in the final answer. Final answer should contain only
|
|
14116
|
-
7.
|
|
14162
|
+
6. Do not include failed SQL attempts, schema exploration, or retry reasoning in the final answer. Final answer should contain only native charts and a short conclusion; never reference charts with filenames like chart1.png or chart2.png.
|
|
14163
|
+
7. When you call render_chart, ChatLab immediately inserts the native chart at that position. If a chart is needed, call the tool directly; do not write SQL-comment placeholders, Markdown images, or text such as "generated chart" or "see chart above".
|
|
14164
|
+
8. If the user asks for multiple charts, place each chart near the relevant summary or explanation. Do not generate all charts together and then reference them later with text.
|
|
14165
|
+
9. When preparing chart data, prefer calling a high-level tool (such as get_time_stats, member_stats) over writing SQL; only use sql when no high-level tool can satisfy the required filters or aggregations. Do not use render_chart for metadata inspection, scalar queries, single-row date strings, or purely explanatory results.
|
|
14166
|
+
10. render_chart tool results include a Data preview; use it to identify peaks, lows, and differences. Do not generate equivalent charts again just to read values.
|
|
14167
|
+
11. Explain only trends, peaks, lows, differences, and synchrony directly supported by chart data. Do not make exaggerated personality or relationship claims.
|
|
14117
14168
|
|
|
14118
14169
|
Workflow:
|
|
14119
14170
|
1. Call get_schema.
|
|
14120
|
-
2. Derive the target members, time range, dimensions, metrics, and chart type from schema
|
|
14121
|
-
3.
|
|
14122
|
-
4.
|
|
14123
|
-
5.
|
|
14171
|
+
2. Derive the target members, time range, dimensions, metrics, and chart type from schema, the user request, system current date, and startup context.
|
|
14172
|
+
3. If you need to investigate facts, build a topic map, select members, or confirm statistical definitions, use available ordinary analysis tools first; do not generate temporary charts for investigation.
|
|
14173
|
+
4. Prepare chart data \u2014 ask yourself first: which available high-level tool can directly provide the data this chart needs? get_time_stats covers time distributions; member_stats covers member rankings. If one fits, call it and pass its data array as rows to render_chart. Only write SQL when no high-level tool can cover the required filters or aggregations.
|
|
14174
|
+
5. Call render_chart at the position where the chart should appear, with data (rows or sql) and ChartSpec v1.
|
|
14175
|
+
6. 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 and place each chart near its most relevant section.
|
|
14124
14176
|
|
|
14125
14177
|
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.
|
|
14126
14178
|
|
|
@@ -14209,23 +14261,23 @@ var defaultLogger3 = {
|
|
|
14209
14261
|
error: () => {
|
|
14210
14262
|
}
|
|
14211
14263
|
};
|
|
14212
|
-
async function checkAndCompress(
|
|
14264
|
+
async function checkAndCompress(aiChatId, config, systemPrompt, llmAdapter, convManager, logger = defaultLogger3) {
|
|
14213
14265
|
if (!config.enabled) {
|
|
14214
14266
|
return { compressed: false, reason: "skipped_disabled" };
|
|
14215
14267
|
}
|
|
14216
14268
|
try {
|
|
14217
14269
|
const contextWindow = llmAdapter.contextWindow || DEFAULT_CONTEXT_WINDOW;
|
|
14218
14270
|
const thresholdTokens = Math.floor(contextWindow * (config.tokenThresholdPercent / 100) * 0.95);
|
|
14219
|
-
const summary = convManager.getLatestSummary(
|
|
14271
|
+
const summary = convManager.getLatestSummary(aiChatId);
|
|
14220
14272
|
let messages;
|
|
14221
14273
|
if (summary) {
|
|
14222
14274
|
const metaBlock = summary.contentBlocks?.find(
|
|
14223
14275
|
(b) => b.type === "summary_meta"
|
|
14224
14276
|
);
|
|
14225
14277
|
const boundary = metaBlock?.bufferBoundaryTimestamp ?? summary.timestamp;
|
|
14226
|
-
messages = convManager.getMessagesAfterSummary(
|
|
14278
|
+
messages = convManager.getMessagesAfterSummary(aiChatId, boundary - 1);
|
|
14227
14279
|
} else {
|
|
14228
|
-
messages = convManager.getAllUserAssistantMessages(
|
|
14280
|
+
messages = convManager.getAllUserAssistantMessages(aiChatId);
|
|
14229
14281
|
}
|
|
14230
14282
|
const historyForTokenCount = [];
|
|
14231
14283
|
if (summary) {
|
|
@@ -14236,7 +14288,7 @@ async function checkAndCompress(conversationId, config, systemPrompt, llmAdapter
|
|
|
14236
14288
|
}
|
|
14237
14289
|
const currentTokens = countMessagesTokens(historyForTokenCount, systemPrompt);
|
|
14238
14290
|
logger.info("Compression", `Token check: ${currentTokens} / ${thresholdTokens} (${contextWindow} window)`, {
|
|
14239
|
-
|
|
14291
|
+
aiChatId,
|
|
14240
14292
|
messageCount: messages.length,
|
|
14241
14293
|
hasSummary: !!summary
|
|
14242
14294
|
});
|
|
@@ -14260,7 +14312,7 @@ async function checkAndCompress(conversationId, config, systemPrompt, llmAdapter
|
|
|
14260
14312
|
summaryText = forceTruncate(compressInput, targetTokens);
|
|
14261
14313
|
}
|
|
14262
14314
|
const bufferBoundary = bufferMessages.length > 0 ? bufferMessages[0].timestamp : messagesToCompress[messagesToCompress.length - 1].timestamp + 1;
|
|
14263
|
-
convManager.addSummaryMessage(
|
|
14315
|
+
convManager.addSummaryMessage(aiChatId, summaryText, {
|
|
14264
14316
|
bufferBoundaryTimestamp: bufferBoundary,
|
|
14265
14317
|
compressedMessageCount: messagesToCompress.length
|
|
14266
14318
|
});
|
|
@@ -14947,7 +14999,7 @@ import {
|
|
|
14947
14999
|
} from "@earendil-works/pi-ai";
|
|
14948
15000
|
|
|
14949
15001
|
// ../../packages/node-runtime/src/ai/agent/constants.ts
|
|
14950
|
-
var DEFAULT_MAX_TOOL_ROUNDS =
|
|
15002
|
+
var DEFAULT_MAX_TOOL_ROUNDS = 20;
|
|
14951
15003
|
|
|
14952
15004
|
// ../../packages/node-runtime/src/ai/agent/core.ts
|
|
14953
15005
|
function createEmptyPiUsage() {
|
|
@@ -15028,14 +15080,6 @@ async function runAgentCore(options) {
|
|
|
15028
15080
|
return clampThinkingLevel(piModel, level);
|
|
15029
15081
|
})();
|
|
15030
15082
|
const finalThinkingLevel = resolvedThinkingLevel ?? (piModel.reasoning ? void 0 : "off");
|
|
15031
|
-
console.debug("[agent-core] thinkingLevel resolution:", {
|
|
15032
|
-
input: options.thinkingLevel,
|
|
15033
|
-
modelId: piModel.id,
|
|
15034
|
-
modelReasoning: effectiveModel.reasoning,
|
|
15035
|
-
isDefault,
|
|
15036
|
-
resolved: resolvedThinkingLevel,
|
|
15037
|
-
final: finalThinkingLevel
|
|
15038
|
-
});
|
|
15039
15083
|
const coreAgent = new PiAgentCore({
|
|
15040
15084
|
initialState: {
|
|
15041
15085
|
systemPrompt,
|
|
@@ -15165,30 +15209,608 @@ async function runAgentCore(options) {
|
|
|
15165
15209
|
}
|
|
15166
15210
|
}
|
|
15167
15211
|
|
|
15168
|
-
// ../../packages/node-runtime/src/ai/agent/
|
|
15169
|
-
function
|
|
15170
|
-
if (!
|
|
15171
|
-
|
|
15172
|
-
|
|
15173
|
-
|
|
15174
|
-
|
|
15175
|
-
|
|
15212
|
+
// ../../packages/node-runtime/src/ai/agent/data-snapshot.ts
|
|
15213
|
+
function roundShare(value) {
|
|
15214
|
+
if (!Number.isFinite(value)) return 0;
|
|
15215
|
+
return Math.round(value * 10) / 10;
|
|
15216
|
+
}
|
|
15217
|
+
function formatNullableTimestamp(timestamp) {
|
|
15218
|
+
return typeof timestamp === "number" && Number.isFinite(timestamp) ? String(timestamp) : "null";
|
|
15219
|
+
}
|
|
15220
|
+
function formatSharePercent(share) {
|
|
15221
|
+
if (!Number.isFinite(share)) return "0%";
|
|
15222
|
+
const rounded = Math.round(share * 10) / 10;
|
|
15223
|
+
return Number.isInteger(rounded) ? `${rounded}%` : `${rounded.toFixed(1)}%`;
|
|
15224
|
+
}
|
|
15225
|
+
function createDataSnapshotFromOverview(overview) {
|
|
15226
|
+
if (!overview) return void 0;
|
|
15227
|
+
const topMembers = overview.topMembers ?? [];
|
|
15228
|
+
return {
|
|
15229
|
+
version: 2,
|
|
15230
|
+
name: overview.name,
|
|
15231
|
+
platform: overview.platform,
|
|
15232
|
+
type: overview.type,
|
|
15233
|
+
totalMessages: overview.totalMessages,
|
|
15234
|
+
totalMembers: overview.totalMembers,
|
|
15235
|
+
firstMessageTs: overview.firstMessageTs,
|
|
15236
|
+
lastMessageTs: overview.lastMessageTs,
|
|
15237
|
+
activeMemberHints: topMembers.slice(0, 10).map((member) => ({
|
|
15238
|
+
memberId: member.id,
|
|
15239
|
+
displayName: member.name,
|
|
15240
|
+
messageCount: member.count,
|
|
15241
|
+
share: overview.totalMessages > 0 ? roundShare(member.count / overview.totalMessages * 100) : 0
|
|
15242
|
+
})),
|
|
15243
|
+
segmentSummaries: {
|
|
15244
|
+
availableCount: overview.summaryCount ?? 0
|
|
15245
|
+
}
|
|
15246
|
+
};
|
|
15176
15247
|
}
|
|
15177
|
-
function
|
|
15178
|
-
if (
|
|
15179
|
-
|
|
15180
|
-
|
|
15181
|
-
|
|
15182
|
-
|
|
15183
|
-
|
|
15184
|
-
}
|
|
15185
|
-
|
|
15186
|
-
|
|
15187
|
-
|
|
15188
|
-
|
|
15189
|
-
|
|
15190
|
-
|
|
15191
|
-
|
|
15248
|
+
function formatDataSnapshotForRouter(dataSnapshot) {
|
|
15249
|
+
if (!dataSnapshot) return "(none)";
|
|
15250
|
+
return [
|
|
15251
|
+
`name: ${dataSnapshot.name}`,
|
|
15252
|
+
`platform: ${dataSnapshot.platform}`,
|
|
15253
|
+
`type: ${dataSnapshot.type}`,
|
|
15254
|
+
`total_messages: ${dataSnapshot.totalMessages}`,
|
|
15255
|
+
`total_members: ${dataSnapshot.totalMembers}`,
|
|
15256
|
+
`first_message_ts: ${formatNullableTimestamp(dataSnapshot.firstMessageTs)}`,
|
|
15257
|
+
`last_message_ts: ${formatNullableTimestamp(dataSnapshot.lastMessageTs)}`,
|
|
15258
|
+
`segment_summaries_available: ${dataSnapshot.segmentSummaries?.availableCount ?? 0}`,
|
|
15259
|
+
`active_member_hint_count: ${dataSnapshot.activeMemberHints?.length ?? 0}`
|
|
15260
|
+
].join("\n");
|
|
15261
|
+
}
|
|
15262
|
+
function formatDataSnapshotForPlanner(dataSnapshot) {
|
|
15263
|
+
if (!dataSnapshot) return "(none)";
|
|
15264
|
+
const memberHints = dataSnapshot.activeMemberHints ?? [];
|
|
15265
|
+
const memberHintLines = memberHints.length > 0 ? memberHints.map(
|
|
15266
|
+
(member, index) => `${index + 1}. member_id=${member.memberId} | display_name=${member.displayName} | messages=${member.messageCount} | share=${formatSharePercent(member.share)}`
|
|
15267
|
+
).join("\n") : "(none)";
|
|
15268
|
+
return `${formatDataSnapshotForRouter(dataSnapshot)}
|
|
15269
|
+
active_member_hints:
|
|
15270
|
+
${memberHintLines}
|
|
15271
|
+
notes:
|
|
15272
|
+
- member_id is a tool lookup hint; display_name may not be unique.
|
|
15273
|
+
- Active member hints reflect historical total message volume, not recent activity.
|
|
15274
|
+
- Use real current date for relative ranges; database bounds only describe data coverage.
|
|
15275
|
+
- Do not plan a tool call only to rediscover min/max timestamp.
|
|
15276
|
+
- When using default recent-day tools, choose a range that intersects database bounds instead of probing an empty real-current-date window first.`;
|
|
15277
|
+
}
|
|
15278
|
+
|
|
15279
|
+
// ../../packages/node-runtime/src/ai/agent/router.ts
|
|
15280
|
+
import {
|
|
15281
|
+
completeSimple as completeSimple2
|
|
15282
|
+
} from "@earendil-works/pi-ai";
|
|
15283
|
+
var DEFAULT_LLM_FALLBACK_CONFIDENCE_THRESHOLD = 0.6;
|
|
15284
|
+
function clampConfidence(value) {
|
|
15285
|
+
if (!Number.isFinite(value)) return 0;
|
|
15286
|
+
return Math.max(0, Math.min(1, value));
|
|
15287
|
+
}
|
|
15288
|
+
function normalizeText(text) {
|
|
15289
|
+
return text.trim().replace(/\s+/g, " ");
|
|
15290
|
+
}
|
|
15291
|
+
function matchAny(text, patterns) {
|
|
15292
|
+
return patterns.some((pattern) => pattern.test(text));
|
|
15293
|
+
}
|
|
15294
|
+
function isRoute(value) {
|
|
15295
|
+
return value === "direct_response" || value === "tool_assisted" || value === "planned_execution";
|
|
15296
|
+
}
|
|
15297
|
+
function resultToText(result) {
|
|
15298
|
+
return typeof result === "string" ? { text: result } : result;
|
|
15299
|
+
}
|
|
15300
|
+
function extractJsonObject3(text) {
|
|
15301
|
+
const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
15302
|
+
if (fenced?.[1]) return fenced[1].trim();
|
|
15303
|
+
const start = text.indexOf("{");
|
|
15304
|
+
const end = text.lastIndexOf("}");
|
|
15305
|
+
if (start >= 0 && end > start) return text.slice(start, end + 1);
|
|
15306
|
+
return text.trim();
|
|
15307
|
+
}
|
|
15308
|
+
function parseLlmDecision(rawText, usage) {
|
|
15309
|
+
try {
|
|
15310
|
+
const parsed = JSON.parse(extractJsonObject3(rawText));
|
|
15311
|
+
if (!isRoute(parsed.route)) return null;
|
|
15312
|
+
return {
|
|
15313
|
+
route: parsed.route,
|
|
15314
|
+
confidence: clampConfidence(typeof parsed.confidence === "number" ? parsed.confidence : 0.5),
|
|
15315
|
+
reason: typeof parsed.reason === "string" && parsed.reason.trim() ? parsed.reason.trim() : "LLM route decision.",
|
|
15316
|
+
source: "llm",
|
|
15317
|
+
usage
|
|
15318
|
+
};
|
|
15319
|
+
} catch {
|
|
15320
|
+
return null;
|
|
15321
|
+
}
|
|
15322
|
+
}
|
|
15323
|
+
function buildLlmRouterPrompt(input, ruleDecision2) {
|
|
15324
|
+
const toolNames = input.availableTools?.length ? input.availableTools.join(", ") : "(none)";
|
|
15325
|
+
const dataSnapshot = formatDataSnapshotForRouter(input.dataSnapshot);
|
|
15326
|
+
return `Classify the user's ChatLab request into exactly one route.
|
|
15327
|
+
|
|
15328
|
+
Routes:
|
|
15329
|
+
- direct_response: no local chat data/tools needed.
|
|
15330
|
+
- tool_assisted: local chat data/tools needed, but the task is simple.
|
|
15331
|
+
- planned_execution: complex analysis, multi-step evidence gathering, retries, long-range comparison, relationship analysis, or insufficient-evidence handling.
|
|
15332
|
+
|
|
15333
|
+
Return strict JSON only:
|
|
15334
|
+
{"route":"direct_response|tool_assisted|planned_execution","confidence":0.0,"reason":"short reason"}
|
|
15335
|
+
|
|
15336
|
+
Context:
|
|
15337
|
+
- locale: ${input.locale}
|
|
15338
|
+
- chatType: ${input.chatType}
|
|
15339
|
+
- availableTools: ${toolNames}
|
|
15340
|
+
- dataSnapshot: ${dataSnapshot}
|
|
15341
|
+
- assistantSummary: ${input.assistantSummary ?? "(none)"}
|
|
15342
|
+
- skillSummary: ${input.skillSummary ?? "(none)"}
|
|
15343
|
+
- recentIntentSummary: ${input.recentIntentSummary ?? "(none)"}
|
|
15344
|
+
- ruleDecision: ${ruleDecision2.route}, confidence=${ruleDecision2.confidence}, reason=${ruleDecision2.reason}
|
|
15345
|
+
|
|
15346
|
+
User request:
|
|
15347
|
+
${input.userMessage}`;
|
|
15348
|
+
}
|
|
15349
|
+
function directRuleDecision(text) {
|
|
15350
|
+
if (matchAny(text, [/不用查聊天记录|不用查询|不用查数据|不用看本地数据/i, /润色|改写|翻译|polish|rewrite|translate/i])) {
|
|
15351
|
+
return {
|
|
15352
|
+
route: "direct_response",
|
|
15353
|
+
confidence: 0.95,
|
|
15354
|
+
reason: "User explicitly asked for a non-data response.",
|
|
15355
|
+
source: "rule"
|
|
15356
|
+
};
|
|
15357
|
+
}
|
|
15358
|
+
if (matchAny(text, [/什么是|解释一下|概念|区别|explain|briefly explain|why .*function calling|react/i])) {
|
|
15359
|
+
return {
|
|
15360
|
+
route: "direct_response",
|
|
15361
|
+
confidence: 0.86,
|
|
15362
|
+
reason: "Conceptual explanation without local chat-data dependency.",
|
|
15363
|
+
source: "rule"
|
|
15364
|
+
};
|
|
15365
|
+
}
|
|
15366
|
+
if (matchAny(text, [/日志在哪里|怎么配置|设置|帮助|help|where .*log/i])) {
|
|
15367
|
+
return {
|
|
15368
|
+
route: "direct_response",
|
|
15369
|
+
confidence: 0.84,
|
|
15370
|
+
reason: "Help or configuration request does not require chat tools.",
|
|
15371
|
+
source: "rule"
|
|
15372
|
+
};
|
|
15373
|
+
}
|
|
15374
|
+
if (matchAny(text, [/你觉得|闲聊|随便聊聊|建议我|should i/i])) {
|
|
15375
|
+
return {
|
|
15376
|
+
route: "direct_response",
|
|
15377
|
+
confidence: 0.78,
|
|
15378
|
+
reason: "Conversational request without clear data dependency.",
|
|
15379
|
+
source: "rule"
|
|
15380
|
+
};
|
|
15381
|
+
}
|
|
15382
|
+
return null;
|
|
15383
|
+
}
|
|
15384
|
+
function plannedRuleDecision(text) {
|
|
15385
|
+
if (matchAny(text, [/如果.*找不到.*继续查|换几个相关|换几个.*继续|search.*if.*not.*found/i])) {
|
|
15386
|
+
return {
|
|
15387
|
+
route: "planned_execution",
|
|
15388
|
+
confidence: 0.88,
|
|
15389
|
+
reason: "Request asks for search failure recovery and retry strategy.",
|
|
15390
|
+
source: "rule"
|
|
15391
|
+
};
|
|
15392
|
+
}
|
|
15393
|
+
const dimensions = [
|
|
15394
|
+
matchAny(text, [/分析|复盘|总结.*规律|趋势|变化|演变|compare|comparison/i]),
|
|
15395
|
+
matchAny(text, [
|
|
15396
|
+
/过去一年|最近一年|近一年|过去.*年|最近半年|今年|去年|上半年|下半年|长期|按季度|按月份|first half|second half/i
|
|
15397
|
+
]),
|
|
15398
|
+
matchAny(text, [/关系|互动|影响力|核心成员|最强|最活跃|被忽略|主动|回应|turning point|转折点/i]),
|
|
15399
|
+
matchAny(text, [/证据|举出|例子|关键分歧|主要矛盾|evidence/i]),
|
|
15400
|
+
matchAny(text, [/并且|同时|以及|分别|每个阶段|按阶段|阶段|多条件|参与|回复|话题|主题|发言规律|topic|theme/i]),
|
|
15401
|
+
matchAny(text, [/证据不够|不足以|不够|uncertain|insufficient/i])
|
|
15402
|
+
];
|
|
15403
|
+
const score = dimensions.filter(Boolean).length;
|
|
15404
|
+
if (score >= 2) {
|
|
15405
|
+
return {
|
|
15406
|
+
route: "planned_execution",
|
|
15407
|
+
confidence: Math.min(0.95, 0.72 + score * 0.04),
|
|
15408
|
+
reason: `Rule matched ${score} complex-analysis signals.`,
|
|
15409
|
+
source: "rule"
|
|
15410
|
+
};
|
|
15411
|
+
}
|
|
15412
|
+
return null;
|
|
15413
|
+
}
|
|
15414
|
+
function toolRuleDecision(text) {
|
|
15415
|
+
if (matchAny(text, [
|
|
15416
|
+
/一共有多少|多少成员|多少条消息|谁发言最多|前\s*\d+\s*名|top\s*\d+/i,
|
|
15417
|
+
/异常活跃|活跃度|发言最多|message count|member count/i
|
|
15418
|
+
])) {
|
|
15419
|
+
return {
|
|
15420
|
+
route: "tool_assisted",
|
|
15421
|
+
confidence: 0.82,
|
|
15422
|
+
reason: "Simple statistics request can be answered by one or a few tools.",
|
|
15423
|
+
source: "rule"
|
|
15424
|
+
};
|
|
15425
|
+
}
|
|
15426
|
+
if (matchAny(text, [
|
|
15427
|
+
/找一下|查一下|有没有聊到|有没有提过|最近提到|昨天.*聊了什么|最近.*发言/i,
|
|
15428
|
+
/search|find|mentioned|talked about/i
|
|
15429
|
+
])) {
|
|
15430
|
+
return {
|
|
15431
|
+
route: "tool_assisted",
|
|
15432
|
+
confidence: 0.78,
|
|
15433
|
+
reason: "Simple search or lookup request with a single clear target.",
|
|
15434
|
+
source: "rule"
|
|
15435
|
+
};
|
|
15436
|
+
}
|
|
15437
|
+
return null;
|
|
15438
|
+
}
|
|
15439
|
+
function ruleDecision(input) {
|
|
15440
|
+
const text = normalizeText(input.userMessage);
|
|
15441
|
+
return plannedRuleDecision(text) ?? toolRuleDecision(text) ?? directRuleDecision(text) ?? {
|
|
15442
|
+
route: "tool_assisted",
|
|
15443
|
+
confidence: 0.45,
|
|
15444
|
+
reason: "Ambiguous request; conservatively keep the existing tool-assisted Agent path.",
|
|
15445
|
+
source: "rule"
|
|
15446
|
+
};
|
|
15447
|
+
}
|
|
15448
|
+
async function decideRequestRoute(input, options = {}) {
|
|
15449
|
+
const decision = ruleDecision(input);
|
|
15450
|
+
const threshold = options.llmFallbackConfidenceThreshold ?? DEFAULT_LLM_FALLBACK_CONFIDENCE_THRESHOLD;
|
|
15451
|
+
if (decision.confidence >= threshold || !options.llmRouter) {
|
|
15452
|
+
return { ...decision, confidence: clampConfidence(decision.confidence) };
|
|
15453
|
+
}
|
|
15454
|
+
const llmDecision = await options.llmRouter(input, decision);
|
|
15455
|
+
return {
|
|
15456
|
+
...llmDecision,
|
|
15457
|
+
confidence: clampConfidence(llmDecision.confidence)
|
|
15458
|
+
};
|
|
15459
|
+
}
|
|
15460
|
+
function createLlmRouteDecider(options) {
|
|
15461
|
+
return async (input, ruleDecision2) => {
|
|
15462
|
+
const prompt = buildLlmRouterPrompt(input, ruleDecision2);
|
|
15463
|
+
try {
|
|
15464
|
+
const rawResult = options.complete ? await options.complete(prompt, options.abortSignal) : await completeWithPiAi(prompt, options);
|
|
15465
|
+
const { text, usage } = resultToText(rawResult);
|
|
15466
|
+
const decision = parseLlmDecision(text, usage);
|
|
15467
|
+
if (decision) return decision;
|
|
15468
|
+
return {
|
|
15469
|
+
...ruleDecision2,
|
|
15470
|
+
reason: `${ruleDecision2.reason} LLM fallback returned invalid route JSON.`
|
|
15471
|
+
};
|
|
15472
|
+
} catch (error) {
|
|
15473
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
15474
|
+
return {
|
|
15475
|
+
...ruleDecision2,
|
|
15476
|
+
reason: `${ruleDecision2.reason} LLM fallback failed: ${message}`
|
|
15477
|
+
};
|
|
15478
|
+
}
|
|
15479
|
+
};
|
|
15480
|
+
}
|
|
15481
|
+
async function completeWithPiAi(prompt, options) {
|
|
15482
|
+
if (!options.piModel || !options.apiKey) {
|
|
15483
|
+
throw new Error("LLM router requires piModel and apiKey");
|
|
15484
|
+
}
|
|
15485
|
+
const result = await completeSimple2(
|
|
15486
|
+
options.piModel,
|
|
15487
|
+
{
|
|
15488
|
+
systemPrompt: "You are a strict JSON classifier for ChatLab AI routing. Return JSON only.",
|
|
15489
|
+
messages: [{ role: "user", content: [{ type: "text", text: prompt }], timestamp: Date.now() }]
|
|
15490
|
+
},
|
|
15491
|
+
{
|
|
15492
|
+
apiKey: options.apiKey,
|
|
15493
|
+
maxTokens: options.maxTokens ?? 180,
|
|
15494
|
+
temperature: options.temperature ?? 0,
|
|
15495
|
+
signal: options.abortSignal
|
|
15496
|
+
}
|
|
15497
|
+
);
|
|
15498
|
+
const text = result.content.filter((item) => item.type === "text").map((item) => item.text).join("");
|
|
15499
|
+
return {
|
|
15500
|
+
text,
|
|
15501
|
+
usage: {
|
|
15502
|
+
promptTokens: result.usage?.input,
|
|
15503
|
+
completionTokens: result.usage?.output,
|
|
15504
|
+
totalTokens: result.usage?.totalTokens
|
|
15505
|
+
}
|
|
15506
|
+
};
|
|
15507
|
+
}
|
|
15508
|
+
|
|
15509
|
+
// ../../packages/node-runtime/src/ai/agent/planner.ts
|
|
15510
|
+
import {
|
|
15511
|
+
completeSimple as completeSimple3,
|
|
15512
|
+
streamSimple
|
|
15513
|
+
} from "@earendil-works/pi-ai";
|
|
15514
|
+
var PLAN_INTENTS = [
|
|
15515
|
+
"summary",
|
|
15516
|
+
"trend",
|
|
15517
|
+
"relationship",
|
|
15518
|
+
"search",
|
|
15519
|
+
"comparison",
|
|
15520
|
+
"mixed"
|
|
15521
|
+
];
|
|
15522
|
+
var STREAM_MARKER_HOLDBACK_CHARS = Math.max("</draft>".length, "</plan>".length, "<json>".length) - 1;
|
|
15523
|
+
function isRecord2(value) {
|
|
15524
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15525
|
+
}
|
|
15526
|
+
function isIntent(value) {
|
|
15527
|
+
return typeof value === "string" && PLAN_INTENTS.includes(value);
|
|
15528
|
+
}
|
|
15529
|
+
function normalizeString(value) {
|
|
15530
|
+
if (typeof value !== "string") return null;
|
|
15531
|
+
const text = value.trim();
|
|
15532
|
+
return text.length > 0 ? text : null;
|
|
15533
|
+
}
|
|
15534
|
+
function extractJsonObject4(text) {
|
|
15535
|
+
const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
15536
|
+
if (fenced?.[1]) return fenced[1].trim();
|
|
15537
|
+
const start = text.indexOf("{");
|
|
15538
|
+
const end = text.lastIndexOf("}");
|
|
15539
|
+
if (start >= 0 && end > start) return text.slice(start, end + 1);
|
|
15540
|
+
return text.trim();
|
|
15541
|
+
}
|
|
15542
|
+
function parsePlanJson(rawText, availableTools) {
|
|
15543
|
+
try {
|
|
15544
|
+
const parsed = JSON.parse(extractJsonObject4(rawText));
|
|
15545
|
+
if (!isRecord2(parsed)) return null;
|
|
15546
|
+
const title = normalizeString(parsed.title);
|
|
15547
|
+
if (!title || !isIntent(parsed.intent) || !Array.isArray(parsed.steps)) return null;
|
|
15548
|
+
const steps = parsed.steps.filter(isRecord2).map((step) => {
|
|
15549
|
+
const goal = normalizeString(step.goal);
|
|
15550
|
+
const evidenceNeeded = normalizeString(step.evidenceNeeded);
|
|
15551
|
+
if (!goal || !evidenceNeeded) return null;
|
|
15552
|
+
const suggestedTools = Array.isArray(step.suggestedTools) ? step.suggestedTools.filter((tool) => typeof tool === "string" && availableTools.has(tool)) : [];
|
|
15553
|
+
return { goal, suggestedTools: Array.from(new Set(suggestedTools)), evidenceNeeded };
|
|
15554
|
+
}).filter((step) => step !== null).slice(0, 5);
|
|
15555
|
+
if (steps.length === 0) return null;
|
|
15556
|
+
const successCriteria = Array.isArray(parsed.successCriteria) ? parsed.successCriteria.map(normalizeString).filter((item) => item !== null).slice(0, 5) : [];
|
|
15557
|
+
if (successCriteria.length === 0) return null;
|
|
15558
|
+
return {
|
|
15559
|
+
version: 1,
|
|
15560
|
+
title,
|
|
15561
|
+
route: "planned_execution",
|
|
15562
|
+
intent: parsed.intent,
|
|
15563
|
+
steps,
|
|
15564
|
+
successCriteria
|
|
15565
|
+
};
|
|
15566
|
+
} catch {
|
|
15567
|
+
return null;
|
|
15568
|
+
}
|
|
15569
|
+
}
|
|
15570
|
+
function resultToText2(result) {
|
|
15571
|
+
return typeof result === "string" ? result : result.text;
|
|
15572
|
+
}
|
|
15573
|
+
function buildPlannerPrompt(input) {
|
|
15574
|
+
const dataSnapshot = formatDataSnapshotForPlanner(input.dataSnapshot);
|
|
15575
|
+
const availableCapabilities = input.availableCapabilities && input.availableCapabilities.length > 0 ? input.availableCapabilities.map((capability) => {
|
|
15576
|
+
const tools = capability.tools.join(", ") || "none";
|
|
15577
|
+
return ` - ${capability.id} (${capability.label}; tools: ${tools}): ${capability.guidance}`;
|
|
15578
|
+
}).join("\n") : "(none)";
|
|
15579
|
+
return `Create a concise user-visible analysis plan for a ChatLab planned_execution request.
|
|
15580
|
+
|
|
15581
|
+
Return exactly three blocks:
|
|
15582
|
+
<draft>
|
|
15583
|
+
A brief user-visible planning note in the user's locale. Keep it high-level; do not reveal hidden chain-of-thought.
|
|
15584
|
+
</draft>
|
|
15585
|
+
<plan>
|
|
15586
|
+
A concise user-facing analysis approach in the user's locale. Do not include suggested tools, evidence fields, or success criteria; those details belong in <json>.
|
|
15587
|
+
</plan>
|
|
15588
|
+
<json>
|
|
15589
|
+
{
|
|
15590
|
+
"title": "short title",
|
|
15591
|
+
"intent": "summary|trend|relationship|search|comparison|mixed",
|
|
15592
|
+
"steps": [
|
|
15593
|
+
{"goal": "what to investigate", "suggestedTools": ["tool_name"], "evidenceNeeded": "what evidence is needed"}
|
|
15594
|
+
],
|
|
15595
|
+
"successCriteria": ["criterion"]
|
|
15596
|
+
}
|
|
15597
|
+
</json>
|
|
15598
|
+
|
|
15599
|
+
Limits:
|
|
15600
|
+
- Max 5 steps.
|
|
15601
|
+
- Max 5 successCriteria.
|
|
15602
|
+
- suggestedTools must come only from availableTools.
|
|
15603
|
+
- If availableCapabilities are listed, you may plan steps that use their tools when the capability helps the user.
|
|
15604
|
+
- Do not reveal hidden chain-of-thought; draft and plan are user-readable summaries only.
|
|
15605
|
+
- The plan is soft guidance, not a mandatory execution script.
|
|
15606
|
+
|
|
15607
|
+
Planning strategy:
|
|
15608
|
+
- For open-ended topic, community profile, influence, interaction-pattern, or multi-dimensional retrospective analysis, first plan a lightweight reconnaissance step to build a topic/member activity map before drawing conclusions.
|
|
15609
|
+
- Prefer segment summaries, keyword frequency, time distribution, member activity, and representative message retrieval when available.
|
|
15610
|
+
- Do not create a dedicated step whose only purpose is finding max timestamp or confirming latest message time.
|
|
15611
|
+
|
|
15612
|
+
Context:
|
|
15613
|
+
- locale: ${input.locale}
|
|
15614
|
+
- chatType: ${input.chatType}
|
|
15615
|
+
- availableTools: ${input.availableTools.join(", ") || "(none)"}
|
|
15616
|
+
- availableCapabilities:
|
|
15617
|
+
${availableCapabilities}
|
|
15618
|
+
- dataSnapshot: ${dataSnapshot}
|
|
15619
|
+
- assistantSummary: ${input.assistantSummary ?? "(none)"}
|
|
15620
|
+
- skillSummary: ${input.skillSummary ?? "(none)"}
|
|
15621
|
+
- recentIntentSummary: ${input.recentIntentSummary ?? "(none)"}
|
|
15622
|
+
|
|
15623
|
+
User request:
|
|
15624
|
+
${input.userMessage}`;
|
|
15625
|
+
}
|
|
15626
|
+
function createAnalysisPlanner(options) {
|
|
15627
|
+
return async (input, signal) => {
|
|
15628
|
+
try {
|
|
15629
|
+
const prompt = buildPlannerPrompt(input);
|
|
15630
|
+
const callbacks = {
|
|
15631
|
+
onPlanDelta: options.onPlanDelta ?? (() => {
|
|
15632
|
+
}),
|
|
15633
|
+
onThinkingDelta: options.onThinkingDelta,
|
|
15634
|
+
onThinkingEnd: options.onThinkingEnd,
|
|
15635
|
+
onValidationDelta: options.onValidationDelta,
|
|
15636
|
+
onValidationEnd: options.onValidationEnd
|
|
15637
|
+
};
|
|
15638
|
+
const rawResult = options.stream ? await options.stream(prompt, callbacks, signal) : options.complete ? await options.complete(prompt, signal) : options.onPlanDelta ? await streamWithPiAi(prompt, options, signal) : await completeWithPiAi2(prompt, options, signal);
|
|
15639
|
+
return parsePlanJson(resultToText2(rawResult), new Set(input.availableTools));
|
|
15640
|
+
} catch {
|
|
15641
|
+
return null;
|
|
15642
|
+
}
|
|
15643
|
+
};
|
|
15644
|
+
}
|
|
15645
|
+
function createPlanContentBlock(plan, status = "created") {
|
|
15646
|
+
return {
|
|
15647
|
+
type: "plan",
|
|
15648
|
+
version: 1,
|
|
15649
|
+
status,
|
|
15650
|
+
plan
|
|
15651
|
+
};
|
|
15652
|
+
}
|
|
15653
|
+
function buildPlanGuidance(plan) {
|
|
15654
|
+
const steps = plan.steps.map((step, index) => {
|
|
15655
|
+
const tools = step.suggestedTools.length > 0 ? step.suggestedTools.join(", ") : "none";
|
|
15656
|
+
return `${index + 1}. ${step.goal}
|
|
15657
|
+
Evidence needed: ${step.evidenceNeeded}
|
|
15658
|
+
Suggested tools: ${tools}`;
|
|
15659
|
+
}).join("\n");
|
|
15660
|
+
const successCriteria = plan.successCriteria.map((item) => `- ${item}`).join("\n");
|
|
15661
|
+
return `A suggested analysis plan is available below. Use it as guidance when helpful, but do not follow it mechanically if the user's question can be answered more directly.
|
|
15662
|
+
|
|
15663
|
+
Plan title: ${plan.title}
|
|
15664
|
+
Intent: ${plan.intent}
|
|
15665
|
+
|
|
15666
|
+
Steps:
|
|
15667
|
+
${steps}
|
|
15668
|
+
|
|
15669
|
+
Success criteria:
|
|
15670
|
+
${successCriteria}`;
|
|
15671
|
+
}
|
|
15672
|
+
async function completeWithPiAi2(prompt, options, signal) {
|
|
15673
|
+
if (!options.piModel || !options.apiKey) {
|
|
15674
|
+
throw new Error("Planner requires piModel and apiKey");
|
|
15675
|
+
}
|
|
15676
|
+
const result = await completeSimple3(
|
|
15677
|
+
options.piModel,
|
|
15678
|
+
{
|
|
15679
|
+
systemPrompt: "You are a strict planner for ChatLab analysis. Return the requested blocks only.",
|
|
15680
|
+
messages: [{ role: "user", content: [{ type: "text", text: prompt }], timestamp: Date.now() }]
|
|
15681
|
+
},
|
|
15682
|
+
{
|
|
15683
|
+
apiKey: options.apiKey,
|
|
15684
|
+
maxTokens: options.maxTokens ?? 900,
|
|
15685
|
+
temperature: options.temperature ?? 0.2,
|
|
15686
|
+
signal
|
|
15687
|
+
}
|
|
15688
|
+
);
|
|
15689
|
+
return {
|
|
15690
|
+
text: result.content.filter((item) => item.type === "text").map((item) => item.text).join("")
|
|
15691
|
+
};
|
|
15692
|
+
}
|
|
15693
|
+
function extractTaggedBlockText(rawText, tag, nextTags) {
|
|
15694
|
+
const openTag = `<${tag}>`;
|
|
15695
|
+
const closeTag = `</${tag}>`;
|
|
15696
|
+
const blockStart = rawText.indexOf(openTag);
|
|
15697
|
+
if (blockStart < 0) return "";
|
|
15698
|
+
const bodyStart = blockStart + openTag.length;
|
|
15699
|
+
const closeStart = rawText.indexOf(closeTag, bodyStart);
|
|
15700
|
+
const nextStarts = nextTags.map((nextTag) => rawText.indexOf(nextTag, bodyStart)).filter((index) => index >= 0);
|
|
15701
|
+
const endCandidates = [closeStart, ...nextStarts].filter((index) => index >= 0);
|
|
15702
|
+
const bodyEnd = endCandidates.length > 0 ? Math.min(...endCandidates) : Math.max(bodyStart, rawText.length - STREAM_MARKER_HOLDBACK_CHARS);
|
|
15703
|
+
const text = rawText.slice(bodyStart, bodyEnd);
|
|
15704
|
+
return text.replace(/^\s+/, "");
|
|
15705
|
+
}
|
|
15706
|
+
async function streamWithPiAi(prompt, options, signal) {
|
|
15707
|
+
if (!options.piModel || !options.apiKey) {
|
|
15708
|
+
throw new Error("Planner requires piModel and apiKey");
|
|
15709
|
+
}
|
|
15710
|
+
const stream = streamSimple(
|
|
15711
|
+
options.piModel,
|
|
15712
|
+
{
|
|
15713
|
+
systemPrompt: "You are a strict planner for ChatLab analysis. Return the requested plan and JSON blocks only.",
|
|
15714
|
+
messages: [{ role: "user", content: [{ type: "text", text: prompt }], timestamp: Date.now() }]
|
|
15715
|
+
},
|
|
15716
|
+
{
|
|
15717
|
+
apiKey: options.apiKey,
|
|
15718
|
+
maxTokens: options.maxTokens ?? 900,
|
|
15719
|
+
temperature: options.temperature ?? 0.2,
|
|
15720
|
+
signal
|
|
15721
|
+
}
|
|
15722
|
+
);
|
|
15723
|
+
let text = "";
|
|
15724
|
+
let emittedDraftLength = 0;
|
|
15725
|
+
let emittedPlanLength = 0;
|
|
15726
|
+
let emittedJsonLength = 0;
|
|
15727
|
+
let thinkingStartedAt;
|
|
15728
|
+
let draftThinkingStartedAt;
|
|
15729
|
+
let draftThinkingEnded = false;
|
|
15730
|
+
let validationStartedAt;
|
|
15731
|
+
let validationEnded = false;
|
|
15732
|
+
for await (const event of stream) {
|
|
15733
|
+
if (signal?.aborted) break;
|
|
15734
|
+
if (event.type === "thinking_start") {
|
|
15735
|
+
thinkingStartedAt = Date.now();
|
|
15736
|
+
continue;
|
|
15737
|
+
}
|
|
15738
|
+
if (event.type === "thinking_delta") {
|
|
15739
|
+
options.onThinkingDelta?.(event.delta);
|
|
15740
|
+
continue;
|
|
15741
|
+
}
|
|
15742
|
+
if (event.type === "thinking_end") {
|
|
15743
|
+
const durationMs = thinkingStartedAt ? Date.now() - thinkingStartedAt : void 0;
|
|
15744
|
+
thinkingStartedAt = void 0;
|
|
15745
|
+
options.onThinkingEnd?.(durationMs);
|
|
15746
|
+
continue;
|
|
15747
|
+
}
|
|
15748
|
+
if (event.type !== "text_delta") continue;
|
|
15749
|
+
text += event.delta;
|
|
15750
|
+
const draftText = extractTaggedBlockText(text, "draft", ["<plan>", "<json>"]);
|
|
15751
|
+
if (draftText.length > emittedDraftLength) {
|
|
15752
|
+
if (!draftThinkingStartedAt) draftThinkingStartedAt = Date.now();
|
|
15753
|
+
const delta = draftText.slice(emittedDraftLength);
|
|
15754
|
+
emittedDraftLength = draftText.length;
|
|
15755
|
+
if (delta.trim().length > 0 || /\s/.test(delta)) {
|
|
15756
|
+
options.onThinkingDelta?.(delta);
|
|
15757
|
+
}
|
|
15758
|
+
}
|
|
15759
|
+
if (!draftThinkingEnded && emittedDraftLength > 0 && (text.includes("</draft>") || text.includes("<plan>"))) {
|
|
15760
|
+
draftThinkingEnded = true;
|
|
15761
|
+
const durationMs = draftThinkingStartedAt ? Date.now() - draftThinkingStartedAt : void 0;
|
|
15762
|
+
options.onThinkingEnd?.(durationMs);
|
|
15763
|
+
}
|
|
15764
|
+
const planText = extractTaggedBlockText(text, "plan", ["<json>"]);
|
|
15765
|
+
if (planText.length > emittedPlanLength) {
|
|
15766
|
+
const delta = planText.slice(emittedPlanLength);
|
|
15767
|
+
emittedPlanLength = planText.length;
|
|
15768
|
+
if (delta.trim().length > 0 || /\s/.test(delta)) {
|
|
15769
|
+
options.onPlanDelta?.(delta);
|
|
15770
|
+
}
|
|
15771
|
+
}
|
|
15772
|
+
const jsonText = extractTaggedBlockText(text, "json", []);
|
|
15773
|
+
if (jsonText.length > emittedJsonLength) {
|
|
15774
|
+
if (!validationStartedAt) validationStartedAt = Date.now();
|
|
15775
|
+
const delta = jsonText.slice(emittedJsonLength);
|
|
15776
|
+
emittedJsonLength = jsonText.length;
|
|
15777
|
+
if (delta.trim().length > 0 || /\s/.test(delta)) {
|
|
15778
|
+
options.onValidationDelta?.(delta);
|
|
15779
|
+
}
|
|
15780
|
+
}
|
|
15781
|
+
if (!validationEnded && emittedJsonLength > 0 && text.includes("</json>")) {
|
|
15782
|
+
validationEnded = true;
|
|
15783
|
+
const durationMs = validationStartedAt ? Date.now() - validationStartedAt : void 0;
|
|
15784
|
+
options.onValidationEnd?.(durationMs);
|
|
15785
|
+
}
|
|
15786
|
+
}
|
|
15787
|
+
return { text };
|
|
15788
|
+
}
|
|
15789
|
+
|
|
15790
|
+
// ../../packages/node-runtime/src/ai/agent/event-handler.ts
|
|
15791
|
+
function estimateTokensFromText(text) {
|
|
15792
|
+
if (!text) return 0;
|
|
15793
|
+
const normalized = text.replace(/\s+/g, " ").trim();
|
|
15794
|
+
if (!normalized) return 0;
|
|
15795
|
+
const cjkCount = (normalized.match(/[\u3400-\u9fff\uf900-\ufaff]/g) || []).length;
|
|
15796
|
+
const latinCount = normalized.length - cjkCount;
|
|
15797
|
+
return Math.max(1, Math.ceil(cjkCount * 1.15 + latinCount / 4));
|
|
15798
|
+
}
|
|
15799
|
+
function extractMessageText(message) {
|
|
15800
|
+
if (message.role === "user") {
|
|
15801
|
+
if (typeof message.content === "string") return message.content;
|
|
15802
|
+
return message.content.map((item) => {
|
|
15803
|
+
if (item.type === "text") return item.text;
|
|
15804
|
+
if (item.type === "image") return "[image]";
|
|
15805
|
+
return "";
|
|
15806
|
+
}).join("\n");
|
|
15807
|
+
}
|
|
15808
|
+
if (message.role === "assistant") {
|
|
15809
|
+
return message.content.map((item) => {
|
|
15810
|
+
if (item.type === "text") return item.text;
|
|
15811
|
+
if (item.type === "thinking") return item.thinking;
|
|
15812
|
+
if (item.type === "toolCall") return `${item.name} ${JSON.stringify(item.arguments || {})}`;
|
|
15813
|
+
return "";
|
|
15192
15814
|
}).join("\n");
|
|
15193
15815
|
}
|
|
15194
15816
|
if (message.role === "toolResult") {
|
|
@@ -15301,6 +15923,39 @@ var AgentEventHandler = class {
|
|
|
15301
15923
|
function agentT(t2, key, locale, options) {
|
|
15302
15924
|
return t2(key, { lng: locale, ...options });
|
|
15303
15925
|
}
|
|
15926
|
+
function formatNullableTimestamp2(timestamp) {
|
|
15927
|
+
return typeof timestamp === "number" && Number.isFinite(timestamp) ? String(timestamp) : "null";
|
|
15928
|
+
}
|
|
15929
|
+
function formatSharePercent2(share) {
|
|
15930
|
+
if (!Number.isFinite(share)) return "0%";
|
|
15931
|
+
const rounded = Math.round(share * 10) / 10;
|
|
15932
|
+
return Number.isInteger(rounded) ? `${rounded}%` : `${rounded.toFixed(1)}%`;
|
|
15933
|
+
}
|
|
15934
|
+
function normalizeInlineText(text) {
|
|
15935
|
+
return text.replace(/\s+/g, " ").trim();
|
|
15936
|
+
}
|
|
15937
|
+
function formatDataSnapshotContext(t2, dataSnapshot, locale) {
|
|
15938
|
+
const memberHints = dataSnapshot.activeMemberHints ?? [];
|
|
15939
|
+
const memberHintTitle = memberHints.length === 0 ? agentT(t2, "ai.agent.dataSnapshotMemberHintsUnavailable", locale) : dataSnapshot.totalMembers <= 10 ? agentT(t2, "ai.agent.dataSnapshotMemberHintsAll", locale) : agentT(t2, "ai.agent.dataSnapshotMemberHintsTop", locale);
|
|
15940
|
+
const memberHintLines = memberHints.length > 0 ? memberHints.map((member, index) => {
|
|
15941
|
+
return `${index + 1}. member_id=${member.memberId} | display_name=${normalizeInlineText(member.displayName)} | messages=${member.messageCount} | share=${formatSharePercent2(member.share)}`;
|
|
15942
|
+
}).join("\n") : agentT(t2, "ai.agent.dataSnapshotMemberHintsEmpty", locale);
|
|
15943
|
+
return agentT(t2, "ai.agent.dataSnapshotContext", locale, {
|
|
15944
|
+
name: dataSnapshot.name,
|
|
15945
|
+
platform: dataSnapshot.platform,
|
|
15946
|
+
type: dataSnapshot.type,
|
|
15947
|
+
totalMessages: dataSnapshot.totalMessages,
|
|
15948
|
+
totalMembers: dataSnapshot.totalMembers,
|
|
15949
|
+
firstMessageTs: formatNullableTimestamp2(dataSnapshot.firstMessageTs),
|
|
15950
|
+
firstMessageTime: formatTimestamp(dataSnapshot.firstMessageTs, locale),
|
|
15951
|
+
lastMessageTs: formatNullableTimestamp2(dataSnapshot.lastMessageTs),
|
|
15952
|
+
lastMessageTime: formatTimestamp(dataSnapshot.lastMessageTs, locale),
|
|
15953
|
+
segmentSummaryCount: dataSnapshot.segmentSummaries?.availableCount ?? 0,
|
|
15954
|
+
memberHintTitle,
|
|
15955
|
+
memberHintLines,
|
|
15956
|
+
usageRules: agentT(t2, "ai.agent.dataSnapshotUsageRules", locale)
|
|
15957
|
+
});
|
|
15958
|
+
}
|
|
15304
15959
|
function getLockedPromptSection(t2, chatType, ownerInfo, locale, mentionedMembers, dataSnapshot) {
|
|
15305
15960
|
const now = /* @__PURE__ */ new Date();
|
|
15306
15961
|
const dateLocale = locale.startsWith("zh") ? "zh-CN" : "en-US";
|
|
@@ -15325,14 +15980,7 @@ ${mentionedMembers.map((member) => {
|
|
|
15325
15980
|
}).join("\n")}
|
|
15326
15981
|
` : "";
|
|
15327
15982
|
const year = now.getFullYear();
|
|
15328
|
-
const dataSnapshotNote = dataSnapshot ? `${
|
|
15329
|
-
name: dataSnapshot.name,
|
|
15330
|
-
platform: dataSnapshot.platform,
|
|
15331
|
-
totalMessages: dataSnapshot.totalMessages,
|
|
15332
|
-
totalMembers: dataSnapshot.totalMembers,
|
|
15333
|
-
firstMessageDate: formatTimestamp(dataSnapshot.firstMessageTs, locale),
|
|
15334
|
-
lastMessageDate: formatTimestamp(dataSnapshot.lastMessageTs, locale)
|
|
15335
|
-
})}
|
|
15983
|
+
const dataSnapshotNote = dataSnapshot ? `${formatDataSnapshotContext(t2, dataSnapshot, locale)}
|
|
15336
15984
|
` : "";
|
|
15337
15985
|
return `${agentT(t2, "ai.agent.currentDateIs", locale)} ${currentDate}\u3002
|
|
15338
15986
|
${ownerNote}
|
|
@@ -15446,7 +16094,7 @@ var zh_CN_default = {
|
|
|
15446
16094
|
}
|
|
15447
16095
|
},
|
|
15448
16096
|
get_time_stats: {
|
|
15449
|
-
desc: '\u83B7\u53D6\u7FA4\u804A\u7684\u65F6\u95F4\u5206\u5E03\u7EDF\u8BA1\u3002\u9002\u7528\u4E8E\u56DE\u7B54"\u4EC0\u4E48\u65F6\u5019\u6700\u6D3B\u8DC3"\u3001"\u5927\u5BB6\u4E00\u822C\u51E0\u70B9\u804A\u5929"\u7B49\u95EE\u9898\u3002',
|
|
16097
|
+
desc: '\u83B7\u53D6\u7FA4\u804A\u7684\u65F6\u95F4\u5206\u5E03\u7EDF\u8BA1\u3002\u9002\u7528\u4E8E\u56DE\u7B54"\u4EC0\u4E48\u65F6\u5019\u6700\u6D3B\u8DC3"\u3001"\u5927\u5BB6\u4E00\u822C\u51E0\u70B9\u804A\u5929"\u7B49\u95EE\u9898\u3002\u8FD4\u56DE\u7684 `data` \u6570\u7EC4\u53EF\u76F4\u63A5\u4F5C\u4E3A `render_chart` \u7684 `rows` \u53C2\u6570\u7528\u4E8E\u7ED8\u56FE\u3002',
|
|
15450
16098
|
params: {
|
|
15451
16099
|
type: "\u7EDF\u8BA1\u7C7B\u578B\uFF1Ahourly\uFF08\u6309\u5C0F\u65F6\uFF09\u3001weekday\uFF08\u6309\u661F\u671F\uFF09\u3001daily\uFF08\u6309\u65E5\u671F\uFF09"
|
|
15452
16100
|
}
|
|
@@ -15481,40 +16129,40 @@ var zh_CN_default = {
|
|
|
15481
16129
|
context_size: "\u4E0A\u4E0B\u6587\u5927\u5C0F\uFF0C\u5373\u83B7\u53D6\u524D\u540E\u5404\u591A\u5C11\u6761\u6D88\u606F\uFF0C\u9ED8\u8BA4 20"
|
|
15482
16130
|
}
|
|
15483
16131
|
},
|
|
15484
|
-
|
|
15485
|
-
desc: "\u641C\u7D22\u804A\u5929\
|
|
16132
|
+
search_segments: {
|
|
16133
|
+
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",
|
|
15486
16134
|
params: {
|
|
15487
|
-
keywords: "\u53EF\u9009\u7684\u641C\u7D22\u5173\u952E\u8BCD\u5217\u8868\uFF0C\u53EA\u8FD4\u56DE\u5305\u542B\u8FD9\u4E9B\u5173\u952E\u8BCD\u7684\
|
|
15488
|
-
limit: "\u8FD4\u56DE\
|
|
15489
|
-
year: "\u6307\u5B9A\u5E74\u4EFD\u7B5B\u9009\
|
|
15490
|
-
month: "\u6307\u5B9A\u6708\u4EFD\u7B5B\u9009\
|
|
15491
|
-
day: "\u6307\u5B9A\u65E5\u671F\u7B5B\u9009\
|
|
16135
|
+
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",
|
|
16136
|
+
limit: "\u8FD4\u56DE\u6BB5\u843D\u6570\u91CF\u9650\u5236\uFF0C\u9ED8\u8BA4 20",
|
|
16137
|
+
year: "\u6307\u5B9A\u5E74\u4EFD\u7B5B\u9009\u6BB5\u843D\uFF0C\u5982 2024",
|
|
16138
|
+
month: "\u6307\u5B9A\u6708\u4EFD\u7B5B\u9009\u6BB5\u843D\uFF081-12\uFF09\uFF0C\u9700\u914D\u5408 year \u4F7F\u7528",
|
|
16139
|
+
day: "\u6307\u5B9A\u65E5\u671F\u7B5B\u9009\u6BB5\u843D\uFF081-31\uFF09\uFF0C\u9700\u914D\u5408 year \u548C month \u4F7F\u7528",
|
|
15492
16140
|
start_time: '\u5F00\u59CB\u65F6\u95F4\uFF0C\u683C\u5F0F "YYYY-MM-DD HH:mm"\uFF0C\u5982 "2024-03-15 14:00"',
|
|
15493
16141
|
end_time: '\u7ED3\u675F\u65F6\u95F4\uFF0C\u683C\u5F0F "YYYY-MM-DD HH:mm"\uFF0C\u5982 "2024-03-15 18:30"'
|
|
15494
16142
|
}
|
|
15495
16143
|
},
|
|
15496
|
-
|
|
15497
|
-
desc: "\u83B7\u53D6\u6307\u5B9A\
|
|
16144
|
+
get_segment_messages: {
|
|
16145
|
+
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",
|
|
15498
16146
|
params: {
|
|
15499
|
-
|
|
15500
|
-
limit: "\u8FD4\u56DE\u6D88\u606F\u6570\u91CF\u9650\u5236\uFF0C\u9ED8\u8BA4 1000\u3002\u5BF9\u4E8E\u8D85\u957F\
|
|
16147
|
+
segment_id: "\u6BB5\u843D ID\uFF0C\u53EF\u4EE5\u4ECE search_segments \u7684\u8FD4\u56DE\u7ED3\u679C\u4E2D\u83B7\u53D6",
|
|
16148
|
+
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"
|
|
15501
16149
|
}
|
|
15502
16150
|
},
|
|
15503
|
-
|
|
15504
|
-
desc: `\u83B7\u53D6\
|
|
16151
|
+
get_segment_summaries: {
|
|
16152
|
+
desc: `\u83B7\u53D6\u6BB5\u843D\u6458\u8981\u5217\u8868\uFF0C\u5FEB\u901F\u4E86\u89E3\u7FA4\u804A\u5386\u53F2\u8BA8\u8BBA\u7684\u4E3B\u9898\u3002
|
|
15505
16153
|
|
|
15506
16154
|
\u9002\u7528\u573A\u666F\uFF1A
|
|
15507
16155
|
1. \u4E86\u89E3\u7FA4\u91CC\u6700\u8FD1\u5728\u804A\u4EC0\u4E48\u8BDD\u9898
|
|
15508
16156
|
2. \u6309\u5173\u952E\u8BCD\u641C\u7D22\u8BA8\u8BBA\u8FC7\u7684\u8BDD\u9898
|
|
15509
16157
|
3. \u6982\u89C8\u6027\u95EE\u9898\u5982"\u7FA4\u91CC\u6709\u6CA1\u6709\u8BA8\u8BBA\u8FC7\u65C5\u6E38"
|
|
15510
16158
|
|
|
15511
|
-
\u8FD4\u56DE\u7684\u6458\u8981\u662F\u5BF9\u6BCF\u4E2A\
|
|
16159
|
+
\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`,
|
|
15512
16160
|
params: {
|
|
15513
16161
|
keywords: "\u5728\u6458\u8981\u4E2D\u641C\u7D22\u7684\u5173\u952E\u8BCD\u5217\u8868\uFF08OR \u903B\u8F91\u5339\u914D\uFF09",
|
|
15514
|
-
limit: "\u8FD4\u56DE\
|
|
15515
|
-
year: "\u6307\u5B9A\u5E74\u4EFD\u7B5B\u9009\
|
|
15516
|
-
month: "\u6307\u5B9A\u6708\u4EFD\u7B5B\u9009\
|
|
15517
|
-
day: "\u6307\u5B9A\u65E5\u671F\u7B5B\u9009\
|
|
16162
|
+
limit: "\u8FD4\u56DE\u6BB5\u843D\u6570\u91CF\u9650\u5236\uFF0C\u9ED8\u8BA4 20",
|
|
16163
|
+
year: "\u6307\u5B9A\u5E74\u4EFD\u7B5B\u9009\u6BB5\u843D",
|
|
16164
|
+
month: "\u6307\u5B9A\u6708\u4EFD\u7B5B\u9009\u6BB5\u843D\uFF081-12\uFF09",
|
|
16165
|
+
day: "\u6307\u5B9A\u65E5\u671F\u7B5B\u9009\u6BB5\u843D\uFF081-31\uFF09",
|
|
15518
16166
|
start_time: '\u5F00\u59CB\u65F6\u95F4\uFF0C\u683C\u5F0F "YYYY-MM-DD HH:mm"',
|
|
15519
16167
|
end_time: '\u7ED3\u675F\u65F6\u95F4\uFF0C\u683C\u5F0F "YYYY-MM-DD HH:mm"'
|
|
15520
16168
|
}
|
|
@@ -15601,14 +16249,14 @@ var zh_CN_default = {
|
|
|
15601
16249
|
fallback: "\u8BE5\u65F6\u95F4\u8303\u56F4\u5185\u6CA1\u6709\u6D88\u606F\u8BB0\u5F55"
|
|
15602
16250
|
},
|
|
15603
16251
|
conversation_initiator_stats: {
|
|
15604
|
-
desc: "\u7EDF\u8BA1\u6BCF\u4E2A\u6210\u5458\u53D1\u8D77\
|
|
16252
|
+
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",
|
|
15605
16253
|
params: {
|
|
15606
16254
|
days: "\u7EDF\u8BA1\u6700\u8FD1\u591A\u5C11\u5929\u7684\u6570\u636E",
|
|
15607
16255
|
limit: "\u8FD4\u56DE\u524D\u591A\u5C11\u540D"
|
|
15608
16256
|
},
|
|
15609
16257
|
rowTemplate: "{name}\uFF1A\u53D1\u8D77 {initiated_count} \u6B21\u8BDD\u9898",
|
|
15610
16258
|
summaryTemplate: "\u8BDD\u9898\u53D1\u8D77\u8005 Top {rowCount}\uFF1A",
|
|
15611
|
-
fallback: "\u8BE5\u65F6\u95F4\u8303\u56F4\u5185\u6CA1\u6709\
|
|
16259
|
+
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"
|
|
15612
16260
|
},
|
|
15613
16261
|
activity_heatmap: {
|
|
15614
16262
|
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",
|
|
@@ -15636,9 +16284,10 @@ var zh_CN_default = {
|
|
|
15636
16284
|
params: {}
|
|
15637
16285
|
},
|
|
15638
16286
|
render_chart: {
|
|
15639
|
-
desc: "\u6839\u636E
|
|
16287
|
+
desc: "\u6839\u636E ChartSpec v1 \u751F\u6210 ChatLab \u539F\u751F\u56FE\u8868\u3002\u652F\u6301 bar\u3001line\u3001pie\u3001heatmap\u3002\u63D0\u4F9B `rows`\uFF08\u6765\u81EA\u9AD8\u5C42\u5DE5\u5177\u7684\u6570\u636E\u6570\u7EC4\uFF0C\u5982 get_time_stats \u7684 `data` \u5B57\u6BB5\uFF09\u6216 `sql`\uFF08\u53EA\u8BFB SELECT\uFF09\u4E8C\u9009\u4E00\uFF1B\u6709\u73B0\u6210\u6570\u636E\u65F6\u4F18\u5148\u7528 `rows`\uFF0C\u53EA\u6709\u9AD8\u5C42\u5DE5\u5177\u65E0\u6CD5\u6EE1\u8DB3\u65F6\u624D\u5199 `sql`\u3002\u7981\u6B62\u8F93\u51FA HTML\u3001JavaScript\u3001SVG\u3001ECharts option \u6216\u6E32\u67D3\u4EE3\u7801\u3002",
|
|
15640
16288
|
params: {
|
|
15641
|
-
|
|
16289
|
+
rows: "\u6765\u81EA\u9AD8\u5C42\u5DE5\u5177\u8FD4\u56DE\u7684\u6570\u636E\u6570\u7EC4\uFF08\u5982 get_time_stats \u7684 `data` \u5B57\u6BB5\uFF09\u3002\u6709\u73B0\u6210\u6570\u636E\u65F6\u4F18\u5148\u4F7F\u7528\uFF0C\u4E0E sql \u4E8C\u9009\u4E00\u3002",
|
|
16290
|
+
sql: "\u53EA\u8BFB SELECT \u6216 WITH SELECT SQL\u3002\u4EC5\u5728\u9AD8\u5C42\u5DE5\u5177\u65E0\u6CD5\u6EE1\u8DB3\u9700\u6C42\u65F6\u4F7F\u7528\uFF0C\u5FC5\u987B\u8FD4\u56DE ChartSpec encoding \u4E2D\u5F15\u7528\u7684\u5B57\u6BB5\u3002",
|
|
15642
16291
|
params: "SQL \u547D\u540D\u53C2\u6570\u5BF9\u8C61\uFF1B\u4E0D\u9700\u8981\u53C2\u6570\u65F6\u4F20\u7A7A\u5BF9\u8C61\u3002",
|
|
15643
16292
|
chartSpec: "ChartSpec v1\uFF0C\u5305\u542B version\u3001type\u3001title\u3001encoding\u3002",
|
|
15644
16293
|
maxRows: "\u56FE\u8868\u67E5\u8BE2\u6700\u5927\u884C\u6570\uFF0C\u9ED8\u8BA4 1000\u3002"
|
|
@@ -15672,6 +16321,35 @@ var zh_CN_default = {
|
|
|
15672
16321
|
timeParamsIntro: '\u65F6\u95F4\u53C2\u6570\uFF1A\u4F7F\u7528 start_time/end_time \u6307\u5B9A\u65F6\u95F4\u8303\u56F4\uFF0C\u683C\u5F0F "YYYY-MM-DD HH:mm"',
|
|
15673
16322
|
defaultYearNote: "\u672A\u6307\u5B9A\u65F6\u95F4\u8303\u56F4\u65F6\u9ED8\u8BA4\u67E5\u8BE2\u5168\u90E8\u3002\u5F53\u524D\u5E74\u4EFD\u4E3A{{year}}\u5E74",
|
|
15674
16323
|
dataSnapshotNote: "\u5F53\u524D\u804A\u5929\u6570\u636E\u5E93\u5FEB\u7167\uFF1A{{name}}\uFF08{{platform}}\uFF09\uFF0C\u603B\u6D88\u606F {{totalMessages}} \u6761\uFF0C\u6210\u5458 {{totalMembers}} \u4EBA\uFF0C\u65F6\u95F4\u8303\u56F4 {{firstMessageDate}} ~ {{lastMessageDate}}\u3002\u8BE5\u5FEB\u7167\u53EA\u7528\u4E8E\u5224\u65AD\u6570\u636E\u8303\u56F4\uFF1B\u56DE\u7B54\u5177\u4F53\u804A\u5929\u4E8B\u5B9E\u4ECD\u5FC5\u987B\u8C03\u7528\u5DE5\u5177\u68C0\u7D22\u5F53\u524D\u6570\u636E\u5E93\u3002",
|
|
16324
|
+
dataSnapshotContext: `\u5F53\u524D\u804A\u5929\u6570\u636E\u5E93\u542F\u52A8\u4E0A\u4E0B\u6587\uFF1A
|
|
16325
|
+
- name: {{name}}
|
|
16326
|
+
- platform: {{platform}}
|
|
16327
|
+
- type: {{type}}
|
|
16328
|
+
- total_messages: {{totalMessages}}
|
|
16329
|
+
- total_members: {{totalMembers}}
|
|
16330
|
+
- first_message_ts: {{firstMessageTs}}
|
|
16331
|
+
- first_message_time: {{firstMessageTime}}
|
|
16332
|
+
- last_message_ts: {{lastMessageTs}}
|
|
16333
|
+
- last_message_time: {{lastMessageTime}}
|
|
16334
|
+
- segment_summaries_available: {{segmentSummaryCount}}
|
|
16335
|
+
|
|
16336
|
+
{{memberHintTitle}}
|
|
16337
|
+
{{memberHintLines}}
|
|
16338
|
+
|
|
16339
|
+
\u4F7F\u7528\u89C4\u5219\uFF1A
|
|
16340
|
+
{{usageRules}}`,
|
|
16341
|
+
dataSnapshotMemberHintsAll: "\u6D3B\u8DC3\u6210\u5458\u67E5\u8BE2\u63D0\u793A\uFF08\u5168\u90E8\u6210\u5458\uFF09\uFF1A",
|
|
16342
|
+
dataSnapshotMemberHintsTop: "\u6D3B\u8DC3\u6210\u5458\u67E5\u8BE2\u63D0\u793A\uFF08\u6309\u5386\u53F2\u603B\u6D88\u606F\u91CF Top 10\uFF09\uFF1A",
|
|
16343
|
+
dataSnapshotMemberHintsUnavailable: "\u6D3B\u8DC3\u6210\u5458\u67E5\u8BE2\u63D0\u793A\uFF1A",
|
|
16344
|
+
dataSnapshotMemberHintsEmpty: "\u65E0\u53EF\u7528\u6210\u5458\u63D0\u793A\u3002",
|
|
16345
|
+
dataSnapshotUsageRules: `- member_id \u662F\u5DE5\u5177\u67E5\u8BE2\u63D0\u793A\uFF1Bdisplay_name \u4EC5\u7528\u4E8E\u4EBA\u7C7B\u8BC6\u522B\uFF0C\u53EF\u80FD\u4E0D\u552F\u4E00\u3002
|
|
16346
|
+
- \u4E0D\u8981\u5728\u6700\u7EC8\u56DE\u7B54\u4E2D\u4E3B\u52A8\u66B4\u9732 member_id \u6216\u542F\u52A8\u4E0A\u4E0B\u6587\u672C\u8EAB\uFF0C\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u6280\u672F\u7EC6\u8282\u3002
|
|
16347
|
+
- \u6D3B\u8DC3\u6210\u5458\u6392\u884C\u53EA\u4EE3\u8868\u5386\u53F2\u603B\u6D88\u606F\u91CF\uFF0C\u4E0D\u4EE3\u8868\u6700\u8FD1\u6D3B\u8DC3\u60C5\u51B5\uFF1B\u4E5F\u4E0D\u8DB3\u4EE5\u4F5C\u4E3A\u5F71\u54CD\u529B\u3001\u5173\u7CFB\u6216\u8FD1\u671F\u8D8B\u52BF\u7ED3\u8BBA\u7684\u8BC1\u636E\u3002
|
|
16348
|
+
- \u76F8\u5BF9\u65F6\u95F4\u8868\u8FBE\u4EE5\u771F\u5B9E\u5F53\u524D\u65E5\u671F\u4E3A\u57FA\u51C6\uFF0C\u800C\u4E0D\u662F\u6570\u636E\u5E93\u6700\u540E\u6D88\u606F\u65F6\u95F4\u3002
|
|
16349
|
+
- \u201C\u6700\u8FD1\u4E00\u5E74/\u8FC7\u53BB\u4E00\u5E74\u201D\u8868\u793A\u4ECE\u771F\u5B9E\u5F53\u524D\u65E5\u671F\u56DE\u63A8\u4E00\u5E74\u5230\u4ECA\u5929\uFF1B\u201C\u53BB\u5E74\u201D\u8868\u793A\u4E0A\u4E00\u81EA\u7136\u5E74\u3002
|
|
16350
|
+
- \u6570\u636E\u5E93\u65F6\u95F4\u8FB9\u754C\u53EA\u7528\u4E8E\u8BF4\u660E\u8986\u76D6\u8303\u56F4\uFF0C\u4E0D\u7528\u4E8E\u91CD\u5B9A\u4E49\u7528\u6237\u8981\u6C42\u7684\u65F6\u95F4\u8303\u56F4\u3002
|
|
16351
|
+
- \u4F7F\u7528\u9ED8\u8BA4\u201C\u8FD1 N \u5929\u201D\u7684\u5DE5\u5177\u65F6\uFF0C\u5148\u9009\u62E9\u4E0E\u6570\u636E\u5E93\u65F6\u95F4\u8FB9\u754C\u6709\u4EA4\u96C6\u7684\u8303\u56F4\uFF0C\u4E0D\u8981\u5148\u63A2\u6D4B\u771F\u5B9E\u5F53\u524D\u65E5\u671F\u7A97\u53E3\u5BFC\u81F4\u7A7A\u7ED3\u679C\u3002
|
|
16352
|
+
- \u4E0D\u8981\u53EA\u4E3A\u4E86\u91CD\u65B0\u53D1\u73B0 min/max timestamp \u8C03\u7528\u5DE5\u5177\uFF1B\u4F46\u56DE\u7B54\u5177\u4F53\u804A\u5929\u4E8B\u5B9E\u3001\u7EDF\u8BA1\u548C\u7ED3\u8BBA\u4ECD\u5FC5\u987B\u8C03\u7528\u5DE5\u5177\u83B7\u53D6\u8BC1\u636E\u3002`,
|
|
15675
16353
|
evidencePolicy: `\u8BC1\u636E\u7B56\u7565\uFF1A
|
|
15676
16354
|
- AI \u5BF9\u8BDD\u5386\u53F2\u3001\u5386\u53F2 AI \u56DE\u590D\u548C\u538B\u7F29\u6458\u8981\u53EA\u7528\u4E8E\u7406\u89E3\u7528\u6237\u610F\u56FE\uFF0C\u4E0D\u80FD\u4F5C\u4E3A\u804A\u5929\u8BB0\u5F55\u4E8B\u5B9E\u8BC1\u636E\u3002
|
|
15677
16355
|
- \u53EA\u8981\u7528\u6237\u8BE2\u95EE\u804A\u5929\u8BB0\u5F55\u5185\u5BB9\u3001\u6700\u8FD1\u804A\u4EC0\u4E48\u3001\u67D0\u4EBA\u8BF4\u8FC7\u4EC0\u4E48\u3001\u7EDF\u8BA1\u6392\u884C\u3001\u662F\u5426\u51FA\u73B0\u8FC7\u67D0\u8BDD\u9898\u6216\u8981\u6C42\u5F15\u7528\u539F\u8BDD\uFF0C\u5FC5\u987B\u5148\u8C03\u7528\u5408\u9002\u7684\u6570\u636E\u5DE5\u5177\u68C0\u7D22\u5F53\u524D\u6570\u636E\u5E93\u3002
|
|
@@ -15712,10 +16390,10 @@ var zh_CN_default = {
|
|
|
15712
16390
|
rawErrorLabel: "\u539F\u59CB\u9519\u8BEF"
|
|
15713
16391
|
},
|
|
15714
16392
|
summary: {
|
|
15715
|
-
|
|
16393
|
+
segmentNotFound: "\u6BB5\u843D\u4E0D\u5B58\u5728\u6216\u6570\u636E\u5E93\u6253\u5F00\u5931\u8D25",
|
|
15716
16394
|
tooFewMessages: "\u6D88\u606F\u6570\u91CF\u5C11\u4E8E{{count}}\u6761\uFF0C\u65E0\u9700\u751F\u6210\u6458\u8981",
|
|
15717
16395
|
tooFewValidMessages: "\u6709\u6548\u6D88\u606F\u6570\u91CF\u5C11\u4E8E{{count}}\u6761\uFF0C\u65E0\u9700\u751F\u6210\u6458\u8981",
|
|
15718
|
-
|
|
16396
|
+
segmentNotExist: "\u6BB5\u843D\u4E0D\u5B58\u5728",
|
|
15719
16397
|
messagesTooFew: "\u6D88\u606F\u592A\u5C11",
|
|
15720
16398
|
validMessagesTooFew: "\u6709\u6548\u6D88\u606F\u592A\u5C11",
|
|
15721
16399
|
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",
|
|
@@ -15780,7 +16458,7 @@ var en_US_default = {
|
|
|
15780
16458
|
}
|
|
15781
16459
|
},
|
|
15782
16460
|
get_time_stats: {
|
|
15783
|
-
desc: 'Get time distribution statistics of chat activity. Suitable for questions like "when is the group most active" or "what time do people usually chat".',
|
|
16461
|
+
desc: 'Get time distribution statistics of chat activity. Suitable for questions like "when is the group most active" or "what time do people usually chat". The returned `data` array can be passed directly as the `rows` parameter of render_chart for visualization.',
|
|
15784
16462
|
params: {
|
|
15785
16463
|
type: "Statistics type: hourly (by hour), weekday (by day of week), daily (by date)"
|
|
15786
16464
|
}
|
|
@@ -15815,40 +16493,40 @@ var en_US_default = {
|
|
|
15815
16493
|
context_size: "Context size, i.e. how many messages before and after to retrieve, default 20"
|
|
15816
16494
|
}
|
|
15817
16495
|
},
|
|
15818
|
-
|
|
15819
|
-
desc: "Search chat
|
|
16496
|
+
search_segments: {
|
|
16497
|
+
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.",
|
|
15820
16498
|
params: {
|
|
15821
|
-
keywords: "Optional keyword list, only returns
|
|
16499
|
+
keywords: "Optional keyword list, only returns segments containing these keywords (OR logic)",
|
|
15822
16500
|
limit: "Session count limit, default 20",
|
|
15823
|
-
year: "Filter
|
|
15824
|
-
month: "Filter
|
|
15825
|
-
day: "Filter
|
|
16501
|
+
year: "Filter segments by year, e.g. 2024",
|
|
16502
|
+
month: "Filter segments by month (1-12), use with year",
|
|
16503
|
+
day: "Filter segments by day (1-31), use with year and month",
|
|
15826
16504
|
start_time: 'Start time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 14:00"',
|
|
15827
16505
|
end_time: 'End time, format "YYYY-MM-DD HH:mm", e.g. "2024-03-15 18:30"'
|
|
15828
16506
|
}
|
|
15829
16507
|
},
|
|
15830
|
-
|
|
15831
|
-
desc: "Get the complete message list for a specific
|
|
16508
|
+
get_segment_messages: {
|
|
16509
|
+
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.",
|
|
15832
16510
|
params: {
|
|
15833
|
-
|
|
15834
|
-
limit: "Message count limit, default 1000. Can be limited for very long
|
|
16511
|
+
segment_id: "Segment ID, can be obtained from search_segments results",
|
|
16512
|
+
limit: "Message count limit, default 1000. Can be limited for very long segments to save tokens"
|
|
15835
16513
|
}
|
|
15836
16514
|
},
|
|
15837
|
-
|
|
15838
|
-
desc: `Get
|
|
16515
|
+
get_segment_summaries: {
|
|
16516
|
+
desc: `Get segment summary list to quickly understand discussion topics in chat history.
|
|
15839
16517
|
|
|
15840
16518
|
Use cases:
|
|
15841
16519
|
1. Understand what topics have been discussed recently
|
|
15842
16520
|
2. Search for discussed topics by keyword
|
|
15843
16521
|
3. Overview questions like "has the group discussed travel"
|
|
15844
16522
|
|
|
15845
|
-
Returned summaries are brief descriptions of each
|
|
16523
|
+
Returned summaries are brief descriptions of each segment, helping quickly locate segments of interest. Use get_segment_messages for details.`,
|
|
15846
16524
|
params: {
|
|
15847
16525
|
keywords: "Keyword list to search within summaries (OR logic)",
|
|
15848
16526
|
limit: "Session count limit, default 20",
|
|
15849
|
-
year: "Filter
|
|
15850
|
-
month: "Filter
|
|
15851
|
-
day: "Filter
|
|
16527
|
+
year: "Filter segments by year",
|
|
16528
|
+
month: "Filter segments by month (1-12)",
|
|
16529
|
+
day: "Filter segments by day (1-31)",
|
|
15852
16530
|
start_time: 'Start time, format "YYYY-MM-DD HH:mm"',
|
|
15853
16531
|
end_time: 'End time, format "YYYY-MM-DD HH:mm"'
|
|
15854
16532
|
}
|
|
@@ -15936,14 +16614,14 @@ Returned summaries are brief descriptions of each session, helping quickly locat
|
|
|
15936
16614
|
fallback: "No messages in this time range"
|
|
15937
16615
|
},
|
|
15938
16616
|
conversation_initiator_stats: {
|
|
15939
|
-
desc: "Count how many times each member initiated a conversation (was the first sender in a
|
|
16617
|
+
desc: "Count how many times each member initiated a conversation (was the first sender in a segment). Requires segment index to be generated.",
|
|
15940
16618
|
params: {
|
|
15941
16619
|
days: "Number of recent days to analyze",
|
|
15942
16620
|
limit: "Number of top members to return"
|
|
15943
16621
|
},
|
|
15944
16622
|
rowTemplate: "{name}: initiated {initiated_count} topics",
|
|
15945
16623
|
summaryTemplate: "Topic initiator Top {rowCount}:",
|
|
15946
|
-
fallback: "No
|
|
16624
|
+
fallback: "No segment records in this time range. Session index may need to be generated first."
|
|
15947
16625
|
},
|
|
15948
16626
|
activity_heatmap: {
|
|
15949
16627
|
desc: "Return a weekday \xD7 hour message count matrix for generating activity heatmaps. weekday: 0=Sun, 1=Mon, ..., 6=Sat.",
|
|
@@ -15971,9 +16649,10 @@ Returned summaries are brief descriptions of each session, helping quickly locat
|
|
|
15971
16649
|
params: {}
|
|
15972
16650
|
},
|
|
15973
16651
|
render_chart: {
|
|
15974
|
-
desc: "Generate a native ChatLab chart from
|
|
16652
|
+
desc: "Generate a native ChatLab chart from ChartSpec v1. Supports bar, line, pie, and heatmap. Provide either `rows` (pre-fetched data array from a tool result, e.g. the `data` field from get_time_stats) or `sql` (read-only SELECT) \u2014 prefer `rows` when data is already available; use `sql` only when high-level tools cannot satisfy the need. Do not output HTML, JavaScript, SVG, ECharts options, or rendering code.",
|
|
15975
16653
|
params: {
|
|
15976
|
-
|
|
16654
|
+
rows: "Pre-fetched data array from a high-level tool result (e.g. the `data` field from get_time_stats). Prefer this over sql when data is already available. Mutually exclusive with sql.",
|
|
16655
|
+
sql: "Read-only SELECT or WITH SELECT SQL. Use only when high-level tools cannot satisfy the need. Must return fields referenced by ChartSpec encoding.",
|
|
15977
16656
|
params: "Named SQL parameters. Use an empty object when no parameters are needed.",
|
|
15978
16657
|
chartSpec: "ChartSpec v1 with version, type, title, and encoding.",
|
|
15979
16658
|
maxRows: "Maximum chart query rows. Default 1000."
|
|
@@ -16008,6 +16687,35 @@ Returned summaries are brief descriptions of each session, helping quickly locat
|
|
|
16008
16687
|
timeParamsIntro: 'Time parameters: use start_time/end_time to specify the range, format "YYYY-MM-DD HH:mm"',
|
|
16009
16688
|
defaultYearNote: "When no time range is specified, queries default to all data. Current year is {{year}}.",
|
|
16010
16689
|
dataSnapshotNote: "Current chat database snapshot: {{name}} ({{platform}}), {{totalMessages}} total messages, {{totalMembers}} members, time range {{firstMessageDate}} ~ {{lastMessageDate}}. This snapshot only helps judge data coverage; concrete chat facts still require tool retrieval from the current database.",
|
|
16690
|
+
dataSnapshotContext: `Current chat database startup context:
|
|
16691
|
+
- name: {{name}}
|
|
16692
|
+
- platform: {{platform}}
|
|
16693
|
+
- type: {{type}}
|
|
16694
|
+
- total_messages: {{totalMessages}}
|
|
16695
|
+
- total_members: {{totalMembers}}
|
|
16696
|
+
- first_message_ts: {{firstMessageTs}}
|
|
16697
|
+
- first_message_time: {{firstMessageTime}}
|
|
16698
|
+
- last_message_ts: {{lastMessageTs}}
|
|
16699
|
+
- last_message_time: {{lastMessageTime}}
|
|
16700
|
+
- segment_summaries_available: {{segmentSummaryCount}}
|
|
16701
|
+
|
|
16702
|
+
{{memberHintTitle}}
|
|
16703
|
+
{{memberHintLines}}
|
|
16704
|
+
|
|
16705
|
+
Usage rules:
|
|
16706
|
+
{{usageRules}}`,
|
|
16707
|
+
dataSnapshotMemberHintsAll: "Active member lookup hints (all members):",
|
|
16708
|
+
dataSnapshotMemberHintsTop: "Active member lookup hints (top 10 by historical total messages):",
|
|
16709
|
+
dataSnapshotMemberHintsUnavailable: "Active member lookup hints:",
|
|
16710
|
+
dataSnapshotMemberHintsEmpty: "No member hints available.",
|
|
16711
|
+
dataSnapshotUsageRules: `- member_id is a tool lookup hint; display_name is only for human recognition and may not be unique.
|
|
16712
|
+
- Do not proactively expose member_id or the startup context in the final answer unless the user explicitly asks for technical details.
|
|
16713
|
+
- Active member ranking only reflects historical total message volume, not recent activity; it is also not evidence for influence, relationships, or recent trends.
|
|
16714
|
+
- Interpret relative time expressions using the real current date, not the database's last message time.
|
|
16715
|
+
- "recent year" / "past year" means one year back from the real current date to today; "last year" means the previous calendar year.
|
|
16716
|
+
- Database time bounds are only for explaining coverage, not for redefining the user's requested time range.
|
|
16717
|
+
- When using default recent-day tools, first choose a range that intersects database time bounds instead of probing an empty real-current-date window.
|
|
16718
|
+
- Do not call tools only to rediscover min/max timestamp; concrete chat facts, statistics, and conclusions still require tool evidence.`,
|
|
16011
16719
|
evidencePolicy: `Evidence policy:
|
|
16012
16720
|
- AI conversation history, prior AI replies, and compressed summaries are only for understanding the user's intent; they are not evidence for chat-record facts.
|
|
16013
16721
|
- Whenever the user asks about chat content, recent topics, what someone said, rankings/statistics, whether a topic appeared, or asks for exact quotes, first call an appropriate data tool to retrieve the current database.
|
|
@@ -16044,10 +16752,10 @@ Your task is to help users understand and analyze their private chat data.
|
|
|
16044
16752
|
rawErrorLabel: "Raw error"
|
|
16045
16753
|
},
|
|
16046
16754
|
summary: {
|
|
16047
|
-
|
|
16755
|
+
segmentNotFound: "Session not found or database could not be opened",
|
|
16048
16756
|
tooFewMessages: "Message count less than {{count}}, no need to generate summary",
|
|
16049
16757
|
tooFewValidMessages: "Valid message count less than {{count}}, no need to generate summary",
|
|
16050
|
-
|
|
16758
|
+
segmentNotExist: "Session not found",
|
|
16051
16759
|
messagesTooFew: "Too few messages",
|
|
16052
16760
|
validMessagesTooFew: "Too few valid messages",
|
|
16053
16761
|
systemPromptDirect: "You are a conversation summarization expert. Summarize conversations concisely.",
|
|
@@ -16112,7 +16820,7 @@ var ja_JP_default = {
|
|
|
16112
16820
|
}
|
|
16113
16821
|
},
|
|
16114
16822
|
get_time_stats: {
|
|
16115
|
-
desc: "\u30B0\u30EB\u30FC\u30D7\u30C1\u30E3\u30C3\u30C8\u306E\u6642\u9593\u5206\u5E03\u7D71\u8A08\u3092\u53D6\u5F97\u3059\u308B\u3002\u300C\u3044\u3064\u304C\u4E00\u756A\u30A2\u30AF\u30C6\u30A3\u30D6\uFF1F\u300D\u300C\u307F\u3093\u306A\u4F55\u6642\u306B\u30C1\u30E3\u30C3\u30C8\u3057\u3066\u3044\u308B\uFF1F\u300D\u306A\u3069\u306E\u8CEA\u554F\u306B\u9069\u3057\u3066\u3044\u308B\u3002",
|
|
16823
|
+
desc: "\u30B0\u30EB\u30FC\u30D7\u30C1\u30E3\u30C3\u30C8\u306E\u6642\u9593\u5206\u5E03\u7D71\u8A08\u3092\u53D6\u5F97\u3059\u308B\u3002\u300C\u3044\u3064\u304C\u4E00\u756A\u30A2\u30AF\u30C6\u30A3\u30D6\uFF1F\u300D\u300C\u307F\u3093\u306A\u4F55\u6642\u306B\u30C1\u30E3\u30C3\u30C8\u3057\u3066\u3044\u308B\uFF1F\u300D\u306A\u3069\u306E\u8CEA\u554F\u306B\u9069\u3057\u3066\u3044\u308B\u3002\u8FD4\u3055\u308C\u308B `data` \u914D\u5217\u306F render_chart \u306E `rows` \u30D1\u30E9\u30E1\u30FC\u30BF\u3068\u3057\u3066\u76F4\u63A5\u4F7F\u7528\u3067\u304D\u308B\u3002",
|
|
16116
16824
|
params: {
|
|
16117
16825
|
type: "\u7D71\u8A08\u30BF\u30A4\u30D7\uFF1Ahourly\uFF08\u6642\u9593\u5225\uFF09\u3001weekday\uFF08\u66DC\u65E5\u5225\uFF09\u3001daily\uFF08\u65E5\u5225\uFF09"
|
|
16118
16826
|
}
|
|
@@ -16147,40 +16855,40 @@ var ja_JP_default = {
|
|
|
16147
16855
|
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"
|
|
16148
16856
|
}
|
|
16149
16857
|
},
|
|
16150
|
-
|
|
16151
|
-
desc: "\u30C1\u30E3\u30C3\u30C8\u30BB\
|
|
16858
|
+
search_segments: {
|
|
16859
|
+
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",
|
|
16152
16860
|
params: {
|
|
16153
|
-
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\
|
|
16154
|
-
limit: "\u8FD4\u5374\u30BB\
|
|
16155
|
-
year: "\u6307\u5B9A\u5E74\u306E\u30BB\
|
|
16156
|
-
month: "\u6307\u5B9A\u6708\u306E\u30BB\
|
|
16157
|
-
day: "\u6307\u5B9A\u65E5\u306E\u30BB\
|
|
16861
|
+
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",
|
|
16862
|
+
limit: "\u8FD4\u5374\u30BB\u30B0\u30E1\u30F3\u30C8\u6570\u306E\u4E0A\u9650\u3002\u30C7\u30D5\u30A9\u30EB\u30C8 20",
|
|
16863
|
+
year: "\u6307\u5B9A\u5E74\u306E\u30BB\u30B0\u30E1\u30F3\u30C8\u3092\u30D5\u30A3\u30EB\u30BF\u30EA\u30F3\u30B0\uFF08\u4F8B\uFF1A2024\uFF09",
|
|
16864
|
+
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",
|
|
16865
|
+
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",
|
|
16158
16866
|
start_time: '\u958B\u59CB\u6642\u523B\u3002\u5F62\u5F0F "YYYY-MM-DD HH:mm"\uFF08\u4F8B\uFF1A"2024-03-15 14:00"\uFF09',
|
|
16159
16867
|
end_time: '\u7D42\u4E86\u6642\u523B\u3002\u5F62\u5F0F "YYYY-MM-DD HH:mm"\uFF08\u4F8B\uFF1A"2024-03-15 18:30"\uFF09'
|
|
16160
16868
|
}
|
|
16161
16869
|
},
|
|
16162
|
-
|
|
16163
|
-
desc: "\u6307\u5B9A\u30BB\
|
|
16870
|
+
get_segment_messages: {
|
|
16871
|
+
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",
|
|
16164
16872
|
params: {
|
|
16165
|
-
|
|
16166
|
-
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\
|
|
16873
|
+
segment_id: "\u30BB\u30B0\u30E1\u30F3\u30C8 ID\u3002search_segments \u306E\u8FD4\u5374\u7D50\u679C\u304B\u3089\u53D6\u5F97\u3067\u304D\u308B",
|
|
16874
|
+
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"
|
|
16167
16875
|
}
|
|
16168
16876
|
},
|
|
16169
|
-
|
|
16170
|
-
desc: `\u30BB\
|
|
16877
|
+
get_segment_summaries: {
|
|
16878
|
+
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
|
|
16171
16879
|
|
|
16172
16880
|
\u9069\u7528\u30B7\u30FC\u30F3\uFF1A
|
|
16173
16881
|
1. \u30B0\u30EB\u30FC\u30D7\u3067\u6700\u8FD1\u4F55\u304C\u8A71\u984C\u306B\u306A\u3063\u3066\u3044\u305F\u304B\u77E5\u308A\u305F\u3044
|
|
16174
16882
|
2. \u30AD\u30FC\u30EF\u30FC\u30C9\u3067\u904E\u53BB\u306B\u8B70\u8AD6\u3055\u308C\u305F\u30C8\u30D4\u30C3\u30AF\u3092\u691C\u7D22
|
|
16175
16883
|
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
|
|
16176
16884
|
|
|
16177
|
-
\u8FD4\u5374\u3055\u308C\u308B\u8981\u7D04\u306F\u5404\u30BB\
|
|
16885
|
+
\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`,
|
|
16178
16886
|
params: {
|
|
16179
16887
|
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",
|
|
16180
|
-
limit: "\u8FD4\u5374\u30BB\
|
|
16181
|
-
year: "\u6307\u5B9A\u5E74\u306E\u30BB\
|
|
16182
|
-
month: "\u6307\u5B9A\u6708\u306E\u30BB\
|
|
16183
|
-
day: "\u6307\u5B9A\u65E5\u306E\u30BB\
|
|
16888
|
+
limit: "\u8FD4\u5374\u30BB\u30B0\u30E1\u30F3\u30C8\u6570\u306E\u4E0A\u9650\u3002\u30C7\u30D5\u30A9\u30EB\u30C8 20",
|
|
16889
|
+
year: "\u6307\u5B9A\u5E74\u306E\u30BB\u30B0\u30E1\u30F3\u30C8\u3092\u30D5\u30A3\u30EB\u30BF\u30EA\u30F3\u30B0",
|
|
16890
|
+
month: "\u6307\u5B9A\u6708\u306E\u30BB\u30B0\u30E1\u30F3\u30C8\u3092\u30D5\u30A3\u30EB\u30BF\u30EA\u30F3\u30B0\uFF081-12\uFF09",
|
|
16891
|
+
day: "\u6307\u5B9A\u65E5\u306E\u30BB\u30B0\u30E1\u30F3\u30C8\u3092\u30D5\u30A3\u30EB\u30BF\u30EA\u30F3\u30B0\uFF081-31\uFF09",
|
|
16184
16892
|
start_time: '\u958B\u59CB\u6642\u523B\u3002\u5F62\u5F0F "YYYY-MM-DD HH:mm"',
|
|
16185
16893
|
end_time: '\u7D42\u4E86\u6642\u523B\u3002\u5F62\u5F0F "YYYY-MM-DD HH:mm"'
|
|
16186
16894
|
}
|
|
@@ -16267,14 +16975,14 @@ var ja_JP_default = {
|
|
|
16267
16975
|
fallback: "\u3053\u306E\u671F\u9593\u306B\u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u8A18\u9332\u304C\u3042\u308A\u307E\u305B\u3093"
|
|
16268
16976
|
},
|
|
16269
16977
|
conversation_initiator_stats: {
|
|
16270
|
-
desc: "\u5404\u30E1\u30F3\u30D0\u30FC\u304C\u4F1A\u8A71\u3092\u958B\u59CB\u3057\u305F\u56DE\u6570\uFF08\u30BB\
|
|
16978
|
+
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",
|
|
16271
16979
|
params: {
|
|
16272
16980
|
days: "\u76F4\u8FD1\u4F55\u65E5\u9593\u306E\u30C7\u30FC\u30BF\u3092\u96C6\u8A08\u3059\u308B\u304B",
|
|
16273
16981
|
limit: "\u4E0A\u4F4D\u4F55\u540D\u3092\u8FD4\u5374\u3059\u308B\u304B"
|
|
16274
16982
|
},
|
|
16275
16983
|
rowTemplate: "{name}\uFF1A{initiated_count} \u56DE\u8A71\u984C\u3092\u958B\u59CB",
|
|
16276
16984
|
summaryTemplate: "\u8A71\u984C\u958B\u59CB\u8005 Top {rowCount}\uFF1A",
|
|
16277
|
-
fallback: "\u3053\u306E\u671F\u9593\u306B\u30BB\
|
|
16985
|
+
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"
|
|
16278
16986
|
},
|
|
16279
16987
|
activity_heatmap: {
|
|
16280
16988
|
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",
|
|
@@ -16302,9 +17010,10 @@ var ja_JP_default = {
|
|
|
16302
17010
|
params: {}
|
|
16303
17011
|
},
|
|
16304
17012
|
render_chart: {
|
|
16305
|
-
desc: "
|
|
17013
|
+
desc: "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\u3002`rows`\uFF08\u9AD8\u30EC\u30D9\u30EB\u30C4\u30FC\u30EB\u306E\u30C7\u30FC\u30BF\u914D\u5217\u3001\u4F8B\uFF1Aget_time_stats \u306E `data` \u30D5\u30A3\u30FC\u30EB\u30C9\uFF09\u307E\u305F\u306F `sql`\uFF08\u8AAD\u307F\u53D6\u308A\u5C02\u7528 SELECT\uFF09\u306E\u3044\u305A\u308C\u304B\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002\u30C7\u30FC\u30BF\u304C\u3059\u3067\u306B\u53D6\u5F97\u6E08\u307F\u306E\u5834\u5408\u306F `rows` \u3092\u512A\u5148\u3057\u3001\u9AD8\u30EC\u30D9\u30EB\u30C4\u30FC\u30EB\u3067\u5BFE\u5FDC\u3067\u304D\u306A\u3044\u5834\u5408\u306E\u307F `sql` \u3092\u4F7F\u7528\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",
|
|
16306
17014
|
params: {
|
|
16307
|
-
|
|
17015
|
+
rows: "\u9AD8\u30EC\u30D9\u30EB\u30C4\u30FC\u30EB\u304B\u3089\u53D6\u5F97\u3057\u305F\u30C7\u30FC\u30BF\u914D\u5217\uFF08\u4F8B\uFF1Aget_time_stats \u306E `data` \u30D5\u30A3\u30FC\u30EB\u30C9\uFF09\u3002\u30C7\u30FC\u30BF\u304C\u53D6\u5F97\u6E08\u307F\u306E\u5834\u5408\u306F sql \u3088\u308A\u512A\u5148\u3057\u3066\u4F7F\u7528\u3057\u307E\u3059\u3002sql \u3068\u306F\u6392\u4ED6\u3002",
|
|
17016
|
+
sql: "\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u306E SELECT \u307E\u305F\u306F WITH SELECT SQL\u3002\u9AD8\u30EC\u30D9\u30EB\u30C4\u30FC\u30EB\u3067\u5BFE\u5FDC\u3067\u304D\u306A\u3044\u5834\u5408\u306E\u307F\u4F7F\u7528\u3057\u307E\u3059\u3002ChartSpec encoding \u3067\u53C2\u7167\u3059\u308B\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u8FD4\u3059\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002",
|
|
16308
17017
|
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",
|
|
16309
17018
|
chartSpec: "version\u3001type\u3001title\u3001encoding \u3092\u542B\u3080 ChartSpec v1\u3002",
|
|
16310
17019
|
maxRows: "\u30C1\u30E3\u30FC\u30C8\u30AF\u30A8\u30EA\u306E\u6700\u5927\u884C\u6570\u3002\u30C7\u30D5\u30A9\u30EB\u30C8\u306F 1000\u3002"
|
|
@@ -16338,6 +17047,35 @@ var ja_JP_default = {
|
|
|
16338
17047
|
timeParamsIntro: '\u6642\u9593\u30D1\u30E9\u30E1\u30FC\u30BF\uFF1Astart_time/end_time \u3067\u7BC4\u56F2\u3092\u6307\u5B9A\u3002\u5F62\u5F0F\u306F "YYYY-MM-DD HH:mm"',
|
|
16339
17048
|
defaultYearNote: "\u6642\u9593\u7BC4\u56F2\u3092\u6307\u5B9A\u3057\u306A\u3044\u5834\u5408\u306F\u5168\u671F\u9593\u304C\u5BFE\u8C61\u3002\u73FE\u5728\u306E\u5E74\u306F{{year}}\u5E74",
|
|
16340
17049
|
dataSnapshotNote: "\u73FE\u5728\u306E\u30C1\u30E3\u30C3\u30C8\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\uFF1A{{name}}\uFF08{{platform}}\uFF09\u3001\u7DCF\u30E1\u30C3\u30BB\u30FC\u30B8 {{totalMessages}} \u4EF6\u3001\u30E1\u30F3\u30D0\u30FC {{totalMembers}} \u4EBA\u3001\u671F\u9593 {{firstMessageDate}} ~ {{lastMessageDate}}\u3002\u3053\u306E\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u306F\u30C7\u30FC\u30BF\u7BC4\u56F2\u306E\u5224\u65AD\u306B\u306E\u307F\u4F7F\u3044\u3001\u5177\u4F53\u7684\u306A\u30C1\u30E3\u30C3\u30C8\u4E8B\u5B9F\u306E\u56DE\u7B54\u306B\u306F\u5FC5\u305A\u73FE\u5728\u306E\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u30C4\u30FC\u30EB\u3067\u691C\u7D22\u3059\u308B\u3002",
|
|
17050
|
+
dataSnapshotContext: `\u73FE\u5728\u306E\u30C1\u30E3\u30C3\u30C8\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u8D77\u52D5\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\uFF1A
|
|
17051
|
+
- name: {{name}}
|
|
17052
|
+
- platform: {{platform}}
|
|
17053
|
+
- type: {{type}}
|
|
17054
|
+
- total_messages: {{totalMessages}}
|
|
17055
|
+
- total_members: {{totalMembers}}
|
|
17056
|
+
- first_message_ts: {{firstMessageTs}}
|
|
17057
|
+
- first_message_time: {{firstMessageTime}}
|
|
17058
|
+
- last_message_ts: {{lastMessageTs}}
|
|
17059
|
+
- last_message_time: {{lastMessageTime}}
|
|
17060
|
+
- segment_summaries_available: {{segmentSummaryCount}}
|
|
17061
|
+
|
|
17062
|
+
{{memberHintTitle}}
|
|
17063
|
+
{{memberHintLines}}
|
|
17064
|
+
|
|
17065
|
+
\u4F7F\u7528\u30EB\u30FC\u30EB\uFF1A
|
|
17066
|
+
{{usageRules}}`,
|
|
17067
|
+
dataSnapshotMemberHintsAll: "\u30A2\u30AF\u30C6\u30A3\u30D6\u30E1\u30F3\u30D0\u30FC\u691C\u7D22\u30D2\u30F3\u30C8\uFF08\u5168\u30E1\u30F3\u30D0\u30FC\uFF09\uFF1A",
|
|
17068
|
+
dataSnapshotMemberHintsTop: "\u30A2\u30AF\u30C6\u30A3\u30D6\u30E1\u30F3\u30D0\u30FC\u691C\u7D22\u30D2\u30F3\u30C8\uFF08\u904E\u53BB\u306E\u7DCF\u30E1\u30C3\u30BB\u30FC\u30B8\u6570 Top 10\uFF09\uFF1A",
|
|
17069
|
+
dataSnapshotMemberHintsUnavailable: "\u30A2\u30AF\u30C6\u30A3\u30D6\u30E1\u30F3\u30D0\u30FC\u691C\u7D22\u30D2\u30F3\u30C8\uFF1A",
|
|
17070
|
+
dataSnapshotMemberHintsEmpty: "\u5229\u7528\u53EF\u80FD\u306A\u30E1\u30F3\u30D0\u30FC\u30D2\u30F3\u30C8\u306F\u3042\u308A\u307E\u305B\u3093\u3002",
|
|
17071
|
+
dataSnapshotUsageRules: `- member_id \u306F\u30C4\u30FC\u30EB\u691C\u7D22\u7528\u306E\u30D2\u30F3\u30C8\u3067\u3059\u3002display_name \u306F\u4EBA\u9593\u304C\u8B58\u5225\u3059\u308B\u305F\u3081\u3060\u3051\u306E\u3082\u306E\u3067\u3001\u4E00\u610F\u3068\u306F\u9650\u308A\u307E\u305B\u3093\u3002
|
|
17072
|
+
- \u30E6\u30FC\u30B6\u30FC\u304C\u6280\u8853\u7684\u8A73\u7D30\u3092\u660E\u793A\u7684\u306B\u6C42\u3081\u306A\u3044\u9650\u308A\u3001\u6700\u7D42\u56DE\u7B54\u3067 member_id \u3084\u8D77\u52D5\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u81EA\u4F53\u3092\u7A4D\u6975\u7684\u306B\u958B\u793A\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
|
|
17073
|
+
- \u30A2\u30AF\u30C6\u30A3\u30D6\u30E1\u30F3\u30D0\u30FC\u9806\u4F4D\u306F\u904E\u53BB\u306E\u7DCF\u30E1\u30C3\u30BB\u30FC\u30B8\u91CF\u3060\u3051\u3092\u793A\u3057\u3001\u6700\u8FD1\u306E\u6D3B\u767A\u3055\u3092\u793A\u3059\u3082\u306E\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002\u307E\u305F\u3001\u5F71\u97FF\u529B\u3001\u95A2\u4FC2\u6027\u3001\u6700\u8FD1\u306E\u50BE\u5411\u306E\u7D50\u8AD6\u8A3C\u62E0\u306B\u3082\u306A\u308A\u307E\u305B\u3093\u3002
|
|
17074
|
+
- \u76F8\u5BFE\u7684\u306A\u6642\u9593\u8868\u73FE\u306F\u3001\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u6700\u7D42\u30E1\u30C3\u30BB\u30FC\u30B8\u6642\u523B\u3067\u306F\u306A\u304F\u3001\u5B9F\u969B\u306E\u73FE\u5728\u65E5\u4ED8\u3092\u57FA\u6E96\u306B\u89E3\u91C8\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
17075
|
+
- \u300C\u6700\u8FD1\u4E00\u5E74/\u904E\u53BB\u4E00\u5E74\u300D\u306F\u5B9F\u969B\u306E\u73FE\u5728\u65E5\u4ED8\u304B\u3089\u4ECA\u65E5\u307E\u3067\u306E1\u5E74\u9593\u3092\u6307\u3057\u3001\u300C\u53BB\u5E74\u300D\u306F\u524D\u306E\u66A6\u5E74\u3092\u6307\u3057\u307E\u3059\u3002
|
|
17076
|
+
- \u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u6642\u9593\u5883\u754C\u306F\u30AB\u30D0\u30EC\u30C3\u30B8\u8AAC\u660E\u306B\u306E\u307F\u4F7F\u3044\u3001\u30E6\u30FC\u30B6\u30FC\u304C\u6C42\u3081\u305F\u6642\u9593\u7BC4\u56F2\u3092\u518D\u5B9A\u7FA9\u3059\u308B\u305F\u3081\u306B\u4F7F\u308F\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
|
|
17077
|
+
- \u30C7\u30D5\u30A9\u30EB\u30C8\u306E\u300C\u76F4\u8FD1 N \u65E5\u300D\u30C4\u30FC\u30EB\u3092\u4F7F\u3046\u5834\u5408\u306F\u3001\u7A7A\u306E\u5B9F\u969B\u73FE\u5728\u65E5\u4ED8\u30A6\u30A3\u30F3\u30C9\u30A6\u3092\u8A66\u3059\u306E\u3067\u306F\u306A\u304F\u3001\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u6642\u9593\u5883\u754C\u3068\u4EA4\u5DEE\u3059\u308B\u7BC4\u56F2\u3092\u5148\u306B\u9078\u3093\u3067\u304F\u3060\u3055\u3044\u3002
|
|
17078
|
+
- min/max timestamp \u3092\u518D\u767A\u898B\u3059\u308B\u305F\u3081\u3060\u3051\u306B\u30C4\u30FC\u30EB\u3092\u547C\u3070\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002\u305F\u3060\u3057\u3001\u5177\u4F53\u7684\u306A\u30C1\u30E3\u30C3\u30C8\u4E8B\u5B9F\u3001\u7D71\u8A08\u3001\u7D50\u8AD6\u306B\u306F\u5F15\u304D\u7D9A\u304D\u30C4\u30FC\u30EB\u8A3C\u62E0\u304C\u5FC5\u8981\u3067\u3059\u3002`,
|
|
16341
17079
|
evidencePolicy: `\u8A3C\u62E0\u30DD\u30EA\u30B7\u30FC\uFF1A
|
|
16342
17080
|
- AI \u4F1A\u8A71\u5C65\u6B74\u3001\u904E\u53BB\u306E AI \u56DE\u7B54\u3001\u5727\u7E2E\u8981\u7D04\u306F\u30E6\u30FC\u30B6\u30FC\u610F\u56F3\u306E\u7406\u89E3\u306B\u306E\u307F\u4F7F\u7528\u3057\u3001\u30C1\u30E3\u30C3\u30C8\u8A18\u9332\u306E\u4E8B\u5B9F\u8A3C\u62E0\u3068\u3057\u3066\u6271\u308F\u306A\u3044\u3002
|
|
16343
17081
|
- \u30E6\u30FC\u30B6\u30FC\u304C\u30C1\u30E3\u30C3\u30C8\u5185\u5BB9\u3001\u6700\u8FD1\u306E\u8A71\u984C\u3001\u8AB0\u304B\u306E\u767A\u8A00\u3001\u30E9\u30F3\u30AD\u30F3\u30B0/\u7D71\u8A08\u3001\u3042\u308B\u8A71\u984C\u304C\u51FA\u305F\u304B\u3069\u3046\u304B\u3001\u307E\u305F\u306F\u539F\u6587\u5F15\u7528\u3092\u6C42\u3081\u305F\u5834\u5408\u306F\u3001\u5FC5\u305A\u5148\u306B\u9069\u5207\u306A\u30C7\u30FC\u30BF\u30C4\u30FC\u30EB\u3067\u73FE\u5728\u306E\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u691C\u7D22\u3059\u308B\u3002
|
|
@@ -16376,10 +17114,10 @@ var ja_JP_default = {
|
|
|
16376
17114
|
rawErrorLabel: "\u5143\u306E\u30A8\u30E9\u30FC"
|
|
16377
17115
|
},
|
|
16378
17116
|
summary: {
|
|
16379
|
-
|
|
17117
|
+
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",
|
|
16380
17118
|
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",
|
|
16381
17119
|
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",
|
|
16382
|
-
|
|
17120
|
+
segmentNotExist: "\u30BB\u30B0\u30E1\u30F3\u30C8\u304C\u5B58\u5728\u3057\u307E\u305B\u3093",
|
|
16383
17121
|
messagesTooFew: "\u30E1\u30C3\u30BB\u30FC\u30B8\u304C\u5C11\u306A\u3059\u304E\u307E\u3059",
|
|
16384
17122
|
validMessagesTooFew: "\u6709\u52B9\u306A\u30E1\u30C3\u30BB\u30FC\u30B8\u304C\u5C11\u306A\u3059\u304E\u307E\u3059",
|
|
16385
17123
|
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",
|
|
@@ -16444,7 +17182,7 @@ var zh_TW_default = {
|
|
|
16444
17182
|
}
|
|
16445
17183
|
},
|
|
16446
17184
|
get_time_stats: {
|
|
16447
|
-
desc: "\u53D6\u5F97\u7FA4\u804A\u7684\u6642\u9593\u5206\u4F48\u7D71\u8A08\u3002\u9069\u7528\u65BC\u56DE\u7B54\u300C\u4EC0\u9EBC\u6642\u5019\u6700\u6D3B\u8E8D\u300D\u3001\u300C\u5927\u5BB6\u4E00\u822C\u5E7E\u9EDE\u804A\u5929\u300D\u7B49\u554F\u984C\u3002",
|
|
17185
|
+
desc: "\u53D6\u5F97\u7FA4\u804A\u7684\u6642\u9593\u5206\u4F48\u7D71\u8A08\u3002\u9069\u7528\u65BC\u56DE\u7B54\u300C\u4EC0\u9EBC\u6642\u5019\u6700\u6D3B\u8E8D\u300D\u3001\u300C\u5927\u5BB6\u4E00\u822C\u5E7E\u9EDE\u804A\u5929\u300D\u7B49\u554F\u984C\u3002\u8FD4\u56DE\u7684 `data` \u9663\u5217\u53EF\u76F4\u63A5\u4F5C\u70BA `render_chart` \u7684 `rows` \u53C3\u6578\u7528\u65BC\u7E6A\u5716\u3002",
|
|
16448
17186
|
params: {
|
|
16449
17187
|
type: "\u7D71\u8A08\u985E\u578B\uFF1Ahourly\uFF08\u6309\u5C0F\u6642\uFF09\u3001weekday\uFF08\u6309\u661F\u671F\uFF09\u3001daily\uFF08\u6309\u65E5\u671F\uFF09"
|
|
16450
17188
|
}
|
|
@@ -16479,7 +17217,7 @@ var zh_TW_default = {
|
|
|
16479
17217
|
context_size: "\u4E0A\u4E0B\u6587\u5927\u5C0F\uFF0C\u5373\u53D6\u5F97\u524D\u5F8C\u5404\u591A\u5C11\u689D\u8A0A\u606F\uFF0C\u9810\u8A2D 20"
|
|
16480
17218
|
}
|
|
16481
17219
|
},
|
|
16482
|
-
|
|
17220
|
+
search_segments: {
|
|
16483
17221
|
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",
|
|
16484
17222
|
params: {
|
|
16485
17223
|
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",
|
|
@@ -16491,22 +17229,22 @@ var zh_TW_default = {
|
|
|
16491
17229
|
end_time: '\u7D50\u675F\u6642\u9593\uFF0C\u683C\u5F0F "YYYY-MM-DD HH:mm"\uFF0C\u5982 "2024-03-15 18:30"'
|
|
16492
17230
|
}
|
|
16493
17231
|
},
|
|
16494
|
-
|
|
16495
|
-
desc: "\u53D6\u5F97\u6307\u5B9A\u6703\u8A71\u7684\u5B8C\u6574\u8A0A\u606F\u6E05\u55AE\u3002\u7528\u65BC\u5728
|
|
17232
|
+
get_segment_messages: {
|
|
17233
|
+
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",
|
|
16496
17234
|
params: {
|
|
16497
|
-
|
|
17235
|
+
segment_id: "\u6703\u8A71 ID\uFF0C\u53EF\u4EE5\u5F9E search_segments \u7684\u56DE\u50B3\u7D50\u679C\u4E2D\u53D6\u5F97",
|
|
16498
17236
|
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"
|
|
16499
17237
|
}
|
|
16500
17238
|
},
|
|
16501
|
-
|
|
16502
|
-
desc: `\u53D6\u5F97\
|
|
17239
|
+
get_segment_summaries: {
|
|
17240
|
+
desc: `\u53D6\u5F97\u6BB5\u843D\u6458\u8981\u6E05\u55AE\uFF0C\u5FEB\u901F\u4E86\u89E3\u7FA4\u804A\u6B77\u53F2\u8A0E\u8AD6\u7684\u4E3B\u984C\u3002
|
|
16503
17241
|
|
|
16504
17242
|
\u9069\u7528\u5834\u666F\uFF1A
|
|
16505
17243
|
1. \u4E86\u89E3\u7FA4\u88E1\u6700\u8FD1\u5728\u804A\u4EC0\u9EBC\u8A71\u984C
|
|
16506
17244
|
2. \u6309\u95DC\u9375\u8A5E\u641C\u5C0B\u8A0E\u8AD6\u904E\u7684\u8A71\u984C
|
|
16507
17245
|
3. \u6982\u89BD\u6027\u554F\u984C\u5982\u300C\u7FA4\u88E1\u6709\u6C92\u6709\u8A0E\u8AD6\u904E\u65C5\u904A\u300D
|
|
16508
17246
|
|
|
16509
|
-
\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
|
|
17247
|
+
\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`,
|
|
16510
17248
|
params: {
|
|
16511
17249
|
keywords: "\u5728\u6458\u8981\u4E2D\u641C\u5C0B\u7684\u95DC\u9375\u8A5E\u6E05\u55AE\uFF08OR \u908F\u8F2F\u5339\u914D\uFF09",
|
|
16512
17250
|
limit: "\u56DE\u50B3\u6703\u8A71\u6578\u91CF\u9650\u5236\uFF0C\u9810\u8A2D 20",
|
|
@@ -16634,9 +17372,10 @@ var zh_TW_default = {
|
|
|
16634
17372
|
params: {}
|
|
16635
17373
|
},
|
|
16636
17374
|
render_chart: {
|
|
16637
|
-
desc: "\u6839\u64DA
|
|
17375
|
+
desc: "\u6839\u64DA ChartSpec v1 \u751F\u6210 ChatLab \u539F\u751F\u5716\u8868\u3002\u652F\u63F4 bar\u3001line\u3001pie\u3001heatmap\u3002\u63D0\u4F9B `rows`\uFF08\u4F86\u81EA\u9AD8\u5C64\u5DE5\u5177\u7684\u8CC7\u6599\u9663\u5217\uFF0C\u5982 get_time_stats \u7684 `data` \u6B04\u4F4D\uFF09\u6216 `sql`\uFF08\u552F\u8B80 SELECT\uFF09\u4E8C\u64C7\u4E00\uFF1B\u6709\u73FE\u6210\u8CC7\u6599\u6642\u512A\u5148\u7528 `rows`\uFF0C\u50C5\u5728\u9AD8\u5C64\u5DE5\u5177\u7121\u6CD5\u6EFF\u8DB3\u9700\u6C42\u6642\u624D\u5BEB `sql`\u3002\u7981\u6B62\u8F38\u51FA HTML\u3001JavaScript\u3001SVG\u3001ECharts option \u6216\u6E32\u67D3\u7A0B\u5F0F\u78BC\u3002",
|
|
16638
17376
|
params: {
|
|
16639
|
-
|
|
17377
|
+
rows: "\u4F86\u81EA\u9AD8\u5C64\u5DE5\u5177\u8FD4\u56DE\u7684\u8CC7\u6599\u9663\u5217\uFF08\u5982 get_time_stats \u7684 `data` \u6B04\u4F4D\uFF09\u3002\u6709\u73FE\u6210\u8CC7\u6599\u6642\u512A\u5148\u4F7F\u7528\uFF0C\u8207 sql \u4E8C\u64C7\u4E00\u3002",
|
|
17378
|
+
sql: "\u552F\u8B80 SELECT \u6216 WITH SELECT SQL\u3002\u50C5\u5728\u9AD8\u5C64\u5DE5\u5177\u7121\u6CD5\u6EFF\u8DB3\u9700\u6C42\u6642\u4F7F\u7528\uFF0C\u5FC5\u9808\u8FD4\u56DE ChartSpec encoding \u4E2D\u5F15\u7528\u7684\u6B04\u4F4D\u3002",
|
|
16640
17379
|
params: "SQL \u547D\u540D\u53C3\u6578\u7269\u4EF6\uFF1B\u4E0D\u9700\u8981\u53C3\u6578\u6642\u50B3\u7A7A\u7269\u4EF6\u3002",
|
|
16641
17380
|
chartSpec: "ChartSpec v1\uFF0C\u5305\u542B version\u3001type\u3001title\u3001encoding\u3002",
|
|
16642
17381
|
maxRows: "\u5716\u8868\u67E5\u8A62\u6700\u5927\u884C\u6578\uFF0C\u9810\u8A2D 1000\u3002"
|
|
@@ -16670,6 +17409,35 @@ var zh_TW_default = {
|
|
|
16670
17409
|
timeParamsIntro: '\u6642\u9593\u53C3\u6578\uFF1A\u4F7F\u7528 start_time/end_time \u6307\u5B9A\u6642\u9593\u7BC4\u570D\uFF0C\u683C\u5F0F "YYYY-MM-DD HH:mm"',
|
|
16671
17410
|
defaultYearNote: "\u672A\u6307\u5B9A\u6642\u9593\u7BC4\u570D\u6642\u9810\u8A2D\u67E5\u8A62\u5168\u90E8\u3002\u7576\u524D\u5E74\u4EFD\u70BA{{year}}\u5E74",
|
|
16672
17411
|
dataSnapshotNote: "\u76EE\u524D\u804A\u5929\u8CC7\u6599\u5EAB\u5FEB\u7167\uFF1A{{name}}\uFF08{{platform}}\uFF09\uFF0C\u7E3D\u8A0A\u606F {{totalMessages}} \u689D\uFF0C\u6210\u54E1 {{totalMembers}} \u4EBA\uFF0C\u6642\u9593\u7BC4\u570D {{firstMessageDate}} ~ {{lastMessageDate}}\u3002\u8A72\u5FEB\u7167\u53EA\u7528\u65BC\u5224\u65B7\u8CC7\u6599\u7BC4\u570D\uFF1B\u56DE\u7B54\u5177\u9AD4\u804A\u5929\u4E8B\u5BE6\u4ECD\u5FC5\u9808\u547C\u53EB\u5DE5\u5177\u6AA2\u7D22\u76EE\u524D\u8CC7\u6599\u5EAB\u3002",
|
|
17412
|
+
dataSnapshotContext: `\u76EE\u524D\u804A\u5929\u8CC7\u6599\u5EAB\u555F\u52D5\u4E0A\u4E0B\u6587\uFF1A
|
|
17413
|
+
- name: {{name}}
|
|
17414
|
+
- platform: {{platform}}
|
|
17415
|
+
- type: {{type}}
|
|
17416
|
+
- total_messages: {{totalMessages}}
|
|
17417
|
+
- total_members: {{totalMembers}}
|
|
17418
|
+
- first_message_ts: {{firstMessageTs}}
|
|
17419
|
+
- first_message_time: {{firstMessageTime}}
|
|
17420
|
+
- last_message_ts: {{lastMessageTs}}
|
|
17421
|
+
- last_message_time: {{lastMessageTime}}
|
|
17422
|
+
- segment_summaries_available: {{segmentSummaryCount}}
|
|
17423
|
+
|
|
17424
|
+
{{memberHintTitle}}
|
|
17425
|
+
{{memberHintLines}}
|
|
17426
|
+
|
|
17427
|
+
\u4F7F\u7528\u898F\u5247\uFF1A
|
|
17428
|
+
{{usageRules}}`,
|
|
17429
|
+
dataSnapshotMemberHintsAll: "\u6D3B\u8E8D\u6210\u54E1\u67E5\u8A62\u63D0\u793A\uFF08\u5168\u90E8\u6210\u54E1\uFF09\uFF1A",
|
|
17430
|
+
dataSnapshotMemberHintsTop: "\u6D3B\u8E8D\u6210\u54E1\u67E5\u8A62\u63D0\u793A\uFF08\u6309\u6B77\u53F2\u7E3D\u8A0A\u606F\u91CF Top 10\uFF09\uFF1A",
|
|
17431
|
+
dataSnapshotMemberHintsUnavailable: "\u6D3B\u8E8D\u6210\u54E1\u67E5\u8A62\u63D0\u793A\uFF1A",
|
|
17432
|
+
dataSnapshotMemberHintsEmpty: "\u7121\u53EF\u7528\u6210\u54E1\u63D0\u793A\u3002",
|
|
17433
|
+
dataSnapshotUsageRules: `- member_id \u662F\u5DE5\u5177\u67E5\u8A62\u63D0\u793A\uFF1Bdisplay_name \u50C5\u7528\u65BC\u4EBA\u985E\u8B58\u5225\uFF0C\u53EF\u80FD\u4E0D\u552F\u4E00\u3002
|
|
17434
|
+
- \u4E0D\u8981\u5728\u6700\u7D42\u56DE\u7B54\u4E2D\u4E3B\u52D5\u66B4\u9732 member_id \u6216\u555F\u52D5\u4E0A\u4E0B\u6587\u672C\u8EAB\uFF0C\u9664\u975E\u4F7F\u7528\u8005\u660E\u78BA\u8981\u6C42\u6280\u8853\u7D30\u7BC0\u3002
|
|
17435
|
+
- \u6D3B\u8E8D\u6210\u54E1\u6392\u884C\u53EA\u4EE3\u8868\u6B77\u53F2\u7E3D\u8A0A\u606F\u91CF\uFF0C\u4E0D\u4EE3\u8868\u8FD1\u671F\u6D3B\u8E8D\u60C5\u6CC1\uFF1B\u4E5F\u4E0D\u8DB3\u4EE5\u4F5C\u70BA\u5F71\u97FF\u529B\u3001\u95DC\u4FC2\u6216\u8FD1\u671F\u8DA8\u52E2\u7D50\u8AD6\u7684\u8B49\u64DA\u3002
|
|
17436
|
+
- \u76F8\u5C0D\u6642\u9593\u8868\u9054\u4EE5\u771F\u5BE6\u76EE\u524D\u65E5\u671F\u70BA\u57FA\u6E96\uFF0C\u800C\u4E0D\u662F\u8CC7\u6599\u5EAB\u6700\u5F8C\u8A0A\u606F\u6642\u9593\u3002
|
|
17437
|
+
-\u300C\u6700\u8FD1\u4E00\u5E74/\u904E\u53BB\u4E00\u5E74\u300D\u8868\u793A\u5F9E\u771F\u5BE6\u76EE\u524D\u65E5\u671F\u56DE\u63A8\u4E00\u5E74\u5230\u4ECA\u5929\uFF1B\u300C\u53BB\u5E74\u300D\u8868\u793A\u4E0A\u4E00\u81EA\u7136\u5E74\u3002
|
|
17438
|
+
- \u8CC7\u6599\u5EAB\u6642\u9593\u908A\u754C\u53EA\u7528\u65BC\u8AAA\u660E\u8986\u84CB\u7BC4\u570D\uFF0C\u4E0D\u7528\u65BC\u91CD\u5B9A\u7FA9\u4F7F\u7528\u8005\u8981\u6C42\u7684\u6642\u9593\u7BC4\u570D\u3002
|
|
17439
|
+
- \u4F7F\u7528\u9810\u8A2D\u300C\u8FD1 N \u5929\u300D\u7684\u5DE5\u5177\u6642\uFF0C\u5148\u9078\u64C7\u8207\u8CC7\u6599\u5EAB\u6642\u9593\u908A\u754C\u6709\u4EA4\u96C6\u7684\u7BC4\u570D\uFF0C\u4E0D\u8981\u5148\u63A2\u6E2C\u771F\u5BE6\u76EE\u524D\u65E5\u671F\u8996\u7A97\u5C0E\u81F4\u7A7A\u7D50\u679C\u3002
|
|
17440
|
+
- \u4E0D\u8981\u53EA\u70BA\u4E86\u91CD\u65B0\u767C\u73FE min/max timestamp \u547C\u53EB\u5DE5\u5177\uFF1B\u4F46\u56DE\u7B54\u5177\u9AD4\u804A\u5929\u4E8B\u5BE6\u3001\u7D71\u8A08\u548C\u7D50\u8AD6\u4ECD\u5FC5\u9808\u547C\u53EB\u5DE5\u5177\u53D6\u5F97\u8B49\u64DA\u3002`,
|
|
16673
17441
|
evidencePolicy: `\u8B49\u64DA\u7B56\u7565\uFF1A
|
|
16674
17442
|
- AI \u5C0D\u8A71\u6B77\u53F2\u3001\u6B77\u53F2 AI \u56DE\u8986\u548C\u58D3\u7E2E\u6458\u8981\u53EA\u7528\u65BC\u7406\u89E3\u4F7F\u7528\u8005\u610F\u5716\uFF0C\u4E0D\u80FD\u4F5C\u70BA\u804A\u5929\u7D00\u9304\u4E8B\u5BE6\u8B49\u64DA\u3002
|
|
16675
17443
|
- \u53EA\u8981\u4F7F\u7528\u8005\u8A62\u554F\u804A\u5929\u7D00\u9304\u5167\u5BB9\u3001\u6700\u8FD1\u804A\u4EC0\u9EBC\u3001\u67D0\u4EBA\u8AAA\u904E\u4EC0\u9EBC\u3001\u7D71\u8A08\u6392\u884C\u3001\u662F\u5426\u51FA\u73FE\u904E\u67D0\u8A71\u984C\u6216\u8981\u6C42\u5F15\u7528\u539F\u8A71\uFF0C\u5FC5\u9808\u5148\u547C\u53EB\u5408\u9069\u7684\u8CC7\u6599\u5DE5\u5177\u6AA2\u7D22\u76EE\u524D\u8CC7\u6599\u5EAB\u3002
|
|
@@ -16708,10 +17476,10 @@ var zh_TW_default = {
|
|
|
16708
17476
|
rawErrorLabel: "\u539F\u59CB\u932F\u8AA4"
|
|
16709
17477
|
},
|
|
16710
17478
|
summary: {
|
|
16711
|
-
|
|
17479
|
+
segmentNotFound: "\u6703\u8A71\u4E0D\u5B58\u5728\u6216\u8CC7\u6599\u5EAB\u958B\u555F\u5931\u6557",
|
|
16712
17480
|
tooFewMessages: "\u8A0A\u606F\u6578\u91CF\u5C11\u65BC {{count}} \u689D\uFF0C\u7121\u9700\u7522\u751F\u6458\u8981",
|
|
16713
17481
|
tooFewValidMessages: "\u6709\u6548\u8A0A\u606F\u6578\u91CF\u5C11\u65BC {{count}} \u689D\uFF0C\u7121\u9700\u7522\u751F\u6458\u8981",
|
|
16714
|
-
|
|
17482
|
+
segmentNotExist: "\u627E\u4E0D\u5230\u6703\u8A71",
|
|
16715
17483
|
messagesTooFew: "\u8A0A\u606F\u592A\u5C11",
|
|
16716
17484
|
validMessagesTooFew: "\u6709\u6548\u8A0A\u606F\u592A\u5C11",
|
|
16717
17485
|
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",
|
|
@@ -16726,9 +17494,9 @@ var localeMap = {
|
|
|
16726
17494
|
"ja-JP": ja_JP_default,
|
|
16727
17495
|
"zh-TW": zh_TW_default
|
|
16728
17496
|
};
|
|
16729
|
-
function getNestedValue(obj,
|
|
17497
|
+
function getNestedValue(obj, path36) {
|
|
16730
17498
|
let current = obj;
|
|
16731
|
-
for (const segment2 of
|
|
17499
|
+
for (const segment2 of path36.split(".")) {
|
|
16732
17500
|
if (current == null || typeof current !== "object") return void 0;
|
|
16733
17501
|
current = current[segment2];
|
|
16734
17502
|
}
|
|
@@ -16924,15 +17692,15 @@ function postProcessSummary(summary, lengthLimit) {
|
|
|
16924
17692
|
}
|
|
16925
17693
|
return result;
|
|
16926
17694
|
}
|
|
16927
|
-
async function generateSessionSummary(deps,
|
|
17695
|
+
async function generateSessionSummary(deps, segmentId, options = {}) {
|
|
16928
17696
|
const { locale = "zh-CN", forceRegenerate = false, strategy = "standard" } = options;
|
|
16929
17697
|
const log = deps.logger;
|
|
16930
17698
|
try {
|
|
16931
17699
|
if (!forceRegenerate) {
|
|
16932
|
-
const existing = deps.getSummary(
|
|
17700
|
+
const existing = deps.getSummary(segmentId);
|
|
16933
17701
|
if (existing) return { success: true, summary: existing };
|
|
16934
17702
|
}
|
|
16935
|
-
const rawMessages = deps.loadMessages(
|
|
17703
|
+
const rawMessages = deps.loadMessages(segmentId);
|
|
16936
17704
|
if (!rawMessages) {
|
|
16937
17705
|
return { success: false, error: deps.t("summary.sessionNotFound") };
|
|
16938
17706
|
}
|
|
@@ -16949,7 +17717,7 @@ async function generateSessionSummary(deps, chatSessionId, options = {}) {
|
|
|
16949
17717
|
const content = formatMessages(validMessages);
|
|
16950
17718
|
log?.info(
|
|
16951
17719
|
"Summary",
|
|
16952
|
-
`Generating summary: sessionId=${
|
|
17720
|
+
`Generating summary: sessionId=${segmentId}, strategy=${strategy}, raw=${rawMessages.length}, valid=${validMessages.length}, chars=${content.length}`
|
|
16953
17721
|
);
|
|
16954
17722
|
let summary;
|
|
16955
17723
|
if (content.length <= SEGMENT_THRESHOLD) {
|
|
@@ -16984,7 +17752,7 @@ async function generateSessionSummary(deps, chatSessionId, options = {}) {
|
|
|
16984
17752
|
}
|
|
16985
17753
|
}
|
|
16986
17754
|
summary = postProcessSummary(summary, lengthLimit);
|
|
16987
|
-
deps.saveSummary(
|
|
17755
|
+
deps.saveSummary(segmentId, summary);
|
|
16988
17756
|
log?.info("Summary", `Summary generated: "${summary.slice(0, 50)}..."`);
|
|
16989
17757
|
return { success: true, summary };
|
|
16990
17758
|
} catch (error) {
|
|
@@ -16992,9 +17760,9 @@ async function generateSessionSummary(deps, chatSessionId, options = {}) {
|
|
|
16992
17760
|
return { success: false, error: error instanceof Error ? error.message : String(error) };
|
|
16993
17761
|
}
|
|
16994
17762
|
}
|
|
16995
|
-
function checkSessionsCanGenerateSummary(deps,
|
|
17763
|
+
function checkSessionsCanGenerateSummary(deps, segmentIds) {
|
|
16996
17764
|
const results = /* @__PURE__ */ new Map();
|
|
16997
|
-
for (const id of
|
|
17765
|
+
for (const id of segmentIds) {
|
|
16998
17766
|
const messages = deps.loadMessages(id);
|
|
16999
17767
|
if (!messages) {
|
|
17000
17768
|
results.set(id, { canGenerate: false, reason: deps.t("summary.sessionNotExist") });
|
|
@@ -17110,7 +17878,7 @@ function buildPiModel(config, options) {
|
|
|
17110
17878
|
}
|
|
17111
17879
|
|
|
17112
17880
|
// ../../packages/node-runtime/src/ai/remote-api.ts
|
|
17113
|
-
import { completeSimple as
|
|
17881
|
+
import { completeSimple as completeSimple4 } from "@earendil-works/pi-ai";
|
|
17114
17882
|
async function fetchRemoteModels(provider, apiKey, baseUrl, apiFormat, options) {
|
|
17115
17883
|
const effectiveApiFormat = apiFormat || "openai-completions";
|
|
17116
17884
|
if (effectiveApiFormat === "anthropic-messages") {
|
|
@@ -17194,7 +17962,7 @@ async function validateApiKey(provider, apiKey, baseUrl, model, apiFormat, optio
|
|
|
17194
17962
|
const abortController = new AbortController();
|
|
17195
17963
|
const timeout = setTimeout(() => abortController.abort(), 15e3);
|
|
17196
17964
|
try {
|
|
17197
|
-
const result = await
|
|
17965
|
+
const result = await completeSimple4(
|
|
17198
17966
|
piModel,
|
|
17199
17967
|
{ messages: [{ role: "user", content: "Hi", timestamp: Date.now() }] },
|
|
17200
17968
|
{ apiKey, maxTokens: 1, signal: abortController.signal }
|
|
@@ -17215,7 +17983,7 @@ async function validateApiKey(provider, apiKey, baseUrl, model, apiFormat, optio
|
|
|
17215
17983
|
}
|
|
17216
17984
|
|
|
17217
17985
|
// ../../packages/node-runtime/src/ai/llm-stream.ts
|
|
17218
|
-
import { streamSimple } from "@earendil-works/pi-ai";
|
|
17986
|
+
import { streamSimple as streamSimple2 } from "@earendil-works/pi-ai";
|
|
17219
17987
|
function toPiMessages(messages, timestamp) {
|
|
17220
17988
|
return messages.map((m) => ({
|
|
17221
17989
|
role: m.role,
|
|
@@ -17228,7 +17996,7 @@ async function runSimpleLlmStream(options) {
|
|
|
17228
17996
|
const systemMsg = messages.find((m) => m.role === "system");
|
|
17229
17997
|
const nonSystemMsgs = messages.filter((m) => m.role !== "system");
|
|
17230
17998
|
const now = Date.now();
|
|
17231
|
-
const eventStream =
|
|
17999
|
+
const eventStream = streamSimple2(
|
|
17232
18000
|
piModel,
|
|
17233
18001
|
{
|
|
17234
18002
|
systemPrompt: systemMsg?.content,
|
|
@@ -17286,7 +18054,7 @@ async function runSimpleLlmStream(options) {
|
|
|
17286
18054
|
}
|
|
17287
18055
|
|
|
17288
18056
|
// ../../packages/node-runtime/src/ai/index.ts
|
|
17289
|
-
import { Type, completeSimple as
|
|
18057
|
+
import { Type, completeSimple as completeSimple6, streamSimple as streamSimple3 } from "@earendil-works/pi-ai";
|
|
17290
18058
|
|
|
17291
18059
|
// ../../packages/node-runtime/src/ai/rag/types.ts
|
|
17292
18060
|
var noopLogger = {
|
|
@@ -17305,7 +18073,7 @@ function getNoopLogger() {
|
|
|
17305
18073
|
var _logger = getNoopLogger();
|
|
17306
18074
|
|
|
17307
18075
|
// ../../packages/node-runtime/src/ai/rag/chunking/session.ts
|
|
17308
|
-
import
|
|
18076
|
+
import Database2 from "better-sqlite3";
|
|
17309
18077
|
var _logger2 = getNoopLogger();
|
|
17310
18078
|
|
|
17311
18079
|
// ../../packages/node-runtime/src/ai/rag/embedding/openai-compatible.ts
|
|
@@ -17315,7 +18083,7 @@ var _logger3 = getNoopLogger();
|
|
|
17315
18083
|
var _logger4 = getNoopLogger();
|
|
17316
18084
|
|
|
17317
18085
|
// ../../packages/node-runtime/src/ai/rag/store/sqlite.ts
|
|
17318
|
-
import
|
|
18086
|
+
import Database3 from "better-sqlite3";
|
|
17319
18087
|
var _logger5 = getNoopLogger();
|
|
17320
18088
|
|
|
17321
18089
|
// ../../packages/node-runtime/src/ai/rag/store/memory.ts
|
|
@@ -17325,7 +18093,7 @@ var _logger6 = getNoopLogger();
|
|
|
17325
18093
|
var _logger7 = getNoopLogger();
|
|
17326
18094
|
|
|
17327
18095
|
// ../../packages/node-runtime/src/ai/rag/pipeline/semantic.ts
|
|
17328
|
-
import { completeSimple as
|
|
18096
|
+
import { completeSimple as completeSimple5 } from "@earendil-works/pi-ai";
|
|
17329
18097
|
var _logger8 = getNoopLogger();
|
|
17330
18098
|
|
|
17331
18099
|
// ../../packages/node-runtime/src/migrations/electron-data-migration.ts
|
|
@@ -17840,7 +18608,216 @@ function expandHome(filePath) {
|
|
|
17840
18608
|
return filePath;
|
|
17841
18609
|
}
|
|
17842
18610
|
|
|
18611
|
+
// ../../packages/node-runtime/src/data-dir-compat.ts
|
|
18612
|
+
import fs34 from "fs";
|
|
18613
|
+
import path31 from "path";
|
|
18614
|
+
var DataDirCompatibilityError = class extends Error {
|
|
18615
|
+
code;
|
|
18616
|
+
userDataDir;
|
|
18617
|
+
metaPath;
|
|
18618
|
+
currentVersion;
|
|
18619
|
+
minRuntimeVersion;
|
|
18620
|
+
statusCode = 409;
|
|
18621
|
+
constructor(code, message, options) {
|
|
18622
|
+
super(message, { cause: options.cause });
|
|
18623
|
+
this.name = "DataDirCompatibilityError";
|
|
18624
|
+
this.code = code;
|
|
18625
|
+
this.userDataDir = options.userDataDir;
|
|
18626
|
+
this.metaPath = options.metaPath;
|
|
18627
|
+
this.currentVersion = options.currentVersion;
|
|
18628
|
+
this.minRuntimeVersion = options.minRuntimeVersion;
|
|
18629
|
+
}
|
|
18630
|
+
};
|
|
18631
|
+
function readDataDirCompatibilityMeta(userDataDir) {
|
|
18632
|
+
const metaPath = getMetaPath(userDataDir);
|
|
18633
|
+
if (!fs34.existsSync(metaPath)) return null;
|
|
18634
|
+
let parsed;
|
|
18635
|
+
try {
|
|
18636
|
+
parsed = JSON.parse(fs34.readFileSync(metaPath, "utf-8"));
|
|
18637
|
+
} catch (error) {
|
|
18638
|
+
throw createInvalidMetaError(userDataDir, metaPath, "Invalid data directory compatibility meta JSON.", error);
|
|
18639
|
+
}
|
|
18640
|
+
return validateDataDirCompatibilityMeta(parsed, userDataDir, metaPath);
|
|
18641
|
+
}
|
|
18642
|
+
function assertDataDirCompatible(pathProvider, runtime, options = {}) {
|
|
18643
|
+
const userDataDir = pathProvider.getUserDataDir();
|
|
18644
|
+
const meta = readDataDirCompatibilityMeta(userDataDir);
|
|
18645
|
+
if (!meta) return;
|
|
18646
|
+
if (!isStableSemver(runtime.version)) {
|
|
18647
|
+
throw new DataDirCompatibilityError(
|
|
18648
|
+
"DATA_DIR_REQUIRES_NEWER_RUNTIME",
|
|
18649
|
+
`ChatLab data directory compatibility check requires a stable runtime version; current version is ${runtime.version}.`,
|
|
18650
|
+
{
|
|
18651
|
+
userDataDir,
|
|
18652
|
+
metaPath: getMetaPath(userDataDir),
|
|
18653
|
+
currentVersion: runtime.version,
|
|
18654
|
+
minRuntimeVersion: meta.minRuntimeVersion
|
|
18655
|
+
}
|
|
18656
|
+
);
|
|
18657
|
+
}
|
|
18658
|
+
if (compareStableSemver(runtime.version, meta.minRuntimeVersion) < 0) {
|
|
18659
|
+
const env = options.env ?? process.env;
|
|
18660
|
+
if (env.CHATLAB_ALLOW_INCOMPATIBLE_DATA_DIR === "1") {
|
|
18661
|
+
const warn = options.warn ?? console.warn;
|
|
18662
|
+
warn(
|
|
18663
|
+
[
|
|
18664
|
+
"CHATLAB_ALLOW_INCOMPATIBLE_DATA_DIR=1 is set. ChatLab will bypass the data directory runtime version gate.",
|
|
18665
|
+
`Current runtime ${runtime.kind}@${runtime.version} is below required version ${meta.minRuntimeVersion}.`,
|
|
18666
|
+
`Data directory: ${userDataDir}. Continuing may risk data corruption.`
|
|
18667
|
+
].join(" ")
|
|
18668
|
+
);
|
|
18669
|
+
return;
|
|
18670
|
+
}
|
|
18671
|
+
throw new DataDirCompatibilityError(
|
|
18672
|
+
"DATA_DIR_REQUIRES_NEWER_RUNTIME",
|
|
18673
|
+
`ChatLab data directory requires runtime version ${meta.minRuntimeVersion} or newer; current version is ${runtime.version}.`,
|
|
18674
|
+
{
|
|
18675
|
+
userDataDir,
|
|
18676
|
+
metaPath: getMetaPath(userDataDir),
|
|
18677
|
+
currentVersion: runtime.version,
|
|
18678
|
+
minRuntimeVersion: meta.minRuntimeVersion
|
|
18679
|
+
}
|
|
18680
|
+
);
|
|
18681
|
+
}
|
|
18682
|
+
}
|
|
18683
|
+
function raiseDataDirMinRuntimeVersion(pathProvider, input) {
|
|
18684
|
+
const userDataDir = pathProvider.getUserDataDir();
|
|
18685
|
+
const metaPath = getMetaPath(userDataDir);
|
|
18686
|
+
assertStableVersion(input.minRuntimeVersion, userDataDir, metaPath, "Invalid minRuntimeVersion.");
|
|
18687
|
+
assertStableVersion(input.runtime.version, userDataDir, metaPath, "Invalid runtime version.");
|
|
18688
|
+
if (!isRuntimeKind(input.runtime.kind)) {
|
|
18689
|
+
throw createInvalidMetaError(userDataDir, metaPath, "Invalid runtime kind.");
|
|
18690
|
+
}
|
|
18691
|
+
if (!isNonEmptyString(input.module) || !isNonEmptyString(input.reason)) {
|
|
18692
|
+
throw createInvalidMetaError(userDataDir, metaPath, "Invalid compatibility raise metadata.");
|
|
18693
|
+
}
|
|
18694
|
+
if (!Number.isInteger(input.dataCompatibilityVersion) || input.dataCompatibilityVersion < 0) {
|
|
18695
|
+
throw createInvalidMetaError(userDataDir, metaPath, "Invalid dataCompatibilityVersion.");
|
|
18696
|
+
}
|
|
18697
|
+
const existing = readDataDirCompatibilityMeta(userDataDir);
|
|
18698
|
+
const minRuntimeVersion = existing && compareStableSemver(existing.minRuntimeVersion, input.minRuntimeVersion) > 0 ? existing.minRuntimeVersion : input.minRuntimeVersion;
|
|
18699
|
+
const dataCompatibilityVersion = Math.max(existing?.dataCompatibilityVersion ?? 0, input.dataCompatibilityVersion);
|
|
18700
|
+
const reasons = mergeReasons(existing?.reasons ?? [], input.reason);
|
|
18701
|
+
const now = input.now ?? (() => Math.floor(Date.now() / 1e3));
|
|
18702
|
+
const nextMeta = {
|
|
18703
|
+
formatVersion: 1,
|
|
18704
|
+
minRuntimeVersion,
|
|
18705
|
+
dataCompatibilityVersion,
|
|
18706
|
+
reasons,
|
|
18707
|
+
updatedBy: {
|
|
18708
|
+
runtime: input.runtime.kind,
|
|
18709
|
+
module: input.module,
|
|
18710
|
+
version: input.runtime.version
|
|
18711
|
+
},
|
|
18712
|
+
updatedAt: now()
|
|
18713
|
+
};
|
|
18714
|
+
writeMetaAtomic(userDataDir, metaPath, nextMeta);
|
|
18715
|
+
return nextMeta;
|
|
18716
|
+
}
|
|
18717
|
+
function getMetaPath(userDataDir) {
|
|
18718
|
+
return path31.join(userDataDir, ".chatlab-meta.json");
|
|
18719
|
+
}
|
|
18720
|
+
function validateDataDirCompatibilityMeta(value, userDataDir, metaPath) {
|
|
18721
|
+
if (!isRecord3(value)) {
|
|
18722
|
+
throw createInvalidMetaError(userDataDir, metaPath, "Data directory compatibility meta must be an object.");
|
|
18723
|
+
}
|
|
18724
|
+
if (value.formatVersion !== 1) {
|
|
18725
|
+
throw createInvalidMetaError(userDataDir, metaPath, "Unsupported data directory compatibility meta format.");
|
|
18726
|
+
}
|
|
18727
|
+
const minRuntimeVersion = value.minRuntimeVersion;
|
|
18728
|
+
const dataCompatibilityVersion = value.dataCompatibilityVersion;
|
|
18729
|
+
const reasons = value.reasons;
|
|
18730
|
+
const updatedBy = value.updatedBy;
|
|
18731
|
+
const updatedAt = value.updatedAt;
|
|
18732
|
+
if (!isStableSemver(minRuntimeVersion) || typeof dataCompatibilityVersion !== "number" || !Number.isInteger(dataCompatibilityVersion) || dataCompatibilityVersion < 0 || !Array.isArray(reasons) || !reasons.every(isNonEmptyString) || !isRecord3(updatedBy) || !isRuntimeKind(updatedBy.runtime) || !isNonEmptyString(updatedBy.module) || !isStableSemver(updatedBy.version) || typeof updatedAt !== "number" || !Number.isInteger(updatedAt) || updatedAt < 0) {
|
|
18733
|
+
throw createInvalidMetaError(userDataDir, metaPath, "Invalid data directory compatibility meta fields.");
|
|
18734
|
+
}
|
|
18735
|
+
return {
|
|
18736
|
+
formatVersion: 1,
|
|
18737
|
+
minRuntimeVersion,
|
|
18738
|
+
dataCompatibilityVersion,
|
|
18739
|
+
reasons: [...reasons],
|
|
18740
|
+
updatedBy: {
|
|
18741
|
+
runtime: updatedBy.runtime,
|
|
18742
|
+
module: updatedBy.module,
|
|
18743
|
+
version: updatedBy.version
|
|
18744
|
+
},
|
|
18745
|
+
updatedAt
|
|
18746
|
+
};
|
|
18747
|
+
}
|
|
18748
|
+
function createInvalidMetaError(userDataDir, metaPath, message, cause) {
|
|
18749
|
+
return new DataDirCompatibilityError("DATA_DIR_COMPATIBILITY_META_INVALID", message, {
|
|
18750
|
+
userDataDir,
|
|
18751
|
+
metaPath,
|
|
18752
|
+
cause
|
|
18753
|
+
});
|
|
18754
|
+
}
|
|
18755
|
+
function assertStableVersion(version, userDataDir, metaPath, message) {
|
|
18756
|
+
if (!isStableSemver(version)) {
|
|
18757
|
+
throw createInvalidMetaError(userDataDir, metaPath, message);
|
|
18758
|
+
}
|
|
18759
|
+
}
|
|
18760
|
+
function isStableSemver(version) {
|
|
18761
|
+
return typeof version === "string" && /^\d+\.\d+\.\d+$/.test(version);
|
|
18762
|
+
}
|
|
18763
|
+
function compareStableSemver(left, right) {
|
|
18764
|
+
const leftParts = left.split(".").map(Number);
|
|
18765
|
+
const rightParts = right.split(".").map(Number);
|
|
18766
|
+
for (let i = 0; i < 3; i += 1) {
|
|
18767
|
+
if (leftParts[i] > rightParts[i]) return 1;
|
|
18768
|
+
if (leftParts[i] < rightParts[i]) return -1;
|
|
18769
|
+
}
|
|
18770
|
+
return 0;
|
|
18771
|
+
}
|
|
18772
|
+
function mergeReasons(existing, next) {
|
|
18773
|
+
return [.../* @__PURE__ */ new Set([...existing, next])];
|
|
18774
|
+
}
|
|
18775
|
+
function writeMetaAtomic(userDataDir, metaPath, meta) {
|
|
18776
|
+
fs34.mkdirSync(userDataDir, { recursive: true });
|
|
18777
|
+
const tempPath = path31.join(userDataDir, `.chatlab-meta.json.${process.pid}.${Date.now()}.tmp`);
|
|
18778
|
+
try {
|
|
18779
|
+
fs34.writeFileSync(tempPath, `${JSON.stringify(meta, null, 2)}
|
|
18780
|
+
`, "utf-8");
|
|
18781
|
+
fs34.renameSync(tempPath, metaPath);
|
|
18782
|
+
} catch (error) {
|
|
18783
|
+
try {
|
|
18784
|
+
if (fs34.existsSync(tempPath)) fs34.unlinkSync(tempPath);
|
|
18785
|
+
} catch {
|
|
18786
|
+
}
|
|
18787
|
+
throw error;
|
|
18788
|
+
}
|
|
18789
|
+
}
|
|
18790
|
+
function isRecord3(value) {
|
|
18791
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18792
|
+
}
|
|
18793
|
+
function isNonEmptyString(value) {
|
|
18794
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
18795
|
+
}
|
|
18796
|
+
function isRuntimeKind(value) {
|
|
18797
|
+
return value === "cli" || value === "desktop" || value === "mcp" || value === "unknown";
|
|
18798
|
+
}
|
|
18799
|
+
|
|
17843
18800
|
// ../../packages/node-runtime/src/migrations/chat-db-migrations.ts
|
|
18801
|
+
var CHAT_DB_COMPATIBILITY_RAISES = [
|
|
18802
|
+
{
|
|
18803
|
+
migrationVersion: 6,
|
|
18804
|
+
minRuntimeVersion: "0.25.1",
|
|
18805
|
+
dataCompatibilityVersion: 1,
|
|
18806
|
+
reason: "segment-schema",
|
|
18807
|
+
module: "chat-db-migration"
|
|
18808
|
+
}
|
|
18809
|
+
];
|
|
18810
|
+
function raiseChatDbCompatibilityGate(pathProvider, runtime) {
|
|
18811
|
+
for (const compatibilityRaise of CHAT_DB_COMPATIBILITY_RAISES) {
|
|
18812
|
+
raiseDataDirMinRuntimeVersion(pathProvider, {
|
|
18813
|
+
minRuntimeVersion: compatibilityRaise.minRuntimeVersion,
|
|
18814
|
+
dataCompatibilityVersion: compatibilityRaise.dataCompatibilityVersion,
|
|
18815
|
+
reason: compatibilityRaise.reason,
|
|
18816
|
+
runtime,
|
|
18817
|
+
module: compatibilityRaise.module
|
|
18818
|
+
});
|
|
18819
|
+
}
|
|
18820
|
+
}
|
|
17844
18821
|
function getChatDbMigrations(deps) {
|
|
17845
18822
|
const hasColumn2 = (db, tableName, columnName) => {
|
|
17846
18823
|
const tableInfo = db.pragma(`table_info(${tableName})`);
|
|
@@ -18015,13 +18992,120 @@ function getChatDbMigrations(deps) {
|
|
|
18015
18992
|
db.exec("CREATE INDEX IF NOT EXISTS idx_session_time ON chat_session(start_ts, end_ts)");
|
|
18016
18993
|
db.exec("CREATE INDEX IF NOT EXISTS idx_context_session ON message_context(session_id)");
|
|
18017
18994
|
}
|
|
18995
|
+
},
|
|
18996
|
+
{
|
|
18997
|
+
version: 6,
|
|
18998
|
+
description: "Rename chat_session index tables to segment terminology",
|
|
18999
|
+
up: (db) => {
|
|
19000
|
+
const hasTable2 = (tableName) => {
|
|
19001
|
+
const row = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name = ?").get(tableName);
|
|
19002
|
+
return !!row;
|
|
19003
|
+
};
|
|
19004
|
+
db.exec(`
|
|
19005
|
+
DROP INDEX IF EXISTS idx_session_time;
|
|
19006
|
+
DROP INDEX IF EXISTS idx_context_session;
|
|
19007
|
+
`);
|
|
19008
|
+
const hasLegacyChatSession = hasTable2("chat_session");
|
|
19009
|
+
const hasSegment = hasTable2("segment");
|
|
19010
|
+
if (hasLegacyChatSession && !hasSegment) {
|
|
19011
|
+
db.exec("ALTER TABLE chat_session RENAME TO segment");
|
|
19012
|
+
} else if (hasLegacyChatSession && hasSegment) {
|
|
19013
|
+
db.exec(`
|
|
19014
|
+
INSERT OR IGNORE INTO segment (id, start_ts, end_ts, message_count, is_manual, summary)
|
|
19015
|
+
SELECT id, start_ts, end_ts, message_count, is_manual, summary
|
|
19016
|
+
FROM chat_session;
|
|
19017
|
+
DROP TABLE chat_session;
|
|
19018
|
+
`);
|
|
19019
|
+
}
|
|
19020
|
+
if (hasTable2("message_context") && hasColumn2(db, "message_context", "session_id")) {
|
|
19021
|
+
db.exec("ALTER TABLE message_context RENAME COLUMN session_id TO segment_id");
|
|
19022
|
+
}
|
|
19023
|
+
db.exec(`
|
|
19024
|
+
CREATE TABLE IF NOT EXISTS segment (
|
|
19025
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
19026
|
+
start_ts INTEGER NOT NULL,
|
|
19027
|
+
end_ts INTEGER NOT NULL,
|
|
19028
|
+
message_count INTEGER DEFAULT 0,
|
|
19029
|
+
is_manual INTEGER DEFAULT 0,
|
|
19030
|
+
summary TEXT
|
|
19031
|
+
);
|
|
19032
|
+
|
|
19033
|
+
CREATE TABLE IF NOT EXISTS message_context (
|
|
19034
|
+
message_id INTEGER PRIMARY KEY,
|
|
19035
|
+
segment_id INTEGER NOT NULL,
|
|
19036
|
+
topic_id INTEGER
|
|
19037
|
+
);
|
|
19038
|
+
|
|
19039
|
+
CREATE INDEX IF NOT EXISTS idx_segment_time ON segment(start_ts, end_ts);
|
|
19040
|
+
CREATE INDEX IF NOT EXISTS idx_context_segment ON message_context(segment_id);
|
|
19041
|
+
`);
|
|
19042
|
+
}
|
|
18018
19043
|
}
|
|
18019
19044
|
];
|
|
18020
19045
|
}
|
|
18021
19046
|
|
|
18022
19047
|
// ../../packages/node-runtime/src/database-manager.ts
|
|
18023
|
-
import * as
|
|
18024
|
-
import * as
|
|
19048
|
+
import * as fs35 from "fs";
|
|
19049
|
+
import * as path32 from "path";
|
|
19050
|
+
|
|
19051
|
+
// ../../packages/node-runtime/src/better-sqlite3-adapter.ts
|
|
19052
|
+
import Database4 from "better-sqlite3";
|
|
19053
|
+
var BetterSqlitePreparedStatement = class {
|
|
19054
|
+
constructor(stmt) {
|
|
19055
|
+
this.stmt = stmt;
|
|
19056
|
+
this.readonly = stmt.readonly;
|
|
19057
|
+
}
|
|
19058
|
+
stmt;
|
|
19059
|
+
readonly;
|
|
19060
|
+
get(...params) {
|
|
19061
|
+
return this.stmt.get(...params);
|
|
19062
|
+
}
|
|
19063
|
+
all(...params) {
|
|
19064
|
+
return this.stmt.all(...params);
|
|
19065
|
+
}
|
|
19066
|
+
run(...params) {
|
|
19067
|
+
const result = this.stmt.run(...params);
|
|
19068
|
+
return {
|
|
19069
|
+
changes: result.changes,
|
|
19070
|
+
lastInsertRowid: result.lastInsertRowid
|
|
19071
|
+
};
|
|
19072
|
+
}
|
|
19073
|
+
};
|
|
19074
|
+
var BetterSqliteAdapter = class {
|
|
19075
|
+
constructor(db) {
|
|
19076
|
+
this.db = db;
|
|
19077
|
+
this.readonly = db.readonly;
|
|
19078
|
+
}
|
|
19079
|
+
db;
|
|
19080
|
+
readonly;
|
|
19081
|
+
exec(sql) {
|
|
19082
|
+
this.db.exec(sql);
|
|
19083
|
+
}
|
|
19084
|
+
prepare(sql) {
|
|
19085
|
+
return new BetterSqlitePreparedStatement(this.db.prepare(sql));
|
|
19086
|
+
}
|
|
19087
|
+
transaction(fn) {
|
|
19088
|
+
return this.db.transaction(fn)();
|
|
19089
|
+
}
|
|
19090
|
+
pragma(pragma) {
|
|
19091
|
+
return this.db.pragma(pragma);
|
|
19092
|
+
}
|
|
19093
|
+
close() {
|
|
19094
|
+
this.db.close();
|
|
19095
|
+
}
|
|
19096
|
+
};
|
|
19097
|
+
function openBetterSqliteDatabase(filePath, options) {
|
|
19098
|
+
const db = new Database4(filePath, {
|
|
19099
|
+
readonly: options?.readonly ?? false,
|
|
19100
|
+
nativeBinding: options?.nativeBinding
|
|
19101
|
+
});
|
|
19102
|
+
if (!options?.readonly) {
|
|
19103
|
+
db.pragma("journal_mode = WAL");
|
|
19104
|
+
}
|
|
19105
|
+
return new BetterSqliteAdapter(db);
|
|
19106
|
+
}
|
|
19107
|
+
|
|
19108
|
+
// ../../packages/node-runtime/src/database-manager.ts
|
|
18025
19109
|
function createMigrationDeps(overrides) {
|
|
18026
19110
|
return {
|
|
18027
19111
|
tokenizeForFts,
|
|
@@ -18029,25 +19113,32 @@ function createMigrationDeps(overrides) {
|
|
|
18029
19113
|
};
|
|
18030
19114
|
}
|
|
18031
19115
|
var DatabaseManager = class {
|
|
18032
|
-
constructor(pathProvider, options) {
|
|
19116
|
+
constructor(pathProvider, options = {}) {
|
|
18033
19117
|
this.pathProvider = pathProvider;
|
|
19118
|
+
if (!options.runtime && !options.allowMissingRuntimeForTests) {
|
|
19119
|
+
throw new Error("DatabaseManager runtime identity is required for data directory compatibility checks.");
|
|
19120
|
+
}
|
|
18034
19121
|
this.nativeBinding = options?.nativeBinding;
|
|
18035
19122
|
this.migrationDeps = createMigrationDeps(options?.migrationDeps);
|
|
19123
|
+
this.runtime = options?.runtime ?? null;
|
|
18036
19124
|
}
|
|
18037
19125
|
pathProvider;
|
|
18038
19126
|
cache = /* @__PURE__ */ new Map();
|
|
18039
19127
|
nativeBinding;
|
|
18040
19128
|
migrationDeps;
|
|
19129
|
+
runtime;
|
|
18041
19130
|
/**
|
|
18042
19131
|
* Open a session DB (read-only by default, cached).
|
|
18043
19132
|
*/
|
|
18044
19133
|
open(sessionId, options) {
|
|
19134
|
+
this.assertCompatible();
|
|
18045
19135
|
if (this.cache.has(sessionId)) {
|
|
18046
19136
|
return this.cache.get(sessionId);
|
|
18047
19137
|
}
|
|
18048
19138
|
const dbPath = this.getDbPath(sessionId);
|
|
18049
|
-
if (!
|
|
19139
|
+
if (!fs35.existsSync(dbPath)) return null;
|
|
18050
19140
|
this.migrateIfNeeded(dbPath);
|
|
19141
|
+
this.assertCompatible();
|
|
18051
19142
|
const adapter = openBetterSqliteDatabase(dbPath, {
|
|
18052
19143
|
readonly: options?.readonly ?? true,
|
|
18053
19144
|
nativeBinding: this.nativeBinding
|
|
@@ -18061,7 +19152,9 @@ var DatabaseManager = class {
|
|
|
18061
19152
|
nativeBinding: this.nativeBinding
|
|
18062
19153
|
});
|
|
18063
19154
|
try {
|
|
18064
|
-
if (!isChatSessionDb(readonlyAdapter)
|
|
19155
|
+
if (!isChatSessionDb(readonlyAdapter)) return;
|
|
19156
|
+
this.raiseCompatibilityGateIfNeeded(getSchemaVersion(readonlyAdapter));
|
|
19157
|
+
if (!needsMigration(readonlyAdapter, CURRENT_SCHEMA_VERSION)) return;
|
|
18065
19158
|
} finally {
|
|
18066
19159
|
readonlyAdapter.close();
|
|
18067
19160
|
}
|
|
@@ -18071,7 +19164,7 @@ var DatabaseManager = class {
|
|
|
18071
19164
|
});
|
|
18072
19165
|
try {
|
|
18073
19166
|
const migrations = getChatDbMigrations(this.migrationDeps);
|
|
18074
|
-
runMigrations(adapter, migrations);
|
|
19167
|
+
this.runMigrations(adapter, migrations);
|
|
18075
19168
|
} finally {
|
|
18076
19169
|
adapter.close();
|
|
18077
19170
|
}
|
|
@@ -18081,6 +19174,7 @@ var DatabaseManager = class {
|
|
|
18081
19174
|
* Falls back to `open(id, { readonly: false })` if migration is unnecessary.
|
|
18082
19175
|
*/
|
|
18083
19176
|
openWritable(sessionId) {
|
|
19177
|
+
this.assertCompatible();
|
|
18084
19178
|
const existing = this.cache.get(sessionId);
|
|
18085
19179
|
if (existing && !existing.readonly) return existing;
|
|
18086
19180
|
if (existing) {
|
|
@@ -18088,14 +19182,17 @@ var DatabaseManager = class {
|
|
|
18088
19182
|
this.cache.delete(sessionId);
|
|
18089
19183
|
}
|
|
18090
19184
|
const dbPath = this.getDbPath(sessionId);
|
|
18091
|
-
if (!
|
|
19185
|
+
if (!fs35.existsSync(dbPath)) return null;
|
|
18092
19186
|
const adapter = openBetterSqliteDatabase(dbPath, {
|
|
18093
19187
|
readonly: false,
|
|
18094
19188
|
nativeBinding: this.nativeBinding
|
|
18095
19189
|
});
|
|
18096
19190
|
if (needsMigration(adapter, CURRENT_SCHEMA_VERSION)) {
|
|
18097
19191
|
const migrations = getChatDbMigrations(this.migrationDeps);
|
|
18098
|
-
runMigrations(adapter, migrations);
|
|
19192
|
+
this.runMigrations(adapter, migrations);
|
|
19193
|
+
this.assertCompatible();
|
|
19194
|
+
} else {
|
|
19195
|
+
this.raiseCompatibilityGateIfNeeded(getSchemaVersion(adapter));
|
|
18099
19196
|
}
|
|
18100
19197
|
this.cache.set(sessionId, adapter);
|
|
18101
19198
|
return adapter;
|
|
@@ -18123,9 +19220,10 @@ var DatabaseManager = class {
|
|
|
18123
19220
|
* 列举数据库目录下的所有聊天会话 ID
|
|
18124
19221
|
*/
|
|
18125
19222
|
listSessionIds() {
|
|
19223
|
+
this.assertCompatible();
|
|
18126
19224
|
const dbDir = this.pathProvider.getDatabaseDir();
|
|
18127
|
-
if (!
|
|
18128
|
-
return
|
|
19225
|
+
if (!fs35.existsSync(dbDir)) return [];
|
|
19226
|
+
return fs35.readdirSync(dbDir).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", "")).filter((id) => {
|
|
18129
19227
|
const db = this.open(id);
|
|
18130
19228
|
if (!db) return false;
|
|
18131
19229
|
return isChatSessionDb(db);
|
|
@@ -18135,9 +19233,70 @@ var DatabaseManager = class {
|
|
|
18135
19233
|
* 获取数据库文件路径
|
|
18136
19234
|
*/
|
|
18137
19235
|
getDbPath(sessionId) {
|
|
18138
|
-
return
|
|
19236
|
+
return path32.join(this.pathProvider.getDatabaseDir(), `${sessionId}.db`);
|
|
19237
|
+
}
|
|
19238
|
+
openRawSessionDatabase(sessionId, options = {}) {
|
|
19239
|
+
this.assertCompatible();
|
|
19240
|
+
const dbPath = this.getDbPath(sessionId);
|
|
19241
|
+
if (!options.create && !fs35.existsSync(dbPath)) {
|
|
19242
|
+
throw new Error(`Session database not found: ${sessionId}`);
|
|
19243
|
+
}
|
|
19244
|
+
if (!options.readonly) {
|
|
19245
|
+
this.close(sessionId);
|
|
19246
|
+
fs35.mkdirSync(path32.dirname(dbPath), { recursive: true });
|
|
19247
|
+
}
|
|
19248
|
+
const adapter = openBetterSqliteDatabase(dbPath, {
|
|
19249
|
+
readonly: options.readonly ?? false,
|
|
19250
|
+
nativeBinding: this.nativeBinding
|
|
19251
|
+
});
|
|
19252
|
+
if (options.initializeChatTables) {
|
|
19253
|
+
adapter.exec(CHAT_DB_TABLES);
|
|
19254
|
+
}
|
|
19255
|
+
return adapter;
|
|
19256
|
+
}
|
|
19257
|
+
deleteSessionDatabaseFiles(sessionId) {
|
|
19258
|
+
this.close(sessionId);
|
|
19259
|
+
const dbPath = this.getDbPath(sessionId);
|
|
19260
|
+
for (const suffix of ["", "-wal", "-shm"]) {
|
|
19261
|
+
try {
|
|
19262
|
+
const filePath = dbPath + suffix;
|
|
19263
|
+
if (fs35.existsSync(filePath)) fs35.unlinkSync(filePath);
|
|
19264
|
+
} catch {
|
|
19265
|
+
}
|
|
19266
|
+
}
|
|
19267
|
+
}
|
|
19268
|
+
raiseCurrentChatDbCompatibilityGate() {
|
|
19269
|
+
if (!this.runtime) return;
|
|
19270
|
+
raiseChatDbCompatibilityGate(this.pathProvider, this.runtime);
|
|
19271
|
+
}
|
|
19272
|
+
assertCompatible() {
|
|
19273
|
+
if (!this.runtime) return;
|
|
19274
|
+
assertDataDirCompatible(this.pathProvider, this.runtime);
|
|
19275
|
+
}
|
|
19276
|
+
runMigrations(adapter, migrations) {
|
|
19277
|
+
const beforeVersion = getSchemaVersion(adapter);
|
|
19278
|
+
const migrated = runMigrations(adapter, migrations);
|
|
19279
|
+
if (!migrated || !this.runtime) return;
|
|
19280
|
+
const afterVersion = getSchemaVersion(adapter);
|
|
19281
|
+
if (shouldRaiseCompatibilityGate(beforeVersion, afterVersion)) {
|
|
19282
|
+
this.raiseCurrentChatDbCompatibilityGate();
|
|
19283
|
+
}
|
|
19284
|
+
}
|
|
19285
|
+
raiseCompatibilityGateIfNeeded(schemaVersion) {
|
|
19286
|
+
if (!this.runtime) return;
|
|
19287
|
+
if (shouldRepairCompatibilityGate(schemaVersion)) {
|
|
19288
|
+
this.raiseCurrentChatDbCompatibilityGate();
|
|
19289
|
+
}
|
|
18139
19290
|
}
|
|
18140
19291
|
};
|
|
19292
|
+
function shouldRaiseCompatibilityGate(beforeVersion, afterVersion) {
|
|
19293
|
+
return CHAT_DB_COMPATIBILITY_RAISES.some(
|
|
19294
|
+
(compatibilityRaise) => beforeVersion < compatibilityRaise.migrationVersion && afterVersion >= compatibilityRaise.migrationVersion
|
|
19295
|
+
);
|
|
19296
|
+
}
|
|
19297
|
+
function shouldRepairCompatibilityGate(schemaVersion) {
|
|
19298
|
+
return CHAT_DB_COMPATIBILITY_RAISES.some((compatibilityRaise) => schemaVersion >= compatibilityRaise.migrationVersion);
|
|
19299
|
+
}
|
|
18141
19300
|
|
|
18142
19301
|
// ../../packages/node-runtime/src/jieba-nlp-provider.ts
|
|
18143
19302
|
function createJiebaNlpProvider(dictType = "default") {
|
|
@@ -18183,7 +19342,7 @@ function exportFilterResultToMarkdown(params, deps, writer) {
|
|
|
18183
19342
|
} else {
|
|
18184
19343
|
writer.write(`- Mode: session filter
|
|
18185
19344
|
`);
|
|
18186
|
-
writer.write(`- Selected sessions: ${params.
|
|
19345
|
+
writer.write(`- Selected sessions: ${params.segmentIds?.length || 0}
|
|
18187
19346
|
`);
|
|
18188
19347
|
}
|
|
18189
19348
|
writer.write("\n");
|
|
@@ -18341,7 +19500,7 @@ function exportConditionMode(db, params, writer, progress) {
|
|
|
18341
19500
|
return { totalMessages, blockIndex };
|
|
18342
19501
|
}
|
|
18343
19502
|
function exportSessionMode(db, params, writer, progress) {
|
|
18344
|
-
if (!params.
|
|
19503
|
+
if (!params.segmentIds || params.segmentIds.length === 0) {
|
|
18345
19504
|
writer.write(`## Statistics
|
|
18346
19505
|
|
|
18347
19506
|
- No sessions selected
|
|
@@ -18352,17 +19511,17 @@ function exportSessionMode(db, params, writer, progress) {
|
|
|
18352
19511
|
progress?.({
|
|
18353
19512
|
stage: "preparing",
|
|
18354
19513
|
currentBlock: 0,
|
|
18355
|
-
totalBlocks: params.
|
|
19514
|
+
totalBlocks: params.segmentIds.length,
|
|
18356
19515
|
percentage: 10,
|
|
18357
|
-
message: `Preparing to export ${params.
|
|
19516
|
+
message: `Preparing to export ${params.segmentIds.length} sessions...`
|
|
18358
19517
|
});
|
|
18359
19518
|
const sessionsSql = `
|
|
18360
19519
|
SELECT id, start_ts as startTs, end_ts as endTs
|
|
18361
|
-
FROM
|
|
18362
|
-
WHERE id IN (${params.
|
|
19520
|
+
FROM segment
|
|
19521
|
+
WHERE id IN (${params.segmentIds.map(() => "?").join(",")})
|
|
18363
19522
|
ORDER BY start_ts ASC
|
|
18364
19523
|
`;
|
|
18365
|
-
const sessions = db.prepare(sessionsSql).all(...params.
|
|
19524
|
+
const sessions = db.prepare(sessionsSql).all(...params.segmentIds);
|
|
18366
19525
|
const totalBlocks = sessions.length;
|
|
18367
19526
|
writer.write(`## Statistics
|
|
18368
19527
|
|
|
@@ -18380,7 +19539,7 @@ function exportSessionMode(db, params, writer, progress) {
|
|
|
18380
19539
|
FROM message_context mc
|
|
18381
19540
|
JOIN message msg ON msg.id = mc.message_id
|
|
18382
19541
|
JOIN member m ON msg.sender_id = m.id
|
|
18383
|
-
WHERE mc.
|
|
19542
|
+
WHERE mc.segment_id = ?
|
|
18384
19543
|
ORDER BY msg.ts ASC
|
|
18385
19544
|
`;
|
|
18386
19545
|
let totalMessages = 0;
|
|
@@ -18413,8 +19572,8 @@ function exportSessionMode(db, params, writer, progress) {
|
|
|
18413
19572
|
}
|
|
18414
19573
|
|
|
18415
19574
|
// ../../packages/node-runtime/src/preferences.ts
|
|
18416
|
-
import * as
|
|
18417
|
-
import * as
|
|
19575
|
+
import * as fs36 from "fs";
|
|
19576
|
+
import * as path33 from "path";
|
|
18418
19577
|
var DEFAULTS = {
|
|
18419
19578
|
pinnedSessionIds: [],
|
|
18420
19579
|
aiPreprocessConfig: {
|
|
@@ -18434,6 +19593,7 @@ var DEFAULTS = {
|
|
|
18434
19593
|
exportFormat: "markdown",
|
|
18435
19594
|
sqlExportFormat: "csv",
|
|
18436
19595
|
enableAutoSkill: true,
|
|
19596
|
+
chartAutoMode: "suggest",
|
|
18437
19597
|
searchContextBefore: 2,
|
|
18438
19598
|
searchContextAfter: 2,
|
|
18439
19599
|
contextCompression: {
|
|
@@ -18450,19 +19610,20 @@ var DEFAULTS = {
|
|
|
18450
19610
|
defaultSchemeId: null,
|
|
18451
19611
|
sessionSchemeOverrides: {}
|
|
18452
19612
|
},
|
|
18453
|
-
filterHistory: []
|
|
19613
|
+
filterHistory: [],
|
|
19614
|
+
thinkingLevels: {}
|
|
18454
19615
|
};
|
|
18455
19616
|
var PreferencesManager = class {
|
|
18456
19617
|
filePath;
|
|
18457
19618
|
cache = null;
|
|
18458
19619
|
constructor(systemDir) {
|
|
18459
|
-
this.filePath =
|
|
19620
|
+
this.filePath = path33.join(systemDir, "preferences.json");
|
|
18460
19621
|
}
|
|
18461
19622
|
load() {
|
|
18462
19623
|
if (this.cache) return this.cache;
|
|
18463
19624
|
try {
|
|
18464
|
-
if (
|
|
18465
|
-
const raw =
|
|
19625
|
+
if (fs36.existsSync(this.filePath)) {
|
|
19626
|
+
const raw = fs36.readFileSync(this.filePath, "utf-8");
|
|
18466
19627
|
const parsed = JSON.parse(raw);
|
|
18467
19628
|
const migrated = this.migrateLegacyDesensitizeRules(parsed, raw);
|
|
18468
19629
|
this.cache = this.mergeDefaults(migrated.preferences);
|
|
@@ -18518,7 +19679,8 @@ var PreferencesManager = class {
|
|
|
18518
19679
|
customKeywordTemplates: partial.customKeywordTemplates ?? DEFAULTS.customKeywordTemplates,
|
|
18519
19680
|
deletedPresetTemplateIds: partial.deletedPresetTemplateIds ?? DEFAULTS.deletedPresetTemplateIds,
|
|
18520
19681
|
wordFilter: partial.wordFilter ? { ...DEFAULTS.wordFilter, ...partial.wordFilter } : { ...DEFAULTS.wordFilter },
|
|
18521
|
-
filterHistory: partial.filterHistory ?? DEFAULTS.filterHistory
|
|
19682
|
+
filterHistory: partial.filterHistory ?? DEFAULTS.filterHistory,
|
|
19683
|
+
thinkingLevels: partial.thinkingLevels ?? DEFAULTS.thinkingLevels
|
|
18522
19684
|
};
|
|
18523
19685
|
}
|
|
18524
19686
|
normalizeAiPreprocessConfig(partial) {
|
|
@@ -18574,21 +19736,21 @@ var PreferencesManager = class {
|
|
|
18574
19736
|
};
|
|
18575
19737
|
}
|
|
18576
19738
|
backupLegacyPreferences(rawContent) {
|
|
18577
|
-
const backupDir =
|
|
18578
|
-
if (!
|
|
18579
|
-
|
|
19739
|
+
const backupDir = path33.join(path33.dirname(this.filePath), "backups");
|
|
19740
|
+
if (!fs36.existsSync(backupDir)) {
|
|
19741
|
+
fs36.mkdirSync(backupDir, { recursive: true });
|
|
18580
19742
|
}
|
|
18581
19743
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
18582
|
-
const backupPath =
|
|
18583
|
-
|
|
19744
|
+
const backupPath = path33.join(backupDir, `preferences-pre-desensitize-groups-${timestamp}.json`);
|
|
19745
|
+
fs36.writeFileSync(backupPath, rawContent, "utf-8");
|
|
18584
19746
|
console.info(`[Preferences] Backed up legacy desensitize rules to ${backupPath}`);
|
|
18585
19747
|
}
|
|
18586
19748
|
writePreferences(preferences) {
|
|
18587
|
-
const dir =
|
|
18588
|
-
if (!
|
|
18589
|
-
|
|
19749
|
+
const dir = path33.dirname(this.filePath);
|
|
19750
|
+
if (!fs36.existsSync(dir)) {
|
|
19751
|
+
fs36.mkdirSync(dir, { recursive: true });
|
|
18590
19752
|
}
|
|
18591
|
-
|
|
19753
|
+
fs36.writeFileSync(this.filePath, JSON.stringify(preferences, null, 2), "utf-8");
|
|
18592
19754
|
}
|
|
18593
19755
|
/**
|
|
18594
19756
|
* Deep merge: arrays are replaced (not concatenated), objects are merged.
|
|
@@ -18708,8 +19870,8 @@ function* serializeChatLabToJsonl(data) {
|
|
|
18708
19870
|
}
|
|
18709
19871
|
|
|
18710
19872
|
// ../../packages/node-runtime/src/merger/temp-db.ts
|
|
18711
|
-
import * as
|
|
18712
|
-
import * as
|
|
19873
|
+
import * as fs37 from "fs";
|
|
19874
|
+
import * as path34 from "path";
|
|
18713
19875
|
var TEMP_DB_SCHEMA = `
|
|
18714
19876
|
CREATE TABLE IF NOT EXISTS meta (
|
|
18715
19877
|
name TEXT NOT NULL,
|
|
@@ -18954,21 +20116,21 @@ function exportSessionToJson(db) {
|
|
|
18954
20116
|
}
|
|
18955
20117
|
function deleteTempDatabase(dbPath) {
|
|
18956
20118
|
try {
|
|
18957
|
-
if (
|
|
20119
|
+
if (fs37.existsSync(dbPath)) fs37.unlinkSync(dbPath);
|
|
18958
20120
|
const walPath = dbPath + "-wal";
|
|
18959
20121
|
const shmPath = dbPath + "-shm";
|
|
18960
|
-
if (
|
|
18961
|
-
if (
|
|
20122
|
+
if (fs37.existsSync(walPath)) fs37.unlinkSync(walPath);
|
|
20123
|
+
if (fs37.existsSync(shmPath)) fs37.unlinkSync(shmPath);
|
|
18962
20124
|
} catch {
|
|
18963
20125
|
}
|
|
18964
20126
|
}
|
|
18965
20127
|
function cleanupTempDatabases(tempDir) {
|
|
18966
20128
|
try {
|
|
18967
|
-
if (!
|
|
18968
|
-
const files =
|
|
20129
|
+
if (!fs37.existsSync(tempDir)) return;
|
|
20130
|
+
const files = fs37.readdirSync(tempDir);
|
|
18969
20131
|
for (const file of files) {
|
|
18970
20132
|
if (file.startsWith("merge_") && file.endsWith(".db")) {
|
|
18971
|
-
deleteTempDatabase(
|
|
20133
|
+
deleteTempDatabase(path34.join(tempDir, file));
|
|
18972
20134
|
}
|
|
18973
20135
|
}
|
|
18974
20136
|
} catch {
|
|
@@ -19129,19 +20291,19 @@ __export(summary_service_exports, {
|
|
|
19129
20291
|
function buildSummaryDeps(db, llmConfig, deps) {
|
|
19130
20292
|
const piModel = deps.buildPiModel(llmConfig);
|
|
19131
20293
|
return {
|
|
19132
|
-
loadMessages(
|
|
19133
|
-
const data =
|
|
20294
|
+
loadMessages(segmentId, limit = 500) {
|
|
20295
|
+
const data = getSegmentMessages(db, segmentId, limit);
|
|
19134
20296
|
if (!data) return null;
|
|
19135
20297
|
return data.messages.map((m) => ({ senderName: m.senderName, content: m.content }));
|
|
19136
20298
|
},
|
|
19137
|
-
saveSummary(
|
|
19138
|
-
|
|
20299
|
+
saveSummary(segmentId, summary) {
|
|
20300
|
+
saveSegmentSummary(db, segmentId, summary);
|
|
19139
20301
|
},
|
|
19140
|
-
getSummary(
|
|
19141
|
-
return
|
|
20302
|
+
getSummary(segmentId) {
|
|
20303
|
+
return getSegmentSummary(db, segmentId);
|
|
19142
20304
|
},
|
|
19143
20305
|
async llmComplete(systemPrompt, userPrompt, options) {
|
|
19144
|
-
const result = await
|
|
20306
|
+
const result = await completeSimple6(
|
|
19145
20307
|
piModel,
|
|
19146
20308
|
{
|
|
19147
20309
|
systemPrompt,
|
|
@@ -19154,14 +20316,14 @@ function buildSummaryDeps(db, llmConfig, deps) {
|
|
|
19154
20316
|
t: (key) => key
|
|
19155
20317
|
};
|
|
19156
20318
|
}
|
|
19157
|
-
async function generateSummary(adapter, sessionId,
|
|
20319
|
+
async function generateSummary(adapter, sessionId, segmentId, serviceDeps, options) {
|
|
19158
20320
|
const llmConfig = serviceDeps.getLlmConfig();
|
|
19159
20321
|
if (!llmConfig) {
|
|
19160
20322
|
return { success: false, error: "No LLM configuration available" };
|
|
19161
20323
|
}
|
|
19162
20324
|
const db = adapter.ensureWritable(sessionId);
|
|
19163
20325
|
const deps = buildSummaryDeps(db, llmConfig, serviceDeps);
|
|
19164
|
-
return generateSessionSummary(deps,
|
|
20326
|
+
return generateSessionSummary(deps, segmentId, options);
|
|
19165
20327
|
}
|
|
19166
20328
|
async function generateAllSummaries(adapter, sessionId, serviceDeps, options) {
|
|
19167
20329
|
const llmConfig = serviceDeps.getLlmConfig();
|
|
@@ -19180,17 +20342,17 @@ async function generateAllSummaries(adapter, sessionId, serviceDeps, options) {
|
|
|
19180
20342
|
}
|
|
19181
20343
|
return { success, failed, total: chatSessions.length };
|
|
19182
20344
|
}
|
|
19183
|
-
function checkCanGenerate(adapter, sessionId,
|
|
20345
|
+
function checkCanGenerate(adapter, sessionId, segmentIds) {
|
|
19184
20346
|
const db = adapter.ensureReadonly(sessionId);
|
|
19185
20347
|
const deps = {
|
|
19186
|
-
loadMessages(
|
|
19187
|
-
const data =
|
|
20348
|
+
loadMessages(segmentId, limit = 500) {
|
|
20349
|
+
const data = getSegmentMessages(db, segmentId, limit);
|
|
19188
20350
|
if (!data) return null;
|
|
19189
20351
|
return data.messages.map((m) => ({ senderName: m.senderName, content: m.content }));
|
|
19190
20352
|
},
|
|
19191
20353
|
t: (key) => key
|
|
19192
20354
|
};
|
|
19193
|
-
const resultMap = checkSessionsCanGenerateSummary(deps,
|
|
20355
|
+
const resultMap = checkSessionsCanGenerateSummary(deps, segmentIds);
|
|
19194
20356
|
const result = {};
|
|
19195
20357
|
for (const [id, info] of resultMap) {
|
|
19196
20358
|
result[id] = info;
|
|
@@ -19224,7 +20386,7 @@ function exportMarkdown(adapter, params) {
|
|
|
19224
20386
|
}
|
|
19225
20387
|
|
|
19226
20388
|
// ../../packages/node-runtime/src/services/adapters/database-manager-adapter.ts
|
|
19227
|
-
import * as
|
|
20389
|
+
import * as fs38 from "fs";
|
|
19228
20390
|
function createDatabaseManagerAdapter(dbManager) {
|
|
19229
20391
|
return {
|
|
19230
20392
|
listSessionIds: () => dbManager.listSessionIds(),
|
|
@@ -19235,8 +20397,8 @@ function createDatabaseManagerAdapter(dbManager) {
|
|
|
19235
20397
|
deleteSessionFile(sessionId) {
|
|
19236
20398
|
dbManager.close(sessionId);
|
|
19237
20399
|
const dbPath = dbManager.getDbPath(sessionId);
|
|
19238
|
-
if (!
|
|
19239
|
-
|
|
20400
|
+
if (!fs38.existsSync(dbPath)) return false;
|
|
20401
|
+
fs38.unlinkSync(dbPath);
|
|
19240
20402
|
return true;
|
|
19241
20403
|
},
|
|
19242
20404
|
ensureReadonly(sessionId) {
|
|
@@ -19257,8 +20419,8 @@ function createDatabaseManagerAdapter(dbManager) {
|
|
|
19257
20419
|
}
|
|
19258
20420
|
|
|
19259
20421
|
// ../../packages/node-runtime/src/services/merge-cache.ts
|
|
19260
|
-
import * as
|
|
19261
|
-
import * as
|
|
20422
|
+
import * as fs39 from "fs";
|
|
20423
|
+
import * as path35 from "path";
|
|
19262
20424
|
import * as crypto from "crypto";
|
|
19263
20425
|
var MergeSessionCache = class {
|
|
19264
20426
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -19267,15 +20429,15 @@ var MergeSessionCache = class {
|
|
|
19267
20429
|
constructor(pathProvider, options) {
|
|
19268
20430
|
this.tempDir = pathProvider.getTempDir();
|
|
19269
20431
|
this.nativeBinding = options?.nativeBinding;
|
|
19270
|
-
if (!
|
|
19271
|
-
|
|
20432
|
+
if (!fs39.existsSync(this.tempDir)) {
|
|
20433
|
+
fs39.mkdirSync(this.tempDir, { recursive: true });
|
|
19272
20434
|
}
|
|
19273
20435
|
}
|
|
19274
20436
|
generateTempDbPath(filename) {
|
|
19275
20437
|
const ts = Date.now();
|
|
19276
20438
|
const rand = Math.random().toString(36).slice(2, 8);
|
|
19277
20439
|
const safeName = filename.replace(/[/\\?%*:|"<>]/g, "_").slice(0, 40);
|
|
19278
|
-
return
|
|
20440
|
+
return path35.join(this.tempDir, `merge_${safeName}_${ts}_${rand}.db`);
|
|
19279
20441
|
}
|
|
19280
20442
|
/** Store a parsed file's temp DB and return a handle for subsequent requests. */
|
|
19281
20443
|
store(filename, tempDbPath) {
|
|
@@ -19286,7 +20448,7 @@ var MergeSessionCache = class {
|
|
|
19286
20448
|
/** Open a TempDbReader for a given handle. Caller must close the reader. */
|
|
19287
20449
|
openReader(handle) {
|
|
19288
20450
|
const entry = this.cache.get(handle);
|
|
19289
|
-
if (!entry || !
|
|
20451
|
+
if (!entry || !fs39.existsSync(entry.tempDbPath)) return null;
|
|
19290
20452
|
const adapter = openBetterSqliteDatabase(entry.tempDbPath, {
|
|
19291
20453
|
readonly: true,
|
|
19292
20454
|
nativeBinding: this.nativeBinding
|
|
@@ -19339,7 +20501,6 @@ export {
|
|
|
19339
20501
|
writeAuthProfile,
|
|
19340
20502
|
MigrationRunner,
|
|
19341
20503
|
ALL_MIGRATIONS,
|
|
19342
|
-
openBetterSqliteDatabase,
|
|
19343
20504
|
writeParseResultToDb,
|
|
19344
20505
|
getTimeRange,
|
|
19345
20506
|
getAvailableYears,
|
|
@@ -19356,9 +20517,9 @@ export {
|
|
|
19356
20517
|
getSessionOverview,
|
|
19357
20518
|
getDatabaseSchema,
|
|
19358
20519
|
getChatOverview,
|
|
19359
|
-
|
|
19360
|
-
|
|
19361
|
-
|
|
20520
|
+
searchSegments,
|
|
20521
|
+
getSegmentMessages,
|
|
20522
|
+
getSegmentSummaries,
|
|
19362
20523
|
generateSessionIndex,
|
|
19363
20524
|
generateIncrementalSessionIndex,
|
|
19364
20525
|
queryMessages,
|
|
@@ -19387,6 +20548,7 @@ export {
|
|
|
19387
20548
|
isNewerStableVersion,
|
|
19388
20549
|
buildChartPayload,
|
|
19389
20550
|
POS_TAG_DEFINITIONS,
|
|
20551
|
+
normalizeBuiltinToolNames,
|
|
19390
20552
|
BUILTIN_TOOL_CATALOG,
|
|
19391
20553
|
BUILTIN_PROVIDERS,
|
|
19392
20554
|
BUILTIN_MODELS,
|
|
@@ -19394,7 +20556,6 @@ export {
|
|
|
19394
20556
|
stripAvatarFields,
|
|
19395
20557
|
generateMessageKey,
|
|
19396
20558
|
buildMemberIdMap,
|
|
19397
|
-
CHAT_DB_TABLES,
|
|
19398
20559
|
CHAT_DB_SCHEMA,
|
|
19399
20560
|
FTS_TABLE_SCHEMA,
|
|
19400
20561
|
detectFormat,
|
|
@@ -19421,7 +20582,7 @@ export {
|
|
|
19421
20582
|
formatAIError,
|
|
19422
20583
|
parseAssistantFile,
|
|
19423
20584
|
AssistantManager,
|
|
19424
|
-
|
|
20585
|
+
AIChatManager,
|
|
19425
20586
|
initTokenizer,
|
|
19426
20587
|
countMessagesTokens,
|
|
19427
20588
|
SkillManagerCore,
|
|
@@ -19429,6 +20590,8 @@ export {
|
|
|
19429
20590
|
createActivateSkillTool,
|
|
19430
20591
|
CHART_CAPABILITY_CORE_TOOLS,
|
|
19431
20592
|
getAllowedBuiltinToolsForChartAutoSkill,
|
|
20593
|
+
shouldUseChartCapabilityForMessage,
|
|
20594
|
+
getChartPlannerCapabilityForMessage,
|
|
19432
20595
|
resolveChartRuntimeForRequest,
|
|
19433
20596
|
getChartCapabilitySkill,
|
|
19434
20597
|
buildSkillMenuWithBuiltinChart,
|
|
@@ -19442,6 +20605,12 @@ export {
|
|
|
19442
20605
|
applyPreprocessingPipeline,
|
|
19443
20606
|
DEFAULT_MAX_TOOL_ROUNDS,
|
|
19444
20607
|
runAgentCore,
|
|
20608
|
+
createDataSnapshotFromOverview,
|
|
20609
|
+
decideRequestRoute,
|
|
20610
|
+
createLlmRouteDecider,
|
|
20611
|
+
createAnalysisPlanner,
|
|
20612
|
+
createPlanContentBlock,
|
|
20613
|
+
buildPlanGuidance,
|
|
19445
20614
|
AgentEventHandler,
|
|
19446
20615
|
buildSystemPrompt,
|
|
19447
20616
|
createAiTranslate,
|
|
@@ -19459,6 +20628,8 @@ export {
|
|
|
19459
20628
|
applyPendingNodeDataDirMigrationIfNeeded,
|
|
19460
20629
|
NodePathProvider,
|
|
19461
20630
|
getDefaultNodeUserDataDir,
|
|
20631
|
+
DataDirCompatibilityError,
|
|
20632
|
+
assertDataDirCompatible,
|
|
19462
20633
|
DatabaseManager,
|
|
19463
20634
|
createJiebaNlpProvider,
|
|
19464
20635
|
PreferencesManager,
|
|
@@ -19475,4 +20646,4 @@ export {
|
|
|
19475
20646
|
createDatabaseManagerAdapter,
|
|
19476
20647
|
MergeSessionCache
|
|
19477
20648
|
};
|
|
19478
|
-
//# sourceMappingURL=chunk-
|
|
20649
|
+
//# sourceMappingURL=chunk-QY67NN65.mjs.map
|