chatlab-cli 0.25.0 → 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.
Files changed (63) hide show
  1. package/dist/chat-command-5XMRLXZM.mjs +166 -0
  2. package/dist/chat-command-5XMRLXZM.mjs.map +1 -0
  3. package/dist/{chunk-4OMV4VNH.mjs → chunk-7VG6QGQ2.mjs} +977 -568
  4. package/dist/chunk-7VG6QGQ2.mjs.map +1 -0
  5. package/dist/{chunk-TCPXAX3F.mjs → chunk-CUCDRAY6.mjs} +17 -25
  6. package/dist/chunk-CUCDRAY6.mjs.map +1 -0
  7. package/dist/chunk-FDK6SPCG.mjs +40 -0
  8. package/dist/chunk-FDK6SPCG.mjs.map +1 -0
  9. package/dist/{chunk-FSHVDWI2.mjs → chunk-GTCTDD2Z.mjs} +116 -569
  10. package/dist/chunk-GTCTDD2Z.mjs.map +1 -0
  11. package/dist/{chunk-E65ABM3C.mjs → chunk-JE3FOFF7.mjs} +53 -53
  12. package/dist/chunk-JE3FOFF7.mjs.map +1 -0
  13. package/dist/{chunk-GNT5G74Z.mjs → chunk-PDQFSQO6.mjs} +59 -33
  14. package/dist/chunk-PDQFSQO6.mjs.map +1 -0
  15. package/dist/chunk-WYHGWTA4.mjs +485 -0
  16. package/dist/chunk-WYHGWTA4.mjs.map +1 -0
  17. package/dist/{chunk-CIBTUWAE.mjs → chunk-YZYP5ST6.mjs} +37 -8
  18. package/dist/chunk-YZYP5ST6.mjs.map +1 -0
  19. package/dist/cli.mjs +3 -2
  20. package/dist/{http-PMNZ42EN.mjs → http-C3CGXUBU.mjs} +8 -6
  21. package/dist/{import-OP7R4CYY.mjs → import-VS7L5JDX.mjs} +4 -4
  22. package/dist/index.mjs +10 -8
  23. package/dist/{mcp-ABXNFUJO.mjs → mcp-6VXDPUQK.mjs} +11 -6
  24. package/dist/mcp-6VXDPUQK.mjs.map +1 -0
  25. package/dist/{stream-import-L6RJHH4L.mjs → stream-import-TFDBNVIW.mjs} +3 -3
  26. package/dist-web/assets/{DebugToolsPanel-DaSNc1o-.css → DebugToolsPanel-vn-bnUxn.css} +1 -1
  27. package/dist-web/assets/{DebugToolsPanel.vue_vue_type_script_setup_true_lang-BUwpIerl.js → DebugToolsPanel.vue_vue_type_script_setup_true_lang-B1xZmp9r.js} +13 -13
  28. package/dist-web/assets/{MessageExportModal-BAJKWX4y.js → MessageExportModal-B79pPBL9.js} +1 -1
  29. package/dist-web/assets/{electron-CZt36wW5.js → electron-DRkrjeIl.js} +1 -1
  30. package/dist-web/assets/{electron-CwERrTWp.js → electron-Dv8jdn_2.js} +1 -1
  31. package/dist-web/assets/{fetch-JzVEwamn.js → fetch-BmZIm6mS.js} +1 -1
  32. package/dist-web/assets/fetch-BqLy63aj.js +1 -0
  33. package/dist-web/assets/fetch-BstX-wd4.js +1 -0
  34. package/dist-web/assets/{fetch-CgBIWyAo.js → fetch-Bvcxe5PI.js} +1 -1
  35. package/dist-web/assets/{fetch-yWwp067l.js → fetch-CDamdvtb.js} +1 -1
  36. package/dist-web/assets/{fetch-GMkMBzBS.js → fetch-DWg-2kOp.js} +1 -1
  37. package/dist-web/assets/{fetch-qoGEVjNg.js → fetch-DfgdagMN.js} +1 -1
  38. package/dist-web/assets/{fetch-DD1EGRKV.js → fetch-Drk9dLaF.js} +1 -1
  39. package/dist-web/assets/{fetch-D4p9vj1A.js → fetch-Y-_WsCuk.js} +1 -1
  40. package/dist-web/assets/{fetch-DXfZysDf.js → fetch-ph2_d79v.js} +1 -1
  41. package/dist-web/assets/{index-BrS_VrIY.js → index-9urfJP1r.js} +1 -1
  42. package/dist-web/assets/{index-DABpUm3J.js → index-CfKjh0Jr.js} +5 -5
  43. package/dist-web/assets/{index-C1t-kzfo.css → index-CprJOAB1.css} +1 -1
  44. package/dist-web/assets/{index-O0PG26_v.js → index-DMWf5On7.js} +1 -1
  45. package/dist-web/assets/{index-Cvlw0RLu.js → index-D_hHm7bQ.js} +2 -2
  46. package/dist-web/assets/index-MCdpiX_O.js +173 -0
  47. package/dist-web/assets/{index-DvWI6Yqa.js → index-deYDOVUa.js} +3 -3
  48. package/dist-web/assets/{web-4rtrAcLu.js → web-XJV6Vj5t.js} +1 -1
  49. package/dist-web/index.html +2 -2
  50. package/package.json +1 -1
  51. package/dist/chunk-4OMV4VNH.mjs.map +0 -1
  52. package/dist/chunk-CIBTUWAE.mjs.map +0 -1
  53. package/dist/chunk-E65ABM3C.mjs.map +0 -1
  54. package/dist/chunk-FSHVDWI2.mjs.map +0 -1
  55. package/dist/chunk-GNT5G74Z.mjs.map +0 -1
  56. package/dist/chunk-TCPXAX3F.mjs.map +0 -1
  57. package/dist/mcp-ABXNFUJO.mjs.map +0 -1
  58. package/dist-web/assets/fetch-BxFAkm7O.js +0 -1
  59. package/dist-web/assets/fetch-DO8lty7_.js +0 -1
  60. package/dist-web/assets/index-OsjX5hXw.js +0 -173
  61. /package/dist/{http-PMNZ42EN.mjs.map → http-C3CGXUBU.mjs.map} +0 -0
  62. /package/dist/{import-OP7R4CYY.mjs.map → import-VS7L5JDX.mjs.map} +0 -0
  63. /package/dist/{stream-import-L6RJHH4L.mjs.map → stream-import-TFDBNVIW.mjs.map} +0 -0
@@ -5,48 +5,29 @@ const require = __createRequire(import.meta.url);
5
5
  const __filename = __fileURLToPath(import.meta.url);
6
6
  const __dirname = __pathDirname(__filename);
7
7
  import {
8
- CHAT_DB_TABLES,
8
+ DataDirCompatibilityError,
9
9
  analyzeIncrementalImport,
10
10
  analyzeNewImport,
11
11
  generateIncrementalSessionIndex,
12
12
  generateSessionIndex,
13
13
  incrementalImport,
14
- openBetterSqliteDatabase,
15
14
  streamingImport
16
- } from "./chunk-4OMV4VNH.mjs";
15
+ } from "./chunk-7VG6QGQ2.mjs";
17
16
 
18
17
  // src/import/stream-import.ts
19
- import * as fs from "fs";
20
- import * as path from "path";
21
18
  import * as crypto from "crypto";
22
19
  function generateSessionId() {
23
20
  const ts = Date.now();
24
21
  const rand = crypto.randomBytes(4).toString("hex");
25
22
  return `chat_${ts}_${rand}`;
26
23
  }
27
- function resolveNativeBinding(dbManager) {
28
- return dbManager.nativeBinding;
29
- }
30
24
  function buildStreamImportDeps(dbManager, onProgress) {
31
- const nativeBinding = resolveNativeBinding(dbManager);
32
25
  return {
33
26
  openDatabase(sessionId) {
34
- const dbPath = dbManager.getDbPath(sessionId);
35
- const dir = path.dirname(dbPath);
36
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
37
- const db = openBetterSqliteDatabase(dbPath, { nativeBinding });
38
- db.exec(CHAT_DB_TABLES);
39
- return db;
27
+ return dbManager.openRawSessionDatabase(sessionId, { create: true, initializeChatTables: true });
40
28
  },
41
29
  deleteDatabase(sessionId) {
42
- const dbPath = dbManager.getDbPath(sessionId);
43
- for (const suffix of ["", "-wal", "-shm"]) {
44
- try {
45
- const p = dbPath + suffix;
46
- if (fs.existsSync(p)) fs.unlinkSync(p);
47
- } catch {
48
- }
49
- }
30
+ dbManager.deleteSessionDatabaseFiles(sessionId);
50
31
  },
51
32
  onProgress: onProgress ?? (() => {
52
33
  }),
@@ -59,6 +40,9 @@ function buildStreamImportDeps(dbManager, onProgress) {
59
40
  generateSessionId
60
41
  };
61
42
  }
43
+ function deleteSessionDatabase(dbManager, sessionId) {
44
+ dbManager.deleteSessionDatabaseFiles(sessionId);
45
+ }
62
46
  async function streamImport(dbManager, filePath, options) {
63
47
  const { formatId, chatIndex, onProgress } = options || {};
64
48
  const formatOptions = {};
@@ -101,17 +85,29 @@ async function streamImport(dbManager, filePath, options) {
101
85
  } : () => {
102
86
  };
103
87
  const deps = buildStreamImportDeps(dbManager, progressAdapter);
104
- return streamingImport(filePath, deps, formatOptions);
88
+ const result = await streamingImport(filePath, deps, formatOptions);
89
+ if (!result.success || !result.sessionId) return result;
90
+ try {
91
+ dbManager.raiseCurrentChatDbCompatibilityGate();
92
+ } catch (error) {
93
+ deleteSessionDatabase(dbManager, result.sessionId);
94
+ return {
95
+ success: false,
96
+ error: error instanceof Error ? error.message : String(error),
97
+ diagnostics: result.diagnostics
98
+ };
99
+ }
100
+ return result;
105
101
  }
106
- function buildIncrementalDeps(dbManager, onProgress) {
107
- const nativeBinding = resolveNativeBinding(dbManager);
102
+ function buildIncrementalDeps(dbManager, onProgress, onCompatibilityError) {
108
103
  return {
109
104
  openDatabase(sessionId, readonly) {
110
- const dbPath = dbManager.getDbPath(sessionId);
111
- if (!fs.existsSync(dbPath)) {
112
- throw new Error(`Session database not found: ${sessionId}`);
105
+ try {
106
+ return dbManager.openRawSessionDatabase(sessionId, { readonly: readonly ?? false });
107
+ } catch (error) {
108
+ if (error instanceof DataDirCompatibilityError) onCompatibilityError?.(error);
109
+ throw error;
113
110
  }
114
- return openBetterSqliteDatabase(dbPath, { readonly: readonly ?? false, nativeBinding });
115
111
  },
116
112
  onProgress: onProgress ?? (() => {
117
113
  }),
@@ -125,10 +121,40 @@ function buildIncrementalDeps(dbManager, onProgress) {
125
121
  }
126
122
  async function incrementalImport2(dbManager, sessionId, filePath, options) {
127
123
  const { onProgress, ...importOpts } = options || {};
128
- return incrementalImport(sessionId, filePath, buildIncrementalDeps(dbManager, onProgress), importOpts);
124
+ let compatibilityError = null;
125
+ const result = await incrementalImport(
126
+ sessionId,
127
+ filePath,
128
+ buildIncrementalDeps(dbManager, onProgress, (error) => {
129
+ compatibilityError = error;
130
+ }),
131
+ importOpts
132
+ );
133
+ if (compatibilityError) throw compatibilityError;
134
+ if (!result.success) return result;
135
+ try {
136
+ dbManager.raiseCurrentChatDbCompatibilityGate();
137
+ } catch (error) {
138
+ return {
139
+ ...result,
140
+ success: false,
141
+ newMessageCount: 0,
142
+ error: error instanceof Error ? error.message : String(error)
143
+ };
144
+ }
145
+ return result;
129
146
  }
130
147
  async function analyzeIncrementalImport2(dbManager, sessionId, filePath, onProgress) {
131
- return analyzeIncrementalImport(sessionId, filePath, buildIncrementalDeps(dbManager, onProgress));
148
+ let compatibilityError = null;
149
+ const result = await analyzeIncrementalImport(
150
+ sessionId,
151
+ filePath,
152
+ buildIncrementalDeps(dbManager, onProgress, (error) => {
153
+ compatibilityError = error;
154
+ })
155
+ );
156
+ if (compatibilityError) throw compatibilityError;
157
+ return result;
132
158
  }
133
159
  async function analyzeNewImport2(filePath, onProgress) {
134
160
  return analyzeNewImport(filePath, onProgress ?? (() => {
@@ -141,4 +167,4 @@ export {
141
167
  analyzeIncrementalImport2 as analyzeIncrementalImport,
142
168
  analyzeNewImport2 as analyzeNewImport
143
169
  };
144
- //# sourceMappingURL=chunk-GNT5G74Z.mjs.map
170
+ //# sourceMappingURL=chunk-PDQFSQO6.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/import/stream-import.ts"],"sourcesContent":["/**\n * Server/CLI streaming import — adapter for @openchatlab/node-runtime StreamingImporter.\n *\n * Replaces the old buffered-in-memory approach with the same high-performance\n * streaming pipeline used by Electron (batched transactions, deferred indexes,\n * nickname history, FTS, format fallback).\n */\n\nimport type { DatabaseManager } from '@openchatlab/node-runtime'\nimport {\n DataDirCompatibilityError,\n streamingImport,\n analyzeNewImport as sharedAnalyzeNewImport,\n analyzeIncrementalImport as sharedAnalyzeIncremental,\n incrementalImport as sharedIncrementalImport,\n} from '@openchatlab/node-runtime'\nimport { generateSessionIndex, generateIncrementalSessionIndex } from '@openchatlab/core'\nimport type {\n StreamImportResult,\n StreamImportDeps,\n ImportProgressCallback,\n IncrementalImportResult,\n IncrementalAnalyzeResult,\n IncrementalImportDeps,\n ImportOptions,\n AnalyzeNewImportResult,\n} from '@openchatlab/node-runtime'\nimport {\n detectFormat as parserDetectFormat,\n detectAllFormats,\n getFormatFeatureById,\n getSupportedFormats as parserGetSupportedFormats,\n scanMultiChatFile as parserScanMultiChatFile,\n findEntryFileInDirectory,\n type FormatFeature,\n type MultiChatInfo,\n type ParseProgress,\n} from '@openchatlab/parser'\nimport * as crypto from 'crypto'\n\n// ==================== Legacy progress interface (for SSE routes) ====================\n\nexport interface StreamImportProgress {\n stage: 'detecting' | 'parsing' | 'saving' | 'indexing' | 'done' | 'error'\n progress: number\n message: string\n bytesRead?: number\n totalBytes?: number\n messagesProcessed?: number\n}\n\nexport interface StreamImportOptions {\n formatId?: string\n chatIndex?: number\n nativeBinding?: string\n onProgress?: (progress: StreamImportProgress) => void\n}\n\nfunction generateSessionId(): string {\n const ts = Date.now()\n const rand = crypto.randomBytes(4).toString('hex')\n return `chat_${ts}_${rand}`\n}\n\nfunction buildStreamImportDeps(dbManager: DatabaseManager, onProgress?: ImportProgressCallback): StreamImportDeps {\n return {\n openDatabase(sessionId: string) {\n return dbManager.openRawSessionDatabase(sessionId, { create: true, initializeChatTables: true })\n },\n deleteDatabase(sessionId: string) {\n dbManager.deleteSessionDatabaseFiles(sessionId)\n },\n onProgress: onProgress ?? (() => {}),\n postImportHook(db) {\n try {\n generateSessionIndex(db)\n } catch {\n /* non-fatal: frontend can regenerate via generate-index route */\n }\n },\n generateSessionId,\n }\n}\n\nfunction deleteSessionDatabase(dbManager: DatabaseManager, sessionId: string): void {\n dbManager.deleteSessionDatabaseFiles(sessionId)\n}\n\n/**\n * High-performance streaming import: parse a file and write to DB\n * with batched transactions, deferred indexes, and FTS.\n */\nexport async function streamImport(\n dbManager: DatabaseManager,\n filePath: string,\n options?: StreamImportOptions\n): Promise<StreamImportResult> {\n const { formatId, chatIndex, onProgress } = options || {}\n\n const formatOptions: Record<string, unknown> = {}\n if (formatId) formatOptions.formatId = formatId\n if (chatIndex !== undefined) formatOptions.chatIndex = chatIndex\n\n const progressAdapter: ImportProgressCallback = onProgress\n ? (progress) => {\n let stage: StreamImportProgress['stage'] = 'parsing'\n let pct = 0\n switch (progress.stage) {\n case 'detecting':\n stage = 'detecting'\n pct = 5\n break\n case 'parsing':\n stage = 'parsing'\n pct = Math.min(Math.round(progress.percentage * 0.7), 70)\n break\n case 'importing':\n case 'saving':\n stage = 'saving'\n pct = 80\n break\n case 'done':\n stage = 'done'\n pct = 100\n break\n case 'error':\n stage = 'error'\n pct = 0\n break\n }\n onProgress({\n stage,\n progress: pct,\n message: progress.message || '',\n bytesRead: progress.bytesRead,\n totalBytes: progress.totalBytes,\n messagesProcessed: progress.messagesProcessed,\n })\n }\n : () => {}\n\n const deps = buildStreamImportDeps(dbManager, progressAdapter)\n const result = await streamingImport(filePath, deps, formatOptions)\n if (!result.success || !result.sessionId) return result\n\n try {\n dbManager.raiseCurrentChatDbCompatibilityGate()\n } catch (error) {\n deleteSessionDatabase(dbManager, result.sessionId)\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n diagnostics: result.diagnostics,\n }\n }\n\n return result\n}\n\n// ==================== Incremental import ====================\n\nfunction buildIncrementalDeps(\n dbManager: DatabaseManager,\n onProgress?: ImportProgressCallback,\n onCompatibilityError?: (error: DataDirCompatibilityError) => void\n): IncrementalImportDeps {\n return {\n openDatabase(sessionId: string, readonly?: boolean) {\n try {\n return dbManager.openRawSessionDatabase(sessionId, { readonly: readonly ?? false })\n } catch (error) {\n if (error instanceof DataDirCompatibilityError) onCompatibilityError?.(error)\n throw error\n }\n },\n onProgress: onProgress ?? (() => {}),\n postImportHook(db) {\n try {\n generateIncrementalSessionIndex(db)\n } catch {\n /* non-fatal */\n }\n },\n }\n}\n\nexport async function incrementalImport(\n dbManager: DatabaseManager,\n sessionId: string,\n filePath: string,\n options?: ImportOptions & { onProgress?: ImportProgressCallback }\n): Promise<IncrementalImportResult> {\n const { onProgress, ...importOpts } = options || {}\n let compatibilityError: DataDirCompatibilityError | null = null\n const result = await sharedIncrementalImport(\n sessionId,\n filePath,\n buildIncrementalDeps(dbManager, onProgress, (error) => {\n compatibilityError = error\n }),\n importOpts\n )\n if (compatibilityError) throw compatibilityError\n if (!result.success) return result\n\n try {\n dbManager.raiseCurrentChatDbCompatibilityGate()\n } catch (error) {\n return {\n ...result,\n success: false,\n newMessageCount: 0,\n error: error instanceof Error ? error.message : String(error),\n }\n }\n\n return result\n}\n\nexport async function analyzeIncrementalImport(\n dbManager: DatabaseManager,\n sessionId: string,\n filePath: string,\n onProgress?: ImportProgressCallback\n): Promise<IncrementalAnalyzeResult> {\n let compatibilityError: DataDirCompatibilityError | null = null\n const result = await sharedAnalyzeIncremental(\n sessionId,\n filePath,\n buildIncrementalDeps(dbManager, onProgress, (error) => {\n compatibilityError = error\n })\n )\n if (compatibilityError) throw compatibilityError\n return result\n}\n\nexport async function analyzeNewImport(\n filePath: string,\n onProgress?: ImportProgressCallback\n): Promise<AnalyzeNewImportResult> {\n return sharedAnalyzeNewImport(filePath, onProgress ?? (() => {}))\n}\n\n// ==================== Re-exports from parser ====================\n\nexport {\n parserDetectFormat as detectFormat,\n detectAllFormats,\n getFormatFeatureById,\n parserGetSupportedFormats as getSupportedFormats,\n parserScanMultiChatFile as scanMultiChatFile,\n findEntryFileInDirectory,\n}\nexport type { FormatFeature, MultiChatInfo, ParseProgress }\nexport type {\n StreamImportResult,\n IncrementalImportResult,\n IncrementalAnalyzeResult,\n AnalyzeNewImportResult,\n ImportOptions,\n}\n"],"mappings":"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","names":["incrementalImport","analyzeIncrementalImport","analyzeNewImport"]}
@@ -0,0 +1,485 @@
1
+ import { createRequire as __createRequire } from 'module';
2
+ import { dirname as __pathDirname } from 'path';
3
+ import { fileURLToPath as __fileURLToPath } from 'url';
4
+ const require = __createRequire(import.meta.url);
5
+ const __filename = __fileURLToPath(import.meta.url);
6
+ const __dirname = __pathDirname(__filename);
7
+ import {
8
+ AGENT_TOOL_REGISTRY,
9
+ CoreDataProvider
10
+ } from "./chunk-JE3FOFF7.mjs";
11
+ import {
12
+ AgentEventHandler,
13
+ AiLogger,
14
+ CHART_CAPABILITY_CORE_TOOLS,
15
+ DEFAULT_MAX_TOOL_ROUNDS,
16
+ SkillManager,
17
+ applyPreprocessingPipeline,
18
+ batchSegmentWithFrequency,
19
+ buildPiModel,
20
+ buildSkillMenuWithBuiltinChart,
21
+ buildSystemPrompt,
22
+ checkAndCompress,
23
+ createActivateSkillTool,
24
+ createAiTranslate,
25
+ createChartSchemaGateState,
26
+ createCompressionLlmAdapter,
27
+ formatAIError,
28
+ getAllowedBuiltinToolsForChartAutoSkill,
29
+ getChartCapabilitySkill,
30
+ getChatOverview,
31
+ getSkillConfigWithBuiltinChart,
32
+ initTokenizer,
33
+ normalizeBuiltinToolNames,
34
+ parseAssistantFile,
35
+ resolveApiKey,
36
+ resolveChartRuntimeForRequest,
37
+ runAgentCore,
38
+ wrapWithChartSchemaGate
39
+ } from "./chunk-7VG6QGQ2.mjs";
40
+
41
+ // src/ai/logger.ts
42
+ var logger = null;
43
+ function initServerAiLogger(logsDir) {
44
+ if (!logger) {
45
+ logger = new AiLogger(logsDir);
46
+ }
47
+ return logger;
48
+ }
49
+ function getServerAiLogger() {
50
+ return logger;
51
+ }
52
+ function closeServerAiLogger() {
53
+ if (logger) {
54
+ logger.close();
55
+ logger = null;
56
+ }
57
+ }
58
+
59
+ // src/ai/tool-adapter.ts
60
+ var DEFAULT_MAX_TOOL_RESULT_TOKENS = 8e3;
61
+ var TOOL_TRUNCATION_STRATEGY = {
62
+ search_messages: "keep_first",
63
+ deep_search_messages: "keep_first",
64
+ get_recent_messages: "keep_last",
65
+ get_message_context: "keep_last",
66
+ get_segment_messages: "keep_last",
67
+ get_conversation_between: "keep_last"
68
+ };
69
+ function convertJsonSchemaToParameters(schema) {
70
+ const properties = {};
71
+ for (const [key, prop] of Object.entries(schema.properties)) {
72
+ properties[key] = { ...prop };
73
+ }
74
+ return {
75
+ type: "object",
76
+ properties,
77
+ required: schema.required || []
78
+ };
79
+ }
80
+ function adaptToolsForAgent(tools, getContext, options) {
81
+ const tokenBudget = options?.maxToolResultTokens ?? DEFAULT_MAX_TOOL_RESULT_TOKENS;
82
+ const chartSchemaGateState = createChartSchemaGateState();
83
+ return tools.map(
84
+ (tool) => wrapWithChartSchemaGate(
85
+ {
86
+ name: tool.name,
87
+ label: tool.name,
88
+ description: tool.description,
89
+ parameters: convertJsonSchemaToParameters(tool.inputSchema),
90
+ async execute(_toolCallId, params) {
91
+ const toolParams = params && typeof params === "object" ? params : {};
92
+ const ctx = getContext();
93
+ const execCtx = {
94
+ db: ctx.db,
95
+ dataProvider: new CoreDataProvider(ctx.db),
96
+ sessionId: ctx.sessionId,
97
+ locale: ctx.locale,
98
+ segmentText: (texts, locale, options2) => batchSegmentWithFrequency(texts, locale, options2)
99
+ };
100
+ try {
101
+ const result = await tool.handler(toolParams, execCtx);
102
+ const chartDetails = result.chart || result.charts ? {
103
+ ...result.chart ? { chart: result.chart } : {},
104
+ ...result.charts ? { charts: result.charts } : {}
105
+ } : {};
106
+ if (result.rawMessages && result.rawMessages.length > 0) {
107
+ const pipelineResult = applyPreprocessingPipeline({
108
+ rawMessages: result.rawMessages,
109
+ locale: ctx.locale,
110
+ maxToolResultTokens: tokenBudget,
111
+ truncationStrategy: TOOL_TRUNCATION_STRATEGY[tool.name] ?? "keep_last",
112
+ extraDetails: result.data ?? {},
113
+ logger: getServerAiLogger() ?? void 0
114
+ });
115
+ return {
116
+ content: [{ type: "text", text: pipelineResult.text }],
117
+ details: Object.keys(chartDetails).length > 0 ? chartDetails : null
118
+ };
119
+ }
120
+ const baseDetails = typeof result.data === "object" && result.data !== null ? result.data : result.data === void 0 ? null : { value: result.data };
121
+ return {
122
+ content: [{ type: "text", text: result.content }],
123
+ details: Object.keys(chartDetails).length > 0 ? { ...baseDetails ?? {}, ...chartDetails } : baseDetails
124
+ };
125
+ } catch (error) {
126
+ const msg = error instanceof Error ? error.message : String(error);
127
+ return { content: [{ type: "text", text: `Error: ${msg}` }], details: null };
128
+ }
129
+ }
130
+ },
131
+ chartSchemaGateState
132
+ )
133
+ );
134
+ }
135
+
136
+ // src/ai/llm-config.ts
137
+ import * as fs from "fs";
138
+ import * as path from "path";
139
+ function loadLlmConfig(aiDataDir) {
140
+ const configPath = path.join(aiDataDir, "llm-config.json");
141
+ if (!fs.existsSync(configPath)) {
142
+ return { configs: [], defaultAssistant: null, fastModel: null };
143
+ }
144
+ try {
145
+ const data = JSON.parse(fs.readFileSync(configPath, "utf-8"));
146
+ const configs = (data.configs || []).map((c) => {
147
+ const provider = c.provider || "";
148
+ const authProfile = c.authProfile;
149
+ const profileKey = resolveApiKey(provider, authProfile);
150
+ const rawKey = c.apiKey || "";
151
+ const fallbackKey = rawKey.startsWith("enc:") ? "" : rawKey;
152
+ return {
153
+ ...c,
154
+ apiKey: profileKey || fallbackKey
155
+ };
156
+ });
157
+ return {
158
+ configs,
159
+ defaultAssistant: data.defaultAssistant ?? null,
160
+ fastModel: data.fastModel ?? null
161
+ };
162
+ } catch {
163
+ return { configs: [], defaultAssistant: null, fastModel: null };
164
+ }
165
+ }
166
+ function resolveSlot(slot, configs) {
167
+ if (slot && configs.some((c) => c.id === slot.configId)) return slot;
168
+ const fallback = configs[0];
169
+ if (!fallback) return null;
170
+ return { configId: fallback.id, modelId: fallback.model };
171
+ }
172
+ function getDefaultAssistantConfig(aiDataDir) {
173
+ const store = loadLlmConfig(aiDataDir);
174
+ const slot = resolveSlot(store.defaultAssistant, store.configs);
175
+ if (!slot) return null;
176
+ const config = store.configs.find((c) => c.id === slot.configId);
177
+ if (!config) return null;
178
+ return { ...config, model: slot.modelId || config.model };
179
+ }
180
+ function buildPiModel2(config) {
181
+ return buildPiModel(config);
182
+ }
183
+
184
+ // src/ai/assistant-loader.ts
185
+ import * as fs2 from "fs";
186
+ import * as path2 from "path";
187
+ function loadAssistantConfig(aiDataDir, assistantId) {
188
+ const filePath = path2.join(aiDataDir, "assistants", `${assistantId}.md`);
189
+ if (!fs2.existsSync(filePath)) return null;
190
+ try {
191
+ const content = fs2.readFileSync(filePath, "utf-8");
192
+ return parseAssistantFile(content, filePath);
193
+ } catch {
194
+ return null;
195
+ }
196
+ }
197
+
198
+ // src/ai/agent.ts
199
+ async function runServerAgent(options) {
200
+ const {
201
+ userMessage,
202
+ aiChatId,
203
+ historyLeafMessageId,
204
+ chatType = "group",
205
+ locale = "zh-CN",
206
+ assistantSystemPrompt,
207
+ skillMenu,
208
+ skillDef,
209
+ compressionConfig,
210
+ tools = [],
211
+ aiDataDir,
212
+ aiChatManager,
213
+ onEvent,
214
+ abortSignal,
215
+ ownerInfo,
216
+ mentionedMembers,
217
+ dataSnapshot,
218
+ thinkingLevel
219
+ } = options;
220
+ const aiLogger = getServerAiLogger();
221
+ await initTokenizer();
222
+ const llmConfig = getDefaultAssistantConfig(aiDataDir);
223
+ if (!llmConfig) {
224
+ onEvent({ type: "error", error: { name: "ConfigError", message: "LLM service not configured" } });
225
+ onEvent({ type: "done", isFinished: true });
226
+ return;
227
+ }
228
+ const piModel = buildPiModel2(llmConfig);
229
+ const t = createAiTranslate(locale);
230
+ let skillCtx;
231
+ if (skillDef) {
232
+ skillCtx = { skillDef };
233
+ } else if (skillMenu) {
234
+ skillCtx = { skillMenu };
235
+ }
236
+ const systemPrompt = buildSystemPrompt({
237
+ t,
238
+ chatType,
239
+ assistantSystemPrompt,
240
+ ownerInfo,
241
+ locale,
242
+ skillCtx,
243
+ mentionedMembers,
244
+ dataSnapshot
245
+ });
246
+ const handler = new AgentEventHandler({
247
+ onChunk: onEvent,
248
+ context: {},
249
+ systemPrompt
250
+ });
251
+ if (compressionConfig?.enabled && historyLeafMessageId === void 0) {
252
+ const llmAdapter = createCompressionLlmAdapter({
253
+ piModel,
254
+ apiKey: llmConfig.apiKey,
255
+ onCompressing: () => handler.emitStatus("compressing", [])
256
+ });
257
+ const compressionResult = await checkAndCompress(
258
+ aiChatId,
259
+ compressionConfig,
260
+ systemPrompt,
261
+ llmAdapter,
262
+ aiChatManager,
263
+ aiLogger ?? void 0
264
+ );
265
+ if (compressionResult.compressed) {
266
+ onEvent({
267
+ type: "compression_done",
268
+ compressionResult: {
269
+ summaryContent: compressionResult.summaryContent ?? "",
270
+ tokensBefore: compressionResult.tokensBefore ?? 0,
271
+ tokensAfter: compressionResult.tokensAfter ?? 0,
272
+ timestamp: Date.now()
273
+ }
274
+ });
275
+ }
276
+ } else if (compressionConfig?.enabled && historyLeafMessageId !== void 0) {
277
+ aiLogger?.info?.("Compression", "Skipping compression for edited branch request", {
278
+ aiChatId,
279
+ historyLeafMessageId
280
+ });
281
+ }
282
+ if (abortSignal?.aborted) {
283
+ handler.emitStatus("aborted", [], { force: true });
284
+ onEvent({ type: "done", isFinished: true, usage: handler.cloneUsage() });
285
+ return;
286
+ }
287
+ let history = [];
288
+ try {
289
+ history = aiChatManager.getHistoryForAgent(aiChatId, void 0, historyLeafMessageId);
290
+ } catch {
291
+ }
292
+ handler.emitStatus("preparing", [], { pendingUserMessage: userMessage, force: true });
293
+ const steerMessage = t("ai.agent.answerWithoutTools");
294
+ let cachedMessages = [];
295
+ try {
296
+ const result = await runAgentCore({
297
+ piModel,
298
+ apiKey: llmConfig.apiKey,
299
+ systemPrompt,
300
+ tools,
301
+ history,
302
+ userMessage,
303
+ maxToolRounds: DEFAULT_MAX_TOOL_ROUNDS,
304
+ abortSignal,
305
+ steerMessage,
306
+ thinkingLevel,
307
+ onConvertToLlm: (filteredMessages) => {
308
+ cachedMessages = filteredMessages;
309
+ },
310
+ onEvent: (coreEvent) => handler.handleCoreEvent(coreEvent, cachedMessages),
311
+ onDebugContext: (messages) => {
312
+ try {
313
+ aiChatManager.setPendingDebugContext(aiChatId, JSON.stringify(messages, null, 2));
314
+ } catch {
315
+ }
316
+ }
317
+ });
318
+ if (result.error) {
319
+ const friendlyMessage = formatAIError(result.error);
320
+ onEvent({ type: "error", error: { name: "AgentError", message: friendlyMessage } });
321
+ }
322
+ handler.emitStatus("completed", cachedMessages, { force: true });
323
+ onEvent({ type: "done", isFinished: true, usage: result.usage });
324
+ } catch (error) {
325
+ const friendlyMessage = formatAIError(error);
326
+ aiLogger?.error("ServerAgent", "Agent execution error", { error: String(error) });
327
+ handler.emitStatus("error", cachedMessages, { force: true });
328
+ onEvent({ type: "error", error: { name: "AgentError", message: friendlyMessage } });
329
+ onEvent({ type: "done", isFinished: true, usage: handler.cloneUsage() });
330
+ }
331
+ }
332
+
333
+ // src/ai/agent-stream-runner.ts
334
+ function getAiDir(dbManager) {
335
+ const pathProvider = dbManager["pathProvider"];
336
+ if (!pathProvider) {
337
+ throw Object.assign(new Error("PathProvider not available"), { statusCode: 500 });
338
+ }
339
+ return pathProvider.getAiDataDir();
340
+ }
341
+ var RAW_SQL_TOOL_NAMES = /* @__PURE__ */ new Set(["execute_sql"]);
342
+ function getAvailableToolDefs(isChartCapability, allowedToolSet) {
343
+ if (isChartCapability) {
344
+ const chartCoreTools = new Set(CHART_CAPABILITY_CORE_TOOLS);
345
+ return AGENT_TOOL_REGISTRY.filter(
346
+ (tool) => chartCoreTools.has(tool.name) || tool.category === "analysis" && allowedToolSet?.has(tool.name) && !RAW_SQL_TOOL_NAMES.has(tool.name)
347
+ );
348
+ }
349
+ return allowedToolSet ? AGENT_TOOL_REGISTRY.filter((tool) => tool.category !== "analysis" || allowedToolSet.has(tool.name)) : AGENT_TOOL_REGISTRY;
350
+ }
351
+ function getAllowedToolSet(isChartCapability, allowedBuiltinTools) {
352
+ if (isChartCapability) {
353
+ return new Set(normalizeBuiltinToolNames(allowedBuiltinTools ?? []));
354
+ }
355
+ return allowedBuiltinTools === void 0 ? null : new Set(normalizeBuiltinToolNames(allowedBuiltinTools));
356
+ }
357
+ function createCliRunAgentStream(dbManager, aiChatManager) {
358
+ return async (params, onEvent, abortSignal) => {
359
+ const {
360
+ userMessage,
361
+ aiChatId,
362
+ historyLeafMessageId,
363
+ sessionId,
364
+ chatType,
365
+ locale,
366
+ assistantId,
367
+ skillId,
368
+ enableAutoSkill,
369
+ compressionConfig,
370
+ ownerInfo,
371
+ mentionedMembers,
372
+ thinkingLevel
373
+ } = params;
374
+ const aiDataDir = getAiDir(dbManager);
375
+ let assistantSystemPrompt;
376
+ let assistantAllowedTools;
377
+ if (assistantId) {
378
+ const assistantConfig = loadAssistantConfig(aiDataDir, assistantId);
379
+ if (assistantConfig?.systemPrompt) {
380
+ assistantSystemPrompt = assistantConfig.systemPrompt;
381
+ }
382
+ assistantAllowedTools = assistantConfig?.allowedBuiltinTools;
383
+ }
384
+ const llmConfig = getDefaultAssistantConfig(aiDataDir);
385
+ const maxToolResultPercent = compressionConfig?.maxToolResultPercent ?? 50;
386
+ const contextWindow = llmConfig ? buildPiModel2(llmConfig).contextWindow ?? 128e3 : 128e3;
387
+ const maxToolResultTokens = Math.floor(contextWindow * (maxToolResultPercent / 100));
388
+ const db = dbManager.open?.(sessionId);
389
+ const chartRuntime = resolveChartRuntimeForRequest({
390
+ skillId,
391
+ userMessage,
392
+ locale,
393
+ assistantAllowedTools
394
+ });
395
+ const isChartCapability = chartRuntime.isChartCapability;
396
+ const autoSkillAllowedTools = !skillId && enableAutoSkill ? getAllowedBuiltinToolsForChartAutoSkill(assistantAllowedTools) : assistantAllowedTools;
397
+ const allowedToolSet = getAllowedToolSet(
398
+ isChartCapability,
399
+ isChartCapability ? chartRuntime.allowedBuiltinTools : autoSkillAllowedTools
400
+ );
401
+ const availableToolDefs = getAvailableToolDefs(isChartCapability, allowedToolSet);
402
+ const agentTools = db ? adaptToolsForAgent(availableToolDefs, () => ({ db, sessionId, locale }), { maxToolResultTokens }) : [];
403
+ const skillMgr = new SkillManager(aiDataDir);
404
+ skillMgr.init();
405
+ const toolNames = agentTools.map((t) => t.name);
406
+ let resolvedSkillDef;
407
+ let resolvedSkillMenu;
408
+ if (isChartCapability) {
409
+ const def = chartRuntime.skillDef ?? getChartCapabilitySkill(locale ?? "zh-CN");
410
+ resolvedSkillDef = { name: def.name, prompt: def.prompt };
411
+ } else if (skillId) {
412
+ const def = skillMgr.getSkillConfig(skillId);
413
+ if (def) resolvedSkillDef = { name: def.name, prompt: def.prompt };
414
+ } else if (enableAutoSkill) {
415
+ const menu = buildSkillMenuWithBuiltinChart(
416
+ skillMgr.getSkillMenu(chatType ?? "group", toolNames),
417
+ locale,
418
+ toolNames
419
+ );
420
+ if (menu) resolvedSkillMenu = menu;
421
+ }
422
+ if (resolvedSkillMenu) {
423
+ const activateSkillTool = createActivateSkillTool({
424
+ chatType: chatType ?? "group",
425
+ allowedTools: toolNames,
426
+ coreToolNames: new Set(CHART_CAPABILITY_CORE_TOOLS),
427
+ locale,
428
+ getSkillConfig: (id) => getSkillConfigWithBuiltinChart(id, locale, (skillConfigId) => skillMgr.getSkillConfig(skillConfigId))
429
+ });
430
+ agentTools.push(activateSkillTool);
431
+ }
432
+ const resolvedCompression = compressionConfig?.enabled ? {
433
+ enabled: true,
434
+ tokenThresholdPercent: compressionConfig.tokenThresholdPercent ?? 75,
435
+ bufferSizePercent: compressionConfig.bufferSizePercent ?? 20,
436
+ maxToolResultPercent: compressionConfig.maxToolResultPercent
437
+ } : void 0;
438
+ let dataSnapshot;
439
+ if (db) {
440
+ try {
441
+ const overview = getChatOverview(db, 5);
442
+ if (overview) {
443
+ dataSnapshot = {
444
+ name: overview.name,
445
+ platform: overview.platform,
446
+ type: overview.type,
447
+ totalMessages: overview.totalMessages,
448
+ totalMembers: overview.totalMembers,
449
+ firstMessageTs: overview.firstMessageTs,
450
+ lastMessageTs: overview.lastMessageTs,
451
+ capturedAt: Math.floor(Date.now() / 1e3)
452
+ };
453
+ }
454
+ } catch {
455
+ }
456
+ }
457
+ await runServerAgent({
458
+ userMessage,
459
+ aiChatId,
460
+ historyLeafMessageId,
461
+ chatType,
462
+ locale,
463
+ assistantSystemPrompt,
464
+ skillMenu: resolvedSkillMenu,
465
+ skillDef: resolvedSkillDef,
466
+ compressionConfig: resolvedCompression,
467
+ tools: agentTools,
468
+ aiDataDir,
469
+ aiChatManager,
470
+ onEvent,
471
+ abortSignal,
472
+ ownerInfo,
473
+ mentionedMembers,
474
+ dataSnapshot,
475
+ thinkingLevel
476
+ });
477
+ };
478
+ }
479
+
480
+ export {
481
+ initServerAiLogger,
482
+ closeServerAiLogger,
483
+ createCliRunAgentStream
484
+ };
485
+ //# sourceMappingURL=chunk-WYHGWTA4.mjs.map