chatlab-cli 0.30.2 → 0.31.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 (141) hide show
  1. package/dist/{chat-command-VBDMWOKL.mjs → chat-command-MOETAGU5.mjs} +9 -8
  2. package/dist/{chat-command-VBDMWOKL.mjs.map → chat-command-MOETAGU5.mjs.map} +1 -1
  3. package/dist/{chunk-M2PXDX4G.mjs → chunk-2IXPWPLR.mjs} +168 -77
  4. package/dist/chunk-2IXPWPLR.mjs.map +1 -0
  5. package/dist/{chunk-TCZHG3G7.mjs → chunk-3VMKS7PU.mjs} +44 -5
  6. package/dist/chunk-3VMKS7PU.mjs.map +1 -0
  7. package/dist/{chunk-TEX44HNL.mjs → chunk-7HBVGVOB.mjs} +5 -15
  8. package/dist/chunk-7HBVGVOB.mjs.map +1 -0
  9. package/dist/{chunk-LVEJHB3X.mjs → chunk-DQ45LDKZ.mjs} +512 -98
  10. package/dist/chunk-DQ45LDKZ.mjs.map +1 -0
  11. package/dist/{chunk-ULNRUS55.mjs → chunk-E6W2RURS.mjs} +3 -3
  12. package/dist/{chunk-36JGKW6K.mjs → chunk-KCPGEILH.mjs} +1503 -530
  13. package/dist/chunk-KCPGEILH.mjs.map +1 -0
  14. package/dist/{chunk-WV5GSRQM.mjs → chunk-LJXSUN25.mjs} +5 -15
  15. package/dist/chunk-LJXSUN25.mjs.map +1 -0
  16. package/dist/chunk-N5AGDT7I.mjs +268 -0
  17. package/dist/chunk-N5AGDT7I.mjs.map +1 -0
  18. package/dist/{chunk-D3DPCDII.mjs → chunk-SZEBCNBB.mjs} +193 -79
  19. package/dist/chunk-SZEBCNBB.mjs.map +1 -0
  20. package/dist/{chunk-5EE2EFPE.mjs → chunk-VOVLPSG6.mjs} +29 -52
  21. package/dist/chunk-VOVLPSG6.mjs.map +1 -0
  22. package/dist/chunk-YAQLYL52.mjs +14 -0
  23. package/dist/chunk-YAQLYL52.mjs.map +1 -0
  24. package/dist/{chunk-326OCJOT.mjs → chunk-ZVWUR7ET.mjs} +2 -2
  25. package/dist/cli.mjs +10 -7
  26. package/dist/contacts-worker.mjs +2 -2
  27. package/dist/global-insight-worker.mjs +179 -0
  28. package/dist/global-insight-worker.mjs.map +1 -0
  29. package/dist/{http-L4AMELPZ.mjs → http-M6NHWJZD.mjs} +12 -11
  30. package/dist/{import-WWCSXGVS.mjs → import-SEYHFXS5.mjs} +12 -7
  31. package/dist/index.mjs +13 -12
  32. package/dist/{mcp-A4M3LT5O.mjs → mcp-MIPFYRLV.mjs} +12 -11
  33. package/dist/{mcp-A4M3LT5O.mjs.map → mcp-MIPFYRLV.mjs.map} +1 -1
  34. package/dist/people-relationships-worker.mjs +2 -2
  35. package/dist/semantic-index-worker.mjs +1 -1
  36. package/dist/{src-MPNBTFOE.mjs → src-7OD6RD5V.mjs} +38 -6
  37. package/dist/{stream-import-HIE7PNL4.mjs → stream-import-AWEHGQJY.mjs} +12 -7
  38. package/dist/{worker-runtime-BJXO24XX.mjs → worker-runtime-TGYMASIE.mjs} +6 -5
  39. package/dist/{worker-runtime-BJXO24XX.mjs.map → worker-runtime-TGYMASIE.mjs.map} +1 -1
  40. package/dist-web/assets/ActionToolsPanel-fAio70bI.css +1 -0
  41. package/dist-web/assets/ActionToolsPanel.vue_vue_type_script_setup_true_lang-CkDGVRXe.js +110 -0
  42. package/dist-web/assets/{BufferResource-q3rzaWWd.js → BufferResource-CHI62pIA.js} +1 -1
  43. package/dist-web/assets/{CanvasRenderer-BRk1y8tp.js → CanvasRenderer-OZRoiF0j.js} +1 -1
  44. package/dist-web/assets/{EChartWordcloud-Clg60FMo.js → EChartWordcloud-DU3ZYdgz.js} +1 -1
  45. package/dist-web/assets/{Filter-BJwode73.js → Filter-DNb5VErW.js} +1 -1
  46. package/dist-web/assets/{LoadingState.vue_vue_type_script_setup_true_lang-D_dJuLWJ.js → LoadingState.vue_vue_type_script_setup_true_lang-DACMroOe.js} +1 -1
  47. package/dist-web/assets/MessageExportModal-CqP-w7HP.js +1 -0
  48. package/dist-web/assets/PageHeader-Ck8ULyZH.js +1 -0
  49. package/dist-web/assets/PageHeader-XIXMTomn.css +1 -0
  50. package/dist-web/assets/{RelationshipGalaxyCanvas-CORMD7vL.js → RelationshipGalaxyCanvas-ioRNObb5.js} +3 -3
  51. package/dist-web/assets/{RelationshipGalaxyThreeCanvas-B_w_P4ob.js → RelationshipGalaxyThreeCanvas-L1Y43p1A.js} +1 -1
  52. package/dist-web/assets/{RenderTargetSystem-CGhV9R9E.js → RenderTargetSystem-fJ7D7Chv.js} +1 -1
  53. package/dist-web/assets/ThemeCard.vue_vue_type_script_setup_true_lang-BoZyssJF.js +1 -0
  54. package/dist-web/assets/TimeSelect.vue_vue_type_script_setup_true_lang-7SEaCxDL.js +1 -0
  55. package/dist-web/assets/{WebGLRenderer-CAokTE5X.js → WebGLRenderer-BD3ZUtxH.js} +1 -1
  56. package/dist-web/assets/{WebGPURenderer-DzP4ggSy.js → WebGPURenderer-DZXYsT6D.js} +1 -1
  57. package/dist-web/assets/annual-summary-time-range-DVLXK1r4.js +1 -0
  58. package/dist-web/assets/base-DTElkJcC.js +1 -0
  59. package/dist-web/assets/{browserAll-CAZCK6dd.js → browserAll-ChT6N6a9.js} +1 -1
  60. package/dist-web/assets/dateFormat-D9WibwOu.js +1 -0
  61. package/dist-web/assets/{electron-CkPDbAaS.js → electron-CIzyGxH_.js} +1 -1
  62. package/dist-web/assets/electron-hcWiB7Gg.js +1 -0
  63. package/dist-web/assets/fetch-Avtnh8cJ.js +3 -0
  64. package/dist-web/assets/{fetch-DQ9UNNAy.js → fetch-BFnrBahy.js} +1 -1
  65. package/dist-web/assets/fetch-C9rx2isC.js +31 -0
  66. package/dist-web/assets/fetch-Ccq_0ecb.js +1 -0
  67. package/dist-web/assets/{fetch-BIEXkvDq.js → fetch-CuiQUcO_.js} +1 -1
  68. package/dist-web/assets/{fetch-LX9jrJCC.js → fetch-CyKILLnB.js} +1 -1
  69. package/dist-web/assets/fetch-Dd6t3p1r.js +6 -0
  70. package/dist-web/assets/{fetch--UbRoBT7.js → fetch-DnGx-1_t.js} +1 -1
  71. package/dist-web/assets/{fetch-wqMSiaK3.js → fetch-qC7om4QG.js} +1 -1
  72. package/dist-web/assets/fetch-wSSfDBdV.js +1 -0
  73. package/dist-web/assets/index-BH9jI5kV.js +173 -0
  74. package/dist-web/assets/index-BWtNqcYK.js +22 -0
  75. package/dist-web/assets/index-BfO_LpDv.css +1 -0
  76. package/dist-web/assets/index-Bkq7-GBp.js +1 -0
  77. package/dist-web/assets/index-Bqr-LkS1.css +1 -0
  78. package/dist-web/assets/index-ByUaiVQK.css +1 -0
  79. package/dist-web/assets/index-C6qtsaP7.js +1 -0
  80. package/dist-web/assets/index-C_0GHEcb.css +1 -0
  81. package/dist-web/assets/index-ChFGuu70.js +1 -0
  82. package/dist-web/assets/{index-S-YQRH1E.js → index-CiS20iAR.js} +1 -1
  83. package/dist-web/assets/index-CqD6u57u.js +1 -0
  84. package/dist-web/assets/index-CzDG8LVr.js +2 -0
  85. package/dist-web/assets/index-D0Euk-vQ.js +1 -0
  86. package/dist-web/assets/index-D26BWhHz.js +1 -0
  87. package/dist-web/assets/index-DXHYzIIj.js +1 -0
  88. package/dist-web/assets/index-Dq8u7gMb.js +2 -0
  89. package/dist-web/assets/index-ZsZwPLWy.css +1 -0
  90. package/dist-web/assets/index-u_UH6rDY.js +64 -0
  91. package/dist-web/assets/index-y7cxH1Et.css +1 -0
  92. package/dist-web/assets/{people-page-header-Mupn-U_b.js → people-page-header-BdKM1qhX.js} +1 -1
  93. package/dist-web/assets/types-CZnACqaB.js +1 -0
  94. package/dist-web/assets/{vendor-echarts-hJVnODyU.js → vendor-echarts-B-i_56Av.js} +1 -1
  95. package/dist-web/assets/{vendor-echarts-wordcloud-k5ih2Jl4.js → vendor-echarts-wordcloud-Ca8n6qS6.js} +1 -1
  96. package/dist-web/assets/{vendor-nuxt-ui-DaLxYaC4.js → vendor-nuxt-ui-CS1uxE9C.js} +2 -2
  97. package/dist-web/assets/{vendor-reka-ui-CzM4kDQ7.js → vendor-reka-ui-Cta6JPvN.js} +1 -1
  98. package/dist-web/assets/{web-DbKs6-1b.js → web-BDBdpdK7.js} +1 -1
  99. package/dist-web/assets/{webworkerAll-Bhv-hBqR.js → webworkerAll-C3dAOQj4.js} +1 -1
  100. package/dist-web/index.html +4 -4
  101. package/package.json +1 -1
  102. package/dist/chunk-36JGKW6K.mjs.map +0 -1
  103. package/dist/chunk-5EE2EFPE.mjs.map +0 -1
  104. package/dist/chunk-D3DPCDII.mjs.map +0 -1
  105. package/dist/chunk-KBSAVUFV.mjs +0 -161
  106. package/dist/chunk-KBSAVUFV.mjs.map +0 -1
  107. package/dist/chunk-LVEJHB3X.mjs.map +0 -1
  108. package/dist/chunk-M2PXDX4G.mjs.map +0 -1
  109. package/dist/chunk-TCZHG3G7.mjs.map +0 -1
  110. package/dist/chunk-TEX44HNL.mjs.map +0 -1
  111. package/dist/chunk-WV5GSRQM.mjs.map +0 -1
  112. package/dist-web/assets/DebugToolsPanel-D_lFIW6j.css +0 -1
  113. package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-F4n0zNX2.js +0 -110
  114. package/dist-web/assets/MessageExportModal-CGcdMOyw.js +0 -1
  115. package/dist-web/assets/PageHeader-Bbn87QZS.css +0 -1
  116. package/dist-web/assets/PageHeader-CZaqOdBQ.js +0 -1
  117. package/dist-web/assets/electron-D9vE5t3H.js +0 -1
  118. package/dist-web/assets/fetch-1pB-HbYw.js +0 -3
  119. package/dist-web/assets/fetch-Apd5OLJw.js +0 -5
  120. package/dist-web/assets/fetch-B8rik0TM.js +0 -17
  121. package/dist-web/assets/fetch-CF_3ZqRa.js +0 -1
  122. package/dist-web/assets/fetch-FSNxSnAp.js +0 -1
  123. package/dist-web/assets/index---rXG1hZ.css +0 -1
  124. package/dist-web/assets/index-B01uUoHE.js +0 -1
  125. package/dist-web/assets/index-B4l3rHie.css +0 -1
  126. package/dist-web/assets/index-BSIyyt0z.js +0 -1
  127. package/dist-web/assets/index-Bh8z441f.js +0 -2
  128. package/dist-web/assets/index-C0rya8v4.js +0 -1
  129. package/dist-web/assets/index-C1p9CbmN.css +0 -1
  130. package/dist-web/assets/index-COpza1A4.css +0 -1
  131. package/dist-web/assets/index-CZbZv2fh.js +0 -64
  132. package/dist-web/assets/index-CqUuHQBQ.js +0 -22
  133. package/dist-web/assets/index-CzeTP5MJ.js +0 -173
  134. package/dist-web/assets/index-DgNxTM_8.js +0 -2
  135. package/dist-web/assets/index-DosG7LmJ.css +0 -1
  136. /package/dist/{chunk-ULNRUS55.mjs.map → chunk-E6W2RURS.mjs.map} +0 -0
  137. /package/dist/{chunk-326OCJOT.mjs.map → chunk-ZVWUR7ET.mjs.map} +0 -0
  138. /package/dist/{http-L4AMELPZ.mjs.map → http-M6NHWJZD.mjs.map} +0 -0
  139. /package/dist/{import-WWCSXGVS.mjs.map → import-SEYHFXS5.mjs.map} +0 -0
  140. /package/dist/{src-MPNBTFOE.mjs.map → src-7OD6RD5V.mjs.map} +0 -0
  141. /package/dist/{stream-import-HIE7PNL4.mjs.map → stream-import-AWEHGQJY.mjs.map} +0 -0
@@ -7,8 +7,10 @@ const __dirname = __pathDirname(__filename);
7
7
  import {
8
8
  AGENT_TOOL_REGISTRY,
9
9
  CoreDataProvider,
10
- SEMANTIC_SEARCH_TOOL_NAME
11
- } from "./chunk-TCZHG3G7.mjs";
10
+ SEMANTIC_SEARCH_TOOL_NAME,
11
+ executeToolForAgent,
12
+ toAgentToolParameters
13
+ } from "./chunk-3VMKS7PU.mjs";
12
14
  import {
13
15
  AgentEventHandler,
14
16
  CHART_CAPABILITY_CORE_TOOLS,
@@ -42,14 +44,14 @@ import {
42
44
  runAgentCore,
43
45
  shouldUseChartCapabilityForMessage,
44
46
  wrapWithChartSchemaGate
45
- } from "./chunk-36JGKW6K.mjs";
47
+ } from "./chunk-KCPGEILH.mjs";
46
48
  import {
47
49
  AiLogger,
48
50
  batchSegmentWithFrequency,
49
51
  getChatOverview,
50
52
  normalizeBuiltinToolNames,
51
53
  resolveApiKey
52
- } from "./chunk-LVEJHB3X.mjs";
54
+ } from "./chunk-DQ45LDKZ.mjs";
53
55
 
54
56
  // src/ai/logger.ts
55
57
  var logger = null;
@@ -79,17 +81,6 @@ var TOOL_TRUNCATION_STRATEGY = {
79
81
  get_segment_messages: "keep_last",
80
82
  get_conversation_between: "keep_last"
81
83
  };
82
- function convertJsonSchemaToParameters(schema) {
83
- const properties = {};
84
- for (const [key, prop] of Object.entries(schema.properties)) {
85
- properties[key] = { ...prop };
86
- }
87
- return {
88
- type: "object",
89
- properties,
90
- required: schema.required || []
91
- };
92
- }
93
84
  function adaptToolsForAgent(tools, getContext, options) {
94
85
  const tokenBudget = options?.maxToolResultTokens ?? DEFAULT_MAX_TOOL_RESULT_TOKENS;
95
86
  const chartSchemaGateState = createChartSchemaGateState();
@@ -99,9 +90,8 @@ function adaptToolsForAgent(tools, getContext, options) {
99
90
  name: tool.name,
100
91
  label: tool.name,
101
92
  description: tool.description,
102
- parameters: convertJsonSchemaToParameters(tool.inputSchema),
93
+ parameters: toAgentToolParameters(tool.inputSchema),
103
94
  async execute(_toolCallId, params) {
104
- const toolParams = params && typeof params === "object" ? params : {};
105
95
  const ctx = getContext();
106
96
  const execCtx = {
107
97
  db: ctx.db,
@@ -120,40 +110,27 @@ function adaptToolsForAgent(tools, getContext, options) {
120
110
  ctx.preprocessConfig
121
111
  )
122
112
  };
123
- try {
124
- const result = await tool.handler(toolParams, execCtx);
125
- const chartDetails = result.chart || result.charts ? {
126
- ...result.chart ? { chart: result.chart } : {},
127
- ...result.charts ? { charts: result.charts } : {}
128
- } : {};
129
- if (result.rawMessages && result.rawMessages.length > 0) {
130
- const { rawMessages: _rawInData, ...extraDetails } = result.data ?? {};
131
- const preprocessCfg = ctx.preprocessConfig;
132
- const pipelineResult = applyPreprocessingPipeline({
133
- rawMessages: result.rawMessages,
134
- preprocessConfig: preprocessCfg,
135
- anonymizeNames: preprocessCfg?.anonymizeNames ?? false,
136
- ownerPlatformId: ctx.ownerPlatformId,
137
- locale: ctx.locale,
138
- maxToolResultTokens: tokenBudget,
139
- truncationStrategy: TOOL_TRUNCATION_STRATEGY[tool.name] ?? "keep_last",
140
- extraDetails,
141
- logger: getServerAiLogger() ?? void 0
142
- });
143
- return {
144
- content: [{ type: "text", text: pipelineResult.text }],
145
- details: Object.keys(chartDetails).length > 0 ? chartDetails : null
146
- };
147
- }
148
- const baseDetails = typeof result.data === "object" && result.data !== null ? result.data : result.data === void 0 ? null : { value: result.data };
149
- return {
150
- content: [{ type: "text", text: result.content }],
151
- details: Object.keys(chartDetails).length > 0 ? { ...baseDetails ?? {}, ...chartDetails } : baseDetails
152
- };
153
- } catch (error) {
154
- const msg = error instanceof Error ? error.message : String(error);
155
- return { content: [{ type: "text", text: `Error: ${msg}` }], details: null };
156
- }
113
+ const result = await executeToolForAgent(tool, params, execCtx);
114
+ const details = result.details;
115
+ if (!Array.isArray(details?.rawMessages)) return result;
116
+ const { rawMessages, chart, charts, ...extraDetails } = details;
117
+ const preprocessCfg = ctx.preprocessConfig;
118
+ const pipelineResult = applyPreprocessingPipeline({
119
+ rawMessages,
120
+ preprocessConfig: preprocessCfg,
121
+ anonymizeNames: preprocessCfg?.anonymizeNames ?? false,
122
+ ownerPlatformId: ctx.ownerPlatformId,
123
+ locale: ctx.locale,
124
+ maxToolResultTokens: tokenBudget,
125
+ truncationStrategy: TOOL_TRUNCATION_STRATEGY[tool.name] ?? "keep_last",
126
+ extraDetails,
127
+ logger: getServerAiLogger() ?? void 0
128
+ });
129
+ const chartDetails = { ...chart ? { chart } : {}, ...charts ? { charts } : {} };
130
+ return {
131
+ content: [{ type: "text", text: pipelineResult.text }],
132
+ details: Object.keys(chartDetails).length > 0 ? chartDetails : null
133
+ };
157
134
  }
158
135
  },
159
136
  chartSchemaGateState
@@ -585,4 +562,4 @@ export {
585
562
  closeServerAiLogger,
586
563
  createCliRunAgentStream
587
564
  };
588
- //# sourceMappingURL=chunk-5EE2EFPE.mjs.map
565
+ //# sourceMappingURL=chunk-VOVLPSG6.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ai/logger.ts","../src/ai/tool-adapter.ts","../src/ai/llm-config.ts","../src/ai/assistant-loader.ts","../src/ai/agent.ts","../src/ai/agent-stream-runner.ts"],"sourcesContent":["/**\n * Server 端 AI 日志\n *\n * 复用 @openchatlab/node-runtime 的 AiLogger,\n * 在 startHttpServer() 中通过 initServerAiLogger() 初始化。\n */\n\nimport { AiLogger } from '@openchatlab/node-runtime'\n\nlet logger: AiLogger | null = null\n\nexport function initServerAiLogger(logsDir: string): AiLogger {\n if (!logger) {\n logger = new AiLogger(logsDir)\n }\n return logger\n}\n\nexport function getServerAiLogger(): AiLogger | null {\n return logger\n}\n\nexport function closeServerAiLogger(): void {\n if (logger) {\n logger.close()\n logger = null\n }\n}\n","/**\n * 工具适配层\n *\n * 将 @openchatlab/tools 的 ToolDefinition 适配为 @earendil-works/pi-agent-core 的 AgentTool 格式。\n * 消息类工具返回 rawMessages 时自动执行预处理管道(清洗、去噪、脱敏、截断、格式化)。\n */\n\nimport type {\n ToolDefinition,\n ToolExecutionContext,\n SemanticSearchToolService,\n RawMessage,\n ToolTimeRange,\n} from '@openchatlab/tools'\nimport { CoreDataProvider, executeToolForAgent, toAgentToolParameters } from '@openchatlab/tools'\nimport type { DatabaseAdapter } from '@openchatlab/core'\nimport {\n applyPreprocessingPipeline,\n batchSegmentWithFrequency,\n preprocessMessages,\n type AgentTool,\n type PreprocessableMessage,\n type PreprocessConfig,\n type TruncationStrategy,\n createChartSchemaGateState,\n wrapWithChartSchemaGate,\n} from '@openchatlab/node-runtime'\nimport { getServerAiLogger } from './logger'\n\nconst DEFAULT_MAX_TOOL_RESULT_TOKENS = 8000\n\nconst TOOL_TRUNCATION_STRATEGY: Record<string, TruncationStrategy> = {\n search_messages: 'keep_first',\n deep_search_messages: 'keep_first',\n get_recent_messages: 'keep_last',\n get_message_context: 'keep_last',\n get_segment_messages: 'keep_last',\n get_conversation_between: 'keep_last',\n}\n\nexport interface ServerToolContext {\n db: DatabaseAdapter\n sessionId: string\n locale?: string\n /** 语义检索窄接口(仅当前会话可检索时由 runner 注入) */\n semanticIndexService?: SemanticSearchToolService\n /** 预处理配置(脱敏/匿名化/清洗) */\n preprocessConfig?: Record<string, unknown>\n /** 当前用户平台 id(昵称匿名化 owner 识别) */\n ownerPlatformId?: string\n /** 会话时间范围筛选(来自请求参数,供证据类工具继承) */\n timeFilter?: ToolTimeRange\n /** 关键词搜索消息条数上限 */\n maxMessagesLimit?: number\n}\n\nexport interface AdaptToolsOptions {\n maxToolResultTokens?: number\n}\n\nexport function adaptToolsForAgent(\n tools: ToolDefinition[],\n getContext: () => ServerToolContext,\n options?: AdaptToolsOptions\n): AgentTool<any, any>[] {\n const tokenBudget = options?.maxToolResultTokens ?? DEFAULT_MAX_TOOL_RESULT_TOKENS\n const chartSchemaGateState = createChartSchemaGateState()\n\n return tools.map((tool) =>\n wrapWithChartSchemaGate(\n {\n name: tool.name,\n label: tool.name,\n description: tool.description,\n parameters: toAgentToolParameters(tool.inputSchema) as any,\n async execute(_toolCallId: string, params: unknown) {\n const ctx = getContext()\n const execCtx: ToolExecutionContext = {\n db: ctx.db,\n dataProvider: new CoreDataProvider(ctx.db),\n sessionId: ctx.sessionId,\n locale: ctx.locale,\n semanticIndexService: ctx.semanticIndexService,\n preprocessConfig: ctx.preprocessConfig,\n ownerPlatformId: ctx.ownerPlatformId,\n timeFilter: ctx.timeFilter,\n maxMessagesLimit: ctx.maxMessagesLimit,\n maxToolResultTokens: tokenBudget,\n segmentText: (texts, locale, options) => batchSegmentWithFrequency(texts, locale as any, options as any),\n desensitizeMessages: (messages: RawMessage[]): RawMessage[] =>\n preprocessMessages(\n messages as PreprocessableMessage[],\n ctx.preprocessConfig as PreprocessConfig | undefined\n ) as RawMessage[],\n }\n const result = await executeToolForAgent(tool, params, execCtx)\n const details = result.details as Record<string, unknown> | null\n if (!Array.isArray(details?.rawMessages)) return result\n\n const { rawMessages, chart, charts, ...extraDetails } = details\n const preprocessCfg = ctx.preprocessConfig as PreprocessConfig | undefined\n const pipelineResult = applyPreprocessingPipeline({\n rawMessages: rawMessages as PreprocessableMessage[],\n preprocessConfig: preprocessCfg,\n anonymizeNames: preprocessCfg?.anonymizeNames ?? false,\n ownerPlatformId: ctx.ownerPlatformId,\n locale: ctx.locale,\n maxToolResultTokens: tokenBudget,\n truncationStrategy: TOOL_TRUNCATION_STRATEGY[tool.name] ?? 'keep_last',\n extraDetails,\n logger: getServerAiLogger() ?? undefined,\n })\n const chartDetails = { ...(chart ? { chart } : {}), ...(charts ? { charts } : {}) }\n return {\n content: [{ type: 'text', text: pipelineResult.text }],\n details: Object.keys(chartDetails).length > 0 ? chartDetails : null,\n }\n },\n },\n chartSchemaGateState\n )\n )\n}\n","/**\n * 服务端 LLM 配置加载\n *\n * API Key 从 ~/.chatlab/auth-profiles.json 读取,\n * 匹配顺序:config.authProfile 精确匹配 > config.provider 兜底匹配。\n *\n * 模型/Provider 等配置仍从 llm-config.json 读取。\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport type { PiModel, PiApi } from '@openchatlab/node-runtime'\nimport { buildPiModel as buildPiModelCore, type PiModelConfig } from '@openchatlab/node-runtime'\nimport { resolveApiKey, writeAuthProfile } from '@openchatlab/config'\nimport { randomUUID } from 'crypto'\n\n// ==================== Types ====================\n\nexport interface AIServiceConfig {\n id: string\n name: string\n provider: string\n apiKey: string\n model?: string\n baseUrl?: string\n maxTokens?: number\n apiFormat?: string\n customModels?: Array<{ id: string; name: string }>\n authProfile?: string\n}\n\ninterface ModelSlot {\n configId: string\n modelId?: string\n}\n\ninterface AIConfigStore {\n configs: AIServiceConfig[]\n defaultAssistant: ModelSlot | null\n fastModel: ModelSlot | null\n}\n\n// ==================== Config Loading ====================\n\nexport function loadLlmConfig(aiDataDir: string): AIConfigStore {\n const configPath = path.join(aiDataDir, 'llm-config.json')\n if (!fs.existsSync(configPath)) {\n return { configs: [], defaultAssistant: null, fastModel: null }\n }\n\n try {\n const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'))\n\n const configs = (data.configs || []).map((c: Record<string, unknown>) => {\n const provider = (c.provider as string) || ''\n const authProfile = c.authProfile as string | undefined\n const profileKey = resolveApiKey(provider, authProfile)\n const rawKey = (c.apiKey as string) || ''\n const fallbackKey = rawKey.startsWith('enc:') ? '' : rawKey\n return {\n ...c,\n apiKey: profileKey || fallbackKey,\n }\n })\n return {\n configs,\n defaultAssistant: data.defaultAssistant ?? null,\n fastModel: data.fastModel ?? null,\n }\n } catch {\n return { configs: [], defaultAssistant: null, fastModel: null }\n }\n}\n\nfunction resolveSlot(slot: ModelSlot | null | undefined, configs: AIServiceConfig[]): ModelSlot | null {\n if (slot && configs.some((c) => c.id === slot.configId)) return slot\n const fallback = configs[0]\n if (!fallback) return null\n return { configId: fallback.id, modelId: fallback.model }\n}\n\nexport function getDefaultAssistantConfig(aiDataDir: string): AIServiceConfig | null {\n const store = loadLlmConfig(aiDataDir)\n const slot = resolveSlot(store.defaultAssistant, store.configs)\n if (!slot) return null\n const config = store.configs.find((c) => c.id === slot.configId)\n if (!config) return null\n return { ...config, model: slot.modelId || config.model }\n}\n\n// ==================== Config Write Operations ====================\n\nconst MAX_CONFIG_COUNT = 99\n\nfunction saveLlmConfig(aiDataDir: string, store: AIConfigStore): void {\n const configPath = path.join(aiDataDir, 'llm-config.json')\n const toSave = {\n ...store,\n configs: store.configs.map((c) => {\n const { apiKey: _k, ...rest } = c\n return rest\n }),\n schemaVersion: 3,\n }\n fs.writeFileSync(configPath, JSON.stringify(toSave, null, 2), 'utf-8')\n}\n\nexport function addLlmConfig(\n aiDataDir: string,\n config: Omit<AIServiceConfig, 'id'>\n): { success: boolean; config?: AIServiceConfig; error?: string } {\n const store = loadLlmConfig(aiDataDir)\n\n if (store.configs.length >= MAX_CONFIG_COUNT) {\n return { success: false, error: `Maximum ${MAX_CONFIG_COUNT} configs reached` }\n }\n\n const newConfig: AIServiceConfig = {\n ...config,\n id: randomUUID(),\n }\n\n const storeForSave = loadRawConfigStore(aiDataDir)\n storeForSave.configs.push({\n ...newConfig,\n apiKey: '',\n })\n\n if (storeForSave.configs.length === 1) {\n storeForSave.defaultAssistant = { configId: newConfig.id, modelId: newConfig.model || '' }\n }\n\n if (config.apiKey) {\n const profileName = config.name?.toLowerCase().replace(/\\s+/g, '-') || config.provider\n writeAuthProfile(profileName, {\n type: 'api_key',\n provider: config.provider,\n key: config.apiKey,\n })\n ;(storeForSave.configs[storeForSave.configs.length - 1] as unknown as Record<string, unknown>).authProfile =\n profileName\n }\n\n saveLlmConfig(aiDataDir, storeForSave)\n return { success: true, config: { ...newConfig, apiKey: '' } }\n}\n\nexport function updateLlmConfig(\n aiDataDir: string,\n id: string,\n updates: Partial<Omit<AIServiceConfig, 'id'>>\n): { success: boolean; error?: string } {\n const storeForSave = loadRawConfigStore(aiDataDir)\n const index = storeForSave.configs.findIndex((c) => c.id === id)\n\n if (index === -1) {\n return { success: false, error: 'Config not found' }\n }\n\n const { apiKey: newApiKey, ...restUpdates } = updates\n const updated = {\n ...storeForSave.configs[index],\n ...restUpdates,\n }\n storeForSave.configs[index] = updated\n\n if (newApiKey) {\n const profileName = updated.name?.toLowerCase().replace(/\\s+/g, '-') || updated.provider\n writeAuthProfile(profileName, {\n type: 'api_key',\n provider: updated.provider,\n key: newApiKey,\n })\n ;(storeForSave.configs[index] as unknown as Record<string, unknown>).authProfile = profileName\n }\n\n saveLlmConfig(aiDataDir, storeForSave)\n return { success: true }\n}\n\nexport function deleteLlmConfig(aiDataDir: string, id: string): { success: boolean; error?: string } {\n const storeForSave = loadRawConfigStore(aiDataDir)\n const index = storeForSave.configs.findIndex((c) => c.id === id)\n\n if (index === -1) {\n return { success: false, error: 'Config not found' }\n }\n\n storeForSave.configs.splice(index, 1)\n\n const fallback = storeForSave.configs[0]\n if (storeForSave.defaultAssistant?.configId === id) {\n storeForSave.defaultAssistant = fallback ? { configId: fallback.id, modelId: fallback.model || '' } : null\n }\n if (storeForSave.fastModel?.configId === id) {\n storeForSave.fastModel = fallback ? { configId: fallback.id, modelId: fallback.model || '' } : null\n }\n\n saveLlmConfig(aiDataDir, storeForSave)\n return { success: true }\n}\n\nexport function setDefaultAssistantSlot(\n aiDataDir: string,\n configId: string,\n modelId: string\n): { success: boolean; error?: string } {\n const storeForSave = loadRawConfigStore(aiDataDir)\n const config = storeForSave.configs.find((c) => c.id === configId)\n\n if (!config) {\n return { success: false, error: 'Config not found' }\n }\n\n storeForSave.defaultAssistant = { configId, modelId }\n saveLlmConfig(aiDataDir, storeForSave)\n return { success: true }\n}\n\nexport function setFastModelSlot(aiDataDir: string, slot: ModelSlot | null): { success: boolean; error?: string } {\n const storeForSave = loadRawConfigStore(aiDataDir)\n\n if (slot !== null) {\n const config = storeForSave.configs.find((c) => c.id === slot.configId)\n if (!config) {\n return { success: false, error: 'Config not found' }\n }\n }\n\n storeForSave.fastModel = slot\n saveLlmConfig(aiDataDir, storeForSave)\n return { success: true }\n}\n\nfunction loadRawConfigStore(aiDataDir: string): AIConfigStore {\n const configPath = path.join(aiDataDir, 'llm-config.json')\n if (!fs.existsSync(configPath)) {\n return { configs: [], defaultAssistant: null, fastModel: null }\n }\n try {\n const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'))\n return {\n configs: data.configs || [],\n defaultAssistant: data.defaultAssistant ?? null,\n fastModel: data.fastModel ?? null,\n }\n } catch {\n return { configs: [], defaultAssistant: null, fastModel: null }\n }\n}\n\n// ==================== PiModel Builder ====================\n\nexport function buildPiModel(config: AIServiceConfig): PiModel<PiApi> {\n return buildPiModelCore(config as PiModelConfig)\n}\n","/**\n * 助手配置加载器\n *\n * 从 ~/.chatlab/ai/assistants/*.md 加载助手系统提示词。\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { parseAssistantFile } from '@openchatlab/node-runtime'\nimport type { AssistantConfig } from '@openchatlab/node-runtime'\n\nexport function loadAssistantConfig(aiDataDir: string, assistantId: string): AssistantConfig | null {\n const filePath = path.join(aiDataDir, 'assistants', `${assistantId}.md`)\n if (!fs.existsSync(filePath)) return null\n\n try {\n const content = fs.readFileSync(filePath, 'utf-8')\n return parseAssistantFile(content, filePath)\n } catch {\n return null\n }\n}\n","/**\n * 服务端 Agent\n *\n * 使用 @openchatlab/node-runtime 的 runAgentCore 编排对话流程,\n * 通过 AgentEventHandler 输出与 Electron 端一致的流式事件。\n */\n\nimport {\n DEFAULT_MAX_TOOL_ROUNDS,\n buildPlanGuidance,\n createAnalysisPlanner,\n createLlmRouteDecider,\n createPlanContentBlock,\n decideRequestRoute,\n runAgentCore,\n checkAndCompress,\n buildSystemPrompt,\n createAiTranslate,\n createCompressionLlmAdapter,\n AgentEventHandler,\n formatAIError,\n shouldUseChartCapabilityForMessage,\n getChartPlannerCapabilityForMessage,\n initTokenizer,\n type AgentStreamChunk,\n type PiMessage,\n type SimpleHistoryMessage,\n type AIChatManager,\n type CompressionConfig,\n type AgentTool,\n type DataSnapshot,\n type OwnerInfo,\n type MentionedMember,\n} from '@openchatlab/node-runtime'\nimport type { ChartAutoMode } from '@openchatlab/shared-types'\n\nimport { getDefaultAssistantConfig, buildPiModel } from './llm-config'\nimport { getServerAiLogger } from './logger'\n\nexport type { AgentStreamChunk }\n\nexport interface RunAgentOptions {\n userMessage: string\n aiChatId: string\n historyLeafMessageId?: string | null\n chatType?: 'group' | 'private'\n locale?: string\n assistantSystemPrompt?: string\n skillMenu?: string | null\n skillDef?: { name: string; prompt: string }\n compressionConfig?: CompressionConfig\n tools?: AgentTool[]\n aiDataDir: string\n aiChatManager: AIChatManager\n onEvent: (event: AgentStreamChunk) => void\n abortSignal?: AbortSignal\n ownerInfo?: OwnerInfo\n mentionedMembers?: MentionedMember[]\n dataSnapshot?: DataSnapshot\n thinkingLevel?: string\n chartAutoMode?: ChartAutoMode\n}\n\nexport async function runServerAgent(options: RunAgentOptions): Promise<void> {\n const {\n userMessage,\n aiChatId,\n historyLeafMessageId,\n chatType = 'group',\n locale = 'zh-CN',\n assistantSystemPrompt,\n skillMenu,\n skillDef,\n compressionConfig,\n tools = [],\n aiDataDir,\n aiChatManager,\n onEvent,\n abortSignal,\n ownerInfo,\n mentionedMembers,\n dataSnapshot,\n thinkingLevel,\n chartAutoMode = 'suggest',\n } = options\n\n const aiLogger = getServerAiLogger()\n\n // 确保 tokenizer rank 表已加载(compression + agent 路径均依赖)\n await initTokenizer()\n\n const llmConfig = getDefaultAssistantConfig(aiDataDir)\n if (!llmConfig) {\n onEvent({ type: 'error', error: { name: 'ConfigError', message: 'LLM service not configured' } })\n onEvent({ type: 'done', isFinished: true })\n return\n }\n\n const piModel = buildPiModel(llmConfig)\n const t = createAiTranslate(locale)\n\n let skillCtx: { skillDef?: { name: string; prompt: string }; skillMenu?: string } | undefined\n if (skillDef) {\n skillCtx = { skillDef }\n } else if (skillMenu) {\n skillCtx = { skillMenu }\n }\n\n const systemPrompt = buildSystemPrompt({\n t,\n chatType,\n assistantSystemPrompt,\n ownerInfo,\n locale,\n skillCtx,\n mentionedMembers,\n dataSnapshot,\n })\n\n const handler = new AgentEventHandler({\n onChunk: onEvent,\n context: {},\n systemPrompt,\n })\n\n if (compressionConfig?.enabled && historyLeafMessageId === undefined) {\n const llmAdapter = createCompressionLlmAdapter({\n piModel,\n apiKey: llmConfig.apiKey,\n onCompressing: () => handler.emitStatus('compressing', []),\n })\n const compressionResult = await checkAndCompress(\n aiChatId,\n compressionConfig,\n systemPrompt,\n llmAdapter,\n aiChatManager,\n aiLogger ?? undefined\n )\n if (compressionResult.compressed) {\n onEvent({\n type: 'compression_done',\n compressionResult: {\n summaryContent: compressionResult.summaryContent ?? '',\n tokensBefore: compressionResult.tokensBefore ?? 0,\n tokensAfter: compressionResult.tokensAfter ?? 0,\n timestamp: Date.now(),\n },\n })\n }\n } else if (compressionConfig?.enabled && historyLeafMessageId !== undefined) {\n aiLogger?.info?.('Compression', 'Skipping compression for edited branch request', {\n aiChatId,\n historyLeafMessageId,\n })\n }\n\n if (abortSignal?.aborted) {\n handler.emitStatus('aborted', [], { force: true })\n onEvent({ type: 'done', isFinished: true, usage: handler.cloneUsage() })\n return\n }\n\n let history: SimpleHistoryMessage[] = []\n try {\n history = aiChatManager.getHistoryForAgent(aiChatId, undefined, historyLeafMessageId)\n } catch {\n // empty history on failure\n }\n\n handler.emitStatus('preparing', [], { pendingUserMessage: userMessage, force: true })\n\n const steerMessage = t('ai.agent.answerWithoutTools')\n let cachedMessages: PiMessage[] = []\n const effectiveTools =\n chartAutoMode === 'explicit' && !shouldUseChartCapabilityForMessage(userMessage)\n ? tools.filter((tool) => tool.name !== 'render_chart')\n : tools\n\n try {\n const routeInput = {\n userMessage,\n chatType,\n locale,\n dataSnapshot,\n availableTools: effectiveTools.map((tool) => tool.name),\n availableCapabilities: [\n getChartPlannerCapabilityForMessage({\n userMessage,\n locale,\n availableTools: effectiveTools.map((tool) => tool.name),\n chartAutoMode,\n }),\n ].filter((capability) => capability !== null),\n skillSummary: skillDef?.name ?? (skillMenu ? 'auto_skill_menu' : undefined),\n }\n const routeStartedAt = Date.now()\n const routeDecision = await decideRequestRoute(routeInput, {\n llmRouter: createLlmRouteDecider({\n piModel,\n apiKey: llmConfig.apiKey,\n abortSignal,\n }),\n })\n aiLogger?.info('Router', 'Shadow route decision', {\n ...routeDecision,\n elapsedMs: Date.now() - routeStartedAt,\n availableToolCount: tools.length,\n shadowOnly: true,\n })\n onEvent({ type: 'route', routeDecision })\n\n let effectiveSystemPrompt = systemPrompt\n if (routeDecision.route === 'planned_execution') {\n const planStartedAt = Date.now()\n const planner = createAnalysisPlanner({\n piModel,\n apiKey: llmConfig.apiKey,\n onPlanDelta: (delta) => onEvent({ type: 'plan_delta', planDelta: delta }),\n onThinkingDelta: (delta) => onEvent({ type: 'think', content: delta, thinkTag: 'thinking' }),\n onThinkingEnd: (durationMs) =>\n onEvent({ type: 'think', content: '', thinkTag: 'thinking', thinkDurationMs: durationMs }),\n onValidationDelta: (delta) => onEvent({ type: 'think', content: delta, thinkTag: 'plan_validation' }),\n onValidationEnd: (durationMs) =>\n onEvent({ type: 'think', content: '', thinkTag: 'plan_validation', thinkDurationMs: durationMs }),\n })\n const plan = await planner(routeInput, abortSignal)\n if (plan) {\n const planBlock = createPlanContentBlock(plan)\n onEvent({ type: 'plan', plan: planBlock })\n effectiveSystemPrompt = `${systemPrompt}\\n\\n${buildPlanGuidance(plan)}`\n aiLogger?.info('Planner', 'Plan generated', {\n title: plan.title,\n steps: plan.steps.length,\n successCriteria: plan.successCriteria.length,\n elapsedMs: Date.now() - planStartedAt,\n })\n } else {\n aiLogger?.warn('Planner', 'Plan generation skipped or failed', {\n elapsedMs: Date.now() - planStartedAt,\n route: routeDecision.route,\n })\n onEvent({ type: 'plan_skipped' })\n }\n }\n\n const result = await runAgentCore({\n piModel,\n apiKey: llmConfig.apiKey,\n systemPrompt: effectiveSystemPrompt,\n tools: effectiveTools,\n history,\n userMessage,\n maxToolRounds: DEFAULT_MAX_TOOL_ROUNDS,\n abortSignal,\n steerMessage,\n thinkingLevel: thinkingLevel as import('@openchatlab/core').ThinkingLevel | undefined,\n onConvertToLlm: (filteredMessages) => {\n cachedMessages = filteredMessages as PiMessage[]\n },\n onEvent: (coreEvent) => handler.handleCoreEvent(coreEvent, cachedMessages),\n onDebugContext: (messages) => {\n try {\n aiChatManager.setPendingDebugContext(aiChatId, JSON.stringify(messages, null, 2))\n } catch {\n // silent\n }\n },\n })\n\n if (result.error) {\n const friendlyMessage = formatAIError(result.error)\n onEvent({ type: 'error', error: { name: 'AgentError', message: friendlyMessage } })\n }\n\n handler.emitStatus('completed', cachedMessages, { force: true })\n onEvent({ type: 'done', isFinished: true, usage: result.usage })\n } catch (error) {\n const friendlyMessage = formatAIError(error)\n aiLogger?.error('ServerAgent', 'Agent execution error', { error: String(error) })\n handler.emitStatus('error', cachedMessages, { force: true })\n onEvent({ type: 'error', error: { name: 'AgentError', message: friendlyMessage } })\n onEvent({ type: 'done', isFinished: true, usage: handler.cloneUsage() })\n }\n}\n","/**\n * CLI Agent stream runner — provides runAgentStream implementation\n * for the shared HTTP route context.\n */\n\nimport type { DatabaseManager, AIChatManager, AgentStreamChunk, SemanticIndexRuntime } from '@openchatlab/node-runtime'\nimport {\n CHART_CAPABILITY_CORE_TOOLS,\n SkillManager,\n buildSkillMenuWithBuiltinChart,\n createActivateSkillTool,\n createDataSnapshotFromOverview,\n getAllowedBuiltinToolsForChartAutoSkill,\n getChartCapabilitySkill,\n getSkillConfigWithBuiltinChart,\n resolveChartRuntimeForRequest,\n} from '@openchatlab/node-runtime'\nimport { getChatOverview, normalizeBuiltinToolNames } from '@openchatlab/core'\nimport type { ChartAutoMode } from '@openchatlab/shared-types'\nimport type { DataSnapshot } from '@openchatlab/node-runtime'\nimport type { AgentStreamRequest } from '@openchatlab/http-routes'\nimport { AGENT_TOOL_REGISTRY, SEMANTIC_SEARCH_TOOL_NAME } from '@openchatlab/tools'\nimport { buildSemanticSearchGuidance } from '@openchatlab/node-runtime'\nimport { adaptToolsForAgent } from './tool-adapter'\nimport { getDefaultAssistantConfig, buildPiModel } from './llm-config'\nimport { loadAssistantConfig } from './assistant-loader'\nimport { runServerAgent } from './agent'\n\nfunction getAiDir(dbManager: DatabaseManager): string {\n const pathProvider = (dbManager as any)['pathProvider']\n if (!pathProvider) {\n throw Object.assign(new Error('PathProvider not available'), { statusCode: 500 })\n }\n return pathProvider.getAiDataDir()\n}\n\nconst RAW_SQL_TOOL_NAMES = new Set(['execute_sql'])\n\nexport function getAvailableToolDefs(isChartCapability: boolean, allowedToolSet: Set<string> | null) {\n if (isChartCapability) {\n const chartCoreTools = new Set<string>(CHART_CAPABILITY_CORE_TOOLS)\n return AGENT_TOOL_REGISTRY.filter(\n (tool) =>\n chartCoreTools.has(tool.name) ||\n (tool.category === 'analysis' && allowedToolSet?.has(tool.name) && !RAW_SQL_TOOL_NAMES.has(tool.name))\n )\n }\n\n return allowedToolSet\n ? AGENT_TOOL_REGISTRY.filter((tool) => tool.category !== 'analysis' || allowedToolSet.has(tool.name))\n : AGENT_TOOL_REGISTRY\n}\n\n// 区分“未配置白名单”和“配置为空白名单”:前者无限制,后者禁用 analysis 工具。\nexport function getAllowedToolSet(\n isChartCapability: boolean,\n allowedBuiltinTools?: readonly string[]\n): Set<string> | null {\n if (isChartCapability) {\n return new Set(normalizeBuiltinToolNames(allowedBuiltinTools ?? []))\n }\n return allowedBuiltinTools === undefined ? null : new Set(normalizeBuiltinToolNames(allowedBuiltinTools))\n}\n\nexport function createCliRunAgentStream(\n dbManager: DatabaseManager,\n aiChatManager: AIChatManager,\n semanticIndexService?: SemanticIndexRuntime\n): (params: AgentStreamRequest, onEvent: (chunk: AgentStreamChunk) => void, abortSignal: AbortSignal) => Promise<void> {\n return async (params, onEvent, abortSignal) => {\n const {\n userMessage,\n aiChatId,\n historyLeafMessageId,\n sessionId,\n chatType,\n locale,\n assistantId,\n skillId,\n enableAutoSkill,\n chartAutoMode,\n compressionConfig,\n ownerInfo,\n mentionedMembers,\n thinkingLevel,\n } = params\n\n const aiDataDir = getAiDir(dbManager)\n\n let assistantSystemPrompt: string | undefined\n let assistantAllowedTools: string[] | undefined\n if (assistantId) {\n const assistantConfig = loadAssistantConfig(aiDataDir, assistantId)\n if (assistantConfig?.systemPrompt) {\n assistantSystemPrompt = assistantConfig.systemPrompt\n }\n assistantAllowedTools = assistantConfig?.allowedBuiltinTools\n }\n\n const llmConfig = getDefaultAssistantConfig(aiDataDir)\n const maxToolResultPercent = compressionConfig?.maxToolResultPercent ?? 50\n const contextWindow = llmConfig ? (buildPiModel(llmConfig).contextWindow ?? 128000) : 128000\n const maxToolResultTokens = Math.floor(contextWindow * (maxToolResultPercent / 100))\n\n const db = (dbManager as any).open?.(sessionId)\n const resolvedChartAutoMode: ChartAutoMode = chartAutoMode ?? 'suggest'\n const chartRuntime = resolveChartRuntimeForRequest({\n skillId,\n userMessage,\n locale,\n assistantAllowedTools,\n enableAutoDetection: enableAutoSkill === true,\n chartAutoMode: resolvedChartAutoMode,\n })\n const isChartCapability = chartRuntime.isChartCapability\n const autoSkillAllowedTools =\n !skillId && enableAutoSkill && resolvedChartAutoMode !== 'explicit'\n ? getAllowedBuiltinToolsForChartAutoSkill(assistantAllowedTools)\n : assistantAllowedTools\n const allowedToolSet = getAllowedToolSet(\n isChartCapability,\n isChartCapability ? chartRuntime.allowedBuiltinTools : autoSkillAllowedTools\n )\n const availableToolDefs = getAvailableToolDefs(isChartCapability, allowedToolSet)\n\n // 语义检索按需暴露:仅当前会话可检索时保留工具,否则从工具集中过滤掉以减少 schema token 与无效调用。\n const canSemanticSearch = !!db && !!semanticIndexService && (await semanticIndexService.canSearch(sessionId))\n const filteredToolDefs = canSemanticSearch\n ? availableToolDefs\n : availableToolDefs.filter((tool) => tool.name !== SEMANTIC_SEARCH_TOOL_NAME)\n\n const agentTools = db\n ? adaptToolsForAgent(\n filteredToolDefs,\n () => ({\n db,\n sessionId,\n locale,\n semanticIndexService,\n preprocessConfig: params.preprocessConfig,\n ownerPlatformId: ownerInfo?.platformId,\n timeFilter: params.timeFilter,\n maxMessagesLimit: params.maxMessagesLimit,\n }),\n { maxToolResultTokens }\n )\n : []\n\n // 工具可用时向 system prompt 加简短引导,提示何时调用语义检索。\n if (canSemanticSearch) {\n assistantSystemPrompt = [assistantSystemPrompt, buildSemanticSearchGuidance(locale)].filter(Boolean).join('\\n\\n')\n }\n\n const skillMgr = new SkillManager(aiDataDir)\n skillMgr.init()\n const toolNames = agentTools.map((t: { name: string }) => t.name)\n\n let resolvedSkillDef: { name: string; prompt: string } | undefined\n let resolvedSkillMenu: string | undefined\n if (isChartCapability) {\n const def = chartRuntime.skillDef ?? getChartCapabilitySkill(locale ?? 'zh-CN')\n resolvedSkillDef = { name: def.name, prompt: def.prompt }\n } else if (skillId) {\n const def = skillMgr.getSkillConfig(skillId)\n if (def) resolvedSkillDef = { name: def.name, prompt: def.prompt }\n } else if (enableAutoSkill) {\n const baseMenu = skillMgr.getSkillMenu(chatType ?? 'group', toolNames)\n const menu =\n resolvedChartAutoMode === 'aggressive' ? buildSkillMenuWithBuiltinChart(baseMenu, locale, toolNames) : baseMenu\n if (menu) resolvedSkillMenu = menu\n }\n\n if (resolvedSkillMenu) {\n const activateSkillTool = createActivateSkillTool({\n chatType: chatType ?? 'group',\n allowedTools: toolNames,\n coreToolNames: new Set<string>(CHART_CAPABILITY_CORE_TOOLS),\n locale,\n getSkillConfig: (id) =>\n resolvedChartAutoMode === 'aggressive'\n ? getSkillConfigWithBuiltinChart(id, locale, (skillConfigId) => skillMgr.getSkillConfig(skillConfigId))\n : skillMgr.getSkillConfig(id),\n })\n agentTools.push(activateSkillTool as any)\n }\n\n const resolvedCompression = compressionConfig?.enabled\n ? {\n enabled: true as const,\n tokenThresholdPercent: compressionConfig.tokenThresholdPercent ?? 75,\n bufferSizePercent: compressionConfig.bufferSizePercent ?? 20,\n maxToolResultPercent: compressionConfig.maxToolResultPercent,\n }\n : undefined\n\n let dataSnapshot: DataSnapshot | undefined\n if (db) {\n try {\n dataSnapshot = createDataSnapshotFromOverview(getChatOverview(db, 10))\n } catch {\n // non-fatal\n }\n }\n\n await runServerAgent({\n userMessage,\n aiChatId,\n historyLeafMessageId,\n chatType,\n locale,\n assistantSystemPrompt,\n skillMenu: resolvedSkillMenu,\n skillDef: resolvedSkillDef,\n compressionConfig: resolvedCompression,\n tools: agentTools,\n aiDataDir,\n aiChatManager,\n onEvent,\n abortSignal,\n ownerInfo,\n mentionedMembers,\n dataSnapshot,\n thinkingLevel,\n chartAutoMode: resolvedChartAutoMode,\n })\n }\n}\n"],"mappings":"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","names":["options","buildPiModel","fs","path","buildPiModel","buildPiModel"]}
@@ -0,0 +1,14 @@
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
+
8
+ // ../../packages/node-runtime/src/services/global-insight/types.ts
9
+ var ANNUAL_SUMMARY_ALGORITHM_VERSION = "annual-summary-v1";
10
+
11
+ export {
12
+ ANNUAL_SUMMARY_ALGORITHM_VERSION
13
+ };
14
+ //# sourceMappingURL=chunk-YAQLYL52.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../packages/node-runtime/src/services/global-insight/types.ts"],"sourcesContent":["import type {\n AnnualSummaryCoverage,\n AnnualSummaryMetrics,\n AnnualSummaryRange,\n AnnualSummaryTextLength,\n} from '@openchatlab/shared-types'\n\nexport const ANNUAL_SUMMARY_ALGORITHM_VERSION = 'annual-summary-v1'\n\nexport interface AnnualSummaryWorkerStats {\n durationMs: number\n totalSessions: number\n processedSessions: number\n cacheHits: number\n cacheMisses: number\n}\n\nexport interface AnnualSummarySnapshot {\n algorithmVersion: string\n signature: string\n computedAt: number\n range: AnnualSummaryRange\n availableDataYears: number[]\n latestDataYear: number | null\n metrics: AnnualSummaryMetrics\n monthlyActivity: Array<{ month: string; messageCount: number }>\n dailyActivity: Array<{ date: string; messageCount: number }>\n messageTypes: Array<{ type: number; count: number }>\n textLength: AnnualSummaryTextLength\n coverage: AnnualSummaryCoverage\n workerStats: AnnualSummaryWorkerStats\n}\n\nexport interface AnnualSummaryComputeProgress {\n processedSessions: number\n totalSessions: number\n currentSessionId?: string\n}\n"],"mappings":";;;;;;;;AAOO,IAAM,mCAAmC;","names":[]}
@@ -10,7 +10,7 @@ import {
10
10
  import {
11
11
  DataDirCompatibilityError,
12
12
  assertDataDirCompatible
13
- } from "./chunk-LVEJHB3X.mjs";
13
+ } from "./chunk-DQ45LDKZ.mjs";
14
14
 
15
15
  // src/runtime-compat.ts
16
16
  function assertCliDataDirCompatible(pathProvider, kind, options) {
@@ -37,4 +37,4 @@ function formatCliDataDirCompatibilityError(error, runtime) {
37
37
  export {
38
38
  assertCliDataDirCompatible
39
39
  };
40
- //# sourceMappingURL=chunk-326OCJOT.mjs.map
40
+ //# sourceMappingURL=chunk-ZVWUR7ET.mjs.map
package/dist/cli.mjs CHANGED
@@ -6,15 +6,18 @@ const __filename = __fileURLToPath(import.meta.url);
6
6
  const __dirname = __pathDirname(__filename);
7
7
  import {
8
8
  run
9
- } from "./chunk-M2PXDX4G.mjs";
10
- import "./chunk-326OCJOT.mjs";
9
+ } from "./chunk-2IXPWPLR.mjs";
10
+ import "./chunk-5FGB42EQ.mjs";
11
+ import "./chunk-N5AGDT7I.mjs";
12
+ import "./chunk-ZVWUR7ET.mjs";
11
13
  import "./chunk-5ADKYYNA.mjs";
14
+ import "./chunk-E6W2RURS.mjs";
15
+ import "./chunk-KCPGEILH.mjs";
12
16
  import "./chunk-FJ35V3TE.mjs";
13
- import "./chunk-ULNRUS55.mjs";
14
- import "./chunk-36JGKW6K.mjs";
15
- import "./chunk-TEX44HNL.mjs";
16
- import "./chunk-WV5GSRQM.mjs";
17
- import "./chunk-LVEJHB3X.mjs";
17
+ import "./chunk-7HBVGVOB.mjs";
18
+ import "./chunk-LJXSUN25.mjs";
19
+ import "./chunk-YAQLYL52.mjs";
20
+ import "./chunk-DQ45LDKZ.mjs";
18
21
  import "./chunk-GFHSSCCR.mjs";
19
22
  export {
20
23
  run
@@ -6,14 +6,14 @@ const __filename = __fileURLToPath(import.meta.url);
6
6
  const __dirname = __pathDirname(__filename);
7
7
  import {
8
8
  computeContactsSnapshot
9
- } from "./chunk-TEX44HNL.mjs";
9
+ } from "./chunk-7HBVGVOB.mjs";
10
10
  import {
11
11
  DatabaseManager,
12
12
  StaticPathProvider,
13
13
  createDatabaseManagerAdapter,
14
14
  getContactsFactsCacheDir,
15
15
  initAppLogger
16
- } from "./chunk-LVEJHB3X.mjs";
16
+ } from "./chunk-DQ45LDKZ.mjs";
17
17
  import "./chunk-GFHSSCCR.mjs";
18
18
 
19
19
  // ../../packages/node-runtime/src/services/contacts/worker-entry.ts
@@ -0,0 +1,179 @@
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
+ ANNUAL_SUMMARY_ALGORITHM_VERSION
9
+ } from "./chunk-YAQLYL52.mjs";
10
+ import {
11
+ DatabaseManager,
12
+ StaticPathProvider,
13
+ aggregateAnnualSummaryFacts,
14
+ appLogger,
15
+ createDatabaseManagerAdapter,
16
+ getAnnualSummaryElapsedDayCount,
17
+ getAnnualSummarySessionFacts,
18
+ getCache,
19
+ getDbFileVersion,
20
+ getGlobalInsightFactsCacheDir,
21
+ initAppLogger,
22
+ setCache,
23
+ toAnnualSummaryRangeKey
24
+ } from "./chunk-DQ45LDKZ.mjs";
25
+ import "./chunk-GFHSSCCR.mjs";
26
+
27
+ // ../../packages/node-runtime/src/services/global-insight/worker-entry.ts
28
+ import { parentPort, workerData } from "worker_threads";
29
+
30
+ // ../../packages/node-runtime/src/services/global-insight/facts-cache.ts
31
+ var FACTS_FORMAT_VERSION = 1;
32
+ function buildAnnualSummaryFactsCacheKey(algorithmVersion, range) {
33
+ return `global-insight:facts:v${FACTS_FORMAT_VERSION}:${algorithmVersion}:${toAnnualSummaryRangeKey(range)}`;
34
+ }
35
+ function readCachedAnnualSummarySessionFacts(sessionId, cacheDir, key, dbVersion, range) {
36
+ const cached = getCache(sessionId, key, cacheDir);
37
+ if (!cached || cached.v !== dbVersion || cached.rangeIdentity !== buildFactsRangeIdentity(range) || !isAnnualSummarySessionFacts(cached.data)) {
38
+ return { hit: false };
39
+ }
40
+ return { hit: true, data: cached.data };
41
+ }
42
+ function writeCachedAnnualSummarySessionFacts(sessionId, cacheDir, key, dbVersion, range, data) {
43
+ setCache(
44
+ sessionId,
45
+ key,
46
+ { v: dbVersion, rangeIdentity: buildFactsRangeIdentity(range), data },
47
+ cacheDir
48
+ );
49
+ }
50
+ function buildFactsRangeIdentity(range) {
51
+ if (range.mode === "year") return `year:${range.year}`;
52
+ return `recent:${toLocalDate(range.startTs)}:${toLocalDate(range.endTs)}`;
53
+ }
54
+ function toLocalDate(ts) {
55
+ const date = new Date(ts * 1e3);
56
+ return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
57
+ }
58
+ function isAnnualSummarySessionFacts(value) {
59
+ if (!value || typeof value !== "object") return false;
60
+ const record = value;
61
+ if (typeof record.kind !== "string" || !Array.isArray(record.availableDataYears)) return false;
62
+ if (record.kind !== "analyzed") return true;
63
+ return isRecord(record.ownerMessagesByDay) && isRecord(record.directContactKeysByDay) && isRecord(record.messageTypeCounts) && isRecord(record.textLengthCounts);
64
+ }
65
+ function isRecord(value) {
66
+ return typeof value === "object" && value !== null && !Array.isArray(value);
67
+ }
68
+
69
+ // ../../packages/node-runtime/src/services/global-insight/compute.ts
70
+ function computeAnnualSummarySnapshot(options) {
71
+ const startedAt = options.now?.() ?? Date.now();
72
+ const sessionIds = options.adapter.listSessionIds();
73
+ const facts = [];
74
+ let cacheHits = 0;
75
+ let cacheMisses = 0;
76
+ const cacheKey = buildAnnualSummaryFactsCacheKey(ANNUAL_SUMMARY_ALGORITHM_VERSION, options.range);
77
+ appLogger.info("global-insight", "annual summary compute started", {
78
+ mode: options.range.mode,
79
+ year: options.range.year,
80
+ totalSessions: sessionIds.length
81
+ });
82
+ for (const [index, sessionId] of sessionIds.entries()) {
83
+ options.onProgress?.({
84
+ processedSessions: index,
85
+ totalSessions: sessionIds.length,
86
+ currentSessionId: sessionId
87
+ });
88
+ const dbVersion = getDbFileVersion(options.adapter.getDbPath(sessionId));
89
+ const cached = readCachedAnnualSummarySessionFacts(
90
+ sessionId,
91
+ options.factsCacheDir,
92
+ cacheKey,
93
+ dbVersion,
94
+ options.range
95
+ );
96
+ if (cached.hit) {
97
+ cacheHits++;
98
+ facts.push(cached.data);
99
+ continue;
100
+ }
101
+ cacheMisses++;
102
+ try {
103
+ const db = options.adapter.openReadonly(sessionId);
104
+ if (!db) {
105
+ facts.push({ kind: "failed", availableDataYears: [] });
106
+ continue;
107
+ }
108
+ const sessionFacts = getAnnualSummarySessionFacts(db, sessionId, options.range);
109
+ facts.push(sessionFacts);
110
+ if (dbVersion === getDbFileVersion(options.adapter.getDbPath(sessionId))) {
111
+ writeCachedAnnualSummarySessionFacts(
112
+ sessionId,
113
+ options.factsCacheDir,
114
+ cacheKey,
115
+ dbVersion,
116
+ options.range,
117
+ sessionFacts
118
+ );
119
+ } else {
120
+ appLogger.debug("global-insight", "skipped annual summary facts cache write because DB changed");
121
+ }
122
+ } catch (error) {
123
+ facts.push({ kind: "failed", availableDataYears: [] });
124
+ appLogger.error("global-insight", "failed to process annual summary session", error);
125
+ }
126
+ }
127
+ options.onProgress?.({ processedSessions: sessionIds.length, totalSessions: sessionIds.length });
128
+ const aggregated = aggregateAnnualSummaryFacts(facts, options.range, getAnnualSummaryElapsedDayCount(options.range));
129
+ const finishedAt = options.now?.() ?? Date.now();
130
+ const snapshot = {
131
+ algorithmVersion: ANNUAL_SUMMARY_ALGORITHM_VERSION,
132
+ signature: options.signature,
133
+ computedAt: finishedAt,
134
+ range: options.range,
135
+ ...aggregated,
136
+ workerStats: {
137
+ durationMs: Math.max(0, finishedAt - startedAt),
138
+ totalSessions: sessionIds.length,
139
+ processedSessions: sessionIds.length,
140
+ cacheHits,
141
+ cacheMisses
142
+ }
143
+ };
144
+ appLogger.info("global-insight", "annual summary compute completed", {
145
+ totalSessions: sessionIds.length,
146
+ analyzedSessions: snapshot.coverage.analyzedSessions,
147
+ cacheHits,
148
+ cacheMisses,
149
+ durationMs: snapshot.workerStats.durationMs
150
+ });
151
+ return snapshot;
152
+ }
153
+
154
+ // ../../packages/node-runtime/src/services/global-insight/worker-entry.ts
155
+ async function main() {
156
+ if (!parentPort) throw new Error("annual summary worker requires parentPort");
157
+ const options = workerData;
158
+ initAppLogger(options.paths.logsDir);
159
+ const pathProvider = new StaticPathProvider(options.paths);
160
+ const dbManager = new DatabaseManager(pathProvider, {
161
+ nativeBinding: options.nativeBinding,
162
+ runtime: options.runtimeIdentity,
163
+ allowMissingRuntimeForTests: !options.runtimeIdentity
164
+ });
165
+ const adapter = createDatabaseManagerAdapter(dbManager);
166
+ const computeOptions = {
167
+ adapter,
168
+ signature: options.signature,
169
+ range: options.range,
170
+ factsCacheDir: getGlobalInsightFactsCacheDir(pathProvider.getUserDataDir()),
171
+ onProgress: (progress) => parentPort?.postMessage({ type: "progress", progress })
172
+ };
173
+ const snapshot = computeAnnualSummarySnapshot(computeOptions);
174
+ parentPort.postMessage({ type: "success", snapshot });
175
+ }
176
+ main().catch((error) => {
177
+ parentPort?.postMessage({ type: "error", error: error instanceof Error ? error.message : String(error) });
178
+ });
179
+ //# sourceMappingURL=global-insight-worker.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../packages/node-runtime/src/services/global-insight/worker-entry.ts","../../../packages/node-runtime/src/services/global-insight/facts-cache.ts","../../../packages/node-runtime/src/services/global-insight/compute.ts"],"sourcesContent":["import { parentPort, workerData } from 'node:worker_threads'\nimport type { AnnualSummaryRange } from '@openchatlab/shared-types'\nimport { DatabaseManager } from '../../database-manager'\nimport type { RuntimeIdentity } from '../../data-dir-compat'\nimport { initAppLogger } from '../../logging/app-logger'\nimport { StaticPathProvider, type StaticPathProviderSnapshot } from '../../semantic-index/static-path-provider'\nimport { createDatabaseManagerAdapter } from '../adapters'\nimport { computeAnnualSummarySnapshot, type ComputeAnnualSummarySnapshotOptions } from './compute'\nimport { getGlobalInsightFactsCacheDir } from './paths'\n\ninterface StartupOptions {\n paths: StaticPathProviderSnapshot\n runtimeIdentity?: RuntimeIdentity\n nativeBinding?: string\n signature: string\n range: AnnualSummaryRange\n}\n\nasync function main(): Promise<void> {\n if (!parentPort) throw new Error('annual summary worker requires parentPort')\n const options = workerData as StartupOptions\n initAppLogger(options.paths.logsDir)\n const pathProvider = new StaticPathProvider(options.paths)\n const dbManager = new DatabaseManager(pathProvider, {\n nativeBinding: options.nativeBinding,\n runtime: options.runtimeIdentity,\n allowMissingRuntimeForTests: !options.runtimeIdentity,\n })\n const adapter = createDatabaseManagerAdapter(dbManager)\n const computeOptions: ComputeAnnualSummarySnapshotOptions = {\n adapter,\n signature: options.signature,\n range: options.range,\n factsCacheDir: getGlobalInsightFactsCacheDir(pathProvider.getUserDataDir()),\n onProgress: (progress) => parentPort?.postMessage({ type: 'progress', progress }),\n }\n const snapshot = computeAnnualSummarySnapshot(computeOptions)\n parentPort.postMessage({ type: 'success', snapshot })\n}\n\nmain().catch((error) => {\n parentPort?.postMessage({ type: 'error', error: error instanceof Error ? error.message : String(error) })\n})\n","import type { AnnualSummarySessionFacts } from '@openchatlab/core'\nimport type { AnnualSummaryRange } from '@openchatlab/shared-types'\nimport { getCache, setCache } from '../../cache/session-cache'\nimport { toAnnualSummaryRangeKey } from './time-range'\n\nconst FACTS_FORMAT_VERSION = 1\n\ninterface CachedFactsEntry {\n v: string\n rangeIdentity: string\n data: AnnualSummarySessionFacts\n}\n\nexport type AnnualSummaryFactsCacheReadResult = { hit: true; data: AnnualSummarySessionFacts } | { hit: false }\n\nexport function buildAnnualSummaryFactsCacheKey(algorithmVersion: string, range: AnnualSummaryRange): string {\n return `global-insight:facts:v${FACTS_FORMAT_VERSION}:${algorithmVersion}:${toAnnualSummaryRangeKey(range)}`\n}\n\nexport function readCachedAnnualSummarySessionFacts(\n sessionId: string,\n cacheDir: string,\n key: string,\n dbVersion: string,\n range: AnnualSummaryRange\n): AnnualSummaryFactsCacheReadResult {\n const cached = getCache<CachedFactsEntry>(sessionId, key, cacheDir)\n if (\n !cached ||\n cached.v !== dbVersion ||\n cached.rangeIdentity !== buildFactsRangeIdentity(range) ||\n !isAnnualSummarySessionFacts(cached.data)\n ) {\n return { hit: false }\n }\n return { hit: true, data: cached.data }\n}\n\nexport function writeCachedAnnualSummarySessionFacts(\n sessionId: string,\n cacheDir: string,\n key: string,\n dbVersion: string,\n range: AnnualSummaryRange,\n data: AnnualSummarySessionFacts\n): void {\n setCache<CachedFactsEntry>(\n sessionId,\n key,\n { v: dbVersion, rangeIdentity: buildFactsRangeIdentity(range), data },\n cacheDir\n )\n}\n\nfunction buildFactsRangeIdentity(range: AnnualSummaryRange): string {\n if (range.mode === 'year') return `year:${range.year}`\n return `recent:${toLocalDate(range.startTs)}:${toLocalDate(range.endTs)}`\n}\n\nfunction toLocalDate(ts: number): string {\n const date = new Date(ts * 1000)\n return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`\n}\n\nfunction isAnnualSummarySessionFacts(value: unknown): value is AnnualSummarySessionFacts {\n if (!value || typeof value !== 'object') return false\n const record = value as Record<string, unknown>\n if (typeof record.kind !== 'string' || !Array.isArray(record.availableDataYears)) return false\n if (record.kind !== 'analyzed') return true\n return (\n isRecord(record.ownerMessagesByDay) &&\n isRecord(record.directContactKeysByDay) &&\n isRecord(record.messageTypeCounts) &&\n isRecord(record.textLengthCounts)\n )\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n","import {\n aggregateAnnualSummaryFacts,\n getAnnualSummarySessionFacts,\n type AnnualSummarySessionFacts,\n} from '@openchatlab/core'\nimport type { AnnualSummaryRange } from '@openchatlab/shared-types'\nimport { getDbFileVersion } from '../../cache/analytics-cache'\nimport { appLogger } from '../../logging/app-logger'\nimport type { SessionRuntimeAdapter } from '../adapters'\nimport {\n buildAnnualSummaryFactsCacheKey,\n readCachedAnnualSummarySessionFacts,\n writeCachedAnnualSummarySessionFacts,\n} from './facts-cache'\nimport { getAnnualSummaryElapsedDayCount } from './time-range'\nimport {\n ANNUAL_SUMMARY_ALGORITHM_VERSION,\n type AnnualSummaryComputeProgress,\n type AnnualSummarySnapshot,\n} from './types'\n\nexport interface ComputeAnnualSummarySnapshotOptions {\n adapter: SessionRuntimeAdapter\n signature: string\n range: AnnualSummaryRange\n factsCacheDir: string\n onProgress?: (progress: AnnualSummaryComputeProgress) => void\n now?: () => number\n}\n\nexport function computeAnnualSummarySnapshot(options: ComputeAnnualSummarySnapshotOptions): AnnualSummarySnapshot {\n const startedAt = options.now?.() ?? Date.now()\n const sessionIds = options.adapter.listSessionIds()\n const facts: AnnualSummarySessionFacts[] = []\n let cacheHits = 0\n let cacheMisses = 0\n const cacheKey = buildAnnualSummaryFactsCacheKey(ANNUAL_SUMMARY_ALGORITHM_VERSION, options.range)\n\n appLogger.info('global-insight', 'annual summary compute started', {\n mode: options.range.mode,\n year: options.range.year,\n totalSessions: sessionIds.length,\n })\n\n for (const [index, sessionId] of sessionIds.entries()) {\n options.onProgress?.({\n processedSessions: index,\n totalSessions: sessionIds.length,\n currentSessionId: sessionId,\n })\n const dbVersion = getDbFileVersion(options.adapter.getDbPath(sessionId))\n const cached = readCachedAnnualSummarySessionFacts(\n sessionId,\n options.factsCacheDir,\n cacheKey,\n dbVersion,\n options.range\n )\n if (cached.hit) {\n cacheHits++\n facts.push(cached.data)\n continue\n }\n\n cacheMisses++\n try {\n const db = options.adapter.openReadonly(sessionId)\n if (!db) {\n facts.push({ kind: 'failed', availableDataYears: [] })\n continue\n }\n const sessionFacts = getAnnualSummarySessionFacts(db, sessionId, options.range)\n facts.push(sessionFacts)\n if (dbVersion === getDbFileVersion(options.adapter.getDbPath(sessionId))) {\n writeCachedAnnualSummarySessionFacts(\n sessionId,\n options.factsCacheDir,\n cacheKey,\n dbVersion,\n options.range,\n sessionFacts\n )\n } else {\n appLogger.debug('global-insight', 'skipped annual summary facts cache write because DB changed')\n }\n } catch (error) {\n facts.push({ kind: 'failed', availableDataYears: [] })\n appLogger.error('global-insight', 'failed to process annual summary session', error)\n }\n }\n\n options.onProgress?.({ processedSessions: sessionIds.length, totalSessions: sessionIds.length })\n const aggregated = aggregateAnnualSummaryFacts(facts, options.range, getAnnualSummaryElapsedDayCount(options.range))\n const finishedAt = options.now?.() ?? Date.now()\n const snapshot: AnnualSummarySnapshot = {\n algorithmVersion: ANNUAL_SUMMARY_ALGORITHM_VERSION,\n signature: options.signature,\n computedAt: finishedAt,\n range: options.range,\n ...aggregated,\n workerStats: {\n durationMs: Math.max(0, finishedAt - startedAt),\n totalSessions: sessionIds.length,\n processedSessions: sessionIds.length,\n cacheHits,\n cacheMisses,\n },\n }\n appLogger.info('global-insight', 'annual summary compute completed', {\n totalSessions: sessionIds.length,\n analyzedSessions: snapshot.coverage.analyzedSessions,\n cacheHits,\n cacheMisses,\n durationMs: snapshot.workerStats.durationMs,\n })\n return snapshot\n}\n"],"mappings":"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","names":[]}
@@ -9,19 +9,20 @@ import {
9
9
  registerWebRoutes,
10
10
  startHttpServer,
11
11
  stopHttpServer
12
- } from "./chunk-D3DPCDII.mjs";
12
+ } from "./chunk-SZEBCNBB.mjs";
13
+ import "./chunk-VOVLPSG6.mjs";
14
+ import "./chunk-3VMKS7PU.mjs";
13
15
  import "./chunk-5FGB42EQ.mjs";
14
- import "./chunk-KBSAVUFV.mjs";
15
- import "./chunk-5EE2EFPE.mjs";
16
- import "./chunk-TCZHG3G7.mjs";
17
- import "./chunk-326OCJOT.mjs";
16
+ import "./chunk-N5AGDT7I.mjs";
17
+ import "./chunk-ZVWUR7ET.mjs";
18
18
  import "./chunk-5ADKYYNA.mjs";
19
+ import "./chunk-E6W2RURS.mjs";
20
+ import "./chunk-KCPGEILH.mjs";
19
21
  import "./chunk-FJ35V3TE.mjs";
20
- import "./chunk-ULNRUS55.mjs";
21
- import "./chunk-36JGKW6K.mjs";
22
- import "./chunk-TEX44HNL.mjs";
23
- import "./chunk-WV5GSRQM.mjs";
24
- import "./chunk-LVEJHB3X.mjs";
22
+ import "./chunk-7HBVGVOB.mjs";
23
+ import "./chunk-LJXSUN25.mjs";
24
+ import "./chunk-YAQLYL52.mjs";
25
+ import "./chunk-DQ45LDKZ.mjs";
25
26
  import "./chunk-GFHSSCCR.mjs";
26
27
  export {
27
28
  createServer,
@@ -29,4 +30,4 @@ export {
29
30
  startHttpServer,
30
31
  stopHttpServer
31
32
  };
32
- //# sourceMappingURL=http-L4AMELPZ.mjs.map
33
+ //# sourceMappingURL=http-M6NHWJZD.mjs.map
@@ -6,12 +6,14 @@ const __filename = __fileURLToPath(import.meta.url);
6
6
  const __dirname = __pathDirname(__filename);
7
7
  import "./chunk-5FGB42EQ.mjs";
8
8
  import {
9
+ analyzeAutoImport,
9
10
  analyzeIncrementalImport,
10
11
  analyzeNewImport,
12
+ autoImport,
11
13
  incrementalImport,
12
14
  streamImport
13
- } from "./chunk-KBSAVUFV.mjs";
14
- import "./chunk-ULNRUS55.mjs";
15
+ } from "./chunk-N5AGDT7I.mjs";
16
+ import "./chunk-E6W2RURS.mjs";
15
17
  import {
16
18
  detectAllFormats,
17
19
  detectFormat,
@@ -19,14 +21,17 @@ import {
19
21
  getFormatFeatureById,
20
22
  getSupportedFormats,
21
23
  scanMultiChatFile
22
- } from "./chunk-36JGKW6K.mjs";
23
- import "./chunk-TEX44HNL.mjs";
24
- import "./chunk-WV5GSRQM.mjs";
25
- import "./chunk-LVEJHB3X.mjs";
24
+ } from "./chunk-KCPGEILH.mjs";
25
+ import "./chunk-7HBVGVOB.mjs";
26
+ import "./chunk-LJXSUN25.mjs";
27
+ import "./chunk-YAQLYL52.mjs";
28
+ import "./chunk-DQ45LDKZ.mjs";
26
29
  import "./chunk-GFHSSCCR.mjs";
27
30
  export {
31
+ analyzeAutoImport,
28
32
  analyzeIncrementalImport,
29
33
  analyzeNewImport,
34
+ autoImport,
30
35
  detectAllFormats,
31
36
  detectFormat,
32
37
  findEntryFileInDirectory,
@@ -36,4 +41,4 @@ export {
36
41
  scanMultiChatFile,
37
42
  streamImport
38
43
  };
39
- //# sourceMappingURL=import-WWCSXGVS.mjs.map
44
+ //# sourceMappingURL=import-SEYHFXS5.mjs.map
package/dist/index.mjs CHANGED
@@ -7,22 +7,23 @@ const __dirname = __pathDirname(__filename);
7
7
  import {
8
8
  startHttpServer,
9
9
  stopHttpServer
10
- } from "./chunk-D3DPCDII.mjs";
11
- import "./chunk-5FGB42EQ.mjs";
12
- import "./chunk-KBSAVUFV.mjs";
13
- import "./chunk-5EE2EFPE.mjs";
14
- import "./chunk-TCZHG3G7.mjs";
10
+ } from "./chunk-SZEBCNBB.mjs";
11
+ import "./chunk-VOVLPSG6.mjs";
12
+ import "./chunk-3VMKS7PU.mjs";
15
13
  import {
16
14
  run
17
- } from "./chunk-M2PXDX4G.mjs";
18
- import "./chunk-326OCJOT.mjs";
15
+ } from "./chunk-2IXPWPLR.mjs";
16
+ import "./chunk-5FGB42EQ.mjs";
17
+ import "./chunk-N5AGDT7I.mjs";
18
+ import "./chunk-ZVWUR7ET.mjs";
19
19
  import "./chunk-5ADKYYNA.mjs";
20
+ import "./chunk-E6W2RURS.mjs";
21
+ import "./chunk-KCPGEILH.mjs";
20
22
  import "./chunk-FJ35V3TE.mjs";
21
- import "./chunk-ULNRUS55.mjs";
22
- import "./chunk-36JGKW6K.mjs";
23
- import "./chunk-TEX44HNL.mjs";
24
- import "./chunk-WV5GSRQM.mjs";
25
- import "./chunk-LVEJHB3X.mjs";
23
+ import "./chunk-7HBVGVOB.mjs";
24
+ import "./chunk-LJXSUN25.mjs";
25
+ import "./chunk-YAQLYL52.mjs";
26
+ import "./chunk-DQ45LDKZ.mjs";
26
27
  import "./chunk-GFHSSCCR.mjs";
27
28
  export {
28
29
  run,