chatlab-cli 0.24.1 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat-command-5XMRLXZM.mjs +166 -0
- package/dist/chat-command-5XMRLXZM.mjs.map +1 -0
- package/dist/{chunk-N5DGZQB4.mjs → chunk-7VG6QGQ2.mjs} +1543 -664
- package/dist/chunk-7VG6QGQ2.mjs.map +1 -0
- package/dist/{chunk-QJI6AOAT.mjs → chunk-CUCDRAY6.mjs} +17 -25
- package/dist/chunk-CUCDRAY6.mjs.map +1 -0
- package/dist/chunk-FDK6SPCG.mjs +40 -0
- package/dist/chunk-FDK6SPCG.mjs.map +1 -0
- package/dist/{chunk-ZL322NVL.mjs → chunk-GTCTDD2Z.mjs} +116 -504
- package/dist/chunk-GTCTDD2Z.mjs.map +1 -0
- package/dist/{chunk-43XWYC3M.mjs → chunk-JE3FOFF7.mjs} +219 -123
- package/dist/chunk-JE3FOFF7.mjs.map +1 -0
- package/dist/{chunk-QY6P2YS7.mjs → chunk-PDQFSQO6.mjs} +59 -33
- package/dist/chunk-PDQFSQO6.mjs.map +1 -0
- package/dist/chunk-WYHGWTA4.mjs +485 -0
- package/dist/chunk-WYHGWTA4.mjs.map +1 -0
- package/dist/{chunk-CIIQ3S2X.mjs → chunk-YZYP5ST6.mjs} +37 -8
- package/dist/chunk-YZYP5ST6.mjs.map +1 -0
- package/dist/cli.mjs +3 -2
- package/dist/{http-TPX74BLK.mjs → http-C3CGXUBU.mjs} +8 -6
- package/dist/{import-B745DRHD.mjs → import-VS7L5JDX.mjs} +4 -4
- package/dist/index.mjs +10 -8
- package/dist/{mcp-YWAVG5XW.mjs → mcp-6VXDPUQK.mjs} +11 -6
- package/dist/mcp-6VXDPUQK.mjs.map +1 -0
- package/dist/{stream-import-OPALPVWF.mjs → stream-import-TFDBNVIW.mjs} +3 -3
- package/dist-web/assets/{DebugToolsPanel-DaSNc1o-.css → DebugToolsPanel-vn-bnUxn.css} +1 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-B1xZmp9r.js +161 -0
- package/dist-web/assets/{EChartWordcloud-VpNJDurs.js → EChartWordcloud-CzhfrEF_.js} +1 -1
- package/dist-web/assets/{MessageExportModal-CSfaY25B.js → MessageExportModal-B79pPBL9.js} +1 -1
- package/dist-web/assets/{electron-BUeXfvxT.js → electron-DRkrjeIl.js} +1 -1
- package/dist-web/assets/electron-Dv8jdn_2.js +1 -0
- package/dist-web/assets/{fetch-RDFt3hmp.js → fetch-BmZIm6mS.js} +1 -1
- package/dist-web/assets/fetch-BqLy63aj.js +1 -0
- package/dist-web/assets/fetch-BstX-wd4.js +1 -0
- package/dist-web/assets/{fetch-BohUj3CQ.js → fetch-Bvcxe5PI.js} +1 -1
- package/dist-web/assets/{fetch-BneHn5qk.js → fetch-CDamdvtb.js} +1 -1
- package/dist-web/assets/{fetch-DypPduyQ.js → fetch-DWg-2kOp.js} +1 -1
- package/dist-web/assets/{fetch-CARsBVl0.js → fetch-DfgdagMN.js} +1 -1
- package/dist-web/assets/{fetch-Ck3tjoLa.js → fetch-Drk9dLaF.js} +1 -1
- package/dist-web/assets/{fetch-B2q6973s.js → fetch-Y-_WsCuk.js} +1 -1
- package/dist-web/assets/{fetch-BGMRmQx0.js → fetch-ph2_d79v.js} +1 -1
- package/dist-web/assets/{index-Bvlj3dMn.js → index-9urfJP1r.js} +1 -1
- package/dist-web/assets/index-CfKjh0Jr.js +9 -0
- package/dist-web/assets/index-CprJOAB1.css +1 -0
- package/dist-web/assets/{index-BvaWRM6_.js → index-DMWf5On7.js} +1 -1
- package/dist-web/assets/{index-DCWvD-4L.js → index-D_hHm7bQ.js} +2 -2
- package/dist-web/assets/index-MCdpiX_O.js +173 -0
- package/dist-web/assets/{index-C5LrQG3N.js → index-deYDOVUa.js} +4 -4
- package/dist-web/assets/vendor-echarts-CITQeskI.js +11 -0
- package/dist-web/assets/{vendor-echarts-wordcloud-CZ9gsX8l.js → vendor-echarts-wordcloud-B1kQMklB.js} +1 -1
- package/dist-web/assets/{vendor-nuxt-ui-BYU7dz8t.js → vendor-nuxt-ui-C_8CsH6e.js} +1 -1
- package/dist-web/assets/{vendor-reka-ui-CnB0mMNX.js → vendor-reka-ui-CIMXwvEp.js} +1 -1
- package/dist-web/assets/{web-CXPkmhis.js → web-XJV6Vj5t.js} +1 -1
- package/dist-web/index.html +4 -4
- package/package.json +1 -1
- package/dist/chunk-43XWYC3M.mjs.map +0 -1
- package/dist/chunk-CIIQ3S2X.mjs.map +0 -1
- package/dist/chunk-N5DGZQB4.mjs.map +0 -1
- package/dist/chunk-QJI6AOAT.mjs.map +0 -1
- package/dist/chunk-QY6P2YS7.mjs.map +0 -1
- package/dist/chunk-ZL322NVL.mjs.map +0 -1
- package/dist/mcp-YWAVG5XW.mjs.map +0 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-BBDrsJfe.js +0 -161
- package/dist-web/assets/electron-BynNUuEA.js +0 -1
- package/dist-web/assets/fetch-BtHwWs8A.js +0 -1
- package/dist-web/assets/fetch-DzNuFdFM.js +0 -1
- package/dist-web/assets/index-BRwEubUe.js +0 -173
- package/dist-web/assets/index-DB-iqXzV.css +0 -1
- package/dist-web/assets/index-DS1rzk1I.js +0 -8
- package/dist-web/assets/vendor-echarts-C5u62NnM.js +0 -11
- /package/dist/{http-TPX74BLK.mjs.map → http-C3CGXUBU.mjs.map} +0 -0
- /package/dist/{import-B745DRHD.mjs.map → import-VS7L5JDX.mjs.map} +0 -0
- /package/dist/{stream-import-OPALPVWF.mjs.map → stream-import-TFDBNVIW.mjs.map} +0 -0
|
@@ -7,31 +7,38 @@ const __dirname = __pathDirname(__filename);
|
|
|
7
7
|
import {
|
|
8
8
|
importData,
|
|
9
9
|
parseFile
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-CUCDRAY6.mjs";
|
|
11
11
|
import {
|
|
12
12
|
analyzeIncrementalImport,
|
|
13
13
|
analyzeNewImport,
|
|
14
14
|
incrementalImport,
|
|
15
15
|
streamImport
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-PDQFSQO6.mjs";
|
|
17
17
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
} from "./chunk-43XWYC3M.mjs";
|
|
18
|
+
assertCliDataDirCompatible
|
|
19
|
+
} from "./chunk-FDK6SPCG.mjs";
|
|
21
20
|
import {
|
|
22
21
|
getVersion
|
|
23
22
|
} from "./chunk-5ADKYYNA.mjs";
|
|
24
23
|
import {
|
|
25
|
-
|
|
24
|
+
closeServerAiLogger,
|
|
25
|
+
createCliRunAgentStream,
|
|
26
|
+
initServerAiLogger
|
|
27
|
+
} from "./chunk-WYHGWTA4.mjs";
|
|
28
|
+
import {
|
|
29
|
+
AGENT_TOOL_REGISTRY,
|
|
30
|
+
CoreDataProvider
|
|
31
|
+
} from "./chunk-JE3FOFF7.mjs";
|
|
32
|
+
import {
|
|
33
|
+
AIChatManager,
|
|
26
34
|
ALL_MIGRATIONS,
|
|
27
|
-
AgentEventHandler,
|
|
28
|
-
AiLogger,
|
|
29
35
|
AssistantManager,
|
|
30
36
|
BUILTIN_MODELS,
|
|
31
37
|
BUILTIN_PROVIDERS,
|
|
32
38
|
BUILTIN_TOOL_CATALOG,
|
|
33
39
|
CustomModelStore,
|
|
34
40
|
CustomProviderStore,
|
|
41
|
+
DataDirCompatibilityError,
|
|
35
42
|
DatabaseManager,
|
|
36
43
|
LLMConfigStore,
|
|
37
44
|
MergeSessionCache,
|
|
@@ -39,22 +46,14 @@ import {
|
|
|
39
46
|
NodePathProvider,
|
|
40
47
|
POS_TAG_DEFINITIONS,
|
|
41
48
|
PreferencesManager,
|
|
42
|
-
SkillManager,
|
|
43
49
|
SkillManagerCore,
|
|
44
50
|
TempDbWriter,
|
|
45
51
|
applyPendingNodeDataDirMigrationIfNeeded,
|
|
46
|
-
applyPreprocessingPipeline,
|
|
47
|
-
batchSegmentWithFrequency,
|
|
48
52
|
buildMergedOutput,
|
|
49
53
|
buildPiModel,
|
|
50
|
-
buildSystemPrompt,
|
|
51
|
-
checkAndCompress,
|
|
52
54
|
checkConflictsFromSources,
|
|
53
55
|
computeWordFrequency,
|
|
54
56
|
countMessagesTokens,
|
|
55
|
-
createActivateSkillTool,
|
|
56
|
-
createAiTranslate,
|
|
57
|
-
createCompressionLlmAdapter,
|
|
58
57
|
createDatabaseManagerAdapter,
|
|
59
58
|
createJiebaNlpProvider,
|
|
60
59
|
createNodeDataDirSwitch,
|
|
@@ -70,11 +69,9 @@ import {
|
|
|
70
69
|
fetchRemoteModels,
|
|
71
70
|
filterMessagesWithContext,
|
|
72
71
|
findEntryFileInDirectory,
|
|
73
|
-
formatAIError,
|
|
74
72
|
getAvailableYears,
|
|
75
73
|
getBuiltinModelsByProvider,
|
|
76
74
|
getCatchphraseAnalysis,
|
|
77
|
-
getChatOverview,
|
|
78
75
|
getClusterGraph,
|
|
79
76
|
getDailyActivity,
|
|
80
77
|
getDefaultNodeUserDataDir,
|
|
@@ -104,17 +101,13 @@ import {
|
|
|
104
101
|
getYearlyActivity,
|
|
105
102
|
hasPendingElectronDataWarning,
|
|
106
103
|
initNlpDir,
|
|
107
|
-
initTokenizer,
|
|
108
104
|
isDictDownloaded,
|
|
109
105
|
isNewerStableVersion,
|
|
110
106
|
loadConfig,
|
|
111
107
|
member_service_exports,
|
|
112
108
|
mergeRulesForLocale,
|
|
113
|
-
openBetterSqliteDatabase,
|
|
114
|
-
parseAssistantFile,
|
|
115
109
|
queryMessages,
|
|
116
110
|
resolveApiKey,
|
|
117
|
-
runAgentCore,
|
|
118
111
|
runSimpleLlmStream,
|
|
119
112
|
scanMultiChatFile,
|
|
120
113
|
segmentText,
|
|
@@ -128,13 +121,13 @@ import {
|
|
|
128
121
|
verifyCliDataPath,
|
|
129
122
|
writeAuthProfile,
|
|
130
123
|
writeConfigField
|
|
131
|
-
} from "./chunk-
|
|
124
|
+
} from "./chunk-7VG6QGQ2.mjs";
|
|
132
125
|
import {
|
|
133
126
|
resolveCliPath
|
|
134
127
|
} from "./chunk-FJ35V3TE.mjs";
|
|
135
128
|
|
|
136
129
|
// src/http/index.ts
|
|
137
|
-
import * as
|
|
130
|
+
import * as fs9 from "fs";
|
|
138
131
|
import * as crypto4 from "crypto";
|
|
139
132
|
|
|
140
133
|
// src/http/server.ts
|
|
@@ -150,6 +143,7 @@ var HTTP_STATUS = {
|
|
|
150
143
|
["SQL_EXECUTION_ERROR" /* SQL_EXECUTION_ERROR */]: 400,
|
|
151
144
|
["EXPORT_TOO_LARGE" /* EXPORT_TOO_LARGE */]: 400,
|
|
152
145
|
["BODY_TOO_LARGE" /* BODY_TOO_LARGE */]: 413,
|
|
146
|
+
["DATA_DIR_INCOMPATIBLE" /* DATA_DIR_INCOMPATIBLE */]: 409,
|
|
153
147
|
["SERVER_ERROR" /* SERVER_ERROR */]: 500
|
|
154
148
|
};
|
|
155
149
|
var ApiError = class extends Error {
|
|
@@ -180,6 +174,14 @@ function exportTooLarge(count, limit) {
|
|
|
180
174
|
function serverError(message = "Internal server error") {
|
|
181
175
|
return new ApiError("SERVER_ERROR" /* SERVER_ERROR */, message);
|
|
182
176
|
}
|
|
177
|
+
function dataDirIncompatible(message) {
|
|
178
|
+
return new ApiError("DATA_DIR_INCOMPATIBLE" /* DATA_DIR_INCOMPATIBLE */, message);
|
|
179
|
+
}
|
|
180
|
+
function apiErrorFromUnknown(error) {
|
|
181
|
+
if (error instanceof ApiError) return error;
|
|
182
|
+
if (error instanceof DataDirCompatibilityError) return dataDirIncompatible(error.message);
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
183
185
|
function successResponse(data, meta) {
|
|
184
186
|
return {
|
|
185
187
|
success: true,
|
|
@@ -790,7 +792,7 @@ function registerExportRoutes(server2, ctx) {
|
|
|
790
792
|
timeFilter: body.timeFilter,
|
|
791
793
|
senderIds: body.senderIds,
|
|
792
794
|
contextSize: body.contextSize,
|
|
793
|
-
|
|
795
|
+
segmentIds: body.segmentIds
|
|
794
796
|
});
|
|
795
797
|
if (!result.success) {
|
|
796
798
|
return reply.code(500).send({ error: result.error });
|
|
@@ -1172,10 +1174,10 @@ function registerAiFilterRoutes(server2, ctx) {
|
|
|
1172
1174
|
return filterMessagesWithContext(db, { keywords, timeFilter, senderIds, contextSize, page, pageSize });
|
|
1173
1175
|
});
|
|
1174
1176
|
server2.post("/_web/ai/multiple-sessions-messages", async (request, reply) => {
|
|
1175
|
-
const { sessionId,
|
|
1177
|
+
const { sessionId, segmentIds, page, pageSize } = request.body;
|
|
1176
1178
|
const db = ctx.dbManager.open(sessionId);
|
|
1177
1179
|
if (!db) return reply.code(404).send({ error: `Session not found: ${sessionId}` });
|
|
1178
|
-
return getMultipleSessionsMessages(db,
|
|
1180
|
+
return getMultipleSessionsMessages(db, segmentIds, page, pageSize);
|
|
1179
1181
|
});
|
|
1180
1182
|
}
|
|
1181
1183
|
|
|
@@ -1254,31 +1256,31 @@ function registerAiToolRoutes(server2, ctx) {
|
|
|
1254
1256
|
});
|
|
1255
1257
|
}
|
|
1256
1258
|
|
|
1257
|
-
// ../../packages/http-routes/src/routes/web/ai-
|
|
1258
|
-
function
|
|
1259
|
-
const cm = ctx.
|
|
1259
|
+
// ../../packages/http-routes/src/routes/web/ai-chats.ts
|
|
1260
|
+
function registerAiChatRoutes(server2, ctx) {
|
|
1261
|
+
const cm = ctx.aiChatManager;
|
|
1260
1262
|
if (!cm) return;
|
|
1261
|
-
server2.post("/_web/ai/
|
|
1263
|
+
server2.post("/_web/ai/chats", async (request) => {
|
|
1262
1264
|
const { sessionId, title, assistantId } = request.body;
|
|
1263
|
-
return cm.
|
|
1265
|
+
return cm.createAIChat(sessionId, title, assistantId);
|
|
1264
1266
|
});
|
|
1265
|
-
server2.get("/_web/ai/
|
|
1267
|
+
server2.get("/_web/ai/chats", async (request) => {
|
|
1266
1268
|
const { sessionId } = request.query;
|
|
1267
1269
|
if (!sessionId) return [];
|
|
1268
|
-
return cm.
|
|
1270
|
+
return cm.getAIChats(sessionId);
|
|
1269
1271
|
});
|
|
1270
|
-
server2.get("/_web/ai/
|
|
1271
|
-
const conv = cm.
|
|
1272
|
-
if (!conv) return reply.code(404).send({ error: "
|
|
1272
|
+
server2.get("/_web/ai/chats/:id", async (request, reply) => {
|
|
1273
|
+
const conv = cm.getAIChat(request.params.id);
|
|
1274
|
+
if (!conv) return reply.code(404).send({ error: "AI chat not found" });
|
|
1273
1275
|
return conv;
|
|
1274
1276
|
});
|
|
1275
|
-
server2.put("/_web/ai/
|
|
1276
|
-
return cm.
|
|
1277
|
+
server2.put("/_web/ai/chats/:id/title", async (request) => {
|
|
1278
|
+
return cm.updateAIChatTitle(request.params.id, request.body.title);
|
|
1277
1279
|
});
|
|
1278
|
-
server2.delete("/_web/ai/
|
|
1279
|
-
return cm.
|
|
1280
|
+
server2.delete("/_web/ai/chats/:id", async (request) => {
|
|
1281
|
+
return cm.deleteAIChat(request.params.id);
|
|
1280
1282
|
});
|
|
1281
|
-
server2.post("/_web/ai/
|
|
1283
|
+
server2.post("/_web/ai/chats/:id/messages", async (request) => {
|
|
1282
1284
|
const { role, content, dataKeywords, dataMessageCount, contentBlocks, tokenUsage } = request.body;
|
|
1283
1285
|
return cm.addMessage(
|
|
1284
1286
|
request.params.id,
|
|
@@ -1290,23 +1292,23 @@ function registerAiConversationRoutes(server2, ctx) {
|
|
|
1290
1292
|
tokenUsage
|
|
1291
1293
|
);
|
|
1292
1294
|
});
|
|
1293
|
-
server2.get("/_web/ai/
|
|
1295
|
+
server2.get("/_web/ai/chats/:id/messages", async (request) => {
|
|
1294
1296
|
return cm.getMessages(request.params.id);
|
|
1295
1297
|
});
|
|
1296
|
-
server2.post("/_web/ai/
|
|
1298
|
+
server2.post("/_web/ai/chats/:id/messages/:messageId/delete-from", async (request, reply) => {
|
|
1297
1299
|
const { id, messageId } = request.params;
|
|
1298
1300
|
if (!id || typeof id !== "string" || !messageId || typeof messageId !== "string") {
|
|
1299
|
-
return reply.code(400).send({ error: "
|
|
1301
|
+
return reply.code(400).send({ error: "aiChatId and messageId are required" });
|
|
1300
1302
|
}
|
|
1301
1303
|
cm.deleteMessagesFrom(id, messageId);
|
|
1302
1304
|
return { success: true };
|
|
1303
1305
|
});
|
|
1304
|
-
server2.post("/_web/ai/
|
|
1306
|
+
server2.post("/_web/ai/chats/:id/fork", async (request, reply) => {
|
|
1305
1307
|
const { upToMessageId, title } = request.body;
|
|
1306
1308
|
if (!upToMessageId || typeof upToMessageId !== "string") {
|
|
1307
1309
|
return reply.code(400).send({ error: "upToMessageId is required" });
|
|
1308
1310
|
}
|
|
1309
|
-
return cm.
|
|
1311
|
+
return cm.forkAIChat(request.params.id, upToMessageId, title);
|
|
1310
1312
|
});
|
|
1311
1313
|
server2.put("/_web/ai/messages/:messageId/content", async (request, reply) => {
|
|
1312
1314
|
const { content } = request.body;
|
|
@@ -1316,23 +1318,23 @@ function registerAiConversationRoutes(server2, ctx) {
|
|
|
1316
1318
|
cm.updateMessageContent(request.params.messageId, content);
|
|
1317
1319
|
return { success: true };
|
|
1318
1320
|
});
|
|
1319
|
-
server2.post("/_web/ai/
|
|
1321
|
+
server2.post("/_web/ai/chats/:id/messages/:messageId/delete-relink", async (request, reply) => {
|
|
1320
1322
|
const { id, messageId } = request.params;
|
|
1321
1323
|
if (!id || !messageId) {
|
|
1322
|
-
return reply.code(400).send({ error: "
|
|
1324
|
+
return reply.code(400).send({ error: "aiChatId and messageId are required" });
|
|
1323
1325
|
}
|
|
1324
1326
|
cm.deleteAndRelinkMessage(id, messageId);
|
|
1325
1327
|
return { success: true };
|
|
1326
1328
|
});
|
|
1327
|
-
server2.post("/_web/ai/
|
|
1329
|
+
server2.post("/_web/ai/chats/:id/messages/insert-after", async (request, reply) => {
|
|
1328
1330
|
const { afterMessageId, role, content, contentBlocks, tokenUsage } = request.body;
|
|
1329
1331
|
if (!afterMessageId || typeof afterMessageId !== "string") {
|
|
1330
1332
|
return reply.code(400).send({ error: "afterMessageId is required" });
|
|
1331
1333
|
}
|
|
1332
1334
|
return cm.insertMessageAfter(request.params.id, afterMessageId, role, content, contentBlocks, tokenUsage);
|
|
1333
1335
|
});
|
|
1334
|
-
server2.get("/_web/ai/
|
|
1335
|
-
return cm.
|
|
1336
|
+
server2.get("/_web/ai/chats/:id/token-usage", async (request) => {
|
|
1337
|
+
return cm.getAIChatTokenUsage(request.params.id);
|
|
1336
1338
|
});
|
|
1337
1339
|
server2.get("/_web/ai/debug/schema", async () => {
|
|
1338
1340
|
return cm.getAiSchema();
|
|
@@ -1353,7 +1355,7 @@ function registerAiConversationRoutes(server2, ctx) {
|
|
|
1353
1355
|
const cleared = cm.clearAllDebugContext();
|
|
1354
1356
|
return { success: true, cleared };
|
|
1355
1357
|
});
|
|
1356
|
-
server2.get("/_web/ai/
|
|
1358
|
+
server2.get("/_web/ai/chats/:id/estimate-tokens", async (request) => {
|
|
1357
1359
|
const history = cm.getHistoryForAgent(request.params.id);
|
|
1358
1360
|
const tokens = countMessagesTokens(history.map((m) => ({ role: m.role, content: m.content })));
|
|
1359
1361
|
return { success: true, tokens, messageCount: history.length };
|
|
@@ -1380,8 +1382,8 @@ function registerAiSummaryRoutes(server2, ctx) {
|
|
|
1380
1382
|
if (!deps) return;
|
|
1381
1383
|
const { sessionAdapter: adapter } = ctx;
|
|
1382
1384
|
server2.post("/_web/sessions/:id/summaries/generate", async (request, reply) => {
|
|
1383
|
-
const {
|
|
1384
|
-
const result = await summary_service_exports.generateSummary(adapter, request.params.id,
|
|
1385
|
+
const { segmentId, locale, forceRegenerate, strategy } = request.body;
|
|
1386
|
+
const result = await summary_service_exports.generateSummary(adapter, request.params.id, segmentId, deps, {
|
|
1385
1387
|
locale,
|
|
1386
1388
|
forceRegenerate,
|
|
1387
1389
|
strategy
|
|
@@ -1403,8 +1405,8 @@ function registerAiSummaryRoutes(server2, ctx) {
|
|
|
1403
1405
|
return result;
|
|
1404
1406
|
});
|
|
1405
1407
|
server2.post("/_web/sessions/:id/summaries/check-can-generate", async (request) => {
|
|
1406
|
-
const {
|
|
1407
|
-
return summary_service_exports.checkCanGenerate(adapter, request.params.id,
|
|
1408
|
+
const { segmentIds } = request.body;
|
|
1409
|
+
return summary_service_exports.checkCanGenerate(adapter, request.params.id, segmentIds);
|
|
1408
1410
|
});
|
|
1409
1411
|
}
|
|
1410
1412
|
|
|
@@ -1844,7 +1846,7 @@ function registerSharedRoutes(server2, ctx, options) {
|
|
|
1844
1846
|
if (options?.requireAi) {
|
|
1845
1847
|
const missing = [];
|
|
1846
1848
|
if (!ctx.aiDataDir) missing.push("aiDataDir");
|
|
1847
|
-
if (!ctx.
|
|
1849
|
+
if (!ctx.aiChatManager) missing.push("aiChatManager");
|
|
1848
1850
|
if (!ctx.assistantManager) missing.push("assistantManager");
|
|
1849
1851
|
if (!ctx.skillManagerCore) missing.push("skillManagerCore");
|
|
1850
1852
|
if (!ctx.llmConfigStore) missing.push("llmConfigStore");
|
|
@@ -1862,7 +1864,7 @@ function registerSharedRoutes(server2, ctx, options) {
|
|
|
1862
1864
|
registerAiAgentStreamRoutes(server2, ctx);
|
|
1863
1865
|
registerAiFilterRoutes(server2, ctx);
|
|
1864
1866
|
registerAiToolRoutes(server2, ctx);
|
|
1865
|
-
|
|
1867
|
+
registerAiChatRoutes(server2, ctx);
|
|
1866
1868
|
registerAiSummaryRoutes(server2, ctx);
|
|
1867
1869
|
registerMergeRoutes(server2, ctx);
|
|
1868
1870
|
registerCacheRoutes(server2, ctx);
|
|
@@ -1920,8 +1922,9 @@ function createServer() {
|
|
|
1920
1922
|
});
|
|
1921
1923
|
server2.addHook("onRequest", authHook);
|
|
1922
1924
|
server2.setErrorHandler((error, _request, reply) => {
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
+
const apiError = apiErrorFromUnknown(error);
|
|
1926
|
+
if (apiError) {
|
|
1927
|
+
reply.code(apiError.statusCode).send(errorResponse(apiError));
|
|
1925
1928
|
return;
|
|
1926
1929
|
}
|
|
1927
1930
|
if (error.statusCode === 413) {
|
|
@@ -2337,7 +2340,7 @@ function registerWebRoutes(server2, dbManager2, options) {
|
|
|
2337
2340
|
const resolvedPathProvider = options?.pathProvider ?? fallbackPathProvider;
|
|
2338
2341
|
const ai = options?.aiContext;
|
|
2339
2342
|
const cliStreamImport = async (dm, filePath) => {
|
|
2340
|
-
const { streamImport: streamImport2 } = await import("./stream-import-
|
|
2343
|
+
const { streamImport: streamImport2 } = await import("./stream-import-TFDBNVIW.mjs");
|
|
2341
2344
|
const result = await streamImport2(dm, filePath);
|
|
2342
2345
|
if (!result.sessionId) throw new Error("Import succeeded but no sessionId returned");
|
|
2343
2346
|
return { sessionId: result.sessionId };
|
|
@@ -2373,7 +2376,7 @@ function registerWebRoutes(server2, dbManager2, options) {
|
|
|
2373
2376
|
},
|
|
2374
2377
|
...ai && {
|
|
2375
2378
|
aiDataDir: ai.aiDataDir,
|
|
2376
|
-
|
|
2379
|
+
aiChatManager: ai.aiChatManager,
|
|
2377
2380
|
assistantManager: ai.assistantManager,
|
|
2378
2381
|
skillManagerCore: ai.skillManagerCore,
|
|
2379
2382
|
llmConfigStore: ai.llmConfigStore,
|
|
@@ -2433,24 +2436,6 @@ function registerProxyRoutes(server2) {
|
|
|
2433
2436
|
});
|
|
2434
2437
|
}
|
|
2435
2438
|
|
|
2436
|
-
// src/ai/logger.ts
|
|
2437
|
-
var logger = null;
|
|
2438
|
-
function initServerAiLogger(logsDir) {
|
|
2439
|
-
if (!logger) {
|
|
2440
|
-
logger = new AiLogger(logsDir);
|
|
2441
|
-
}
|
|
2442
|
-
return logger;
|
|
2443
|
-
}
|
|
2444
|
-
function getServerAiLogger() {
|
|
2445
|
-
return logger;
|
|
2446
|
-
}
|
|
2447
|
-
function closeServerAiLogger() {
|
|
2448
|
-
if (logger) {
|
|
2449
|
-
logger.close();
|
|
2450
|
-
logger = null;
|
|
2451
|
-
}
|
|
2452
|
-
}
|
|
2453
|
-
|
|
2454
2439
|
// src/ai/manager-factory.ts
|
|
2455
2440
|
import * as fs5 from "fs";
|
|
2456
2441
|
import * as path7 from "path";
|
|
@@ -2510,379 +2495,14 @@ function getSkillManagerCore(aiDataDir) {
|
|
|
2510
2495
|
return cached.skill;
|
|
2511
2496
|
}
|
|
2512
2497
|
|
|
2513
|
-
// src/ai/tool-adapter.ts
|
|
2514
|
-
var DEFAULT_MAX_TOOL_RESULT_TOKENS = 8e3;
|
|
2515
|
-
var TOOL_TRUNCATION_STRATEGY = {
|
|
2516
|
-
search_messages: "keep_first",
|
|
2517
|
-
deep_search_messages: "keep_first",
|
|
2518
|
-
get_recent_messages: "keep_last",
|
|
2519
|
-
get_message_context: "keep_last",
|
|
2520
|
-
get_session_messages: "keep_last",
|
|
2521
|
-
get_conversation_between: "keep_last"
|
|
2522
|
-
};
|
|
2523
|
-
function convertJsonSchemaToParameters(schema) {
|
|
2524
|
-
const properties = {};
|
|
2525
|
-
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
2526
|
-
properties[key] = { ...prop };
|
|
2527
|
-
}
|
|
2528
|
-
return {
|
|
2529
|
-
type: "object",
|
|
2530
|
-
properties,
|
|
2531
|
-
required: schema.required || []
|
|
2532
|
-
};
|
|
2533
|
-
}
|
|
2534
|
-
function adaptToolsForAgent(tools, getContext, options) {
|
|
2535
|
-
const tokenBudget = options?.maxToolResultTokens ?? DEFAULT_MAX_TOOL_RESULT_TOKENS;
|
|
2536
|
-
return tools.map((tool) => ({
|
|
2537
|
-
name: tool.name,
|
|
2538
|
-
label: tool.name,
|
|
2539
|
-
description: tool.description,
|
|
2540
|
-
parameters: convertJsonSchemaToParameters(tool.inputSchema),
|
|
2541
|
-
async execute(_toolCallId, params) {
|
|
2542
|
-
const toolParams = params && typeof params === "object" ? params : {};
|
|
2543
|
-
const ctx = getContext();
|
|
2544
|
-
const execCtx = {
|
|
2545
|
-
db: ctx.db,
|
|
2546
|
-
dataProvider: new CoreDataProvider(ctx.db),
|
|
2547
|
-
sessionId: ctx.sessionId,
|
|
2548
|
-
locale: ctx.locale,
|
|
2549
|
-
segmentText: (texts, locale, options2) => batchSegmentWithFrequency(texts, locale, options2)
|
|
2550
|
-
};
|
|
2551
|
-
try {
|
|
2552
|
-
const result = await tool.handler(toolParams, execCtx);
|
|
2553
|
-
if (result.rawMessages && result.rawMessages.length > 0) {
|
|
2554
|
-
const pipelineResult = applyPreprocessingPipeline({
|
|
2555
|
-
rawMessages: result.rawMessages,
|
|
2556
|
-
locale: ctx.locale,
|
|
2557
|
-
maxToolResultTokens: tokenBudget,
|
|
2558
|
-
truncationStrategy: TOOL_TRUNCATION_STRATEGY[tool.name] ?? "keep_last",
|
|
2559
|
-
extraDetails: result.data ?? {},
|
|
2560
|
-
logger: getServerAiLogger() ?? void 0
|
|
2561
|
-
});
|
|
2562
|
-
return { content: [{ type: "text", text: pipelineResult.text }], details: null };
|
|
2563
|
-
}
|
|
2564
|
-
return { content: [{ type: "text", text: result.content }], details: null };
|
|
2565
|
-
} catch (error) {
|
|
2566
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
2567
|
-
return { content: [{ type: "text", text: `Error: ${msg}` }], details: null };
|
|
2568
|
-
}
|
|
2569
|
-
}
|
|
2570
|
-
}));
|
|
2571
|
-
}
|
|
2572
|
-
|
|
2573
|
-
// src/ai/llm-config.ts
|
|
2574
|
-
import * as fs6 from "fs";
|
|
2575
|
-
import * as path8 from "path";
|
|
2576
|
-
function loadLlmConfig(aiDataDir) {
|
|
2577
|
-
const configPath = path8.join(aiDataDir, "llm-config.json");
|
|
2578
|
-
if (!fs6.existsSync(configPath)) {
|
|
2579
|
-
return { configs: [], defaultAssistant: null, fastModel: null };
|
|
2580
|
-
}
|
|
2581
|
-
try {
|
|
2582
|
-
const data = JSON.parse(fs6.readFileSync(configPath, "utf-8"));
|
|
2583
|
-
const configs = (data.configs || []).map((c) => {
|
|
2584
|
-
const provider = c.provider || "";
|
|
2585
|
-
const authProfile = c.authProfile;
|
|
2586
|
-
const profileKey = resolveApiKey(provider, authProfile);
|
|
2587
|
-
const rawKey = c.apiKey || "";
|
|
2588
|
-
const fallbackKey = rawKey.startsWith("enc:") ? "" : rawKey;
|
|
2589
|
-
return {
|
|
2590
|
-
...c,
|
|
2591
|
-
apiKey: profileKey || fallbackKey
|
|
2592
|
-
};
|
|
2593
|
-
});
|
|
2594
|
-
return {
|
|
2595
|
-
configs,
|
|
2596
|
-
defaultAssistant: data.defaultAssistant ?? null,
|
|
2597
|
-
fastModel: data.fastModel ?? null
|
|
2598
|
-
};
|
|
2599
|
-
} catch {
|
|
2600
|
-
return { configs: [], defaultAssistant: null, fastModel: null };
|
|
2601
|
-
}
|
|
2602
|
-
}
|
|
2603
|
-
function resolveSlot(slot, configs) {
|
|
2604
|
-
if (slot && configs.some((c) => c.id === slot.configId)) return slot;
|
|
2605
|
-
const fallback = configs[0];
|
|
2606
|
-
if (!fallback) return null;
|
|
2607
|
-
return { configId: fallback.id, modelId: fallback.model };
|
|
2608
|
-
}
|
|
2609
|
-
function getDefaultAssistantConfig(aiDataDir) {
|
|
2610
|
-
const store = loadLlmConfig(aiDataDir);
|
|
2611
|
-
const slot = resolveSlot(store.defaultAssistant, store.configs);
|
|
2612
|
-
if (!slot) return null;
|
|
2613
|
-
const config = store.configs.find((c) => c.id === slot.configId);
|
|
2614
|
-
if (!config) return null;
|
|
2615
|
-
return { ...config, model: slot.modelId || config.model };
|
|
2616
|
-
}
|
|
2617
|
-
function buildPiModel2(config) {
|
|
2618
|
-
return buildPiModel(config);
|
|
2619
|
-
}
|
|
2620
|
-
|
|
2621
|
-
// src/ai/assistant-loader.ts
|
|
2622
|
-
import * as fs7 from "fs";
|
|
2623
|
-
import * as path9 from "path";
|
|
2624
|
-
function loadAssistantConfig(aiDataDir, assistantId) {
|
|
2625
|
-
const filePath = path9.join(aiDataDir, "assistants", `${assistantId}.md`);
|
|
2626
|
-
if (!fs7.existsSync(filePath)) return null;
|
|
2627
|
-
try {
|
|
2628
|
-
const content = fs7.readFileSync(filePath, "utf-8");
|
|
2629
|
-
return parseAssistantFile(content, filePath);
|
|
2630
|
-
} catch {
|
|
2631
|
-
return null;
|
|
2632
|
-
}
|
|
2633
|
-
}
|
|
2634
|
-
|
|
2635
|
-
// src/ai/agent.ts
|
|
2636
|
-
async function runServerAgent(options) {
|
|
2637
|
-
const {
|
|
2638
|
-
userMessage,
|
|
2639
|
-
conversationId,
|
|
2640
|
-
historyLeafMessageId,
|
|
2641
|
-
chatType = "group",
|
|
2642
|
-
locale = "zh-CN",
|
|
2643
|
-
assistantSystemPrompt,
|
|
2644
|
-
skillMenu,
|
|
2645
|
-
skillDef,
|
|
2646
|
-
compressionConfig,
|
|
2647
|
-
tools = [],
|
|
2648
|
-
aiDataDir,
|
|
2649
|
-
convManager: convManager2,
|
|
2650
|
-
onEvent,
|
|
2651
|
-
abortSignal,
|
|
2652
|
-
ownerInfo,
|
|
2653
|
-
mentionedMembers,
|
|
2654
|
-
dataSnapshot,
|
|
2655
|
-
thinkingLevel
|
|
2656
|
-
} = options;
|
|
2657
|
-
const aiLogger = getServerAiLogger();
|
|
2658
|
-
await initTokenizer();
|
|
2659
|
-
const llmConfig = getDefaultAssistantConfig(aiDataDir);
|
|
2660
|
-
if (!llmConfig) {
|
|
2661
|
-
onEvent({ type: "error", error: { name: "ConfigError", message: "LLM service not configured" } });
|
|
2662
|
-
onEvent({ type: "done", isFinished: true });
|
|
2663
|
-
return;
|
|
2664
|
-
}
|
|
2665
|
-
const piModel = buildPiModel2(llmConfig);
|
|
2666
|
-
const t = createAiTranslate(locale);
|
|
2667
|
-
let skillCtx;
|
|
2668
|
-
if (skillDef) {
|
|
2669
|
-
skillCtx = { skillDef };
|
|
2670
|
-
} else if (skillMenu) {
|
|
2671
|
-
skillCtx = { skillMenu };
|
|
2672
|
-
}
|
|
2673
|
-
const systemPrompt = buildSystemPrompt({
|
|
2674
|
-
t,
|
|
2675
|
-
chatType,
|
|
2676
|
-
assistantSystemPrompt,
|
|
2677
|
-
ownerInfo,
|
|
2678
|
-
locale,
|
|
2679
|
-
skillCtx,
|
|
2680
|
-
mentionedMembers,
|
|
2681
|
-
dataSnapshot
|
|
2682
|
-
});
|
|
2683
|
-
const handler = new AgentEventHandler({
|
|
2684
|
-
onChunk: onEvent,
|
|
2685
|
-
context: {},
|
|
2686
|
-
systemPrompt
|
|
2687
|
-
});
|
|
2688
|
-
if (compressionConfig?.enabled && historyLeafMessageId === void 0) {
|
|
2689
|
-
const llmAdapter = createCompressionLlmAdapter({
|
|
2690
|
-
piModel,
|
|
2691
|
-
apiKey: llmConfig.apiKey,
|
|
2692
|
-
onCompressing: () => handler.emitStatus("compressing", [])
|
|
2693
|
-
});
|
|
2694
|
-
const compressionResult = await checkAndCompress(
|
|
2695
|
-
conversationId,
|
|
2696
|
-
compressionConfig,
|
|
2697
|
-
systemPrompt,
|
|
2698
|
-
llmAdapter,
|
|
2699
|
-
convManager2,
|
|
2700
|
-
aiLogger ?? void 0
|
|
2701
|
-
);
|
|
2702
|
-
if (compressionResult.compressed) {
|
|
2703
|
-
onEvent({
|
|
2704
|
-
type: "compression_done",
|
|
2705
|
-
compressionResult: {
|
|
2706
|
-
summaryContent: compressionResult.summaryContent ?? "",
|
|
2707
|
-
tokensBefore: compressionResult.tokensBefore ?? 0,
|
|
2708
|
-
tokensAfter: compressionResult.tokensAfter ?? 0,
|
|
2709
|
-
timestamp: Date.now()
|
|
2710
|
-
}
|
|
2711
|
-
});
|
|
2712
|
-
}
|
|
2713
|
-
} else if (compressionConfig?.enabled && historyLeafMessageId !== void 0) {
|
|
2714
|
-
aiLogger?.info?.("Compression", "Skipping compression for edited branch request", {
|
|
2715
|
-
conversationId,
|
|
2716
|
-
historyLeafMessageId
|
|
2717
|
-
});
|
|
2718
|
-
}
|
|
2719
|
-
if (abortSignal?.aborted) {
|
|
2720
|
-
handler.emitStatus("aborted", [], { force: true });
|
|
2721
|
-
onEvent({ type: "done", isFinished: true, usage: handler.cloneUsage() });
|
|
2722
|
-
return;
|
|
2723
|
-
}
|
|
2724
|
-
let history = [];
|
|
2725
|
-
try {
|
|
2726
|
-
history = convManager2.getHistoryForAgent(conversationId, void 0, historyLeafMessageId);
|
|
2727
|
-
} catch {
|
|
2728
|
-
}
|
|
2729
|
-
handler.emitStatus("preparing", [], { pendingUserMessage: userMessage, force: true });
|
|
2730
|
-
const steerMessage = t("ai.agent.answerWithoutTools");
|
|
2731
|
-
let cachedMessages = [];
|
|
2732
|
-
try {
|
|
2733
|
-
const result = await runAgentCore({
|
|
2734
|
-
piModel,
|
|
2735
|
-
apiKey: llmConfig.apiKey,
|
|
2736
|
-
systemPrompt,
|
|
2737
|
-
tools,
|
|
2738
|
-
history,
|
|
2739
|
-
userMessage,
|
|
2740
|
-
maxToolRounds: 5,
|
|
2741
|
-
abortSignal,
|
|
2742
|
-
steerMessage,
|
|
2743
|
-
thinkingLevel,
|
|
2744
|
-
onConvertToLlm: (filteredMessages) => {
|
|
2745
|
-
cachedMessages = filteredMessages;
|
|
2746
|
-
},
|
|
2747
|
-
onEvent: (coreEvent) => handler.handleCoreEvent(coreEvent, cachedMessages),
|
|
2748
|
-
onDebugContext: (messages) => {
|
|
2749
|
-
try {
|
|
2750
|
-
convManager2.setPendingDebugContext(conversationId, JSON.stringify(messages, null, 2));
|
|
2751
|
-
} catch {
|
|
2752
|
-
}
|
|
2753
|
-
}
|
|
2754
|
-
});
|
|
2755
|
-
if (result.error) {
|
|
2756
|
-
const friendlyMessage = formatAIError(result.error);
|
|
2757
|
-
onEvent({ type: "error", error: { name: "AgentError", message: friendlyMessage } });
|
|
2758
|
-
}
|
|
2759
|
-
handler.emitStatus("completed", cachedMessages, { force: true });
|
|
2760
|
-
onEvent({ type: "done", isFinished: true, usage: result.usage });
|
|
2761
|
-
} catch (error) {
|
|
2762
|
-
const friendlyMessage = formatAIError(error);
|
|
2763
|
-
aiLogger?.error("ServerAgent", "Agent execution error", { error: String(error) });
|
|
2764
|
-
handler.emitStatus("error", cachedMessages, { force: true });
|
|
2765
|
-
onEvent({ type: "error", error: { name: "AgentError", message: friendlyMessage } });
|
|
2766
|
-
onEvent({ type: "done", isFinished: true, usage: handler.cloneUsage() });
|
|
2767
|
-
}
|
|
2768
|
-
}
|
|
2769
|
-
|
|
2770
|
-
// src/ai/agent-stream-runner.ts
|
|
2771
|
-
function getAiDir(dbManager2) {
|
|
2772
|
-
const pathProvider = dbManager2["pathProvider"];
|
|
2773
|
-
if (!pathProvider) {
|
|
2774
|
-
throw Object.assign(new Error("PathProvider not available"), { statusCode: 500 });
|
|
2775
|
-
}
|
|
2776
|
-
return pathProvider.getAiDataDir();
|
|
2777
|
-
}
|
|
2778
|
-
function createCliRunAgentStream(dbManager2, convManager2) {
|
|
2779
|
-
return async (params, onEvent, abortSignal) => {
|
|
2780
|
-
const {
|
|
2781
|
-
userMessage,
|
|
2782
|
-
conversationId,
|
|
2783
|
-
historyLeafMessageId,
|
|
2784
|
-
sessionId,
|
|
2785
|
-
chatType,
|
|
2786
|
-
locale,
|
|
2787
|
-
assistantId,
|
|
2788
|
-
skillId,
|
|
2789
|
-
enableAutoSkill,
|
|
2790
|
-
compressionConfig,
|
|
2791
|
-
ownerInfo,
|
|
2792
|
-
mentionedMembers,
|
|
2793
|
-
thinkingLevel
|
|
2794
|
-
} = params;
|
|
2795
|
-
const aiDataDir = getAiDir(dbManager2);
|
|
2796
|
-
let assistantSystemPrompt;
|
|
2797
|
-
if (assistantId) {
|
|
2798
|
-
const assistantConfig = loadAssistantConfig(aiDataDir, assistantId);
|
|
2799
|
-
if (assistantConfig?.systemPrompt) {
|
|
2800
|
-
assistantSystemPrompt = assistantConfig.systemPrompt;
|
|
2801
|
-
}
|
|
2802
|
-
}
|
|
2803
|
-
const llmConfig = getDefaultAssistantConfig(aiDataDir);
|
|
2804
|
-
const maxToolResultPercent = compressionConfig?.maxToolResultPercent ?? 50;
|
|
2805
|
-
const contextWindow = llmConfig ? buildPiModel2(llmConfig).contextWindow ?? 128e3 : 128e3;
|
|
2806
|
-
const maxToolResultTokens = Math.floor(contextWindow * (maxToolResultPercent / 100));
|
|
2807
|
-
const db = dbManager2.open?.(sessionId);
|
|
2808
|
-
const agentTools = db ? adaptToolsForAgent(AGENT_TOOL_REGISTRY, () => ({ db, sessionId, locale }), { maxToolResultTokens }) : [];
|
|
2809
|
-
const skillMgr = new SkillManager(aiDataDir);
|
|
2810
|
-
skillMgr.init();
|
|
2811
|
-
const toolNames = agentTools.map((t) => t.name);
|
|
2812
|
-
let resolvedSkillDef;
|
|
2813
|
-
let resolvedSkillMenu;
|
|
2814
|
-
if (skillId) {
|
|
2815
|
-
const def = skillMgr.getSkillConfig(skillId);
|
|
2816
|
-
if (def) resolvedSkillDef = { name: def.name, prompt: def.prompt };
|
|
2817
|
-
} else if (enableAutoSkill) {
|
|
2818
|
-
const menu = skillMgr.getSkillMenu(chatType ?? "group", toolNames);
|
|
2819
|
-
if (menu) resolvedSkillMenu = menu;
|
|
2820
|
-
}
|
|
2821
|
-
if (resolvedSkillMenu) {
|
|
2822
|
-
const activateSkillTool = createActivateSkillTool({
|
|
2823
|
-
chatType: chatType ?? "group",
|
|
2824
|
-
allowedTools: toolNames,
|
|
2825
|
-
locale,
|
|
2826
|
-
getSkillConfig: (id) => skillMgr.getSkillConfig(id)
|
|
2827
|
-
});
|
|
2828
|
-
agentTools.push(activateSkillTool);
|
|
2829
|
-
}
|
|
2830
|
-
const resolvedCompression = compressionConfig?.enabled ? {
|
|
2831
|
-
enabled: true,
|
|
2832
|
-
tokenThresholdPercent: compressionConfig.tokenThresholdPercent ?? 75,
|
|
2833
|
-
bufferSizePercent: compressionConfig.bufferSizePercent ?? 20,
|
|
2834
|
-
maxToolResultPercent: compressionConfig.maxToolResultPercent
|
|
2835
|
-
} : void 0;
|
|
2836
|
-
let dataSnapshot;
|
|
2837
|
-
if (db) {
|
|
2838
|
-
try {
|
|
2839
|
-
const overview = getChatOverview(db, 5);
|
|
2840
|
-
if (overview) {
|
|
2841
|
-
dataSnapshot = {
|
|
2842
|
-
name: overview.name,
|
|
2843
|
-
platform: overview.platform,
|
|
2844
|
-
type: overview.type,
|
|
2845
|
-
totalMessages: overview.totalMessages,
|
|
2846
|
-
totalMembers: overview.totalMembers,
|
|
2847
|
-
firstMessageTs: overview.firstMessageTs,
|
|
2848
|
-
lastMessageTs: overview.lastMessageTs,
|
|
2849
|
-
capturedAt: Math.floor(Date.now() / 1e3)
|
|
2850
|
-
};
|
|
2851
|
-
}
|
|
2852
|
-
} catch {
|
|
2853
|
-
}
|
|
2854
|
-
}
|
|
2855
|
-
await runServerAgent({
|
|
2856
|
-
userMessage,
|
|
2857
|
-
conversationId,
|
|
2858
|
-
historyLeafMessageId,
|
|
2859
|
-
chatType,
|
|
2860
|
-
locale,
|
|
2861
|
-
assistantSystemPrompt,
|
|
2862
|
-
skillMenu: resolvedSkillMenu,
|
|
2863
|
-
skillDef: resolvedSkillDef,
|
|
2864
|
-
compressionConfig: resolvedCompression,
|
|
2865
|
-
tools: agentTools,
|
|
2866
|
-
aiDataDir,
|
|
2867
|
-
convManager: convManager2,
|
|
2868
|
-
onEvent,
|
|
2869
|
-
abortSignal,
|
|
2870
|
-
ownerInfo,
|
|
2871
|
-
mentionedMembers,
|
|
2872
|
-
dataSnapshot,
|
|
2873
|
-
thinkingLevel
|
|
2874
|
-
});
|
|
2875
|
-
};
|
|
2876
|
-
}
|
|
2877
|
-
|
|
2878
2498
|
// ../../packages/sync/src/types.ts
|
|
2879
2499
|
var noop = () => {
|
|
2880
2500
|
};
|
|
2881
2501
|
var NOOP_LOGGER = { info: noop, warn: noop, error: noop };
|
|
2882
2502
|
|
|
2883
2503
|
// ../../packages/sync/src/data-source-manager.ts
|
|
2884
|
-
import * as
|
|
2885
|
-
import * as
|
|
2504
|
+
import * as fs6 from "fs";
|
|
2505
|
+
import * as path8 from "path";
|
|
2886
2506
|
import * as crypto from "crypto";
|
|
2887
2507
|
var CONFIG_FILE = "data-sources.json";
|
|
2888
2508
|
function generateId(prefix = "ds") {
|
|
@@ -2905,22 +2525,22 @@ function isValidDataSourceArray(data) {
|
|
|
2905
2525
|
var DataSourceManager = class {
|
|
2906
2526
|
configDir;
|
|
2907
2527
|
logger;
|
|
2908
|
-
constructor(configDir,
|
|
2528
|
+
constructor(configDir, logger) {
|
|
2909
2529
|
this.configDir = configDir;
|
|
2910
|
-
this.logger =
|
|
2530
|
+
this.logger = logger ?? NOOP_LOGGER;
|
|
2911
2531
|
}
|
|
2912
2532
|
getConfigPath() {
|
|
2913
|
-
return
|
|
2533
|
+
return path8.join(this.configDir, CONFIG_FILE);
|
|
2914
2534
|
}
|
|
2915
2535
|
ensureDir() {
|
|
2916
|
-
|
|
2536
|
+
fs6.mkdirSync(this.configDir, { recursive: true });
|
|
2917
2537
|
}
|
|
2918
2538
|
// ==================== Load / Save ====================
|
|
2919
2539
|
loadAll() {
|
|
2920
2540
|
try {
|
|
2921
2541
|
const filePath = this.getConfigPath();
|
|
2922
|
-
if (
|
|
2923
|
-
const raw =
|
|
2542
|
+
if (fs6.existsSync(filePath)) {
|
|
2543
|
+
const raw = fs6.readFileSync(filePath, "utf-8");
|
|
2924
2544
|
const parsed = JSON.parse(raw);
|
|
2925
2545
|
if (!isValidDataSourceArray(parsed)) {
|
|
2926
2546
|
this.logger.warn("[DataSource] Incompatible config format detected, returning empty.");
|
|
@@ -2939,7 +2559,7 @@ var DataSourceManager = class {
|
|
|
2939
2559
|
saveAll(sources) {
|
|
2940
2560
|
try {
|
|
2941
2561
|
this.ensureDir();
|
|
2942
|
-
|
|
2562
|
+
fs6.writeFileSync(this.getConfigPath(), JSON.stringify(sources, null, 2), "utf-8");
|
|
2943
2563
|
} catch (err) {
|
|
2944
2564
|
this.logger.error("[DataSource] Failed to save config", err);
|
|
2945
2565
|
}
|
|
@@ -3064,7 +2684,7 @@ function parseRemoteSessionsResponse(body) {
|
|
|
3064
2684
|
}
|
|
3065
2685
|
|
|
3066
2686
|
// ../../packages/sync/src/pull-engine.ts
|
|
3067
|
-
import * as
|
|
2687
|
+
import * as fs7 from "fs";
|
|
3068
2688
|
import * as crypto2 from "crypto";
|
|
3069
2689
|
var MAX_PAGES_PER_PULL = 5e3;
|
|
3070
2690
|
var PULL_OVERLAP_SECONDS = 60;
|
|
@@ -3084,7 +2704,7 @@ function parseSyncFromFile(filePath) {
|
|
|
3084
2704
|
try {
|
|
3085
2705
|
const isJsonl = filePath.endsWith(".jsonl");
|
|
3086
2706
|
if (isJsonl) {
|
|
3087
|
-
const content =
|
|
2707
|
+
const content = fs7.readFileSync(filePath, "utf-8");
|
|
3088
2708
|
const lines = content.trimEnd().split("\n");
|
|
3089
2709
|
for (let i = lines.length - 1; i >= Math.max(0, lines.length - 5); i--) {
|
|
3090
2710
|
try {
|
|
@@ -3103,7 +2723,7 @@ function parseSyncFromFile(filePath) {
|
|
|
3103
2723
|
}
|
|
3104
2724
|
return null;
|
|
3105
2725
|
}
|
|
3106
|
-
const raw =
|
|
2726
|
+
const raw = fs7.readFileSync(filePath, "utf-8");
|
|
3107
2727
|
const parsed = JSON.parse(raw);
|
|
3108
2728
|
if (parsed.sync && typeof parsed.sync === "object") {
|
|
3109
2729
|
const s = parsed.sync;
|
|
@@ -3117,7 +2737,7 @@ function parseSyncFromFile(filePath) {
|
|
|
3117
2737
|
function fileContainsMessages(filePath) {
|
|
3118
2738
|
try {
|
|
3119
2739
|
if (filePath.endsWith(".jsonl")) {
|
|
3120
|
-
const content =
|
|
2740
|
+
const content = fs7.readFileSync(filePath, "utf-8");
|
|
3121
2741
|
for (const line of content.split("\n")) {
|
|
3122
2742
|
const trimmed = line.trim();
|
|
3123
2743
|
if (!trimmed) continue;
|
|
@@ -3130,7 +2750,7 @@ function fileContainsMessages(filePath) {
|
|
|
3130
2750
|
}
|
|
3131
2751
|
return false;
|
|
3132
2752
|
}
|
|
3133
|
-
const raw =
|
|
2753
|
+
const raw = fs7.readFileSync(filePath, "utf-8");
|
|
3134
2754
|
const parsed = JSON.parse(raw);
|
|
3135
2755
|
return Array.isArray(parsed.messages) && parsed.messages.length > 0;
|
|
3136
2756
|
} catch {
|
|
@@ -3139,7 +2759,7 @@ function fileContainsMessages(filePath) {
|
|
|
3139
2759
|
}
|
|
3140
2760
|
function cleanupTempFile(filePath) {
|
|
3141
2761
|
try {
|
|
3142
|
-
if (
|
|
2762
|
+
if (fs7.existsSync(filePath)) fs7.unlinkSync(filePath);
|
|
3143
2763
|
} catch {
|
|
3144
2764
|
}
|
|
3145
2765
|
}
|
|
@@ -3199,7 +2819,7 @@ var PullEngine = class {
|
|
|
3199
2819
|
limit: ds.pullLimit
|
|
3200
2820
|
});
|
|
3201
2821
|
try {
|
|
3202
|
-
const stat2 =
|
|
2822
|
+
const stat2 = fs7.statSync(tempFile);
|
|
3203
2823
|
this.logger.info(`[Pull] "${sess.name}" page ${pageCount}: fetched ${stat2.size} bytes`);
|
|
3204
2824
|
const sync0 = parseSyncFromFile(tempFile);
|
|
3205
2825
|
if (stat2.size < 1024) {
|
|
@@ -3217,7 +2837,7 @@ var PullEngine = class {
|
|
|
3217
2837
|
since,
|
|
3218
2838
|
limit: ds.pullLimit
|
|
3219
2839
|
});
|
|
3220
|
-
const retryStat =
|
|
2840
|
+
const retryStat = fs7.statSync(retryFile);
|
|
3221
2841
|
this.logger.info(`[Pull] "${sess.name}" retry ${ri + 1}: fetched ${retryStat.size} bytes`);
|
|
3222
2842
|
const retrySync = parseSyncFromFile(retryFile);
|
|
3223
2843
|
if (retryStat.size < 1024 && !fileContainsMessages(retryFile) && retrySync?.hasMore === false) {
|
|
@@ -3491,13 +3111,13 @@ function reloadTimer(dsId, skipInitialPull = false) {
|
|
|
3491
3111
|
}
|
|
3492
3112
|
|
|
3493
3113
|
// src/sync/adapters.ts
|
|
3494
|
-
import * as
|
|
3114
|
+
import * as fs8 from "fs";
|
|
3495
3115
|
import * as os4 from "os";
|
|
3496
|
-
import * as
|
|
3116
|
+
import * as path9 from "path";
|
|
3497
3117
|
import * as crypto3 from "crypto";
|
|
3498
3118
|
function getTempFilePath(ext) {
|
|
3499
3119
|
const id = crypto3.randomBytes(8).toString("hex");
|
|
3500
|
-
return
|
|
3120
|
+
return path9.join(os4.tmpdir(), `chatlab-pull-${id}${ext}`);
|
|
3501
3121
|
}
|
|
3502
3122
|
var NodeFetcher = class {
|
|
3503
3123
|
async fetchToTempFile(baseUrl, remoteSessionId, token, params) {
|
|
@@ -3514,45 +3134,38 @@ var NodeFetcher = class {
|
|
|
3514
3134
|
const isJsonl = contentType.includes("ndjson") || contentType.includes("jsonl");
|
|
3515
3135
|
const tempFile = getTempFilePath(isJsonl ? ".jsonl" : ".json");
|
|
3516
3136
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
3517
|
-
|
|
3137
|
+
fs8.writeFileSync(tempFile, buffer);
|
|
3518
3138
|
return tempFile;
|
|
3519
3139
|
}
|
|
3520
3140
|
};
|
|
3521
|
-
function resolveNativeBinding2() {
|
|
3522
|
-
if (process.versions.electron) return void 0;
|
|
3523
|
-
const nativePath = resolveCliPath("native/better_sqlite3.node");
|
|
3524
|
-
if (fs10.existsSync(nativePath)) return nativePath;
|
|
3525
|
-
return void 0;
|
|
3526
|
-
}
|
|
3527
3141
|
var DirectImporter = class {
|
|
3528
3142
|
dbManager;
|
|
3529
|
-
nativeBinding;
|
|
3530
3143
|
logger;
|
|
3531
|
-
constructor(dbManager2,
|
|
3144
|
+
constructor(dbManager2, logger) {
|
|
3532
3145
|
this.dbManager = dbManager2;
|
|
3533
|
-
this.
|
|
3534
|
-
this.logger = logger2 ?? NOOP_LOGGER;
|
|
3146
|
+
this.logger = logger ?? NOOP_LOGGER;
|
|
3535
3147
|
}
|
|
3536
3148
|
sessionExists(sessionId) {
|
|
3537
3149
|
const dbPath = this.dbManager.getDbPath(sessionId);
|
|
3538
|
-
if (!
|
|
3150
|
+
if (!fs8.existsSync(dbPath)) return false;
|
|
3539
3151
|
try {
|
|
3540
|
-
const db =
|
|
3152
|
+
const db = this.dbManager.openRawSessionDatabase(sessionId, { readonly: true });
|
|
3541
3153
|
const row = db.prepare("SELECT COUNT(*) as cnt FROM sqlite_master WHERE type='table' AND name='message'").get();
|
|
3542
3154
|
db.close();
|
|
3543
3155
|
if (row.cnt === 0) {
|
|
3544
3156
|
this.logger.warn(`[DirectImporter] DB file exists but has no message table: ${sessionId}, removing`);
|
|
3545
3157
|
try {
|
|
3546
|
-
|
|
3158
|
+
fs8.unlinkSync(dbPath);
|
|
3547
3159
|
} catch {
|
|
3548
3160
|
}
|
|
3549
3161
|
return false;
|
|
3550
3162
|
}
|
|
3551
3163
|
return true;
|
|
3552
|
-
} catch {
|
|
3164
|
+
} catch (error) {
|
|
3165
|
+
if (error instanceof DataDirCompatibilityError) throw error;
|
|
3553
3166
|
this.logger.warn(`[DirectImporter] Cannot validate DB file: ${sessionId}, removing`);
|
|
3554
3167
|
try {
|
|
3555
|
-
|
|
3168
|
+
fs8.unlinkSync(dbPath);
|
|
3556
3169
|
} catch {
|
|
3557
3170
|
}
|
|
3558
3171
|
return false;
|
|
@@ -3573,8 +3186,7 @@ var DirectImporter = class {
|
|
|
3573
3186
|
const data = await parseFile(tempFile);
|
|
3574
3187
|
this.dbManager.close(sessionId);
|
|
3575
3188
|
const result = await importData(this.dbManager, data, {
|
|
3576
|
-
sessionId
|
|
3577
|
-
nativeBinding: this.nativeBinding
|
|
3189
|
+
sessionId
|
|
3578
3190
|
});
|
|
3579
3191
|
if (result.success) {
|
|
3580
3192
|
this.logger.info(
|
|
@@ -3599,8 +3211,7 @@ var DirectImporter = class {
|
|
|
3599
3211
|
try {
|
|
3600
3212
|
const data = await parseFile(tempFile);
|
|
3601
3213
|
const result = await importData(this.dbManager, data, {
|
|
3602
|
-
sessionId: externalId
|
|
3603
|
-
nativeBinding: this.nativeBinding
|
|
3214
|
+
sessionId: externalId
|
|
3604
3215
|
});
|
|
3605
3216
|
if (result.success) {
|
|
3606
3217
|
this.logger.info(
|
|
@@ -3672,8 +3283,8 @@ function registerAutomationRoutes(server2, ctx) {
|
|
|
3672
3283
|
if (request.query.deleteData === "true" && removed.targetSessionId) {
|
|
3673
3284
|
dbManager2.close(removed.targetSessionId);
|
|
3674
3285
|
const dbPath = dbManager2.getDbPath(removed.targetSessionId);
|
|
3675
|
-
const
|
|
3676
|
-
if (
|
|
3286
|
+
const fs10 = await import("fs");
|
|
3287
|
+
if (fs10.existsSync(dbPath)) fs10.unlinkSync(dbPath);
|
|
3677
3288
|
}
|
|
3678
3289
|
return { success: true };
|
|
3679
3290
|
});
|
|
@@ -3748,26 +3359,26 @@ function cleanupSync() {
|
|
|
3748
3359
|
// src/http/index.ts
|
|
3749
3360
|
var server = null;
|
|
3750
3361
|
var dbManager = null;
|
|
3751
|
-
var
|
|
3362
|
+
var aiChatManager = null;
|
|
3752
3363
|
function createFileConfigStorage(aiDataDir) {
|
|
3753
3364
|
return {
|
|
3754
3365
|
readJson(key) {
|
|
3755
3366
|
try {
|
|
3756
|
-
return JSON.parse(
|
|
3367
|
+
return JSON.parse(fs9.readFileSync(`${aiDataDir}/${key}.json`, "utf-8"));
|
|
3757
3368
|
} catch {
|
|
3758
3369
|
return null;
|
|
3759
3370
|
}
|
|
3760
3371
|
},
|
|
3761
3372
|
writeJson(key, data) {
|
|
3762
|
-
if (!
|
|
3763
|
-
|
|
3373
|
+
if (!fs9.existsSync(aiDataDir)) fs9.mkdirSync(aiDataDir, { recursive: true });
|
|
3374
|
+
fs9.writeFileSync(`${aiDataDir}/${key}.json`, JSON.stringify(data, null, 2), "utf-8");
|
|
3764
3375
|
}
|
|
3765
3376
|
};
|
|
3766
3377
|
}
|
|
3767
|
-
function
|
|
3378
|
+
function resolveNativeBinding2() {
|
|
3768
3379
|
if (process.versions.electron) return void 0;
|
|
3769
3380
|
const nativePath = resolveCliPath("native/better_sqlite3.node");
|
|
3770
|
-
if (
|
|
3381
|
+
if (fs9.existsSync(nativePath)) return nativePath;
|
|
3771
3382
|
return void 0;
|
|
3772
3383
|
}
|
|
3773
3384
|
function ensureToken(config) {
|
|
@@ -3799,6 +3410,7 @@ async function startHttpServer(options) {
|
|
|
3799
3410
|
const userDataDir = config.data.user_data_dir || void 0;
|
|
3800
3411
|
const pathProvider = new NodePathProvider(userDataDir);
|
|
3801
3412
|
pathProvider.ensureAllDirs();
|
|
3413
|
+
const runtime = assertCliDataDirCompatible(pathProvider, "cli");
|
|
3802
3414
|
if (hasPendingElectronDataWarning() || !verifyCliDataPath(pathProvider.getDatabaseDir())) {
|
|
3803
3415
|
console.error(
|
|
3804
3416
|
"\n" + "=".repeat(68) + "\n ChatLab: Electron desktop data not found\n" + "=".repeat(68) + '\n\n Detected that ChatLab desktop app was installed on this machine,\n but could not locate your chat databases.\n\n This usually means you changed the data directory in desktop settings.\n\n To fix this, choose one of:\n\n 1. Open ChatLab desktop app \u2014 it will auto-migrate your data\n 2. Set the data directory manually:\n export CHATLAB_DATA_DIR="/path/to/your/data"\n 3. Edit ~/.chatlab/config.toml:\n [data]\n user_data_dir = "/path/to/your/data"\n\n' + "=".repeat(68) + "\n"
|
|
@@ -3814,10 +3426,10 @@ async function startHttpServer(options) {
|
|
|
3814
3426
|
}
|
|
3815
3427
|
});
|
|
3816
3428
|
await migrationRunner.run();
|
|
3817
|
-
const nativeBinding =
|
|
3818
|
-
dbManager = new DatabaseManager(pathProvider, { nativeBinding });
|
|
3429
|
+
const nativeBinding = resolveNativeBinding2();
|
|
3430
|
+
dbManager = new DatabaseManager(pathProvider, { nativeBinding, runtime });
|
|
3819
3431
|
const aiDataDir = pathProvider.getAiDataDir();
|
|
3820
|
-
|
|
3432
|
+
aiChatManager = new AIChatManager(aiDataDir, { nativeBinding });
|
|
3821
3433
|
const assistantManager = getAssistantManager(aiDataDir);
|
|
3822
3434
|
const skillManagerCore = getSkillManagerCore(aiDataDir);
|
|
3823
3435
|
const llmConfigStore = new LLMConfigStore(createFileConfigStorage(aiDataDir), {
|
|
@@ -3842,17 +3454,17 @@ async function startHttpServer(options) {
|
|
|
3842
3454
|
nativeBinding,
|
|
3843
3455
|
aiContext: {
|
|
3844
3456
|
aiDataDir,
|
|
3845
|
-
|
|
3457
|
+
aiChatManager,
|
|
3846
3458
|
assistantManager,
|
|
3847
3459
|
skillManagerCore,
|
|
3848
3460
|
llmConfigStore,
|
|
3849
3461
|
customProviderStore: new CustomProviderStore(createFileConfigStorage(aiDataDir)),
|
|
3850
3462
|
customModelStore: new CustomModelStore(createFileConfigStorage(aiDataDir)),
|
|
3851
|
-
runAgentStream: createCliRunAgentStream(dbManager,
|
|
3463
|
+
runAgentStream: createCliRunAgentStream(dbManager, aiChatManager)
|
|
3852
3464
|
}
|
|
3853
3465
|
});
|
|
3854
3466
|
initSync(server, dbManager, pathProvider, { port, host, token });
|
|
3855
|
-
if (options?.webRoot &&
|
|
3467
|
+
if (options?.webRoot && fs9.existsSync(options.webRoot)) {
|
|
3856
3468
|
registerProxyRoutes(server);
|
|
3857
3469
|
const fastifyStatic = await import("@fastify/static");
|
|
3858
3470
|
await server.register(fastifyStatic.default, {
|
|
@@ -3873,9 +3485,9 @@ async function stopHttpServer() {
|
|
|
3873
3485
|
await server.close();
|
|
3874
3486
|
} finally {
|
|
3875
3487
|
cleanupSync();
|
|
3876
|
-
if (
|
|
3877
|
-
|
|
3878
|
-
|
|
3488
|
+
if (aiChatManager) {
|
|
3489
|
+
aiChatManager.close();
|
|
3490
|
+
aiChatManager = null;
|
|
3879
3491
|
}
|
|
3880
3492
|
if (dbManager) {
|
|
3881
3493
|
dbManager.closeAll();
|
|
@@ -3893,4 +3505,4 @@ export {
|
|
|
3893
3505
|
startHttpServer,
|
|
3894
3506
|
stopHttpServer
|
|
3895
3507
|
};
|
|
3896
|
-
//# sourceMappingURL=chunk-
|
|
3508
|
+
//# sourceMappingURL=chunk-GTCTDD2Z.mjs.map
|