chatlab-cli 0.37.1 → 0.37.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chat-command-YAFRLHMQ.mjs → chat-command-RQC44FPF.mjs} +53 -13
- package/dist/chat-command-RQC44FPF.mjs.map +1 -0
- package/dist/{chunk-FPVRSXQ4.mjs → chunk-4FAEB4C2.mjs} +12 -12
- package/dist/{chunk-MMTEGUQA.mjs → chunk-5OA4QI3Q.mjs} +3 -3
- package/dist/{chunk-UP6JIV3S.mjs → chunk-E2ZFGNZQ.mjs} +16 -12
- package/dist/chunk-E2ZFGNZQ.mjs.map +1 -0
- package/dist/{chunk-JWJREWVN.mjs → chunk-E6IRRNBQ.mjs} +27 -3
- package/dist/chunk-E6IRRNBQ.mjs.map +1 -0
- package/dist/{chunk-PDQV4RUA.mjs → chunk-GDKQKHJT.mjs} +2 -2
- package/dist/{chunk-GKCIRKOH.mjs → chunk-HJWBFHNR.mjs} +4 -4
- package/dist/{chunk-73TJ2S7W.mjs → chunk-IDDTW5JN.mjs} +313 -24
- package/dist/chunk-IDDTW5JN.mjs.map +1 -0
- package/dist/{chunk-2PY4XCH3.mjs → chunk-IMJVOODY.mjs} +2 -2
- package/dist/{chunk-ARIBCH47.mjs → chunk-LUENE6L7.mjs} +25 -15
- package/dist/chunk-LUENE6L7.mjs.map +1 -0
- package/dist/{chunk-WDLO7OLX.mjs → chunk-O57SQSCO.mjs} +2 -2
- package/dist/{chunk-N4SB6QZV.mjs → chunk-ZGXXAPLX.mjs} +2 -2
- package/dist/{chunk-OTYNMDDL.mjs → chunk-ZOHSWBD2.mjs} +2237 -1977
- package/dist/chunk-ZOHSWBD2.mjs.map +1 -0
- package/dist/cli.mjs +9 -9
- package/dist/contacts-worker.mjs +2 -2
- package/dist/global-insight-worker.mjs +1 -1
- package/dist/{http-LPFPVTBC.mjs → http-QJDZKDNJ.mjs} +12 -12
- package/dist/{import-T4WX2ZJL.mjs → import-XK6YM26A.mjs} +7 -7
- package/dist/index.mjs +12 -12
- package/dist/{mcp-SMF3NWIN.mjs → mcp-DMGZFSYN.mjs} +24 -17
- package/dist/mcp-DMGZFSYN.mjs.map +1 -0
- package/dist/people-relationships-worker.mjs +2 -2
- package/dist/semantic-index-worker.mjs +1 -1
- package/dist/{src-EGLLMTAU.mjs → src-4AHJUFCW.mjs} +6 -6
- package/dist/{stream-import-2BXJTTCE.mjs → stream-import-7VQVT5ST.mjs} +7 -7
- package/dist/{worker-runtime-RDLSPXFT.mjs → worker-runtime-PQBAV75N.mjs} +5 -5
- package/dist-cli-web/assets/{AISettingsTab-CEhrXlYR.js → AISettingsTab-qS3XKnvh.js} +1 -1
- package/dist-cli-web/assets/{AboutTab-Bbu0SsMM.js → AboutTab-K-i40dPv.js} +1 -1
- package/dist-cli-web/assets/{Alert-510jTN3l.js → Alert-GSvA5B7J.js} +1 -1
- package/dist-cli-web/assets/{ApiSettingsTab-Bi1GRMN4.js → ApiSettingsTab-DIVGTR3g.js} +1 -1
- package/dist-cli-web/assets/{BatchManageTab-DhnqMCSM.js → BatchManageTab-CJhwvYWV.js} +1 -1
- package/dist-cli-web/assets/{BufferResource-CKZxnACp.js → BufferResource-Cjm0m7sF.js} +1 -1
- package/dist-cli-web/assets/{CanvasRenderer-BeK5POBy.js → CanvasRenderer-C-fmrahh.js} +1 -1
- package/dist-cli-web/assets/{CardDecoration-RuBA3N2j.js → CardDecoration-Cz54ZPyh.js} +1 -1
- package/dist-cli-web/assets/{ChatRecordDrawer-BY_-lIEj.js → ChatRecordDrawer-Cst8zTUv.js} +1 -1
- package/dist-cli-web/assets/{ChatRecordWorkspace-7prKd-Tq.js → ChatRecordWorkspace-DKVKaimw.js} +1 -1
- package/dist-cli-web/assets/{Checkbox-_eH64bb0.js → Checkbox-CrlY3jiJ.js} +1 -1
- package/dist-cli-web/assets/{DataDirCleanupNotice-BHaXwlfr.js → DataDirCleanupNotice-Cjqiub4e.js} +1 -1
- package/dist-cli-web/assets/{DatePicker.vue_vue_type_script_setup_true_lang-D9Ul_GYz.js → DatePicker.vue_vue_type_script_setup_true_lang-BYY2UmPA.js} +1 -1
- package/dist-cli-web/assets/{DebugToolsPanel-ByKItGrS.js → DebugToolsPanel-I00RV_Lr.js} +1 -1
- package/dist-cli-web/assets/{EChart.vue_vue_type_script_setup_true_lang-DubnuUXI.js → EChart.vue_vue_type_script_setup_true_lang-CRTZh9kh.js} +1 -1
- package/dist-cli-web/assets/{EChartBar.vue_vue_type_script_setup_true_lang-DKNCZuFm.js → EChartBar.vue_vue_type_script_setup_true_lang-DjDFhnN9.js} +1 -1
- package/dist-cli-web/assets/{EChartLine.vue_vue_type_script_setup_true_lang-Fl7xAOSR.js → EChartLine.vue_vue_type_script_setup_true_lang-BLqlW9E4.js} +1 -1
- package/dist-cli-web/assets/{EChartWordcloud-C6XM4KOX.js → EChartWordcloud-ChKJM8bU.js} +1 -1
- package/dist-cli-web/assets/{FileDropZone.vue_vue_type_script_setup_true_lang-DYDdRSNE.js → FileDropZone.vue_vue_type_script_setup_true_lang-CsRmQhVQ.js} +1 -1
- package/dist-cli-web/assets/{Filter-CByj_rCR.js → Filter-Duzxgudo.js} +1 -1
- package/dist-cli-web/assets/{GlobalTaskBar-BdELjzrs.js → GlobalTaskBar-DL0IJxlt.js} +1 -1
- package/dist-cli-web/assets/{GroupRelationshipGalaxyView-CnzPEgUS.js → GroupRelationshipGalaxyView-BZrB2o2g.js} +1 -1
- package/dist-cli-web/assets/{Label-DCIcxkhU.js → Label-CaVKlQnJ.js} +1 -1
- package/dist-cli-web/assets/{LoadingState.vue_vue_type_script_setup_true_lang-BBcCt_Qm.js → LoadingState.vue_vue_type_script_setup_true_lang-uF54r-dT.js} +1 -1
- package/dist-cli-web/assets/{MessageExportModal-DNU16Bs8.js → MessageExportModal-JpurBsUW.js} +1 -1
- package/dist-cli-web/assets/{PageHeader-CKeZjNNR.js → PageHeader-BciykZ_-.js} +1 -1
- package/dist-cli-web/assets/{PageTabs.vue_vue_type_script_setup_true_lang-C8M3wNNH.js → PageTabs.vue_vue_type_script_setup_true_lang-2Xe2iUFO.js} +1 -1
- package/dist-cli-web/assets/{RelationshipGalaxyCanvas-CDhljGyJ.js → RelationshipGalaxyCanvas-BO5-MowG.js} +3 -3
- package/dist-cli-web/assets/{RelationshipGalaxyThreeCanvas-BP8fsvvf.js → RelationshipGalaxyThreeCanvas-Dp4CcWU5.js} +1 -1
- package/dist-cli-web/assets/{RenderTargetSystem-D76QrDT_.js → RenderTargetSystem-CfuoUG_y.js} +1 -1
- package/dist-cli-web/assets/{RovingFocusItem-BJMUQ5DJ.js → RovingFocusItem-FpYwYEP_.js} +1 -1
- package/dist-cli-web/assets/{ScreenCaptureModal-DkX4z-M1.js → ScreenCaptureModal-cElYPaSj.js} +1 -1
- package/dist-cli-web/assets/SectionTabs.vue_vue_type_script_setup_true_lang-pVQMbTsj.js +1 -0
- package/dist-cli-web/assets/{Select-B5oJc5y1.js → Select-H8Fz6RkU.js} +1 -1
- package/dist-cli-web/assets/{SettingsModal-BO-QKQ2h.js → SettingsModal-52Fw4fVW.js} +2 -2
- package/dist-cli-web/assets/{StorageTab-CPPXXaRm.js → StorageTab-BnugE5BO.js} +1 -1
- package/dist-cli-web/assets/{Switch-CDk3LZ4_.js → Switch-K4aqYC4Y.js} +1 -1
- package/dist-cli-web/assets/{Tabs-DqWTBV8x.js → Tabs-BXjD45rO.js} +1 -1
- package/dist-cli-web/assets/{Tabs-BMq9wODW.js → Tabs-DJ5p8gb6.js} +1 -1
- package/dist-cli-web/assets/{ThemeCard.vue_vue_type_script_setup_true_lang-D2outEOV.js → ThemeCard.vue_vue_type_script_setup_true_lang-BLmTpx4f.js} +1 -1
- package/dist-cli-web/assets/{TimeSelect.vue_vue_type_script_setup_true_lang-BcflxP_U.js → TimeSelect.vue_vue_type_script_setup_true_lang-geQAlopO.js} +1 -1
- package/dist-cli-web/assets/{VisuallyHiddenInput-BAFpkxMI.js → VisuallyHiddenInput-J2KEIQBX.js} +1 -1
- package/dist-cli-web/assets/{WebGLRenderer-DjCPvR_O.js → WebGLRenderer-BDFzRniS.js} +1 -1
- package/dist-cli-web/assets/{WebGPURenderer-C2B_u03z.js → WebGPURenderer-BKYZyUCZ.js} +1 -1
- package/dist-cli-web/assets/aiChat-CdJzpNYW.js +8 -0
- package/dist-cli-web/assets/{base-F6s0vTrr.js → base-129JztT1.js} +1 -1
- package/dist-cli-web/assets/{browserAll-DiUAZg4L.js → browserAll-CZNZDK1i.js} +1 -1
- package/dist-cli-web/assets/{chatMessages-Bd33SSXI.js → chatMessages-zmzHCUCy.js} +3 -3
- package/dist-cli-web/assets/{cli-web-DoibEdj2.js → cli-web-_WGCg-ZY.js} +1 -1
- package/dist-cli-web/assets/{fetch-CXM-cjDS.js → fetch-B7Tdp7Uo.js} +1 -1
- package/dist-cli-web/assets/{fetch-DBpDMy29.js → fetch-BBdyPNj3.js} +1 -1
- package/dist-cli-web/assets/{fetch-B_YFABxI.js → fetch-Bafz8jLM.js} +1 -1
- package/dist-cli-web/assets/{fetch-CxVcHNid.js → fetch-C4W6tD-D.js} +1 -1
- package/dist-cli-web/assets/{fetch-BeX69kpS.js → fetch-DOsmgros.js} +1 -1
- package/dist-cli-web/assets/{fetch-CRocA-4C.js → fetch-DTPDtL38.js} +1 -1
- package/dist-cli-web/assets/{fetch-CXqeAbnY.js → fetch-DaeoNUip.js} +1 -1
- package/dist-cli-web/assets/{fetch-7lUvXbhU.js → fetch-DgHdAlO7.js} +1 -1
- package/dist-cli-web/assets/{fetch-DKBBS9Op.js → fetch-Di4QpfqL.js} +1 -1
- package/dist-cli-web/assets/{fetch-4nh1LaVF.js → fetch-Dw33HaVP.js} +11 -13
- package/dist-cli-web/assets/{fetch-BEaW1j5H.js → fetch-IP6i-mtr.js} +1 -1
- package/dist-cli-web/assets/{fetch-epFXmPIQ.js → fetch-sbr95ipd.js} +1 -1
- package/dist-cli-web/assets/{host-CtSqR_Zm.js → host-CMnAiJSx.js} +1 -1
- package/dist-cli-web/assets/{host-C4rU8pKA.js → host-CuuNLUWx.js} +1 -1
- package/dist-cli-web/assets/{index-ekvsNmfe.js → index-BBYtZa7g.js} +1 -1
- package/dist-cli-web/assets/{index-mXe1LssU.js → index-BOXh7X5Y.js} +1 -1
- package/dist-cli-web/assets/index-BepItDCQ.js +64 -0
- package/dist-cli-web/assets/{index-4DVZ2g0M.js → index-BmGA3geF.js} +1 -1
- package/dist-cli-web/assets/{index-BvMAw3Zd.js → index-C-u3l4Uh.js} +1 -1
- package/dist-cli-web/assets/{index-D8cHMqV-.js → index-CN9WMxb3.js} +2 -2
- package/dist-cli-web/assets/{index-BFH1j_R9.js → index-Chh0gCp7.js} +1 -1
- package/dist-cli-web/assets/index-DRFMz0cs.css +1 -0
- package/dist-cli-web/assets/{index-BgelKQTW.css → index-DbP9vQhR.css} +1 -1
- package/dist-cli-web/assets/index-DgCXdbsG.js +2 -0
- package/dist-cli-web/assets/{index-CuCQ1d9f.js → index-DhRaZS6z.js} +1 -1
- package/dist-cli-web/assets/{index-_m1mf1jm.js → index-Dz4yfeg6.js} +1 -1
- package/dist-cli-web/assets/{index-mbLXPIyC.js → index-EtteazuD.js} +1 -1
- package/dist-cli-web/assets/index-GNMlsoVH.js +137 -0
- package/dist-cli-web/assets/{index-B1oj9KDv.js → index-bQ9oj54q.js} +4 -4
- package/dist-cli-web/assets/{index-DlHuILT_.js → index-fsLAooCi.js} +1 -1
- package/dist-cli-web/assets/{people-page-header-BbYSSpsO.js → people-page-header-CKXRSnpl.js} +1 -1
- package/dist-cli-web/assets/{prompt-C-ofJ7t_.js → prompt-DNxAd1Bj.js} +1 -1
- package/dist-cli-web/assets/{semantic-index-config-builder-D3TYVYC-.js → semantic-index-config-builder-CQ27G4TK.js} +1 -1
- package/dist-cli-web/assets/{service-CppETV4a.js → service-BwbGKwDn.js} +1 -1
- package/dist-cli-web/assets/service-DQjyjQZx.js +1 -0
- package/dist-cli-web/assets/service-Dtve_40X.js +1 -0
- package/dist-cli-web/assets/useFormControl-CNmp_2bd.js +1 -0
- package/dist-cli-web/assets/{ActionToolsPanel.vue_vue_type_script_setup_true_lang-IB1yZxCE.js → useInsightTabAnalytics-DaU_ADbQ.js} +8 -8
- package/dist-cli-web/assets/{useTable-Clk7ecq-.js → useTable-BYXxnZMd.js} +1 -1
- package/dist-cli-web/assets/{useToast-B5LaA6c-.js → useToast-DPkgv34s.js} +1 -1
- package/dist-cli-web/assets/{webworkerAll-CyA4b4LT.js → webworkerAll-Um4PrCaA.js} +1 -1
- package/dist-cli-web/index.html +1 -1
- package/package.json +1 -1
- package/dist/chat-command-YAFRLHMQ.mjs.map +0 -1
- package/dist/chunk-73TJ2S7W.mjs.map +0 -1
- package/dist/chunk-ARIBCH47.mjs.map +0 -1
- package/dist/chunk-JWJREWVN.mjs.map +0 -1
- package/dist/chunk-OTYNMDDL.mjs.map +0 -1
- package/dist/chunk-UP6JIV3S.mjs.map +0 -1
- package/dist/mcp-SMF3NWIN.mjs.map +0 -1
- package/dist-cli-web/assets/SectionTabs.vue_vue_type_script_setup_true_lang-qFhJO5B0.js +0 -1
- package/dist-cli-web/assets/aiChat--CR4g2M7.js +0 -8
- package/dist-cli-web/assets/index-CIIyg_o9.css +0 -1
- package/dist-cli-web/assets/index-CaYtkONV.js +0 -64
- package/dist-cli-web/assets/index-D3Hyjv4e.js +0 -137
- package/dist-cli-web/assets/index-R4LqAnx9.js +0 -2
- package/dist-cli-web/assets/service-BYOUkk7V.js +0 -1
- package/dist-cli-web/assets/service-tEx-5LUL.js +0 -1
- package/dist-cli-web/assets/useFormControl-CrWi_6Hn.js +0 -1
- /package/dist/{chunk-FPVRSXQ4.mjs.map → chunk-4FAEB4C2.mjs.map} +0 -0
- /package/dist/{chunk-MMTEGUQA.mjs.map → chunk-5OA4QI3Q.mjs.map} +0 -0
- /package/dist/{chunk-PDQV4RUA.mjs.map → chunk-GDKQKHJT.mjs.map} +0 -0
- /package/dist/{chunk-GKCIRKOH.mjs.map → chunk-HJWBFHNR.mjs.map} +0 -0
- /package/dist/{chunk-2PY4XCH3.mjs.map → chunk-IMJVOODY.mjs.map} +0 -0
- /package/dist/{chunk-WDLO7OLX.mjs.map → chunk-O57SQSCO.mjs.map} +0 -0
- /package/dist/{chunk-N4SB6QZV.mjs.map → chunk-ZGXXAPLX.mjs.map} +0 -0
- /package/dist/{http-LPFPVTBC.mjs.map → http-QJDZKDNJ.mjs.map} +0 -0
- /package/dist/{import-T4WX2ZJL.mjs.map → import-XK6YM26A.mjs.map} +0 -0
- /package/dist/{src-EGLLMTAU.mjs.map → src-4AHJUFCW.mjs.map} +0 -0
- /package/dist/{stream-import-2BXJTTCE.mjs.map → stream-import-7VQVT5ST.mjs.map} +0 -0
- /package/dist/{worker-runtime-RDLSPXFT.mjs.map → worker-runtime-PQBAV75N.mjs.map} +0 -0
- /package/dist-cli-web/assets/{ActionToolsPanel-DDNXXH8v.css → useInsightTabAnalytics-DDNXXH8v.css} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../packages/tools/src/utils/limits.ts","../../../packages/tools/src/definitions/sql-query.ts","../../../packages/tools/src/definitions/render-chart.ts","../../../packages/tools/src/definitions/session-info.ts","../../../packages/tools/src/definitions/sessions.ts","../../../packages/tools/src/utils/format.ts","../../../packages/tools/src/definitions/chat-overview.ts","../../../packages/tools/src/utils/time-params.ts","../../../packages/tools/src/utils/schemas.ts","../../../packages/tools/src/definitions/search-context.ts","../../../packages/tools/src/definitions/search-messages.ts","../../../packages/tools/src/definitions/deep-search-messages.ts","../../../packages/tools/src/definitions/get-message-context.ts","../../../packages/tools/src/definitions/get-segment-messages.ts","../../../packages/tools/src/definitions/get-members.ts","../../../packages/tools/src/definitions/member-stats.ts","../../../packages/tools/src/definitions/time-stats.ts","../../../packages/tools/src/definitions/recent-messages.ts","../../../packages/tools/src/definitions/get-member-name-history.ts","../../../packages/tools/src/definitions/get-conversation-between.ts","../../../packages/tools/src/definitions/get-segment-summaries.ts","../../../packages/tools/src/definitions/response-time-analysis.ts","../../../packages/tools/src/definitions/keyword-frequency.ts","../../../packages/tools/src/types.ts","../../../packages/tools/src/definitions/semantic-search-current-chat.ts","../../../packages/tools/src/definitions/retrieve-chat-evidence.ts","../../../packages/tools/src/definitions/cross-chat-tools.ts","../../../packages/tools/src/definitions/memory-tools.ts","../../../packages/tools/src/sql/definitions.ts","../../../packages/tools/src/sql/executor.ts","../../../packages/tools/src/registry.ts","../../../packages/tools/src/providers/core-data-provider.ts","../../../packages/tools/src/tool-metadata.ts","../../../packages/tools/src/agent-adapter.ts"],"sourcesContent":["export function resolveMessageLimit(requestedLimit: unknown, defaultLimit: number, maxMessagesLimit?: number): number {\n const requested =\n typeof requestedLimit === 'number' && Number.isFinite(requestedLimit) && requestedLimit > 0\n ? Math.max(1, Math.floor(requestedLimit))\n : defaultLimit\n return maxMessagesLimit && maxMessagesLimit > 0 ? Math.min(requested, maxMessagesLimit) : requested\n}\n","/**\n * SQL 查询工具\n *\n * 对聊天数据库执行只读 SQL 查询。\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { resolveMessageLimit } from '../utils/limits'\n\ninterface SqlResultLike {\n rows?: unknown[]\n rowCount?: number\n truncated?: boolean\n}\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n sql: {\n type: 'string',\n description: '要执行的 SELECT SQL 查询语句。建议显式添加 LIMIT,工具输出仍会被 max_rows 截断。',\n },\n max_rows: {\n type: 'number',\n description: '最多返回多少行,默认 1000;还会受调用上下文的消息上限限制。',\n },\n },\n required: ['sql'],\n}\n\nfunction clampSqlResultRows(result: unknown, maxRows: number): unknown {\n // provider 理论上会截断;这里做二次保护,防止外部适配层返回过大结果污染上下文。\n if (!result || typeof result !== 'object' || maxRows <= 0) return result\n\n const resultLike = result as SqlResultLike\n if (!Array.isArray(resultLike.rows) || resultLike.rows.length <= maxRows) return result\n\n return {\n ...resultLike,\n rows: resultLike.rows.slice(0, maxRows),\n rowCount: maxRows,\n truncated: true,\n }\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const sql = params.sql as string\n const maxRows = resolveMessageLimit(params.max_rows, 1000, context.maxMessagesLimit)\n\n try {\n const result = clampSqlResultRows(await context.dataProvider!.executeSql(sql, { maxRows }), maxRows)\n return {\n content: JSON.stringify(result),\n data: result,\n }\n } catch (err) {\n return {\n content: JSON.stringify({ error: err instanceof Error ? err.message : String(err) }),\n }\n }\n}\n\nconst schemaInputSchema: JsonSchema = {\n type: 'object',\n properties: {},\n}\n\nasync function schemaHandler(_params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const schema = await context.dataProvider!.getSchema()\n return {\n content: JSON.stringify({ tables: schema }),\n data: schema,\n }\n}\n\nexport const sqlQueryTool: ToolDefinition = {\n name: 'execute_sql',\n description:\n '对聊天数据库执行只读 SELECT 查询。使用前可先调用 get_schema 查看表结构。建议 SQL 显式添加 LIMIT;工具会按 max_rows 截断输出,避免返回过大结果集。',\n inputSchema,\n handler,\n category: 'analysis',\n}\n\nexport const schemaTool: ToolDefinition = {\n name: 'get_schema',\n description: '查看聊天数据库的表结构(所有表的 CREATE TABLE 语句)',\n inputSchema: schemaInputSchema,\n handler: schemaHandler,\n}\n","/**\n * Dynamic chart rendering tool.\n *\n * The model provides read-only SQL plus a ChartSpec. ChatLab executes and\n * validates the result before producing a chart payload for the chat UI.\n */\n\nimport { buildChartPayload } from '@openchatlab/core'\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\n\nconst DEFAULT_MAX_ROWS = 1000\nconst DEFAULT_PREVIEW_ROWS = 20\nconst RE_SECONDS_TIMESTAMP_DIVIDED_AS_MILLISECONDS = /\\b(?:\\w+\\.)?ts\\s*\\/\\s*1000\\b/i\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n rows: {\n type: 'array',\n description:\n 'Pre-fetched data rows to render directly, skipping SQL execution. Pass the data array from a high-level tool result (e.g. the `data` field from get_time_stats, or member activity rows). Prefer this over sql when data is already available. Mutually exclusive with sql.',\n items: { type: 'object' },\n },\n sql: {\n type: 'string',\n description:\n 'Read-only SELECT or WITH SELECT SQL used to produce chart rows. Use only when pre-fetched data is unavailable or custom aggregation is required.',\n },\n params: {\n type: 'object',\n description: 'Named SQL parameters. Only used when sql is provided.',\n additionalProperties: true,\n default: {},\n },\n chartSpec: {\n type: 'object',\n description:\n 'ChartSpec v1. Required fields: version, type, title, encoding. Supported types: bar, line, pie, heatmap.',\n additionalProperties: true,\n },\n maxRows: {\n type: 'number',\n description: 'Maximum rows to fetch before chart normalization.',\n default: DEFAULT_MAX_ROWS,\n minimum: 1,\n maximum: 5000,\n },\n },\n required: ['chartSpec'],\n}\n\nfunction normalizeSql(sql: unknown, maxRows: number): string {\n if (typeof sql !== 'string' || sql.trim().length === 0) {\n throw new Error('sql must be a non-empty string')\n }\n\n const trimmed = sql.trim().replace(/;+\\s*$/, '')\n if (trimmed.includes(';')) {\n throw new Error('Only a single read-only SQL statement is allowed')\n }\n\n const statementStart = trimmed.replace(/^(\\s|--[^\\n]*(\\n|$)|\\/\\*[\\s\\S]*?\\*\\/)*/, '')\n if (!/^(SELECT|WITH)\\b/i.test(statementStart)) {\n throw new Error('render_chart only accepts SELECT or WITH SELECT SQL')\n }\n\n if (RE_SECONDS_TIMESTAMP_DIVIDED_AS_MILLISECONDS.test(trimmed)) {\n throw new Error('message.ts is already a Unix timestamp in seconds; do not divide ts by 1000')\n }\n\n return `SELECT * FROM (\\n${trimmed}\\n) AS chart_query LIMIT ${maxRows + 1}`\n}\n\nfunction normalizeParams(raw: unknown): Record<string, unknown> {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return {}\n return raw as Record<string, unknown>\n}\n\nfunction normalizeRows(raw: unknown, maxRows: number): { rows: Record<string, unknown>[]; truncated: boolean } {\n if (!Array.isArray(raw)) throw new Error('rows must be an array')\n const items = raw.filter(\n (item): item is Record<string, unknown> => typeof item === 'object' && item !== null && !Array.isArray(item)\n )\n const truncated = items.length > maxRows\n return { rows: truncated ? items.slice(0, maxRows) : items, truncated }\n}\n\nfunction normalizeMaxRows(raw: unknown): number {\n const value = typeof raw === 'number' ? raw : DEFAULT_MAX_ROWS\n if (!Number.isFinite(value)) return DEFAULT_MAX_ROWS\n return Math.min(5000, Math.max(1, Math.floor(value)))\n}\n\nfunction summarizeChart(type: string, title: string, rowCount: number, truncated: boolean, locale?: string): string {\n if (locale?.startsWith('zh')) {\n return `已生成图表「${title}」(${type},${rowCount} 行数据${truncated ? ',已截断' : ''})。`\n }\n return `Generated chart \"${title}\" (${type}, ${rowCount} rows${truncated ? ', truncated' : ''}).`\n}\n\nfunction summarizeChartForModel(\n type: string,\n title: string,\n rows: Record<string, unknown>[],\n truncated: boolean,\n locale?: string\n): string {\n const summary = summarizeChart(type, title, rows.length, truncated, locale)\n const previewRows = rows.slice(0, DEFAULT_PREVIEW_ROWS)\n const coverage = locale?.startsWith('zh')\n ? `图表已使用${truncated ? '截断后的' : '全部'} ${rows.length} 行数据生成;下面只是数据预览,不要为了查看预览外的行重复调用 render_chart。`\n : `The chart already uses ${truncated ? 'the truncated' : 'all'} ${rows.length} rows; the rows below are only a preview. Do not call render_chart again just to inspect rows outside the preview.`\n if (previewRows.length === 0) return `${summary}\\n${coverage}`\n\n const preview = JSON.stringify(previewRows)\n if (locale?.startsWith('zh')) {\n return `${summary}\\n${coverage}\\n数据预览(前 ${previewRows.length} 行,用于分析峰值、低谷和差异):${preview}`\n }\n return `${summary}\\n${coverage}\\nData preview (first ${previewRows.length} rows; use this to identify peaks, lows, and differences): ${preview}`\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n if (!context.dataProvider) throw new Error('render_chart requires a data provider')\n\n const hasSql = typeof params.sql === 'string' && params.sql.trim().length > 0\n const hasRows = Array.isArray(params.rows)\n if (!hasSql && !hasRows) throw new Error('render_chart requires either sql or rows')\n\n const maxRows = normalizeMaxRows(params.maxRows)\n let rows: Record<string, unknown>[]\n let truncated: boolean\n\n if (hasRows) {\n const normalized = normalizeRows(params.rows, maxRows)\n rows = normalized.rows\n truncated = normalized.truncated\n } else {\n const sql = normalizeSql(params.sql, maxRows)\n const sqlParams = normalizeParams(params.params)\n const fetchedRows = await context.dataProvider.executeParameterizedSql<Record<string, unknown>>(sql, sqlParams)\n truncated = fetchedRows.length > maxRows\n rows = truncated ? fetchedRows.slice(0, maxRows) : fetchedRows\n }\n\n const chart = buildChartPayload(rows, params.chartSpec, { truncated })\n\n return {\n content: summarizeChartForModel(chart.spec.type, chart.spec.title, rows, truncated, context.locale),\n data: {\n rowCount: rows.length,\n truncated,\n chartType: chart.spec.type,\n title: chart.spec.title,\n },\n chart,\n }\n}\n\nexport const renderChartTool: ToolDefinition = {\n name: 'render_chart',\n description:\n \"Generate a native ChatLab chart from ChartSpec v1. Provide either `rows` (pre-fetched data array from a tool result such as get_time_stats or member_stats) or `sql` (read-only SELECT). Prefer `rows` when data is already available — pass the tool's data array directly. Use `sql` only for custom aggregations not covered by existing tools. Never output HTML, JavaScript, SVG, ECharts options, or rendering code.\",\n inputSchema,\n handler,\n category: 'analysis',\n executionMode: 'sequential',\n}\n","/**\n * 会话信息工具\n *\n * 获取指定会话的详细信息(概览统计)。\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { getSessionMeta, getSessionOverview, getMembers } from '@openchatlab/core'\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n include_members: {\n type: 'boolean',\n description: '是否包含成员列表(默认 false)',\n default: false,\n },\n },\n}\n\nfunction handler(params: Record<string, unknown>, context: ToolExecutionContext): ToolResult {\n const db = context.db!\n const meta = getSessionMeta(db)\n const overview = getSessionOverview(db)\n const includeMembers = params.include_members as boolean\n\n const data: Record<string, unknown> = { ...meta, ...overview }\n\n if (includeMembers) {\n data.members = getMembers(db)\n }\n\n return {\n content: JSON.stringify(data),\n data,\n }\n}\n\nexport const sessionInfoTool: ToolDefinition = {\n name: 'get_session_info',\n description: '获取当前会话的详细信息,包括名称、平台、消息总数、成员数、时间范围等',\n inputSchema,\n handler,\n}\n","/**\n * 会话列表工具\n *\n * MCP 场景下列出所有可用的聊天会话。\n * 这是 MCP 场景下的完整聊天记录发现工具,不是 segment 搜索工具。\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { getSessionMeta, getSessionOverview } from '@openchatlab/core'\nimport type { DatabaseAdapter } from '@openchatlab/core'\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n keyword: {\n type: 'string',\n description: '按名称筛选会话(可选)',\n },\n },\n}\n\nexport interface SessionListContext extends ToolExecutionContext {\n listSessionIds: () => string[]\n openDb: (sessionId: string) => DatabaseAdapter | null\n}\n\nfunction handler(_params: Record<string, unknown>, context: SessionListContext): ToolResult {\n const keyword = (_params.keyword as string | undefined)?.toLowerCase()\n const sessionIds = context.listSessionIds()\n\n const sessions = sessionIds\n .map((id) => {\n const db = context.openDb(id)\n if (!db) return null\n const meta = getSessionMeta(db)\n if (!meta) return null\n if (keyword && !meta.name.toLowerCase().includes(keyword)) return null\n const overview = getSessionOverview(db)\n return { id, ...meta, ...overview }\n })\n .filter(Boolean)\n\n return {\n content: JSON.stringify({ total: sessions.length, sessions }),\n data: sessions,\n }\n}\n\nexport const sessionsListTool: ToolDefinition = {\n name: 'list_sessions',\n description: '列出所有可用的聊天会话,返回会话名称、平台、消息数等基本信息',\n inputSchema,\n handler: handler as ToolDefinition['handler'],\n}\n","/**\n * 工具结果格式化 & i18n 辅助(平台无关)\n *\n * 从 @openchatlab/node-runtime 复制核心子集,避免引入 node-runtime 重依赖。\n */\n\nexport function isChineseLocale(locale?: string): boolean {\n return locale?.startsWith('zh') ?? false\n}\n\nexport const i18nTexts = {\n allTime: { zh: '全部时间', en: 'All time' },\n noContent: { zh: '[无内容]', en: '[No content]' },\n memberNotFound: { zh: '未找到该成员', en: 'Member not found' },\n untilNow: { zh: '至今', en: 'Present' },\n noChangeRecord: { zh: '无变更记录', en: 'No change record' },\n noConversation: { zh: '未找到这两人之间的对话', en: 'No conversation found between these two members' },\n noMessageContext: { zh: '未找到指定的消息或上下文', en: 'Message or context not found' },\n messages: { zh: '条', en: '' },\n alias: { zh: '别名', en: 'Alias' },\n}\n\ntype TextEntryKey = keyof typeof i18nTexts\n\nexport function t(key: TextEntryKey, locale?: string): string {\n const text = i18nTexts[key]\n if (typeof text === 'object' && 'zh' in text && 'en' in text) {\n return isChineseLocale(locale) ? text.zh : text.en\n }\n return ''\n}\n\nexport function formatTimeRange(\n timeFilter?: { startTs: number; endTs: number },\n locale?: string\n): string | { start: string; end: string } {\n if (!timeFilter) return t('allTime', locale)\n const localeStr = isChineseLocale(locale) ? 'zh-CN' : 'en-US'\n return {\n start: new Date(timeFilter.startTs * 1000).toLocaleString(localeStr),\n end: new Date(timeFilter.endTs * 1000).toLocaleString(localeStr),\n }\n}\n\nexport function formatMessageCompact(\n msg: {\n id?: number\n senderName: string\n content: string | null\n timestamp: number\n },\n locale?: string\n): string {\n const localeStr = isChineseLocale(locale) ? 'zh-CN' : 'en-US'\n const time = new Date(msg.timestamp * 1000).toLocaleString(localeStr)\n let content = msg.content || t('noContent', locale)\n if (content.length > 200) {\n content = content.slice(0, 200) + '...'\n }\n return `${time} ${msg.senderName}: ${content}`\n}\n","/**\n * 聊天概览工具\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { isChineseLocale } from '../utils/format'\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n top_n: { type: 'number', description: '返回活跃度最高的前 N 个成员,默认 10' },\n },\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const { locale } = context\n const topN = (params.top_n as number) || 10\n\n const result = await context.dataProvider!.getChatOverview(topN)\n if (!result) {\n const msg = isChineseLocale(locale) ? '无法获取聊天概览' : 'Unable to get chat overview'\n return { content: msg, data: { error: msg } }\n }\n\n const msgSuffix = isChineseLocale(locale) ? '条' : ''\n const lines: string[] = [\n `name: ${result.name}`,\n `platform: ${result.platform}`,\n `type: ${result.type}`,\n `totalMessages: ${result.totalMessages}`,\n `totalMembers: ${result.totalMembers}`,\n ]\n\n if (result.firstMessageTs != null && result.lastMessageTs != null) {\n const start = new Date(result.firstMessageTs * 1000).toLocaleDateString()\n const end = new Date(result.lastMessageTs * 1000).toLocaleDateString()\n lines.push(`timeRange: ${start} ~ ${end}`)\n }\n\n if (result.topMembers.length > 0) {\n lines.push(`topMembers:`)\n for (let i = 0; i < result.topMembers.length; i++) {\n const m = result.topMembers[i]\n const pct = result.totalMessages > 0 ? ((m.count / result.totalMessages) * 100).toFixed(1) : '0'\n lines.push(`${i + 1}. ${m.name} ${m.count}${msgSuffix}(${pct}%)`)\n }\n }\n\n return { content: lines.join('\\n'), data: result }\n}\n\nexport const chatOverviewTool: ToolDefinition = {\n name: 'get_chat_overview',\n description: '获取聊天概览信息,包括聊天名称、平台、总消息数、总成员数、时间范围和活跃成员排行',\n inputSchema,\n handler,\n category: 'core',\n}\n","/**\n * 时间参数解析工具\n *\n * 从 Electron 工具提取的共享实用函数,处理 start_time/end_time 字符串参数。\n */\n\nimport type { ToolTimeRange } from '../types'\n\nexport interface ExtendedTimeParams {\n start_time?: string\n end_time?: string\n}\n\n/**\n * 解析时间参数,返回时间过滤器\n * 优先级: start_time/end_time > contextToolTimeRange\n */\nexport function parseExtendedTimeParams(\n params: ExtendedTimeParams,\n contextToolTimeRange?: ToolTimeRange\n): ToolTimeRange | undefined {\n if (params.start_time || params.end_time) {\n let startTs: number | undefined\n let endTs: number | undefined\n\n if (params.start_time) {\n const startDate = new Date(params.start_time.replace(' ', 'T'))\n if (!isNaN(startDate.getTime())) {\n startTs = Math.floor(startDate.getTime() / 1000)\n }\n }\n\n if (params.end_time) {\n const endDate = new Date(params.end_time.replace(' ', 'T'))\n if (!isNaN(endDate.getTime())) {\n endTs = Math.floor(endDate.getTime() / 1000)\n }\n }\n\n if (startTs !== undefined || endTs !== undefined) {\n return {\n startTs: startTs ?? 0,\n endTs: endTs ?? Math.floor(Date.now() / 1000),\n }\n }\n }\n\n return contextToolTimeRange\n}\n","/**\n * 共享 JSON Schema 片段\n */\n\nexport const timeParamProperties = {\n start_time: {\n type: 'string' as const,\n description: '起始时间, 格式: YYYY-MM-DD HH:mm',\n },\n end_time: {\n type: 'string' as const,\n description: '结束时间, 格式: YYYY-MM-DD HH:mm',\n },\n}\n","import type { RawMessage } from '../types'\n\nexport function requireSearchKeywords(value: unknown): string[] {\n const keywords = Array.isArray(value)\n ? value.filter((keyword): keyword is string => typeof keyword === 'string').map((keyword) => keyword.trim())\n : []\n const nonEmptyKeywords = keywords.filter(Boolean)\n if (nonEmptyKeywords.length === 0) throw new Error('At least one non-empty keyword is required')\n return nonEmptyKeywords\n}\n\nexport function trimMessagesPreservingHits(messages: RawMessage[], hitIds: number[], limit: number): RawMessage[] {\n if (limit <= 0) return []\n if (messages.length <= limit) return messages\n\n const requiredIds = new Set(hitIds)\n if (requiredIds.size === 0) return messages.slice(0, limit)\n\n const trimmed = messages.slice(0, limit)\n const presentIds = new Set(trimmed.map((message) => message.id).filter((id): id is number => id != null))\n const missingHits = messages.filter(\n (message) => message.id != null && requiredIds.has(message.id) && !presentIds.has(message.id)\n )\n\n for (const hit of missingHits) {\n let replaceIndex = -1\n for (let i = trimmed.length - 1; i >= 0; i--) {\n const id = trimmed[i].id\n if (id == null || !requiredIds.has(id)) {\n replaceIndex = i\n break\n }\n }\n if (replaceIndex === -1) break\n trimmed[replaceIndex] = hit\n }\n\n return trimmed.sort((a, b) => messages.indexOf(a) - messages.indexOf(b))\n}\n","/**\n * 关键词搜索消息工具\n *\n * 支持多关键词、发送者过滤、时间范围、上下文扩展。\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { parseExtendedTimeParams } from '../utils/time-params'\nimport { formatTimeRange } from '../utils/format'\nimport { timeParamProperties } from '../utils/schemas'\nimport { resolveMessageLimit } from '../utils/limits'\nimport { requireSearchKeywords, trimMessagesPreservingHits } from './search-context'\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n keywords: { type: 'array', items: { type: 'string' }, description: '搜索关键词列表' },\n sender_id: { type: 'number', description: '按发送者 ID 过滤(通过 get_members 获取)' },\n limit: { type: 'number', description: '返回的最大消息条数' },\n ...timeParamProperties,\n },\n required: ['keywords'],\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const { locale, timeFilter: contextTimeFilter, maxMessagesLimit } = context\n const keywords = requireSearchKeywords(params.keywords)\n const limit = Math.min(resolveMessageLimit(params.limit, 1000, maxMessagesLimit), 50000)\n const effectiveTimeFilter = parseExtendedTimeParams(params as any, contextTimeFilter)\n\n const result = await context.dataProvider!.searchMessages(keywords, {\n timeFilter: effectiveTimeFilter,\n limit,\n senderId: params.sender_id as number | undefined,\n })\n\n const contextBefore = context.searchContextBefore ?? 2\n const contextAfter = context.searchContextAfter ?? 2\n let finalMessages = result.messages\n const hitIds = result.messages.map((m) => m.id).filter((id): id is number => id != null)\n\n if ((contextBefore > 0 || contextAfter > 0) && result.messages.length > 0) {\n if (hitIds.length > 0) {\n finalMessages = await context.dataProvider!.getSearchMessageContext(hitIds, contextBefore, contextAfter)\n }\n }\n finalMessages = trimMessagesPreservingHits(finalMessages, hitIds, limit)\n\n const data = {\n total: result.total,\n returned: finalMessages.length,\n timeRange: formatTimeRange(effectiveTimeFilter, locale),\n rawMessages: finalMessages,\n }\n\n return { content: JSON.stringify(data), data, rawMessages: finalMessages }\n}\n\nexport const searchMessagesTool: ToolDefinition = {\n name: 'search_messages',\n description:\n '根据关键词搜索群聊记录。适用于用户想要查找特定话题、关键词相关的聊天内容。可以指定时间范围和发送者来筛选消息。',\n inputSchema,\n handler,\n category: 'core',\n truncationStrategy: 'keep_first',\n}\n","/**\n * 深度搜索消息工具\n *\n * LIKE 子串匹配,速度较慢但不会遗漏。与 search-messages 结构相同,底层使用不同搜索策略。\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { parseExtendedTimeParams } from '../utils/time-params'\nimport { formatTimeRange } from '../utils/format'\nimport { timeParamProperties } from '../utils/schemas'\nimport { resolveMessageLimit } from '../utils/limits'\nimport { requireSearchKeywords, trimMessagesPreservingHits } from './search-context'\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n keywords: { type: 'array', items: { type: 'string' }, description: '搜索关键词列表' },\n sender_id: { type: 'number', description: '按发送者 ID 过滤(通过 get_members 获取)' },\n limit: { type: 'number', description: '返回的最大消息条数' },\n ...timeParamProperties,\n },\n required: ['keywords'],\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const { locale, timeFilter: contextTimeFilter, maxMessagesLimit } = context\n const keywords = requireSearchKeywords(params.keywords)\n const limit = Math.min(resolveMessageLimit(params.limit, 1000, maxMessagesLimit), 50000)\n const effectiveTimeFilter = parseExtendedTimeParams(params as any, contextTimeFilter)\n\n const result = await context.dataProvider!.deepSearchMessages(keywords, {\n timeFilter: effectiveTimeFilter,\n limit,\n senderId: params.sender_id as number | undefined,\n })\n\n const contextBefore = context.searchContextBefore ?? 2\n const contextAfter = context.searchContextAfter ?? 2\n let finalMessages = result.messages\n const hitIds = result.messages.map((m) => m.id).filter((id): id is number => id != null)\n\n if ((contextBefore > 0 || contextAfter > 0) && result.messages.length > 0) {\n if (hitIds.length > 0) {\n finalMessages = await context.dataProvider!.getSearchMessageContext(hitIds, contextBefore, contextAfter)\n }\n }\n finalMessages = trimMessagesPreservingHits(finalMessages, hitIds, limit)\n\n const data = {\n total: result.total,\n returned: finalMessages.length,\n timeRange: formatTimeRange(effectiveTimeFilter, locale),\n rawMessages: finalMessages,\n }\n\n return { content: JSON.stringify(data), data, rawMessages: finalMessages }\n}\n\nexport const deepSearchMessagesTool: ToolDefinition = {\n name: 'deep_search_messages',\n description: '深度搜索消息(LIKE 子串匹配),适用于需要精确文本片段匹配的场景。',\n inputSchema,\n handler,\n category: 'core',\n truncationStrategy: 'keep_first',\n}\n","/**\n * 消息上下文工具\n *\n * 根据消息 ID 获取前后的上下文消息。\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { t } from '../utils/format'\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n message_ids: { type: 'array', items: { type: 'number' }, description: '消息 ID 列表' },\n context_size: { type: 'number', description: '每条消息前后获取的上下文条数,默认 20' },\n },\n required: ['message_ids'],\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const { locale } = context\n const maxMessagesLimit = context.maxMessagesLimit\n const requestedMessageIds = params.message_ids as number[]\n const messageIds =\n maxMessagesLimit && maxMessagesLimit > 0 ? requestedMessageIds.slice(0, maxMessagesLimit) : requestedMessageIds\n const requestedContextSize = params.context_size\n let contextSize =\n typeof requestedContextSize === 'number' && Number.isFinite(requestedContextSize)\n ? Math.max(0, Math.floor(requestedContextSize))\n : 20\n\n if (maxMessagesLimit && maxMessagesLimit > 0 && messageIds.length > 0) {\n const maxMessagesPerId = Math.max(1, Math.floor(maxMessagesLimit / messageIds.length))\n const maxContextSize = Math.max(0, Math.floor((maxMessagesPerId - 1) / 2))\n contextSize = Math.min(contextSize, maxContextSize)\n }\n\n const messages = await context.dataProvider!.getMessageContext(messageIds, contextSize)\n\n if (messages.length === 0) {\n const data = {\n error: t('noMessageContext', locale),\n messageIds,\n }\n return { content: JSON.stringify(data), data }\n }\n\n const data = {\n totalMessages: messages.length,\n contextSize,\n requestedMessageIds: messageIds,\n rawMessages: messages,\n }\n\n return { content: JSON.stringify(data), data, rawMessages: messages }\n}\n\nexport const getMessageContextTool: ToolDefinition = {\n name: 'get_message_context',\n description: '根据消息 ID 获取前后的上下文消息。适用于需要查看某条消息前后聊天内容的场景。',\n inputSchema,\n handler,\n category: 'core',\n truncationStrategy: 'keep_last',\n}\n","/**\n * 获取段落完整消息工具\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { isChineseLocale } from '../utils/format'\nimport { resolveMessageLimit } from '../utils/limits'\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n segment_id: { type: 'number', description: '段落 ID(通过 get_segment_summaries 获取)' },\n limit: { type: 'number', description: '返回的最大消息条数' },\n },\n required: ['segment_id'],\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const { locale, maxMessagesLimit } = context\n const limit = resolveMessageLimit(params.limit, 1000, maxMessagesLimit)\n\n const result = await context.dataProvider!.getSegmentMessages(params.segment_id as number, limit)\n\n if (!result) {\n const data = {\n error: isChineseLocale(locale) ? '未找到指定的段落' : 'Segment not found',\n segmentId: params.segment_id,\n }\n return { content: JSON.stringify(data), data }\n }\n\n const localeStr = isChineseLocale(locale) ? 'zh-CN' : 'en-US'\n const startTime = new Date(result.startTs * 1000).toLocaleString(localeStr)\n const endTime = new Date(result.endTs * 1000).toLocaleString(localeStr)\n const rawMessages = result.messages.map((m) => ({\n id: m.id,\n senderName: m.senderName,\n content: m.content,\n timestamp: m.timestamp,\n }))\n\n const data = {\n segmentId: result.segmentId,\n time: `${startTime} ~ ${endTime}`,\n messageCount: result.messageCount,\n returnedCount: result.returnedCount,\n participants: result.participants,\n rawMessages,\n }\n\n return { content: JSON.stringify(data), data, rawMessages }\n}\n\nexport const getSegmentMessagesTool: ToolDefinition = {\n name: 'get_segment_messages',\n description:\n '获取指定段落的完整消息列表。用于在 get_segment_summaries 找到相关段落摘要后,获取该段落的完整原文上下文。',\n inputSchema,\n handler,\n category: 'core',\n truncationStrategy: 'keep_last',\n}\n","/**\n * 获取成员列表工具\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { isChineseLocale, t } from '../utils/format'\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n search: { type: 'string', description: '按名称/别名/平台ID搜索过滤' },\n limit: { type: 'number', description: '最大返回数量' },\n },\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const { locale } = context\n const members = await context.dataProvider!.getMembers()\n\n let filteredMembers = members\n if (params.search) {\n const keyword = (params.search as string).toLowerCase()\n filteredMembers = members.filter((m) => {\n if (m.groupNickname && m.groupNickname.toLowerCase().includes(keyword)) return true\n if (m.accountName && m.accountName.toLowerCase().includes(keyword)) return true\n if (m.platformId.includes(keyword)) return true\n if (m.aliases.some((alias) => alias.toLowerCase().includes(keyword))) return true\n return false\n })\n }\n\n if (params.limit && (params.limit as number) > 0) {\n filteredMembers = filteredMembers.slice(0, params.limit as number)\n }\n\n const msgSuffix = isChineseLocale(locale) ? '条' : ''\n const aliasLabel = t('alias', locale)\n const data = {\n totalMembers: members.length,\n returnedMembers: filteredMembers.length,\n members: filteredMembers.map((m) => {\n const displayName = m.groupNickname || m.accountName || m.platformId\n const aliasStr = m.aliases.length > 0 ? `|${aliasLabel}:${m.aliases.join(',')}` : ''\n return `${m.id}|${m.platformId}|${displayName}|${m.messageCount}${msgSuffix}${aliasStr}`\n }),\n }\n\n return { content: JSON.stringify(data), data }\n}\n\nexport const getMembersTool: ToolDefinition = {\n name: 'get_members',\n description: '获取成员列表,包括成员的基本信息、别名和消息统计。适用于查询\"有哪些人\"、\"某人的别名是什么\"等问题。',\n inputSchema,\n handler,\n category: 'core',\n}\n","/**\n * 成员统计工具\n *\n * 获取成员活跃度排行和统计信息。\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n top: {\n type: 'number',\n description: '返回前 N 个活跃成员',\n default: 20,\n },\n },\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const top = (params.top as number) || 20\n const members = await context.dataProvider!.getMemberStats({ timeFilter: context.timeFilter, top })\n\n const data = {\n total: members.length,\n members: members.map((m) => ({\n name: m.name,\n messageCount: m.messageCount,\n percentage: m.percentage,\n })),\n }\n\n return {\n content: JSON.stringify(data),\n data,\n }\n}\n\nexport const memberStatsTool: ToolDefinition = {\n name: 'get_member_stats',\n description: '获取成员活跃度排行,包括消息数量和占比',\n inputSchema,\n handler,\n category: 'analysis',\n}\n","/**\n * 时间统计工具\n *\n * 获取聊天活跃时段分布(小时、星期、每日、每月趋势)。\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { parseExtendedTimeParams } from '../utils/time-params'\nimport { timeParamProperties } from '../utils/schemas'\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n type: {\n type: 'string',\n description: '统计类型:hourly(按小时)、weekday(按星期)、daily(按天)、monthly(按月)',\n enum: ['hourly', 'weekday', 'daily', 'monthly'],\n default: 'hourly',\n },\n ...timeParamProperties,\n },\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const type = (params.type as 'hourly' | 'weekday' | 'daily' | 'monthly') || 'hourly'\n const effectiveTimeFilter = parseExtendedTimeParams(params as any, context.timeFilter)\n const data = await context.dataProvider!.getTimeStats(type, { timeFilter: effectiveTimeFilter })\n\n return {\n content: JSON.stringify({ type, data }),\n data,\n }\n}\n\nexport const timeStatsTool: ToolDefinition = {\n name: 'get_time_stats',\n description: '获取聊天活跃时段分布(按小时/星期/每日/每月趋势)',\n inputSchema,\n handler,\n category: 'analysis',\n}\n","/**\n * 最近消息工具\n *\n * 获取指定时间段内的群聊消息,支持 start_time/end_time 参数。\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { parseExtendedTimeParams } from '../utils/time-params'\nimport { formatTimeRange } from '../utils/format'\nimport { timeParamProperties } from '../utils/schemas'\nimport { resolveMessageLimit } from '../utils/limits'\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n limit: {\n type: 'number',\n description: '返回的消息条数',\n default: 100,\n },\n ...timeParamProperties,\n },\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const { locale, timeFilter: contextTimeFilter, maxMessagesLimit } = context\n const limit = resolveMessageLimit(params.limit, 100, maxMessagesLimit)\n const effectiveTimeFilter = parseExtendedTimeParams(params as any, contextTimeFilter)\n\n const result = await context.dataProvider!.getRecentMessages({ timeFilter: effectiveTimeFilter, limit })\n\n const data = {\n total: result.total,\n returned: result.messages.length,\n timeRange: formatTimeRange(effectiveTimeFilter, locale),\n rawMessages: result.messages,\n }\n\n return {\n content: JSON.stringify(data),\n data,\n rawMessages: result.messages,\n }\n}\n\nexport const recentMessagesTool: ToolDefinition = {\n name: 'get_recent_messages',\n description: '获取指定时间段内的群聊消息。适用于回答\"最近大家聊了什么\"等概览性问题。支持精确到分钟级别的时间查询。',\n inputSchema,\n handler,\n category: 'core',\n truncationStrategy: 'keep_last',\n}\n","/**\n * 获取成员昵称变更历史工具\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { isChineseLocale, t } from '../utils/format'\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n member_id: { type: 'number', description: '成员 ID(通过 get_members 获取)' },\n },\n required: ['member_id'],\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const { locale } = context\n const memberId = params.member_id as number\n\n const members = await context.dataProvider!.getMembers()\n const member = members.find((m) => m.id === memberId)\n\n if (!member) {\n const data = {\n error: t('memberNotFound', locale),\n member_id: memberId,\n }\n return { content: JSON.stringify(data), data }\n }\n\n const history = await context.dataProvider!.getMemberNameHistory(memberId)\n\n const localeStr = isChineseLocale(locale) ? 'zh-CN' : 'en-US'\n const untilNow = t('untilNow', locale)\n const formatHistory = (h: { name: string; startTs: number; endTs: number | null }) => {\n const start = new Date(h.startTs * 1000).toLocaleDateString(localeStr)\n const end = h.endTs ? new Date(h.endTs * 1000).toLocaleDateString(localeStr) : untilNow\n return `${h.name} (${start} ~ ${end})`\n }\n\n const accountNames = history.filter((h) => h.nameType === 'account_name').map(formatHistory)\n const groupNicknames = history.filter((h) => h.nameType === 'group_nickname').map(formatHistory)\n\n const displayName = member.groupNickname || member.accountName || member.platformId\n const aliasLabel = t('alias', locale)\n const aliasStr = member.aliases.length > 0 ? `|${aliasLabel}:${member.aliases.join(',')}` : ''\n const noChangeRecord = t('noChangeRecord', locale)\n\n const data = {\n member: `${member.id}|${member.platformId}|${displayName}${aliasStr}`,\n accountNameHistory: accountNames.length > 0 ? accountNames : noChangeRecord,\n groupNicknameHistory: groupNicknames.length > 0 ? groupNicknames : noChangeRecord,\n }\n\n return { content: JSON.stringify(data), data }\n}\n\nexport const getMemberNameHistoryTool: ToolDefinition = {\n name: 'get_member_name_history',\n description: '获取成员的昵称变更历史记录。适用于回答\"某人以前叫什么名字\"、\"某人的昵称变化\"等问题。',\n inputSchema,\n handler,\n category: 'analysis',\n}\n","/**\n * 两人对话查询工具\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { parseExtendedTimeParams } from '../utils/time-params'\nimport { formatTimeRange, t } from '../utils/format'\nimport { timeParamProperties } from '../utils/schemas'\nimport { resolveMessageLimit } from '../utils/limits'\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n member_id_1: { type: 'number', description: '第一个成员的 ID(通过 get_members 获取)' },\n member_id_2: { type: 'number', description: '第二个成员的 ID(通过 get_members 获取)' },\n limit: { type: 'number', description: '返回的最大消息条数' },\n ...timeParamProperties,\n },\n required: ['member_id_1', 'member_id_2'],\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const { locale, timeFilter: contextTimeFilter, maxMessagesLimit } = context\n const limit = resolveMessageLimit(params.limit, 100, maxMessagesLimit)\n const effectiveTimeFilter = parseExtendedTimeParams(params as any, contextTimeFilter)\n\n const result = await context.dataProvider!.getConversationBetween(\n params.member_id_1 as number,\n params.member_id_2 as number,\n effectiveTimeFilter,\n limit\n )\n\n if (result.messages.length === 0) {\n const data = {\n error: t('noConversation', locale),\n member1Id: params.member_id_1,\n member2Id: params.member_id_2,\n }\n return { content: JSON.stringify(data), data }\n }\n\n const data = {\n total: result.total,\n returned: result.messages.length,\n member1: result.member1Name,\n member2: result.member2Name,\n timeRange: formatTimeRange(effectiveTimeFilter, locale),\n rawMessages: result.messages,\n }\n\n return { content: JSON.stringify(data), data, rawMessages: result.messages }\n}\n\nexport const getConversationBetweenTool: ToolDefinition = {\n name: 'get_conversation_between',\n description: '获取两个群成员之间的对话记录。适用于回答\"A和B之间聊了什么\"等问题。需要先通过 get_members 获取成员 ID。',\n inputSchema,\n handler,\n category: 'analysis',\n truncationStrategy: 'keep_last',\n}\n","/**\n * 获取段落摘要列表工具\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { parseExtendedTimeParams } from '../utils/time-params'\nimport { formatTimeRange, isChineseLocale } from '../utils/format'\nimport { timeParamProperties } from '../utils/schemas'\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n keywords: { type: 'array', items: { type: 'string' }, description: '按关键词过滤摘要内容' },\n limit: { type: 'number', description: '返回的最大段落数,默认 20' },\n ...timeParamProperties,\n },\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const { locale, timeFilter: contextTimeFilter } = context\n const limit = (params.limit as number) || 20\n const effectiveTimeFilter = parseExtendedTimeParams(params as any, contextTimeFilter)\n\n const segments = await context.dataProvider!.getSegmentSummaries({\n limit: limit * 2,\n timeFilter: effectiveTimeFilter,\n })\n\n if (!segments || segments.length === 0) {\n const data = {\n message: isChineseLocale(locale)\n ? '未找到带摘要的段落。可能还没有生成摘要,请在段落时间线中点击\"批量生成\"按钮。'\n : 'No segments with summaries found. Summaries may not have been generated yet.',\n }\n return { content: JSON.stringify(data), data }\n }\n\n let filteredSegments = segments\n const keywords = params.keywords as string[] | undefined\n if (keywords && keywords.length > 0) {\n const lowerKeywords = keywords.map((k) => k.toLowerCase())\n filteredSegments = segments.filter((s) =>\n lowerKeywords.some((keyword) => s.summary?.toLowerCase().includes(keyword))\n )\n }\n\n filteredSegments = filteredSegments.filter((s) => s.summary)\n const limitedSegments = filteredSegments.slice(0, limit)\n\n const localeStr = isChineseLocale(locale) ? 'zh-CN' : 'en-US'\n\n const data = {\n total: filteredSegments.length,\n returned: limitedSegments.length,\n timeRange: formatTimeRange(effectiveTimeFilter, locale),\n segments: limitedSegments.map((s) => {\n const startTime = new Date(s.startTs * 1000).toLocaleString(localeStr)\n const endTime = new Date(s.endTs * 1000).toLocaleString(localeStr)\n return {\n segmentId: s.id,\n time: `${startTime} ~ ${endTime}`,\n messageCount: s.messageCount,\n participants: s.participants,\n summary: s.summary,\n }\n }),\n }\n\n return { content: JSON.stringify(data), data }\n}\n\nexport const getSegmentSummariesTool: ToolDefinition = {\n name: 'get_segment_summaries',\n description: '获取段落摘要列表,快速了解群聊历史讨论的主题。可以按关键词搜索讨论过的话题。',\n inputSchema,\n handler,\n category: 'analysis',\n}\n","/**\n * 响应时间分析工具\n *\n * 基于参数化 SQL + JS 聚合的启发式回复延迟统计。\n */\n\nimport { computeResponseTimeStats } from '@openchatlab/core'\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { formatTimeRange, isChineseLocale } from '../utils/format'\nimport { parseExtendedTimeParams, type ExtendedTimeParams } from '../utils/time-params'\nimport { timeParamProperties } from '../utils/schemas'\n\ninterface MsgRow {\n sender_id: number\n name: string\n ts: number\n}\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n days: {\n type: 'number',\n description: 'Recent days to analyze when no explicit or selected time range is available; defaults to 30',\n },\n top_n: { type: 'number', description: '返回前多少名,默认 10' },\n ...timeParamProperties,\n },\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const { locale } = context\n const isZh = isChineseLocale(locale)\n const days = (params.days as number) || 30\n const topN = (params.top_n as number) || 10\n\n const effectiveTimeFilter = parseExtendedTimeParams(params as ExtendedTimeParams, context.timeFilter)\n const timeCondition = effectiveTimeFilter\n ? 'msg.ts >= @startTs AND msg.ts <= @endTs'\n : \"msg.ts > unixepoch('now', '-' || @days || ' days')\"\n const sql = `\n SELECT msg.sender_id, COALESCE(m.group_nickname, m.account_name) AS name, msg.ts\n FROM message msg\n JOIN member m ON msg.sender_id = m.id\n WHERE msg.type = 0\n AND ${timeCondition}\n ORDER BY msg.ts ASC\n `\n const rows = await context.dataProvider!.executeParameterizedSql<MsgRow>(\n sql,\n effectiveTimeFilter ? { ...effectiveTimeFilter } : { days }\n )\n if (!rows || rows.length < 2) {\n const text = isZh\n ? '该时间范围内消息不足,无法分析响应时间'\n : 'Not enough messages in this time range to analyze response time'\n return { content: text, data: null }\n }\n\n const stats = computeResponseTimeStats(\n rows.map((r) => ({ senderId: r.sender_id, name: r.name, ts: r.ts })),\n topN\n )\n\n if (stats.length === 0) {\n const text = isZh ? '没有足够的响应数据进行分析' : 'Not enough response data for analysis'\n return { content: text, data: null }\n }\n\n const formatTime = (s: number) => {\n if (s < 60) return isZh ? `${s}秒` : `${s}s`\n const m = Math.floor(s / 60)\n const sec = s % 60\n return isZh ? `${m}分${sec}秒` : `${m}m${sec}s`\n }\n\n const ranking = stats.map((s, i) => ({\n rank: i + 1,\n name: s.name,\n median: formatTime(s.medianSeconds),\n avg: formatTime(s.avgSeconds),\n count: s.responseCount,\n }))\n\n const formattedRange = formatTimeRange(effectiveTimeFilter, locale)\n const period =\n typeof formattedRange === 'string'\n ? isZh\n ? `近${days}天`\n : `Last ${days} days`\n : `${formattedRange.start} – ${formattedRange.end}`\n const data = {\n period,\n totalResponders: stats.length,\n ranking: ranking.map(\n (r) =>\n `${r.rank}. ${r.name} — ${isZh ? '中位数' : 'median'} ${r.median}, ${isZh ? '平均' : 'avg'} ${r.avg} (${r.count}${isZh ? '次' : ' responses'})`\n ),\n }\n\n return { content: JSON.stringify(data), data }\n}\n\nexport const responseTimeAnalysisTool: ToolDefinition = {\n name: 'response_time_analysis',\n description: '分析群成员的响应速度排行,基于回复间隔的中位数和平均值。',\n inputSchema,\n handler,\n category: 'analysis',\n}\n","/**\n * 关键词词频分析工具\n *\n * 通过 SQL 获取文本消息,使用 NLP 分词统计高频词。\n * NLP 分词能力通过 context.segmentText 回调注入。\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { formatTimeRange, isChineseLocale } from '../utils/format'\nimport { parseExtendedTimeParams, type ExtendedTimeParams } from '../utils/time-params'\nimport { timeParamProperties } from '../utils/schemas'\n\ninterface TextRow {\n content: string\n}\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n days: {\n type: 'number',\n description: 'Recent days to analyze when no explicit or selected time range is available; defaults to 30',\n },\n top_n: { type: 'number', description: '返回前多少个高频词,默认 50' },\n ...timeParamProperties,\n },\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const { locale, segmentText } = context\n const isZh = isChineseLocale(locale)\n const days = (params.days as number) || 30\n const topN = (params.top_n as number) || 50\n\n if (!segmentText) {\n const text = isZh ? '当前环境不支持分词功能' : 'Text segmentation is not available in this environment'\n return { content: text, data: null }\n }\n\n const effectiveTimeFilter = parseExtendedTimeParams(params as ExtendedTimeParams, context.timeFilter)\n const timeCondition = effectiveTimeFilter\n ? 'ts >= @startTs AND ts <= @endTs'\n : \"ts > unixepoch('now', '-' || @days || ' days')\"\n const sql = `\n SELECT content FROM message\n WHERE type = 0 AND content IS NOT NULL AND LENGTH(content) > 1\n AND ${timeCondition}\n LIMIT 50000\n `\n const rows = await context.dataProvider!.executeParameterizedSql<TextRow>(\n sql,\n effectiveTimeFilter ? { ...effectiveTimeFilter } : { days }\n )\n if (!rows || rows.length === 0) {\n const text = isZh ? '该时间范围内没有文本消息' : 'No text messages in this time range'\n return { content: text, data: null }\n }\n\n const texts = rows.map((r) => r.content)\n const segLocale: string = locale?.startsWith('ja') ? 'ja-JP' : locale?.startsWith('zh') ? 'zh-CN' : 'en-US'\n const freqResult = segmentText(texts, segLocale, {\n minCount: 2,\n topN,\n posFilterMode: 'meaningful',\n enableStopwords: true,\n })\n\n if (freqResult.words.size === 0) {\n const text = isZh ? '分词后没有有意义的高频词' : 'No meaningful high-frequency words found after segmentation'\n return { content: text, data: null }\n }\n\n const ranking = [...freqResult.words.entries()].map(([word, count], i) => ({\n rank: i + 1,\n word,\n count,\n }))\n\n const formattedRange = formatTimeRange(effectiveTimeFilter, locale)\n const period =\n typeof formattedRange === 'string'\n ? isZh\n ? `近${days}天`\n : `Last ${days} days`\n : `${formattedRange.start} – ${formattedRange.end}`\n const data = {\n period,\n totalMessages: rows.length,\n totalKeywords: ranking.length,\n keywords: ranking.map((r) => `${r.rank}. ${r.word} (${r.count}${isZh ? '次' : ''})`),\n }\n\n return { content: JSON.stringify(data), data }\n}\n\nexport const keywordFrequencyTool: ToolDefinition = {\n name: 'keyword_frequency',\n description: '统计群聊中的高频关键词,通过 NLP 分词分析消息内容。',\n inputSchema,\n handler,\n category: 'analysis',\n}\n","/**\n * 工具系统类型定义\n *\n * 平台无关的工具注册表类型,同时服务于 MCP Server、HTTP API 和 Electron Agent。\n */\n\nimport type { ChartPayload, DatabaseAdapter, EvidenceTimeRangeMs } from '@openchatlab/core'\nimport type {\n AIEntityRef,\n AIMemoryEntry,\n AIMemoryScope,\n AIMemorySourceType,\n CrossChatContactLookupResult,\n CrossChatContactSessionsRequest,\n CrossChatContactSessionsResult,\n CrossChatEntityResolution,\n CrossChatGroupSessionsRankingRequest,\n CrossChatGroupSessionsRankingResult,\n CrossChatGlobalActivitySummaryRequest,\n CrossChatGlobalActivitySummaryResult,\n CrossChatMessageContextRequest,\n CrossChatMessageContextResult,\n CrossChatMessageSource,\n CrossChatOperationOptions,\n CrossChatPrivateContactsRankingRequest,\n CrossChatPrivateContactsRankingResult,\n CrossChatOverviewRequest,\n CrossChatOverviewResult,\n CrossChatRecentSessionResult,\n CrossChatRecentSessionSummary,\n CrossChatSearchRequest,\n CrossChatSearchResult,\n CrossChatSharedInteractionsRequest,\n CrossChatSharedInteractionsResult,\n ToolProgress,\n} from '@openchatlab/shared-types'\n\nexport type { ToolProgress } from '@openchatlab/shared-types'\n\nexport type {\n EvidenceRetrievalMode,\n EvidenceStatus,\n EvidencePayloadStatus,\n EvidenceWarning,\n EvidenceTimeRangeMs,\n ChatEvidenceSource,\n ChatEvidenceGroup,\n ChatEvidencePayload,\n} from '@openchatlab/core'\n\n// ==================== Schema ====================\n\n/**\n * JSON Schema 参数定义(兼容 MCP tool input schema)\n */\nexport interface JsonSchema {\n type: 'object'\n properties: Record<\n string,\n {\n type: string\n description?: string\n items?: {\n type: string\n properties?: Record<string, unknown>\n required?: string[]\n }\n properties?: Record<string, unknown>\n additionalProperties?: boolean | Record<string, unknown>\n default?: unknown\n enum?: unknown[]\n minimum?: number\n maximum?: number\n }\n >\n required?: string[]\n}\n\n// ==================== Time Filter ====================\n\nexport interface ToolTimeRange {\n startTs: number\n endTs: number\n}\n\n// ==================== Data Provider ====================\n\nexport interface SearchMessagesResult {\n messages: RawMessage[]\n total: number\n}\n\nexport interface MemberStatItem {\n name: string\n messageCount: number\n percentage: number\n}\n\nexport interface SchemaTableInfo {\n name: string\n sql: string\n}\n\nexport interface ChatOverviewResult {\n name: string\n platform: string\n type: string\n totalMessages: number\n totalMembers: number\n firstMessageTs: number | null\n lastMessageTs: number | null\n topMembers: Array<{ id: number; name: string; count: number }>\n}\n\nexport interface MemberInfo {\n id: number\n platformId: string\n accountName: string | null\n groupNickname: string | null\n aliases: string[]\n messageCount: number\n}\n\nexport interface NameHistoryItem {\n nameType: string\n name: string\n startTs: number\n endTs: number | null\n}\n\nexport interface SegmentMessagesResult {\n segmentId: number\n startTs: number\n endTs: number\n messageCount: number\n returnedCount: number\n participants: string[]\n messages: Array<{\n id: number\n senderName: string\n content: string | null\n timestamp: number\n }>\n}\n\nexport interface ConversationResult {\n messages: RawMessage[]\n total: number\n member1Name: string\n member2Name: string\n}\n\nexport interface SegmentSummaryItem {\n id: number\n startTs: number\n endTs: number\n messageCount: number\n participants: string[]\n summary: string | null\n}\n\n/**\n * 声明式 SQL 工具执行配置\n */\nexport interface SqlToolExecution {\n type: 'sqlite'\n query: string\n rowTemplate: string\n summaryTemplate?: string\n fallback: string\n}\n\n/**\n * 声明式 SQL 工具定义\n */\nexport interface SqlToolDef {\n name: string\n description: string\n parameters: JsonSchema\n execution: SqlToolExecution\n}\n\n/**\n * 工具数据查询抽象接口\n *\n * Server 和 Electron 各自实现:\n * - CoreDataProvider: 通过 @openchatlab/core 查询函数 + DatabaseAdapter\n * - WorkerDataProvider: 通过 workerManager IPC 调用 Worker 线程\n */\nexport interface SearchMessagesOptions {\n timeFilter?: ToolTimeRange\n limit?: number\n senderId?: number\n /** Pagination offset (CLI cursor paging). */\n offset?: number\n /** Keyword join mode: 'any' (OR, default) or 'all' (AND). */\n matchMode?: 'any' | 'all'\n /** Blacklist pushdown: rows containing any keyword are excluded from results and total. */\n excludeKeywords?: string[]\n /** Timestamp ordering, default 'desc'. */\n sort?: 'asc' | 'desc'\n}\n\nexport interface ToolDataProvider {\n // === 基础查询 ===\n searchMessages(keywords: string[], options?: SearchMessagesOptions): Promise<SearchMessagesResult>\n\n deepSearchMessages(keywords: string[], options?: SearchMessagesOptions): Promise<SearchMessagesResult>\n\n getSearchMessageContext(messageIds: number[], contextBefore: number, contextAfter: number): Promise<RawMessage[]>\n\n getRecentMessages(options?: { timeFilter?: ToolTimeRange; limit?: number }): Promise<SearchMessagesResult>\n\n getMessageContext(messageIds: number[], contextSize: number): Promise<RawMessage[]>\n\n // === 聊天概览 ===\n getChatOverview(topN?: number): Promise<ChatOverviewResult | null>\n\n // === 成员相关 ===\n getMembers(): Promise<MemberInfo[]>\n\n getMemberStats(options?: { timeFilter?: ToolTimeRange; top?: number }): Promise<MemberStatItem[]>\n\n getMemberNameHistory(memberId: number): Promise<NameHistoryItem[]>\n\n // === 时间统计 ===\n getTimeStats(\n type: 'hourly' | 'weekday' | 'daily' | 'monthly',\n options?: { timeFilter?: ToolTimeRange }\n ): Promise<unknown[]>\n\n // === 段落相关 ===\n getSegmentMessages(segmentId: number, limit?: number): Promise<SegmentMessagesResult | null>\n\n getSegmentSummaries(options?: { limit?: number; timeFilter?: ToolTimeRange }): Promise<SegmentSummaryItem[]>\n\n // === 对话查询 ===\n getConversationBetween(\n memberId1: number,\n memberId2: number,\n timeFilter?: ToolTimeRange,\n limit?: number\n ): Promise<ConversationResult>\n\n // === SQL ===\n executeSql(sql: string, options?: { maxRows?: number }): Promise<unknown>\n\n executeParameterizedSql<T = Record<string, unknown>>(query: string, params: Record<string, unknown>): Promise<T[]>\n\n getSchema(): Promise<SchemaTableInfo[]>\n}\n\n// ==================== Semantic Search Tool ====================\n\n/** 单次语义检索默认返回片段数(用户可配置范围 5-15) */\nexport const SEMANTIC_SEARCH_DEFAULT_MAX_RESULTS = 10\n/** 单次语义检索片段数硬上限(LLM 不可超过;须与 node-runtime SEARCH_MAX_RESULTS_HARD_CAP 一致) */\nexport const SEMANTIC_SEARCH_MAX_RESULTS_HARD_CAP = 20\n\n/** 工具返回的安全来源条目(已脱敏,不含原始消息) */\nexport interface SemanticSearchToolSource {\n startMessageId: number\n endMessageId: number\n score: number\n chunkIds: string[]\n /** 已脱敏的片段预览 */\n snippet: string\n /** 已脱敏的完整证据块文本,用于证据检索分类与引用 */\n text?: string\n /** ISO 时间 */\n startTime?: string\n endTime?: string\n}\n\n/** 语义检索工具结果:text 为面向 LLM 的安全证据文本,其余为安全 metadata */\nexport interface SemanticSearchToolResult {\n available: boolean\n reason?: string\n /** 已清洗/脱敏/匿名化/截断的证据文本 */\n text: string\n returned: number\n hitCount: number\n partial: boolean\n coverage: number\n truncated: boolean\n timeRange?: { earliest: string; latest: string }\n sources: SemanticSearchToolSource[]\n}\n\nexport interface SemanticSearchToolOptions {\n /** 期望返回片段数;未指定时由 service 用配置默认值 */\n maxResults?: number\n /** 预处理配置(脱敏/匿名化/清洗规则) */\n preprocessConfig?: Record<string, unknown>\n /** 当前用户平台 id,用于昵称匿名化 owner 识别 */\n ownerPlatformId?: string\n locale?: string\n /** 证据文本 token 预算 */\n maxResultTokens?: number\n /** 毫秒级时间范围过滤(可单边);仅保留与 chunk 时间范围有交集的语义候选 */\n timeFilter?: EvidenceTimeRangeMs\n}\n\n/**\n * 语义检索窄接口\n *\n * 由 node-runtime 的 SemanticIndexService 实现并经 adapter 注入。\n * 工具层只消费已脱敏的安全结果,脱敏在 service 内通过 applyPreprocessingPipeline 完成。\n */\nexport interface SemanticSearchToolService {\n /** 当前会话是否可检索(已启用 + 有 chunk + 模型一致) */\n canSearch(sessionId: string): boolean | Promise<boolean>\n searchForTool(\n sessionId: string,\n query: string,\n options?: SemanticSearchToolOptions\n ): Promise<SemanticSearchToolResult>\n}\n\n// ==================== Tool Context ====================\n\n/**\n * NLP 分词结果\n */\nexport interface SegmentResult {\n words: Map<string, number>\n uniqueWords: number\n totalWords: number\n}\n\n/**\n * 工具执行上下文\n */\nexport interface ToolExecutionContext {\n sessionId: string\n locale?: string\n timeFilter?: ToolTimeRange\n abortSignal?: AbortSignal\n /** Report meaningful phases for long-running tool execution. */\n reportProgress?: (progress: ToolProgress) => void\n /** 抽象查询接口 */\n dataProvider?: ToolDataProvider\n /** 语义检索窄接口(仅当前会话可检索时由 adapter 注入) */\n semanticIndexService?: SemanticSearchToolService\n /** 预处理配置(脱敏/匿名化/清洗),供需要自处理的工具(如语义检索)使用 */\n preprocessConfig?: Record<string, unknown>\n /** 当前用户平台 id,用于昵称匿名化 owner 识别 */\n ownerPlatformId?: string\n /** @deprecated 逐步迁移到 dataProvider 后移除;Electron 端不提供此字段 */\n db?: DatabaseAdapter\n /** 搜索结果上下文:向前取多少条 */\n searchContextBefore?: number\n /** 搜索结果上下文:向后取多少条 */\n searchContextAfter?: number\n /** 消息条数上限 */\n maxMessagesLimit?: number\n /** 工具结果 token 预算(语义检索证据文本截断用) */\n maxToolResultTokens?: number\n /** NLP 分词回调(由平台注入 batchSegmentWithFrequency 实现) */\n segmentText?: (texts: string[], locale: string, options: Record<string, unknown>) => SegmentResult\n /** i18n 模板翻译回调(用于 SQL 工具模板国际化) */\n translateTemplate?: (key: string) => string | undefined\n /**\n * 消息脱敏回调:对一组原始消息执行清洗 + 脱敏,返回安全消息(含 id/发送者/时间/脱敏后内容)。\n *\n * 供需要在工具内部生成可持久化安全 snippet 的工具使用(如证据检索的关键词路径)。\n * 由平台 adapter 注入 applyPreprocessingPipeline 等价实现;清洗可能删除/合并消息,\n * 返回条数可能少于输入。未注入时调用方应回退到不脱敏或跳过相关能力。\n */\n desensitizeMessages?: (messages: RawMessage[], options?: { anonymizeNames?: boolean }) => RawMessage[]\n}\n\nexport interface CrossChatAnalysisToolService {\n lookupContact(query: string): CrossChatContactLookupResult\n resolveEntities(refs: AIEntityRef[], options?: CrossChatOperationOptions): Promise<CrossChatEntityResolution>\n inspectContactSessions(\n request: CrossChatContactSessionsRequest,\n options?: CrossChatOperationOptions\n ): Promise<CrossChatContactSessionsResult>\n inspectSharedInteractions(\n request: CrossChatSharedInteractionsRequest,\n options?: CrossChatOperationOptions\n ): Promise<CrossChatSharedInteractionsResult>\n readRecentSession(sessionId: string): CrossChatRecentSessionResult\n rankPrivateContacts(\n request: CrossChatPrivateContactsRankingRequest,\n options?: CrossChatOperationOptions\n ): Promise<CrossChatPrivateContactsRankingResult>\n rankGroupSessions(\n request: CrossChatGroupSessionsRankingRequest,\n options?: CrossChatOperationOptions\n ): Promise<CrossChatGroupSessionsRankingResult>\n getGlobalActivitySummary(request: CrossChatGlobalActivitySummaryRequest): CrossChatGlobalActivitySummaryResult\n searchMessages(request: CrossChatSearchRequest, options?: CrossChatOperationOptions): Promise<CrossChatSearchResult>\n getMessageContext(request: CrossChatMessageContextRequest): CrossChatMessageContextResult\n getOverview(request: CrossChatOverviewRequest, options?: CrossChatOperationOptions): Promise<CrossChatOverviewResult>\n}\n\nexport interface AIMemoryToolService {\n list(scope?: AIMemoryScope): AIMemoryEntry[]\n search(\n scope: AIMemoryScope,\n query: string,\n locale?: string\n ): { entries: AIMemoryEntry[]; retrievalMode: 'relevance' | 'recent_fallback' }\n get(id: string): AIMemoryEntry | null\n create(\n input: AIMemoryScope & {\n content: string\n sourceType: AIMemorySourceType\n sourceAIChatId?: string | null\n sourceMessageId?: string | null\n }\n ): AIMemoryEntry\n update(\n id: string,\n input: {\n content: string\n sourceType: AIMemorySourceType\n sourceAIChatId?: string | null\n sourceMessageId?: string | null\n }\n ): AIMemoryEntry\n forget(id: string): boolean\n}\n\nexport interface CrossChatToolExecutionContext {\n locale?: string\n /** Stable entities explicitly selected for the current user turn. */\n entityRefs?: AIEntityRef[]\n /** Stable entities successfully resolved by tools during the current Agent run. */\n resolvedEntityRefs?: AIEntityRef[]\n abortSignal?: AbortSignal\n reportProgress?: (progress: ToolProgress) => void\n maxToolResultTokens?: number\n /** 平台注入的统一 tokenizer;未注入时 handler 使用 CJK-aware 轻量估算。 */\n countTokens?: (text: string) => number\n analysisService: CrossChatAnalysisToolService\n memoryService: AIMemoryToolService\n aiChatId: string\n /** Reports a successful memory create/update without exposing it to the model context. */\n reportMemoryChange?: (memoryId: string) => void\n preprocessMessagesBySession: (\n sessionId: string,\n messages: CrossChatMessageSource[]\n ) => CrossChatMessageSource[] | Promise<CrossChatMessageSource[]>\n preprocessSummariesBySession: (\n sessionId: string,\n summaries: CrossChatRecentSessionSummary[]\n ) => CrossChatRecentSessionSummary[] | Promise<CrossChatRecentSessionSummary[]>\n preprocessModelLabel: (value: string, pseudonym: string) => string\n}\n\n// ==================== Raw Message ====================\n\n/**\n * 可预处理的原始消息(与 @openchatlab/node-runtime PreprocessableMessage 兼容)\n */\nexport interface RawMessage {\n id?: number\n senderId?: number\n senderName: string\n senderPlatformId?: string\n content: string | null\n timestamp: number\n}\n\n// ==================== Tool Result ====================\n\n/**\n * 工具执行结果\n */\nexport interface ToolResult {\n content: string\n data?: unknown\n chart?: ChartPayload\n charts?: ChartPayload[]\n /** 消息类工具可透传原始消息数据,供预处理管道消费 */\n rawMessages?: RawMessage[]\n}\n\n// ==================== Tool Definition ====================\n\nexport type ToolCategory = 'core' | 'analysis'\nexport type TruncationStrategy = 'keep_first' | 'keep_last'\nexport type ToolExecutionMode = 'parallel' | 'sequential'\n\n/**\n * 平台无关的工具定义\n *\n * handler 支持同步和异步返回,兼容 Server(同步 DB)和 Electron(异步 Worker)。\n */\nexport interface ToolDefinition<TContext = ToolExecutionContext> {\n name: string\n description: string\n inputSchema: JsonSchema\n handler: (params: Record<string, unknown>, context: TContext) => ToolResult | Promise<ToolResult>\n category?: ToolCategory\n truncationStrategy?: TruncationStrategy\n /** Override the Agent's parallel default when this tool has an ordering dependency. */\n executionMode?: ToolExecutionMode\n}\n","/**\n * 当前对话语义检索工具\n *\n * 由 LLM 按需调用:当问题需要当前聊天历史中的具体事实/人物/地点/事件/过往提及时调用。\n * 仅检索当前会话,结果由 SemanticIndexService 经 applyPreprocessingPipeline 脱敏后返回,\n * 工具层不接触原始消息,details 不夹带 rawMessages。\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, JsonSchema } from '../types'\nimport { SEMANTIC_SEARCH_MAX_RESULTS_HARD_CAP } from '../types'\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description:\n '语义检索查询,应改写成适合检索当前聊天历史的自然语言描述(围绕需要确认的事实/人物/地点/事件/过往提及)。',\n },\n max_results: {\n type: 'number',\n description: `期望返回的相关片段数,可选。不填使用用户配置的默认值;可按问题复杂度提高,硬上限 ${SEMANTIC_SEARCH_MAX_RESULTS_HARD_CAP}。`,\n minimum: 1,\n maximum: SEMANTIC_SEARCH_MAX_RESULTS_HARD_CAP,\n },\n },\n required: ['query'],\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const service = context.semanticIndexService\n if (!service) {\n return { content: 'Semantic search is not available for this conversation.' }\n }\n\n const query = typeof params.query === 'string' ? params.query.trim() : ''\n if (!query) {\n return { content: 'Please provide a non-empty query describing what to look up in this conversation history.' }\n }\n\n const maxResults =\n typeof params.max_results === 'number' && Number.isFinite(params.max_results)\n ? Math.max(1, Math.min(SEMANTIC_SEARCH_MAX_RESULTS_HARD_CAP, Math.floor(params.max_results)))\n : undefined\n\n const result = await service.searchForTool(context.sessionId, query, {\n maxResults,\n preprocessConfig: context.preprocessConfig,\n ownerPlatformId: context.ownerPlatformId,\n locale: context.locale,\n maxResultTokens: context.maxToolResultTokens,\n timeFilter: context.timeFilter\n ? { startTs: context.timeFilter.startTs * 1000, endTs: context.timeFilter.endTs * 1000 }\n : undefined,\n })\n\n if (!result.available) {\n return { content: `No semantic index available for this conversation (${result.reason ?? 'unavailable'}).` }\n }\n\n const data = {\n query,\n returned: result.returned,\n hitCount: result.hitCount,\n partial: result.partial,\n coverage: result.coverage,\n truncated: result.truncated,\n timeRange: result.timeRange,\n sources: result.sources,\n }\n\n if (result.returned === 0) {\n return { content: 'No relevant excerpts found in this conversation history.', data }\n }\n\n let content = result.text\n if (result.partial) {\n content = `Note: index is incomplete, evidence may be partial.\\n\\n${content}`\n }\n if (result.truncated) {\n content = `${content}\\n\\nReached the result limit; there may be more matching history. Use a narrower query to continue searching.`\n }\n\n return { content, data }\n}\n\nexport const semanticSearchCurrentChatTool: ToolDefinition = {\n name: 'semantic_search_current_chat',\n description:\n 'Semantically search the CURRENT conversation history for relevant excerpts. Use when the question needs concrete facts, people, places, events, or past mentions from this chat. Do NOT use for greetings, writing, or explaining general concepts.',\n inputSchema,\n handler,\n category: 'core',\n truncationStrategy: 'keep_first',\n}\n","/**\n * 证据检索工具 retrieve_chat_evidence\n *\n * 面向“多少次 / 有没有 / 是否曾经 / 给证据链”这类历史事实判断问题:\n * 同时(或按 mode)跑语义召回与关键词召回,合并去重并保守分组,\n * 产出可持久化、已脱敏的结构化证据 payload(data.evidence)和给 LLM 的安全摘要文本。\n *\n * 单位约定:聊天库 / RawMessage.timestamp 为秒;evidence payload 统一毫秒。\n * 关键词路径必须在工具层按时间范围兜底过滤(CLI provider 不保证时间过滤生效)。\n */\n\nimport type {\n ChatEvidenceGroup,\n ChatEvidencePayload,\n ChatEvidenceSource,\n EvidencePayloadStatus,\n EvidenceRetrievalMode,\n EvidenceStatus,\n EvidenceTimeRangeMs,\n EvidenceWarning,\n JsonSchema,\n RawMessage,\n ToolDefinition,\n ToolExecutionContext,\n ToolResult,\n} from '../types'\nimport { SEMANTIC_SEARCH_MAX_RESULTS_HARD_CAP } from '../types'\nimport { timeParamProperties } from '../utils/schemas'\n\nconst EVIDENCE_GROUP_GAP_SECONDS = 2 * 60 * 60\nconst EVIDENCE_GROUP_GAP_MS = EVIDENCE_GROUP_GAP_SECONDS * 1000\nconst EVIDENCE_GROUP_MAX_SOURCES = 5\nconst EVIDENCE_SNIPPET_MAX_CHARS = 160\nconst KEYWORD_DEFAULT_LIMIT = 80\n\n/** 计划/意向词:仅出现这些且无实际证据词,倾向判为“不计入” */\nconst PLANNING_WORDS = ['准备', '打算', '攻略', '想去', '计划', '要不要去', '考虑去', '安排一下']\n/** 实际发生证据词:出现则倾向判为“计入” */\nconst EVIDENCE_WORDS = ['到了', '到达', '出发', '返程', '回来', '入住', '住了', '门票', '合影', '打卡', '玩了']\n\nconst inputSchema: JsonSchema = {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: '需要用聊天证据确认的问题/检索目标,例如“我们去乐山旅行过多少次”。',\n },\n criteria: {\n type: 'string',\n description:\n '判定标准:什么算计入、什么不计入。统计/判断类问题应填写,例如“计入:有实际出行/到达/住宿证据;不计入:仅计划、攻略、别人经历、泛聊”。',\n },\n keywords: {\n type: 'array',\n items: { type: 'string' },\n description: '关键词列表,由你显式给出(工具不做同义词扩展)。hybrid/keyword 模式用于精确召回。',\n },\n mode: {\n type: 'string',\n enum: ['auto', 'hybrid', 'semantic', 'keyword'],\n description: 'auto(默认)/hybrid(语义+关键词)/semantic(仅语义)/keyword(仅关键词)。历史事实统计通常用 hybrid。',\n },\n max_results: {\n type: 'number',\n description: `语义路径期望返回片段数,硬上限 ${SEMANTIC_SEARCH_MAX_RESULTS_HARD_CAP}。`,\n minimum: 1,\n maximum: SEMANTIC_SEARCH_MAX_RESULTS_HARD_CAP,\n },\n ...timeParamProperties,\n },\n required: ['query'],\n}\n\n/** 内部统一候选 */\ninterface EvidenceCandidate {\n messageId: number\n startMessageId?: number\n endMessageId?: number\n timestamp: number // 毫秒\n rangeStartMs: number // 毫秒,用于时间交集\n rangeEndMs: number // 毫秒\n snippet: string\n senderName?: string\n sourceKind: 'semantic' | 'keyword'\n score?: number\n}\n\nfunction isChinese(locale?: string): boolean {\n return !locale || locale.toLowerCase().startsWith('zh')\n}\n\nfunction truncateSnippet(text: string): string {\n const t = text.trim()\n return t.length > EVIDENCE_SNIPPET_MAX_CHARS ? `${t.slice(0, EVIDENCE_SNIPPET_MAX_CHARS)}…` : t\n}\n\n/**\n * 语义 snippet 由预处理管道渲染为多行「时间 发送者: 内容」,时间对证据块展示是噪声\n * (分组已给出总时间)。这里去掉每行行首的时间前缀,仅保留「发送者: 内容」。\n * 覆盖 zh-CN(`2025/3/3 07:25:04`)与 en-US(`3/3/2025, 7:25:04 AM`)两种 toLocaleString 输出。\n */\nconst LINE_TIME_PREFIX = /^\\s*\\d{1,4}[/-]\\d{1,2}[/-]\\d{1,4},?\\s+\\d{1,2}:\\d{2}(?::\\d{2})?(?:\\s?[APap][Mm])?\\s+/\nfunction stripLineTimestamps(text: string): string {\n return text\n .split('\\n')\n .map((line) => line.replace(LINE_TIME_PREFIX, ''))\n .join('\\n')\n .trim()\n}\n\nfunction parseDateMs(s?: unknown): number | undefined {\n if (typeof s !== 'string' || !s.trim()) return undefined\n const d = new Date(s.trim().replace(' ', 'T'))\n const t = d.getTime()\n return Number.isNaN(t) ? undefined : t\n}\n\nfunction parseIsoMs(s?: string): number | undefined {\n if (!s) return undefined\n const t = Date.parse(s)\n return Number.isNaN(t) ? undefined : t\n}\n\n/** 解析时间范围为毫秒(可单边);显式参数优先,其次继承 context.timeFilter(秒→毫秒) */\nfunction parseEvidenceTimeRange(\n params: Record<string, unknown>,\n context: ToolExecutionContext\n): EvidenceTimeRangeMs | undefined {\n const startMs = parseDateMs(params.start_time)\n const endMs = parseDateMs(params.end_time)\n if (startMs != null || endMs != null) {\n return { startTs: startMs, endTs: endMs }\n }\n if (context.timeFilter) {\n return { startTs: context.timeFilter.startTs * 1000, endTs: context.timeFilter.endTs * 1000 }\n }\n return undefined\n}\n\nfunction overlapsTimeRangeMs(startMs: number, endMs: number, filter?: EvidenceTimeRangeMs): boolean {\n if (!filter) return true\n if (filter.startTs != null && endMs < filter.startTs) return false\n if (filter.endTs != null && startMs > filter.endTs) return false\n return true\n}\n\nfunction clampMaxResults(value: unknown): number | undefined {\n if (typeof value !== 'number' || !Number.isFinite(value)) return undefined\n return Math.max(1, Math.min(SEMANTIC_SEARCH_MAX_RESULTS_HARD_CAP, Math.floor(value)))\n}\n\nfunction toKeywordTimeFilter(rangeMs: EvidenceTimeRangeMs | undefined): { startTs: number; endTs: number } | undefined {\n if (!rangeMs) return undefined\n const filter: { startTs?: number; endTs?: number } = {}\n if (rangeMs.startTs != null) filter.startTs = Math.floor(rangeMs.startTs / 1000)\n if (rangeMs.endTs != null) filter.endTs = Math.floor(rangeMs.endTs / 1000)\n return Object.keys(filter).length > 0 ? (filter as { startTs: number; endTs: number }) : undefined\n}\n\ninterface ResolveResult {\n mode: Exclude<EvidenceRetrievalMode, 'auto'>\n warnings: Set<EvidenceWarning>\n}\n\nfunction resolveMode(\n requested: EvidenceRetrievalMode,\n semanticAvailable: boolean,\n hasKeywords: boolean\n): ResolveResult {\n const warnings = new Set<EvidenceWarning>()\n if (requested !== 'auto') return { mode: requested, warnings }\n\n if (semanticAvailable && hasKeywords) return { mode: 'hybrid', warnings }\n if (semanticAvailable && !hasKeywords) {\n warnings.add('keywords_missing_for_hybrid')\n return { mode: 'semantic', warnings }\n }\n warnings.add('semantic_unavailable')\n if (!hasKeywords) warnings.add('keywords_required_for_keyword_mode')\n return { mode: 'keyword', warnings }\n}\n\n/** 关键词消息 → 候选(脱敏 + 时间兜底) */\nfunction keywordMessagesToCandidates(\n messages: RawMessage[],\n rangeMs: EvidenceTimeRangeMs | undefined,\n desensitize: ToolExecutionContext['desensitizeMessages']\n): EvidenceCandidate[] {\n const safe = desensitize ? desensitize(messages) : messages\n const candidates: EvidenceCandidate[] = []\n for (const m of safe) {\n if (m.id == null || !m.content) continue\n const tsMs = m.timestamp * 1000\n if (!overlapsTimeRangeMs(tsMs, tsMs, rangeMs)) continue\n candidates.push({\n messageId: m.id,\n timestamp: tsMs,\n rangeStartMs: tsMs,\n rangeEndMs: tsMs,\n snippet: truncateSnippet(m.content),\n senderName: m.senderName,\n sourceKind: 'keyword',\n })\n }\n return candidates\n}\n\n/** 合并去重:关键词命中的时间戳落在语义片段时间范围内则丢弃;按 messageId 去重;按时间排序 */\nfunction mergeCandidates(semantic: EvidenceCandidate[], keyword: EvidenceCandidate[]): EvidenceCandidate[] {\n const keptKeyword = keyword.filter(\n (kc) => !semantic.some((sc) => kc.timestamp >= sc.rangeStartMs && kc.timestamp <= sc.rangeEndMs)\n )\n\n const byId = new Map<number, EvidenceCandidate>()\n for (const c of [...semantic, ...keptKeyword]) {\n if (!byId.has(c.messageId)) byId.set(c.messageId, c)\n }\n return [...byId.values()].sort((a, b) => a.timestamp - b.timestamp)\n}\n\nfunction classifyGroup(snippets: string[], hasCriteria: boolean, locale?: string): EvidenceStatus {\n if (!hasCriteria) return 'uncertain'\n if (!isChinese(locale)) return 'uncertain'\n const joined = snippets.join('\\n')\n const hasEvidence = EVIDENCE_WORDS.some((w) => joined.includes(w))\n const hasPlanning = PLANNING_WORDS.some((w) => joined.includes(w))\n if (hasEvidence) return 'included'\n if (hasPlanning) return 'excluded'\n return 'uncertain'\n}\n\nfunction formatDate(ms: number, locale?: string): string {\n const d = new Date(ms)\n const y = d.getFullYear()\n const m = String(d.getMonth() + 1).padStart(2, '0')\n const day = String(d.getDate()).padStart(2, '0')\n return isChinese(locale) ? `${y}年${m}月${day}日` : `${y}-${m}-${day}`\n}\n\nfunction buildGroups(candidates: EvidenceCandidate[], hasCriteria: boolean, locale?: string): ChatEvidenceGroup[] {\n const groups: ChatEvidenceGroup[] = []\n let current: ChatEvidenceGroup | null = null\n let lastTs = 0\n\n for (const c of candidates) {\n const source: ChatEvidenceSource = {\n messageId: c.messageId,\n startMessageId: c.startMessageId,\n endMessageId: c.endMessageId,\n timestamp: c.timestamp,\n senderName: c.senderName,\n snippet: c.snippet,\n sourceKind: c.sourceKind,\n }\n const continues =\n current && c.timestamp - lastTs <= EVIDENCE_GROUP_GAP_MS && current.sources.length < EVIDENCE_GROUP_MAX_SOURCES\n if (continues && current) {\n current.sources.push(source)\n current.timeRange = { startTs: current.timeRange!.startTs, endTs: c.timestamp }\n } else {\n current = {\n id: `g${groups.length + 1}`,\n status: 'uncertain',\n title: '',\n reason: '',\n timeRange: { startTs: c.timestamp, endTs: c.timestamp },\n sources: [source],\n }\n groups.push(current)\n }\n lastTs = c.timestamp\n }\n\n const cn = isChinese(locale)\n for (const g of groups) {\n const snippets = g.sources.map((s) => s.snippet)\n g.status = classifyGroup(snippets, hasCriteria, locale)\n const start = formatDate(g.timeRange!.startTs, locale)\n const end = formatDate(g.timeRange!.endTs, locale)\n g.title = start === end ? start : cn ? `${start} 至 ${end}` : `${start} – ${end}`\n g.reason = cn ? GROUP_REASON_CN[g.status] : GROUP_REASON_EN[g.status]\n }\n return groups\n}\n\nconst GROUP_REASON_CN: Record<EvidenceStatus, string> = {\n included: '含实际发生/到达等证据,建议计入',\n excluded: '仅含计划/意向,未见实际发生证据,建议不计入',\n uncertain: '证据不足,无法确认是否计入',\n}\nconst GROUP_REASON_EN: Record<EvidenceStatus, string> = {\n included: 'Contains concrete evidence of an actual event; suggest counting it.',\n excluded: 'Only plans/intentions without evidence of occurrence; suggest excluding.',\n uncertain: 'Insufficient evidence to confirm.',\n}\n\nfunction buildContent(payload: ChatEvidencePayload, locale: string | undefined): string {\n const cn = isChinese(locale)\n const lines: string[] = []\n lines.push(\n cn\n ? `证据检索结果(mode=${payload.mode},status=${payload.status})`\n : `Evidence (mode=${payload.mode}, status=${payload.status})`\n )\n if (payload.warnings && payload.warnings.length > 0) {\n lines.push((cn ? '告警: ' : 'Warnings: ') + payload.warnings.join(', '))\n }\n if (payload.groups.length === 0) {\n lines.push(cn ? '未找到可计入的明确证据。' : 'No conclusive evidence found.')\n }\n for (const g of payload.groups) {\n lines.push(`\\n[${g.status}] ${g.title} — ${g.reason}`)\n for (const s of g.sources) {\n const who = s.senderName ? `${s.senderName}: ` : ''\n lines.push(` · ${who}${s.snippet}`)\n }\n }\n lines.push(\n cn\n ? '\\n请基于以上证据保守作答:只把 included 计入确定结论,excluded/uncertain 不计入;证据不足时回答”无法确认”。'\n : '\\nAnswer conservatively: count `included` groups toward the conclusion; for `uncertain` groups, judge based on the snippet content whether evidence of actual occurrence is present; do not count `excluded` groups.'\n )\n return lines.join('\\n')\n}\n\nfunction computeStatus(\n anyPathRan: boolean,\n hasResults: boolean,\n warnings: Set<EvidenceWarning>\n): EvidencePayloadStatus {\n if (!anyPathRan) return 'unavailable'\n if (!hasResults) return 'empty'\n const degraded =\n warnings.has('semantic_partial') || warnings.has('semantic_unavailable') || warnings.has('keyword_unavailable')\n return degraded ? 'partial' : 'complete'\n}\n\nasync function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {\n const locale = context.locale\n const query = typeof params.query === 'string' ? params.query.trim() : ''\n const criteria = typeof params.criteria === 'string' && params.criteria.trim() ? params.criteria.trim() : undefined\n const keywords = Array.isArray(params.keywords)\n ? (params.keywords.filter((k) => typeof k === 'string' && k.trim()) as string[])\n : []\n const requestedMode: EvidenceRetrievalMode =\n params.mode === 'hybrid' || params.mode === 'semantic' || params.mode === 'keyword' || params.mode === 'auto'\n ? params.mode\n : 'auto'\n\n context.reportProgress?.({ phase: 'checking_capabilities' })\n const service = context.semanticIndexService\n const semanticAvailable = !!service && (await service.canSearch(context.sessionId))\n const rangeMs = parseEvidenceTimeRange(params, context)\n\n const { mode, warnings } = resolveMode(requestedMode, semanticAvailable, keywords.length > 0)\n if (!criteria) warnings.add('criteria_missing')\n\n const runSemantic = mode === 'semantic' || mode === 'hybrid'\n const runKeyword = mode === 'keyword' || mode === 'hybrid'\n\n let semanticRan = false\n let keywordRan = false\n const semanticCandidates: EvidenceCandidate[] = []\n let keywordCandidates: EvidenceCandidate[] = []\n\n // 语义路径:service 内按 chunk 时间范围过滤;工具层再按 startTime/endTime 兜底过滤\n if (runSemantic) {\n if (!service || !semanticAvailable) {\n warnings.add('semantic_unavailable')\n } else {\n context.reportProgress?.({ phase: 'semantic_search' })\n const result = await service.searchForTool(context.sessionId, query, {\n maxResults: clampMaxResults(params.max_results),\n preprocessConfig: context.preprocessConfig,\n ownerPlatformId: context.ownerPlatformId,\n locale,\n maxResultTokens: context.maxToolResultTokens,\n timeFilter: rangeMs,\n })\n semanticRan = true\n if (!result.available) {\n warnings.add('semantic_unavailable')\n } else {\n if (result.partial) warnings.add('semantic_partial')\n for (const s of result.sources) {\n const startMs = parseIsoMs(s.startTime)\n const endMs = parseIsoMs(s.endTime) ?? startMs\n if (rangeMs && startMs != null && endMs != null && !overlapsTimeRangeMs(startMs, endMs, rangeMs)) continue\n const evidenceText = stripLineTimestamps(s.text || s.snippet)\n semanticCandidates.push({\n messageId: s.startMessageId,\n startMessageId: s.startMessageId,\n endMessageId: s.endMessageId,\n timestamp: startMs ?? 0,\n rangeStartMs: startMs ?? 0,\n rangeEndMs: endMs ?? startMs ?? 0,\n snippet: evidenceText,\n sourceKind: 'semantic',\n score: s.score,\n })\n }\n }\n }\n }\n\n // 关键词路径\n if (runKeyword) {\n if (keywords.length === 0) {\n warnings.add(mode === 'keyword' ? 'keywords_required_for_keyword_mode' : 'keywords_missing_for_hybrid')\n } else if (!context.dataProvider) {\n warnings.add('keyword_unavailable')\n } else {\n context.reportProgress?.({ phase: 'keyword_search' })\n const secFilter = toKeywordTimeFilter(rangeMs)\n const searchResult = await context.dataProvider.searchMessages(keywords, {\n timeFilter: secFilter,\n limit: context.maxMessagesLimit || KEYWORD_DEFAULT_LIMIT,\n })\n keywordRan = true\n keywordCandidates = keywordMessagesToCandidates(searchResult.messages, rangeMs, context.desensitizeMessages)\n }\n }\n\n context.reportProgress?.({ phase: 'assembling_evidence' })\n const merged = mergeCandidates(semanticCandidates, keywordCandidates)\n const groups = buildGroups(merged, !!criteria, locale)\n\n const status = computeStatus(semanticRan || keywordRan, groups.length > 0, warnings)\n\n const payload: ChatEvidencePayload = {\n version: 1,\n query,\n criteria,\n mode,\n status,\n warnings: warnings.size > 0 ? [...warnings] : undefined,\n groups,\n }\n if (rangeMs) {\n payload.appliedTimeFilter = {\n startTs: rangeMs.startTs,\n endTs: rangeMs.endTs,\n }\n }\n\n const cn = isChinese(locale)\n payload.summary =\n groups.length === 0\n ? cn\n ? '未找到明确可计入的证据。'\n : 'No conclusive evidence found.'\n : cn\n ? `共 ${groups.length} 组候选证据。`\n : `${groups.length} candidate evidence group(s).`\n\n return { content: buildContent(payload, locale), data: { evidence: payload } }\n}\n\nexport const retrieveChatEvidenceTool: ToolDefinition = {\n name: 'retrieve_chat_evidence',\n description:\n 'Retrieve and assemble conservative, de-identified evidence from the CURRENT conversation for fact/occurrence/count questions (e.g. \"how many times did we...\", \"did we ever...\", \"prove from chat history...\"). Runs semantic + keyword retrieval, groups results, and returns a structured evidence payload. Prefer this over search_messages/semantic_search_current_chat for evidence-chain or counting questions.',\n inputSchema,\n handler,\n category: 'core',\n truncationStrategy: 'keep_first',\n}\n","import type {\n AIEntityRef,\n CrossChatContactLookupResult,\n CrossChatContactSessionsResult,\n CrossChatEntityResolution,\n CrossChatEvidencePayload,\n CrossChatGroupSessionsRankingResult,\n CrossChatGlobalActivitySummaryResult,\n CrossChatMessageSource,\n CrossChatOverviewItem,\n CrossChatOverviewResult,\n CrossChatParticipantRef,\n CrossChatPrivateContactsRankingResult,\n CrossChatResolvedContactSession,\n CrossChatResolvedSession,\n CrossChatSearchScope,\n CrossChatSharedInteractionsResult,\n} from '@openchatlab/shared-types'\nimport type { CrossChatToolExecutionContext, JsonSchema, ToolDefinition, ToolResult } from '../types'\nimport { parseExtendedTimeParams } from '../utils/time-params'\nimport { timeParamProperties } from '../utils/schemas'\n\nconst scopeItems = {\n type: 'object',\n properties: {\n sessionId: { type: 'string', description: 'Stable session ID returned by resolve_chat_entities' },\n memberIds: { type: 'array', items: { type: 'number' }, description: 'Local member IDs for this session' },\n label: { type: 'string', description: 'Human-readable scope label' },\n },\n required: ['sessionId'],\n}\n\nconst recentDaysProperty = {\n type: 'number' as const,\n minimum: 1,\n description:\n 'Relative time window ending at the real current time. Use 30 for unspecified recent activity, but omit it for a latest available private-chat recap without an explicit date or duration.',\n}\n\nconst resolveSchema: JsonSchema = {\n type: 'object',\n properties: {\n entities: {\n type: 'array',\n description:\n 'Contact or session references. A contact may use a stable contactKey or a displayName lookup from the user text.',\n items: {\n type: 'object',\n properties: {\n type: { type: 'string', enum: ['contact', 'session'] },\n contactKey: { type: 'string' },\n sessionId: { type: 'string' },\n displayName: { type: 'string' },\n sessionType: { type: 'string', enum: ['private', 'group'] },\n },\n required: ['type', 'displayName'],\n },\n },\n },\n required: ['entities'],\n}\n\nconst searchSchema: JsonSchema = {\n type: 'object',\n properties: {\n keywords: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Exact substring keywords. May be omitted only with explicit scopes to sample recent messages from those scopes.',\n },\n scopes: {\n type: 'array',\n description: 'Resolved session/member scopes. Omit only when the user clearly requested global discovery.',\n items: scopeItems,\n },\n match_mode: { type: 'string', enum: ['any', 'all'], description: 'Whether any or all keywords must match' },\n recent_days: recentDaysProperty,\n sender: {\n type: 'string',\n enum: ['all', 'owner'],\n description:\n \"Message sender filter. Use owner when the user's wording makes them the subject, such as 'I discussed buying a home'.\",\n },\n sort: { type: 'string', enum: ['asc', 'desc'], description: 'Timestamp order; defaults to newest first' },\n ...timeParamProperties,\n },\n}\n\nconst recentSessionSchema: JsonSchema = {\n type: 'object',\n properties: {\n session_id: {\n type: 'string',\n description: 'One exact session ID returned by resolve_chat_entities',\n },\n },\n required: ['session_id'],\n}\n\nconst contextSchema: JsonSchema = {\n type: 'object',\n properties: {\n session_id: { type: 'string', description: 'Source session ID from cross-chat search evidence' },\n message_id: { type: 'number', description: 'Message ID inside that source session' },\n context_size: { type: 'number', description: 'Messages before and after the source message; defaults to 10' },\n },\n required: ['session_id', 'message_id'],\n}\n\nconst overviewSchema: JsonSchema = {\n type: 'object',\n properties: {\n scopes: {\n type: 'array',\n description: 'Resolved session/member scopes to summarize separately',\n items: scopeItems,\n },\n recent_days: recentDaysProperty,\n ...timeParamProperties,\n },\n required: ['scopes'],\n}\n\nconst rankPrivateContactsSchema: JsonSchema = {\n type: 'object',\n properties: {\n rank_by: {\n type: 'string',\n enum: ['message_count', 'active_days'],\n description: 'Ranking metric. Defaults to total private-chat message count.',\n },\n limit: { type: 'number', minimum: 1, maximum: 50, description: 'Number of ranked contacts to return' },\n recent_days: recentDaysProperty,\n ...timeParamProperties,\n },\n}\n\nconst rankGroupSessionsSchema: JsonSchema = {\n type: 'object',\n properties: {\n mode: {\n type: 'string',\n enum: ['owner_activity', 'total_activity'],\n description:\n \"Use owner_activity for 'where was I most active' and total_activity for 'which groups were busiest overall'.\",\n },\n limit: { type: 'number', minimum: 1, maximum: 50, description: 'Number of ranked groups to return' },\n recent_days: recentDaysProperty,\n ...timeParamProperties,\n },\n required: ['mode'],\n}\n\nconst globalActivitySummarySchema: JsonSchema = {\n type: 'object',\n properties: {\n mode: {\n type: 'string',\n enum: ['year', 'recent_365'],\n description: 'Use year for a calendar year and recent_365 for the rolling latest 365 days. Defaults to year.',\n },\n year: {\n type: 'number',\n minimum: 1970,\n description: 'Calendar year for mode=year. Omit it to use the current year.',\n },\n },\n}\n\nconst inspectContactSessionsSchema: JsonSchema = {\n type: 'object',\n properties: {\n contact_key: {\n type: 'string',\n description: 'Stable contact key returned by resolve_chat_entities; display names are not accepted',\n },\n recent_days: recentDaysProperty,\n include_roster_only: {\n type: 'boolean',\n description: 'Include imported sessions where the member is recorded but did not speak in the selected range',\n default: true,\n },\n cursor: { type: 'string', description: 'Opaque continuation cursor from the previous result' },\n page_size: { type: 'number', description: 'Maximum matching sessions returned in this batch' },\n max_wall_time_ms: { type: 'number', description: 'Maximum wall time for this inspection batch' },\n ...timeParamProperties,\n },\n required: ['contact_key'],\n}\n\nconst MAX_SHARED_ANCHORS_PER_PAIR = 8\n\nconst inspectSharedInteractionsSchema: JsonSchema = {\n type: 'object',\n properties: {\n participants: {\n type: 'array',\n description:\n 'Two to five distinct people. Use type=owner for the local user in each session or type=contact with a stable contact_key.',\n items: {\n type: 'object',\n properties: {\n type: { type: 'string', enum: ['owner', 'contact'] },\n contact_key: { type: 'string' },\n },\n required: ['type'],\n },\n },\n recent_days: recentDaysProperty,\n cursor: { type: 'string', description: 'Opaque continuation cursor from the previous result' },\n page_size: { type: 'number', description: 'Maximum common sessions returned in this batch' },\n max_anchors_per_pair: {\n type: 'number',\n description: 'Maximum direct-reply and proximity message anchors returned for each participant pair',\n minimum: 0,\n maximum: MAX_SHARED_ANCHORS_PER_PAIR,\n },\n max_wall_time_ms: { type: 'number', description: 'Maximum wall time for this inspection batch' },\n ...timeParamProperties,\n },\n required: ['participants'],\n}\n\nconst DEFAULT_CONTACT_INSPECTION_PAGE_SIZE = 50\nconst MAX_CONTACT_INSPECTION_PAGE_SIZE = 100\nconst MODEL_LABEL_MAX_LENGTH = 80\nconst DEFAULT_SHARED_INSPECTION_PAGE_SIZE = 20\nconst DEFAULT_SHARED_ANCHORS_PER_PAIR = 4\nconst TOOL_RESULT_CHARS_PER_TOKEN = 4\nconst TOOL_RESULT_BASE_CHARS = 1_500\nconst CONTACT_SESSION_ESTIMATED_CHARS = 650\nconst SHARED_SESSION_BASE_CHARS = 550\nconst SHARED_PARTICIPANT_ESTIMATED_CHARS = 240\nconst SHARED_PAIR_BASE_CHARS = 260\nconst SHARED_ANCHOR_ESTIMATED_CHARS = 180\n\nasync function resolveHandler(\n params: Record<string, unknown>,\n context: CrossChatToolExecutionContext\n): Promise<ToolResult> {\n const inputs = parseEntityInputs(params.entities)\n const refs: AIEntityRef[] = []\n const contactLookups: CrossChatContactLookupResult[] = []\n for (const input of inputs) {\n if (input.type === 'contact' && !input.contactKey) {\n const lookup = context.analysisService.lookupContact(input.displayName)\n contactLookups.push(lookup)\n if (lookup.status === 'resolved' && lookup.candidates[0]) {\n refs.push({\n type: 'contact',\n contactKey: lookup.candidates[0].contactKey,\n displayName: lookup.candidates[0].displayName,\n })\n }\n continue\n }\n refs.push(input as AIEntityRef)\n }\n const resolution = await context.analysisService.resolveEntities(dedupeEntityRefs(refs), {\n signal: context.abortSignal,\n })\n trackResolvedEntityRefs(context.resolvedEntityRefs, resolution)\n const data = { ...resolution, contactLookups }\n const modelData = limitEntityResolutionToBudget(\n resolution,\n contactLookups,\n context.maxToolResultTokens,\n context.countTokens\n )\n return { content: JSON.stringify(modelData), data }\n}\n\nasync function searchHandler(\n params: Record<string, unknown>,\n context: CrossChatToolExecutionContext\n): Promise<ToolResult> {\n const timeFilter = parseExtendedTimeParams(params)\n const keywords = params.keywords === undefined ? [] : parseStringArray(params.keywords)\n const result = await context.analysisService.searchMessages(\n {\n keywords,\n scopes: params.scopes === undefined ? undefined : parseScopes(params.scopes),\n startTs: timeFilter?.startTs,\n endTs: timeFilter?.endTs,\n recentDays: parseOptionalNumber(params.recent_days),\n sender: params.sender === 'owner' ? 'owner' : 'all',\n matchMode: params.match_mode === 'all' ? 'all' : 'any',\n sort: params.sort === 'asc' ? 'asc' : 'desc',\n },\n {\n signal: context.abortSignal,\n onProgress: (progress) =>\n context.reportProgress?.({\n phase: 'searching',\n current: progress.processedSessions,\n total: progress.totalSessions,\n }),\n }\n )\n const safeMessages = await preprocessBySession(context, result.messages)\n const buildCoverage = (budgetTruncated: boolean) => ({\n ...result.coverage,\n truncated: result.coverage.truncated || budgetTruncated,\n truncatedReasons: budgetTruncated\n ? [...new Set([...result.coverage.truncatedReasons, 'evidence_budget' as const])]\n : result.coverage.truncatedReasons,\n })\n const buildModelData = (messages: CrossChatMessageSource[], budgetTruncated: boolean) => ({\n totalMatches: result.totalMatches,\n returned: messages.length,\n selection: summarizeEvidenceSelection(messages),\n appliedFilters: result.appliedFilters,\n coverage: buildCoverage(budgetTruncated),\n messages: messages.map(toModelMessage),\n })\n const limited = limitMessagesToBudget(safeMessages, context.maxToolResultTokens, buildModelData, {\n countTokens: context.countTokens,\n })\n const modelData = buildModelData(limited.messages, limited.truncated)\n const evidence: CrossChatEvidencePayload = {\n version: 1,\n query: keywords.join(' '),\n sources: limited.messages.map(toEvidenceSource),\n coverage: modelData.coverage,\n }\n const data = {\n ...modelData,\n crossChatEvidence: evidence,\n }\n // Evidence details are persisted for source cards, but duplicating their snippets in content would charge the\n // model twice for the same text and invalidate maxToolResultTokens.\n return { content: JSON.stringify(modelData), data }\n}\n\nasync function readRecentSessionHandler(\n params: Record<string, unknown>,\n context: CrossChatToolExecutionContext\n): Promise<ToolResult> {\n const result = context.analysisService.readRecentSession(requireString(params.session_id, 'session_id'))\n const safeMessages = await preprocessBySession(context, result.messages)\n const safeSummaries = await context.preprocessSummariesBySession(result.source.sessionId, result.summaries)\n const sessionPseudonym = 'Session1'\n const modelSource = {\n ...result.source,\n sessionName: context.preprocessModelLabel(result.source.sessionName, sessionPseudonym),\n }\n const toRecentModelMessage = (message: CrossChatMessageSource) => ({\n ...toModelMessage(message),\n sessionName: context.preprocessModelLabel(message.sessionName, sessionPseudonym),\n })\n const buildModelData = (messages: CrossChatMessageSource[], budgetTruncated: boolean) => ({\n source: modelSource,\n selection: {\n strategy: 'latest_session_slice',\n totalMessages: result.coverage.totalMessages,\n returnedMessages: messages.length,\n returnedSummaries: safeSummaries.length,\n hasEarlierMessages: result.coverage.hasEarlierMessages,\n toolResultTruncated: budgetTruncated,\n },\n summaries: safeSummaries,\n messages: messages.map(toRecentModelMessage),\n })\n const limited = limitMessagesToBudget(safeMessages, context.maxToolResultTokens, buildModelData, {\n countTokens: context.countTokens,\n })\n const modelData = buildModelData(limited.messages, limited.truncated)\n const evidence: CrossChatEvidencePayload = {\n version: 1,\n query: 'recent session recap',\n sources: limited.messages.map(toEvidenceSource),\n coverage: {\n candidateSessions: 1,\n scannedSessions: 1,\n matchedSessions: limited.messages.length > 0 ? 1 : 0,\n failedSessions: 0,\n truncated: limited.truncated,\n truncatedReasons: limited.truncated ? ['evidence_budget'] : [],\n },\n }\n return {\n content: JSON.stringify(modelData),\n data: {\n ...modelData,\n source: result.source,\n messages: limited.messages.map(toModelMessage),\n crossChatEvidence: evidence,\n },\n }\n}\n\nasync function contextHandler(\n params: Record<string, unknown>,\n context: CrossChatToolExecutionContext\n): Promise<ToolResult> {\n const sessionId = requireString(params.session_id, 'session_id')\n const messageId = requireNumber(params.message_id, 'message_id')\n const contextSize = parseOptionalNumber(params.context_size)\n const result = context.analysisService.getMessageContext({ sessionId, messageId, contextSize })\n const safeMessages = await preprocessBySession(context, result.messages)\n const buildModelData = (messages: CrossChatMessageSource[], truncated: boolean) => ({\n source: result.source,\n returned: messages.length,\n truncated,\n messages: messages.map(toModelMessage),\n })\n const limited = limitMessagesToBudget(safeMessages, context.maxToolResultTokens, buildModelData, {\n priorityIndexes: buildContextPriority(safeMessages, messageId),\n continueAfterOverflow: true,\n countTokens: context.countTokens,\n })\n const data = buildModelData(limited.messages, limited.truncated)\n return { content: JSON.stringify(data), data }\n}\n\nasync function overviewHandler(\n params: Record<string, unknown>,\n context: CrossChatToolExecutionContext\n): Promise<ToolResult> {\n const timeFilter = parseExtendedTimeParams(params)\n const result = await context.analysisService.getOverview(\n {\n scopes: parseScopes(params.scopes),\n startTs: timeFilter?.startTs,\n endTs: timeFilter?.endTs,\n recentDays: parseOptionalNumber(params.recent_days),\n },\n {\n signal: context.abortSignal,\n onProgress: (progress) =>\n context.reportProgress?.({\n phase: 'analyzing',\n current: progress.processedSessions,\n total: progress.totalSessions,\n }),\n }\n )\n const data = {\n appliedRange: result.appliedRange,\n items: result.items.map(({ memberNames: _memberNames, ...item }) => item),\n coverage: result.coverage,\n }\n const fullModelData: OverviewModelData = {\n ...data,\n items: data.items.map((item, index) => {\n const sessionPseudonym = `Session${index + 1}`\n const preprocessMember = (member: (typeof item.memberActivities)[number]) => ({\n ...member,\n memberName: context.preprocessModelLabel(member.memberName, `U${member.memberId}@${item.sessionId}`),\n })\n return {\n ...item,\n sessionName: context.preprocessModelLabel(item.sessionName, sessionPseudonym),\n label: context.preprocessModelLabel(item.label, sessionPseudonym),\n memberActivities: item.memberActivities.map(preprocessMember),\n topMembers: item.topMembers.map(preprocessMember),\n }\n }),\n }\n const modelData = limitOverviewToBudget(\n fullModelData,\n context.maxToolResultTokens,\n context.countTokens ?? estimatePayloadTokens\n )\n return { content: JSON.stringify(modelData), data }\n}\n\nasync function rankPrivateContactsHandler(\n params: Record<string, unknown>,\n context: CrossChatToolExecutionContext\n): Promise<ToolResult> {\n const timeFilter = parseExtendedTimeParams(params)\n const result: CrossChatPrivateContactsRankingResult = await context.analysisService.rankPrivateContacts(\n {\n startTs: timeFilter?.startTs,\n endTs: timeFilter?.endTs,\n recentDays: parseOptionalNumber(params.recent_days),\n rankBy: params.rank_by === 'active_days' ? 'active_days' : 'message_count',\n limit: parseOptionalNumber(params.limit),\n },\n {\n signal: context.abortSignal,\n onProgress: (progress) =>\n context.reportProgress?.({\n phase: 'analyzing',\n current: progress.processedSessions,\n total: progress.totalSessions,\n }),\n }\n )\n const modelData = {\n ...result,\n items: result.items.map((item) => ({\n ...item,\n displayName: context.preprocessModelLabel(item.displayName, `Contact${item.rank}`),\n })),\n }\n return { content: JSON.stringify(modelData), data: result }\n}\n\nasync function rankGroupSessionsHandler(\n params: Record<string, unknown>,\n context: CrossChatToolExecutionContext\n): Promise<ToolResult> {\n const timeFilter = parseExtendedTimeParams(params)\n const mode = requireString(params.mode, 'mode')\n if (mode !== 'owner_activity' && mode !== 'total_activity') {\n throw new Error('mode must be owner_activity or total_activity')\n }\n const result: CrossChatGroupSessionsRankingResult = await context.analysisService.rankGroupSessions(\n {\n mode,\n startTs: timeFilter?.startTs,\n endTs: timeFilter?.endTs,\n recentDays: parseOptionalNumber(params.recent_days),\n limit: parseOptionalNumber(params.limit),\n },\n {\n signal: context.abortSignal,\n onProgress: (progress) =>\n context.reportProgress?.({\n phase: 'analyzing',\n current: progress.processedSessions,\n total: progress.totalSessions,\n }),\n }\n )\n const modelData = {\n ...result,\n items: result.items.map((item) => ({\n ...item,\n sessionName: context.preprocessModelLabel(item.sessionName, `Group${item.rank}`),\n })),\n }\n return { content: JSON.stringify(modelData), data: result }\n}\n\nasync function globalActivitySummaryHandler(\n params: Record<string, unknown>,\n context: CrossChatToolExecutionContext\n): Promise<ToolResult> {\n const mode = params.mode ?? 'year'\n if (mode !== 'year' && mode !== 'recent_365') throw new Error('mode must be year or recent_365')\n const result: CrossChatGlobalActivitySummaryResult = context.analysisService.getGlobalActivitySummary({\n mode,\n year: parseOptionalNumber(params.year),\n })\n const modelData = limitGlobalActivitySummaryToBudget(\n buildGlobalActivityModelData(result),\n context.maxToolResultTokens,\n context.countTokens ?? estimatePayloadTokens\n )\n return { content: JSON.stringify(modelData), data: result }\n}\n\nfunction buildGlobalActivityModelData(result: CrossChatGlobalActivitySummaryResult) {\n const summary = result.summary\n return {\n mode: result.mode,\n dataState: result.dataState,\n range: summary.range,\n availableDataYears: summary.availableDataYears,\n latestDataYear: summary.latestDataYear,\n metrics: summary.metrics,\n monthlyActivity: summary.monthlyActivity,\n monthlyDirectContacts: summary.monthlyDirectContacts,\n dailyActivity: summary.dailyActivity,\n messageTypes: summary.messageTypes,\n textLength: summary.textLength,\n coverage: summary.coverage,\n cache: {\n status: summary.cache.status,\n computedAt: summary.cache.computedAt,\n staleReason: summary.cache.staleReason,\n },\n task: {\n status: summary.task.status,\n startedAt: summary.task.startedAt,\n finishedAt: summary.task.finishedAt,\n processedSessions: summary.task.processedSessions,\n totalSessions: summary.task.totalSessions,\n },\n selection: {\n dailyActivityTotal: summary.dailyActivity.length,\n dailyActivityReturned: summary.dailyActivity.length,\n dailyActivityFormat: 'objects',\n toolResultTruncated: false,\n truncatedReasons: [] as string[],\n },\n }\n}\n\nasync function inspectContactSessionsHandler(\n params: Record<string, unknown>,\n context: CrossChatToolExecutionContext\n): Promise<ToolResult> {\n const timeFilter = parseExtendedTimeParams(params)\n const requestedPageSize = parseOptionalNumber(params.page_size)\n const budgetedPageSize = limitContactPageSizeToBudget(requestedPageSize, context.maxToolResultTokens)\n const result = await context.analysisService.inspectContactSessions(\n {\n contactKey: requireString(params.contact_key, 'contact_key'),\n startTs: timeFilter?.startTs,\n endTs: timeFilter?.endTs,\n recentDays: parseOptionalNumber(params.recent_days),\n includeRosterOnly: params.include_roster_only === undefined ? true : requireBoolean(params.include_roster_only),\n cursor: typeof params.cursor === 'string' && params.cursor.trim() ? params.cursor.trim() : undefined,\n pageSize: budgetedPageSize.value,\n maxWallTimeMs: parseOptionalNumber(params.max_wall_time_ms),\n },\n {\n signal: context.abortSignal,\n onProgress: (progress) =>\n context.reportProgress?.({\n phase: 'analyzing',\n current: progress.processedSessions,\n total: progress.totalSessions,\n }),\n }\n )\n const countTokens = context.countTokens ?? estimatePayloadTokens\n const pageBudgetTruncated = budgetedPageSize.limited && result.coverage.truncatedReasons.includes('page_size')\n const payloadExceedsBudget =\n !!context.maxToolResultTokens &&\n context.maxToolResultTokens > 0 &&\n countTokens(JSON.stringify(result)) > context.maxToolResultTokens\n const data = pageBudgetTruncated || payloadExceedsBudget ? withToolResultBudgetReason(result) : result\n const modelData = limitContactResultToBudget(data, context.maxToolResultTokens, countTokens)\n return { content: JSON.stringify(modelData), data }\n}\n\nasync function inspectSharedInteractionsHandler(\n params: Record<string, unknown>,\n context: CrossChatToolExecutionContext\n): Promise<ToolResult> {\n const timeFilter = parseExtendedTimeParams(params)\n const participants = parseParticipants(params.participants)\n const requestedPageSize = parseOptionalNumber(params.page_size)\n const requestedAnchorsPerPair = parseOptionalNumber(params.max_anchors_per_pair)\n const budget = limitSharedRequestToBudget(\n participants.length,\n requestedPageSize,\n requestedAnchorsPerPair,\n context.maxToolResultTokens\n )\n const result = await context.analysisService.inspectSharedInteractions(\n {\n participants,\n startTs: timeFilter?.startTs,\n endTs: timeFilter?.endTs,\n recentDays: parseOptionalNumber(params.recent_days),\n cursor: typeof params.cursor === 'string' && params.cursor.trim() ? params.cursor.trim() : undefined,\n pageSize: budget.pageSize,\n maxAnchorsPerPair: budget.maxAnchorsPerPair,\n maxWallTimeMs: parseOptionalNumber(params.max_wall_time_ms),\n },\n {\n signal: context.abortSignal,\n onProgress: (progress) =>\n context.reportProgress?.({\n phase: 'analyzing',\n current: progress.processedSessions,\n total: progress.totalSessions,\n }),\n }\n )\n const pageBudgetTruncated =\n budget.pageLimited && result.coverage.nextCursor !== null && result.coverage.truncatedReasons.includes('page_size')\n const anchorBudgetTruncated =\n budget.anchorsLimited && result.sessions.some((session) => session.pairs.some((pair) => pair.anchorsTruncated))\n const countTokens = context.countTokens ?? estimatePayloadTokens\n const payloadExceedsBudget =\n !!context.maxToolResultTokens &&\n context.maxToolResultTokens > 0 &&\n countTokens(JSON.stringify(result)) > context.maxToolResultTokens\n const data: CrossChatSharedInteractionsResult =\n pageBudgetTruncated || anchorBudgetTruncated || payloadExceedsBudget ? withToolResultBudgetReason(result) : result\n const modelData = limitSharedModelResultToBudget(data, context.maxToolResultTokens, countTokens)\n return { content: JSON.stringify(modelData), data }\n}\n\nexport const resolveChatEntitiesTool: ToolDefinition<CrossChatToolExecutionContext> = {\n name: 'resolve_chat_entities',\n description:\n 'Resolve contacts and sessions into exact source scopes. Stable refs resolve directly; typed contact names search the contact catalog. Continue automatically for one candidate, ask the user to choose when contactLookups reports ambiguous, and never guess among multiple candidates.',\n inputSchema: resolveSchema,\n handler: resolveHandler,\n category: 'core',\n}\n\nexport const readRecentSessionTool: ToolDefinition<CrossChatToolExecutionContext> = {\n name: 'read_recent_session',\n description:\n 'Read one exactly resolved session for a concise latest-available recap. The tool internally returns a bounded newest message slice plus up to five existing segment summaries, with source evidence and preprocessing. Use it after resolve_chat_entities when the user asks what happened recently in one private chat or one explicitly selected session without a calendar range. Do not pass message budgets. For explicit dates, durations, keywords, multi-session work, or deeper history, use search_messages_globally instead.',\n inputSchema: recentSessionSchema,\n handler: readRecentSessionHandler,\n category: 'core',\n truncationStrategy: 'keep_first',\n}\n\nexport const searchMessagesGloballyTool: ToolDefinition<CrossChatToolExecutionContext> = {\n name: 'search_messages_globally',\n description:\n 'Search exact keywords across resolved contacts or sessions. Use recent_days=30 for unspecified recent activity, but for a latest available private-chat recap without an explicit date or duration, scope only the direct private session and omit recent_days. Use sender=owner when the user is the subject of the requested action. The tool controls evidence volume internally, prioritizes private-chat evidence, ranks remaining group sources by matching activity, and automatically includes surrounding context. With explicit scopes, omit keywords to sample recent messages. Unscoped global discovery always requires keywords. Results include applied filters, source identity, coverage, and truncation status.',\n inputSchema: searchSchema,\n handler: searchHandler,\n category: 'core',\n truncationStrategy: 'keep_first',\n}\n\nexport const getCrossChatMessageContextTool: ToolDefinition<CrossChatToolExecutionContext> = {\n name: 'get_cross_chat_message_context',\n description:\n 'Load surrounding messages for one cross-chat evidence item. Both session_id and message_id are required because message IDs are only unique inside a session.',\n inputSchema: contextSchema,\n handler: contextHandler,\n category: 'core',\n truncationStrategy: 'keep_last',\n}\n\nexport const getCrossChatOverviewTool: ToolDefinition<CrossChatToolExecutionContext> = {\n name: 'get_cross_chat_overview',\n description:\n 'Compare already-resolved contact or session scopes within an exact time range. Returns deterministic message counts, active days and members, per-requested-member activity, owner coverage, fixed top members for groups, dataset cutoff, and completeness. It does not discover or rank sessions globally.',\n inputSchema: overviewSchema,\n handler: overviewHandler,\n category: 'core',\n}\n\nexport const rankPrivateContactsTool: ToolDefinition<CrossChatToolExecutionContext> = {\n name: 'rank_private_contacts',\n description:\n 'Deterministically rank private-chat contacts across all eligible imported sessions for an exact time range. Use this for questions such as who the user chatted with most or had the most active private-chat days. This tool counts non-system messages and never uses keyword-search hits as a ranking proxy. Results include owner/contact splits, dataset cutoff, identity coverage, and completeness.',\n inputSchema: rankPrivateContactsSchema,\n handler: rankPrivateContactsHandler,\n category: 'core',\n}\n\nexport const rankGroupSessionsTool: ToolDefinition<CrossChatToolExecutionContext> = {\n name: 'rank_group_sessions',\n description:\n 'Deterministically rank imported group sessions for an exact time range. mode=owner_activity answers where the user personally spoke most; mode=total_activity answers which groups were busiest overall. Never mix these metrics or substitute sampled search hits. Results include total and owner counts, active members/days, owner-resolution coverage, dataset cutoff, and completeness.',\n inputSchema: rankGroupSessionsSchema,\n handler: rankGroupSessionsHandler,\n category: 'core',\n}\n\nexport const getGlobalActivitySummaryTool: ToolDefinition<CrossChatToolExecutionContext> = {\n name: 'get_global_activity_summary',\n description:\n 'Read the existing deterministic owner activity snapshot for the current calendar year, another calendar year, or the rolling latest 365 days. Use it for total sent messages, active days, direct-contact counts, monthly/daily trends, message types, and text-length distribution. It never reads chat text or returns contact/group rankings. fresh and stale states contain usable metrics; preparing and failed do not and must not be described as zero activity. Do not poll a preparing result in the same answer.',\n inputSchema: globalActivitySummarySchema,\n handler: globalActivitySummaryHandler,\n category: 'core',\n}\n\nexport const inspectContactSessionsTool: ToolDefinition<CrossChatToolExecutionContext> = {\n name: 'inspect_contact_sessions',\n description:\n \"Inspect one resolved contact across imported private and group sessions. Returns the contact's own message counts, first/last speech, active days, roster-only presence, dataset cutoff, and coverage. Use recent_days=30 for recent activity without an explicit duration; never derive start_time from the dataset cutoff. Use only for person source/activity questions after exact identity resolution; this tool does not infer relationship labels or return message text.\",\n inputSchema: inspectContactSessionsSchema,\n handler: inspectContactSessionsHandler,\n category: 'core',\n}\n\nexport const inspectSharedInteractionsTool: ToolDefinition<CrossChatToolExecutionContext> = {\n name: 'inspect_shared_interactions',\n description:\n 'Inspect common imported sessions for two to five exactly resolved people, including owner when requested. Returns per-person activity, directional replies, proximity signals, co-active days, message anchors, dataset cutoff, and coverage. Use recent_days=30 for recent interaction questions without an explicit duration; never derive start_time from the dataset cutoff. Common sessions contain every requested participant. These structural signals guide evidence reading and must never be treated as relationship labels or replace message context.',\n inputSchema: inspectSharedInteractionsSchema,\n handler: inspectSharedInteractionsHandler,\n category: 'core',\n}\n\ntype ParsedEntityInput =\n | { type: 'contact'; contactKey?: string; displayName: string }\n | Extract<AIEntityRef, { type: 'session' }>\n\nfunction parseEntityInputs(value: unknown): ParsedEntityInput[] {\n if (!Array.isArray(value)) throw new Error('entities must be an array')\n return value.map((item) => {\n if (!isRecord(item)) throw new Error('each entity must be an object')\n const type = requireString(item.type, 'entity.type')\n const displayName = requireString(item.displayName, 'entity.displayName')\n if (type === 'contact') {\n return {\n type,\n ...(typeof item.contactKey === 'string' && item.contactKey.trim()\n ? { contactKey: item.contactKey.trim() }\n : {}),\n displayName,\n }\n }\n if (type === 'session') {\n const sessionType = item.sessionType === 'private' ? 'private' : item.sessionType === 'group' ? 'group' : null\n if (!sessionType) throw new Error('entity.sessionType must be private or group')\n return { type, sessionId: requireString(item.sessionId, 'entity.sessionId'), displayName, sessionType }\n }\n throw new Error('entity.type must be contact or session')\n })\n}\n\nfunction dedupeEntityRefs(refs: AIEntityRef[]): AIEntityRef[] {\n const byKey = new Map<string, AIEntityRef>()\n for (const ref of refs) {\n byKey.set(entityRefKey(ref), ref)\n }\n return [...byKey.values()]\n}\n\nfunction trackResolvedEntityRefs(\n currentRunRefs: AIEntityRef[] | undefined,\n resolution: CrossChatEntityResolution\n): void {\n if (!currentRunRefs) return\n const resolvedRefs: AIEntityRef[] = [\n ...resolution.contacts\n .filter((item) => item.status === 'resolved' || item.status === 'partial')\n .map((item) => item.ref),\n ...resolution.sessions.filter((item) => item.status === 'resolved').map((item) => item.ref),\n ]\n const existingKeys = new Set(currentRunRefs.map(entityRefKey))\n for (const ref of resolvedRefs) {\n const key = entityRefKey(ref)\n if (existingKeys.has(key)) continue\n currentRunRefs.push(ref)\n existingKeys.add(key)\n }\n}\n\nfunction entityRefKey(ref: AIEntityRef): string {\n return ref.type === 'contact' ? `contact:${ref.contactKey}` : `session:${ref.sessionId}`\n}\n\nfunction parseScopes(value: unknown): CrossChatSearchScope[] {\n if (!Array.isArray(value)) throw new Error('scopes must be an array')\n return value.map((item) => {\n if (!isRecord(item)) throw new Error('each scope must be an object')\n return {\n sessionId: requireString(item.sessionId, 'scope.sessionId'),\n memberIds: item.memberIds === undefined ? undefined : parseNumberArray(item.memberIds),\n label: typeof item.label === 'string' ? item.label : undefined,\n }\n })\n}\n\nfunction parseParticipants(value: unknown): CrossChatParticipantRef[] {\n if (!Array.isArray(value)) throw new Error('participants must be an array')\n return value.map((item) => {\n if (!isRecord(item)) throw new Error('each participant must be an object')\n if (item.type === 'owner') return { type: 'owner' }\n if (item.type === 'contact') {\n return { type: 'contact', contactKey: requireString(item.contact_key, 'participant.contact_key') }\n }\n throw new Error('participant.type must be owner or contact')\n })\n}\n\ntype GlobalActivityModelData = ReturnType<typeof buildGlobalActivityModelData>\n\ninterface OverviewModelData {\n appliedRange: CrossChatOverviewResult['appliedRange']\n items: Array<Omit<CrossChatOverviewItem, 'memberNames'>>\n coverage: CrossChatOverviewResult['coverage']\n}\n\ntype OverviewItemFormat = 'compact' | 'core' | 'identity' | 'omitted'\n\nfunction limitOverviewToBudget(\n fullData: OverviewModelData,\n maxToolResultTokens: number | undefined,\n countTokens: (text: string) => number\n): unknown {\n if (!maxToolResultTokens || maxToolResultTokens <= 0) return fullData\n if (countTokens(JSON.stringify(fullData)) <= maxToolResultTokens) return fullData\n\n const compactItems = fullData.items.map((item) => ({\n ...item,\n sessionName: truncateModelLabel(item.sessionName),\n label: truncateModelLabel(item.label),\n memberActivities: item.memberActivities.map((member) => ({\n memberId: member.memberId,\n memberName: truncateModelLabel(member.memberName),\n messageCount: member.messageCount,\n activeDays: member.activeDays,\n firstMessageTs: member.firstMessageTs,\n lastMessageTs: member.lastMessageTs,\n })),\n topMembers: item.topMembers.map((member) => ({\n memberName: truncateModelLabel(member.memberName),\n messageCount: member.messageCount,\n activeDays: member.activeDays,\n lastMessageTs: member.lastMessageTs,\n })),\n }))\n const buildCandidate = (items: Array<Record<string, unknown>>, itemFormat: OverviewItemFormat) => ({\n appliedRange: fullData.appliedRange,\n items,\n coverage: fullData.coverage,\n selection: buildOverviewSelection(fullData.items, items, itemFormat),\n })\n const fits = (candidate: unknown) => countTokens(JSON.stringify(candidate)) <= maxToolResultTokens\n\n // 优先保留所有会话的核心统计,先均匀收缩每个会话的成员明细,避免只留下输入顺序靠前的会话。\n const maxTopMembers = compactItems.reduce((max, item) => Math.max(max, item.topMembers.length), 0)\n const topMemberCandidate = findLargestOverviewDetailLimit(maxTopMembers, (limit) =>\n buildCandidate(\n compactItems.map((item) => ({ ...item, topMembers: item.topMembers.slice(0, limit) })),\n 'compact'\n )\n )\n if (topMemberCandidate && fits(topMemberCandidate)) return topMemberCandidate\n\n const maxMemberActivities = compactItems.reduce((max, item) => Math.max(max, item.memberActivities.length), 0)\n const memberActivityCandidate = findLargestOverviewDetailLimit(maxMemberActivities, (limit) =>\n buildCandidate(\n compactItems.map((item) => ({\n ...item,\n memberActivities: item.memberActivities.slice(0, limit),\n topMembers: [],\n })),\n 'compact'\n )\n )\n if (memberActivityCandidate && fits(memberActivityCandidate)) return memberActivityCandidate\n\n const coreItems = compactItems.map((item) => ({\n sessionId: item.sessionId,\n sessionName: item.sessionName,\n sessionType: item.sessionType,\n platform: item.platform,\n label: item.label,\n totalMessages: item.totalMessages,\n activeDays: item.activeDays,\n activeMembers: item.activeMembers,\n firstMessageTs: item.firstMessageTs,\n lastMessageTs: item.lastMessageTs,\n ownerStatus: item.ownerStatus,\n ownerMessages: item.ownerMessages,\n ownerActiveDays: item.ownerActiveDays,\n }))\n const coreCandidate = buildCandidate(coreItems, 'core')\n if (fits(coreCandidate)) return coreCandidate\n\n const identityItems = compactItems.map((item) => ({\n sessionId: item.sessionId,\n sessionName: item.sessionName,\n sessionType: item.sessionType,\n label: item.label,\n totalMessages: item.totalMessages,\n activeDays: item.activeDays,\n lastMessageTs: item.lastMessageTs,\n }))\n const identityCandidate = buildCandidate(identityItems, 'identity')\n if (fits(identityCandidate)) return identityCandidate\n\n const returnedItems = findLargestOverviewItemSlice(identityItems, (items) => buildCandidate(items, 'identity'))\n if (returnedItems) return returnedItems\n\n const omitted = buildCandidate([], 'omitted')\n const candidates: unknown[] = [\n omitted,\n {\n selection: buildOverviewSelection(fullData.items, [], 'omitted'),\n },\n { toolResultTruncated: true, truncatedReasons: ['tool_result_budget'] },\n {},\n ]\n return candidates.find(fits) ?? {}\n\n function findLargestOverviewDetailLimit(\n maximum: number,\n build: (limit: number) => ReturnType<typeof buildCandidate>\n ): ReturnType<typeof buildCandidate> | null {\n if (!fits(build(0))) return null\n let low = 0\n let high = maximum\n while (low < high) {\n const middle = Math.ceil((low + high) / 2)\n if (fits(build(middle))) low = middle\n else high = middle - 1\n }\n return build(low)\n }\n\n function findLargestOverviewItemSlice(\n items: Array<Record<string, unknown>>,\n build: (items: Array<Record<string, unknown>>) => ReturnType<typeof buildCandidate>\n ): ReturnType<typeof buildCandidate> | null {\n if (!fits(build([]))) return null\n let low = 0\n let high = items.length\n while (low < high) {\n const middle = Math.ceil((low + high) / 2)\n if (fits(build(items.slice(0, middle)))) low = middle\n else high = middle - 1\n }\n return build(items.slice(0, low))\n }\n}\n\nfunction buildOverviewSelection(\n fullItems: OverviewModelData['items'],\n returnedItems: Array<Record<string, unknown>>,\n itemFormat: OverviewItemFormat\n) {\n const memberActivitiesTotal = fullItems.reduce((sum, item) => sum + item.memberActivities.length, 0)\n const topMembersTotal = fullItems.reduce((sum, item) => sum + item.topMembers.length, 0)\n const memberActivitiesReturned = returnedItems.reduce(\n (sum, item) => sum + (Array.isArray(item.memberActivities) ? item.memberActivities.length : 0),\n 0\n )\n const topMembersReturned = returnedItems.reduce(\n (sum, item) => sum + (Array.isArray(item.topMembers) ? item.topMembers.length : 0),\n 0\n )\n const truncatedReasons = [\n ...(memberActivitiesReturned < memberActivitiesTotal ? ['member_activities_budget'] : []),\n ...(topMembersReturned < topMembersTotal ? ['top_members_budget'] : []),\n ...(returnedItems.length < fullItems.length ? ['session_items_budget'] : []),\n 'item_fields_budget',\n 'tool_result_budget',\n ]\n return {\n sessionItemsTotal: fullItems.length,\n sessionItemsReturned: returnedItems.length,\n memberActivitiesTotal,\n memberActivitiesReturned,\n topMembersTotal,\n topMembersReturned,\n itemFormat,\n toolResultTruncated: true,\n truncatedReasons,\n }\n}\n\nfunction limitGlobalActivitySummaryToBudget(\n fullData: GlobalActivityModelData,\n maxToolResultTokens: number | undefined,\n countTokens: (text: string) => number\n): unknown {\n if (!maxToolResultTokens || maxToolResultTokens <= 0) return fullData\n if (countTokens(JSON.stringify(fullData)) <= maxToolResultTokens) return fullData\n\n const totalDailyPoints = fullData.dailyActivity.length\n const buildCompactedDailyData = (returned: number) => ({\n ...fullData,\n dailyActivity: sampleEvenly(fullData.dailyActivity, returned).map(\n (point) => [point.date, point.messageCount] as const\n ),\n selection: {\n dailyActivityTotal: totalDailyPoints,\n dailyActivityReturned: returned,\n dailyActivityFormat: 'date_message_count_tuples',\n toolResultTruncated: returned < totalDailyPoints,\n truncatedReasons: returned < totalDailyPoints ? ['daily_activity_budget'] : [],\n },\n })\n\n let low = 0\n let high = totalDailyPoints\n while (low < high) {\n const middle = Math.ceil((low + high) / 2)\n if (countTokens(JSON.stringify(buildCompactedDailyData(middle))) <= maxToolResultTokens) low = middle\n else high = middle - 1\n }\n const compacted = buildCompactedDailyData(low)\n if (countTokens(JSON.stringify(compacted)) <= maxToolResultTokens) return compacted\n\n const truncatedReasons = [...(totalDailyPoints > 0 ? ['daily_activity_budget'] : []), 'tool_result_budget']\n const selection = {\n dailyActivityTotal: totalDailyPoints,\n dailyActivityReturned: 0,\n dailyActivityFormat: 'omitted',\n toolResultTruncated: true,\n truncatedReasons,\n }\n const candidates: unknown[] = [\n {\n mode: fullData.mode,\n dataState: fullData.dataState,\n range: fullData.range,\n metrics: fullData.metrics,\n monthlyActivity: fullData.monthlyActivity,\n monthlyDirectContacts: fullData.monthlyDirectContacts,\n messageTypes: fullData.messageTypes,\n textLength: fullData.textLength,\n coverage: fullData.coverage,\n cache: fullData.cache,\n selection,\n },\n {\n mode: fullData.mode,\n dataState: fullData.dataState,\n range: fullData.range,\n metrics: fullData.metrics,\n coverage: fullData.coverage,\n cache: fullData.cache,\n selection,\n },\n { mode: fullData.mode, dataState: fullData.dataState, metrics: fullData.metrics, selection },\n { dataState: fullData.dataState, selection },\n { toolResultTruncated: true, truncatedReasons: ['tool_result_budget'] },\n {},\n ]\n return candidates.find((candidate) => countTokens(JSON.stringify(candidate)) <= maxToolResultTokens) ?? {}\n}\n\nfunction sampleEvenly<T>(items: T[], limit: number): T[] {\n if (limit <= 0 || items.length === 0) return []\n if (limit >= items.length) return [...items]\n if (limit === 1) return [items[items.length - 1]!]\n return Array.from({ length: limit }, (_, index) => {\n const sourceIndex = Math.round((index * (items.length - 1)) / (limit - 1))\n return items[sourceIndex]!\n })\n}\n\nfunction limitContactPageSizeToBudget(\n requestedPageSize: number | undefined,\n maxToolResultTokens: number | undefined\n): { value: number | undefined; limited: boolean } {\n if (!maxToolResultTokens || maxToolResultTokens <= 0) {\n return { value: requestedPageSize, limited: false }\n }\n const requested = Math.min(\n MAX_CONTACT_INSPECTION_PAGE_SIZE,\n Math.max(1, Math.floor(requestedPageSize ?? DEFAULT_CONTACT_INSPECTION_PAGE_SIZE))\n )\n // service 调用前先收缩分页,保证 nextCursor 指向模型实际看过的最后一批结果,而不是截断后的尾部。\n const maxChars = maxToolResultTokens * TOOL_RESULT_CHARS_PER_TOKEN\n const budgeted = Math.max(1, Math.floor((maxChars - TOOL_RESULT_BASE_CHARS) / CONTACT_SESSION_ESTIMATED_CHARS))\n return {\n value: budgeted < requested ? budgeted : requestedPageSize,\n limited: budgeted < requested,\n }\n}\n\nfunction limitSharedRequestToBudget(\n participantCount: number,\n requestedPageSize: number | undefined,\n requestedAnchorsPerPair: number | undefined,\n maxToolResultTokens: number | undefined\n): {\n pageSize: number | undefined\n maxAnchorsPerPair: number | undefined\n pageLimited: boolean\n anchorsLimited: boolean\n} {\n const normalizedAnchorsPerPair =\n requestedAnchorsPerPair === undefined\n ? undefined\n : Math.min(MAX_SHARED_ANCHORS_PER_PAIR, Math.max(0, Math.floor(requestedAnchorsPerPair)))\n if (!maxToolResultTokens || maxToolResultTokens <= 0) {\n return {\n pageSize: requestedPageSize,\n maxAnchorsPerPair: normalizedAnchorsPerPair,\n pageLimited: false,\n anchorsLimited: false,\n }\n }\n\n const pairCount = (participantCount * (participantCount - 1)) / 2\n const requestedPage = requestedPageSize ?? DEFAULT_SHARED_INSPECTION_PAGE_SIZE\n const requestedAnchors = normalizedAnchorsPerPair ?? DEFAULT_SHARED_ANCHORS_PER_PAIR\n const maxChars = maxToolResultTokens * TOOL_RESULT_CHARS_PER_TOKEN\n let maxAnchorsPerPair = requestedAnchors\n\n const estimateSessionChars = (anchorsPerPair: number): number =>\n SHARED_SESSION_BASE_CHARS +\n participantCount * SHARED_PARTICIPANT_ESTIMATED_CHARS +\n pairCount * (SHARED_PAIR_BASE_CHARS + anchorsPerPair * SHARED_ANCHOR_ESTIMATED_CHARS)\n\n while (maxAnchorsPerPair > 0 && TOOL_RESULT_BASE_CHARS + estimateSessionChars(maxAnchorsPerPair) > maxChars) {\n maxAnchorsPerPair--\n }\n const pageSize = Math.min(\n requestedPage,\n Math.max(1, Math.floor((maxChars - TOOL_RESULT_BASE_CHARS) / estimateSessionChars(maxAnchorsPerPair)))\n )\n return {\n pageSize,\n maxAnchorsPerPair,\n pageLimited: pageSize < requestedPage,\n anchorsLimited: maxAnchorsPerPair < requestedAnchors,\n }\n}\n\nfunction withToolResultBudgetReason<T extends CrossChatContactSessionsResult | CrossChatSharedInteractionsResult>(\n result: T\n): T {\n return {\n ...result,\n coverage: {\n ...result.coverage,\n truncated: true,\n truncatedReasons: [...new Set([...result.coverage.truncatedReasons, 'tool_result_budget' as const])],\n },\n }\n}\n\nfunction limitContactResultToBudget(\n result: CrossChatContactSessionsResult,\n maxToolResultTokens: number | undefined,\n countTokens: (text: string) => number\n): unknown {\n if (!maxToolResultTokens || maxToolResultTokens <= 0) return result\n if (countTokens(JSON.stringify(result)) <= maxToolResultTokens) return result\n\n // details 保留完整结构供 UI 和日志追溯;这里只逐级压缩模型可见文本,并始终保留 coverage/continuation。\n const compactLabels = {\n ...result,\n contact: result.contact ? { ...result.contact, displayName: truncateModelLabel(result.contact.displayName) } : null,\n sessions: result.sessions.map((session) => ({\n ...session,\n sessionName: truncateModelLabel(session.sessionName),\n memberName: truncateModelLabel(session.memberName),\n })),\n }\n const coreFacts = {\n algorithmVersion: result.algorithmVersion,\n contact: compactLabels.contact,\n appliedRange: result.appliedRange,\n summary: result.summary,\n sessions: result.sessions.map((session) => ({\n sessionId: session.sessionId,\n sessionName: truncateModelLabel(session.sessionName),\n sessionType: session.sessionType,\n platform: session.platform,\n presence: session.presence,\n ownMessageCount: session.ownMessageCount,\n sessionMessageCount: session.sessionMessageCount,\n firstOwnMessageTs: session.firstOwnMessageTs,\n lastOwnMessageTs: session.lastOwnMessageTs,\n activeDays: session.activeDays,\n memberCount: session.memberCount,\n sessionFirstMessageTs: session.sessionFirstMessageTs,\n lastMessageTs: session.lastMessageTs,\n })),\n coverage: result.coverage,\n }\n const identityFacts = {\n contact: result.contact\n ? {\n contactKey: result.contact.contactKey,\n displayName: truncateModelLabel(result.contact.displayName),\n platform: result.contact.platform,\n }\n : null,\n sessions: result.sessions.map((session) => ({\n sessionId: session.sessionId,\n sessionType: session.sessionType,\n presence: session.presence,\n ownMessageCount: session.ownMessageCount,\n lastOwnMessageTs: session.lastOwnMessageTs,\n })),\n coverage: result.coverage,\n }\n const coverageOnly = { coverage: result.coverage }\n const candidates: unknown[] = [compactLabels, coreFacts, identityFacts, coverageOnly]\n return (\n candidates.find((candidate) => countTokens(JSON.stringify(candidate)) <= maxToolResultTokens) ?? {\n truncated: true,\n truncatedReasons: ['tool_result_budget'],\n }\n )\n}\n\nfunction limitSharedModelResultToBudget(\n result: CrossChatSharedInteractionsResult,\n maxToolResultTokens: number | undefined,\n countTokens: (text: string) => number\n): unknown {\n if (!maxToolResultTokens || maxToolResultTokens <= 0) return result\n if (countTokens(JSON.stringify(result)) <= maxToolResultTokens) return result\n\n // details 保留完整调查结果;模型可见文本逐级压缩名称和锚点,并优先保留已被 cursor 消费的 session 身份。\n const compactLabels = {\n ...result,\n participants: result.participants.map((participant) => ({\n ...participant,\n displayName: truncateModelLabel(participant.displayName),\n })),\n sessions: result.sessions.map((session) => ({\n ...session,\n sessionName: truncateModelLabel(session.sessionName),\n participants: session.participants.map((participant) => ({\n ...participant,\n memberName: truncateModelLabel(participant.memberName),\n })),\n })),\n }\n const withAnchorLimit = (maxAnchorsPerPair: number) => ({\n ...compactLabels,\n sessions: compactLabels.sessions.map((session) => ({\n ...session,\n pairs: session.pairs.map((pair) => ({\n ...pair,\n anchors: pair.anchors.slice(0, maxAnchorsPerPair).map(({ sessionId: _sessionId, ...anchor }) => anchor),\n anchorsTruncated: pair.anchorsTruncated || pair.anchors.length > maxAnchorsPerPair,\n })),\n })),\n })\n const identityFacts = {\n algorithmVersion: result.algorithmVersion,\n proximityAlgorithmVersion: result.proximityAlgorithmVersion,\n participants: compactLabels.participants.map((participant) => ({\n index: participant.index,\n ref: participant.ref,\n status: participant.status,\n displayName: participant.displayName,\n platform: participant.platform,\n })),\n appliedRange: result.appliedRange,\n summary: result.summary,\n sessions: compactLabels.sessions.map((session) => ({\n sessionId: session.sessionId,\n sessionName: session.sessionName,\n sessionType: session.sessionType,\n platform: session.platform,\n lastMessageTs: session.lastMessageTs,\n memberCount: session.memberCount,\n priorityReasons: session.priorityReasons,\n proximityStatus: session.proximityStatus,\n })),\n coverage: result.coverage,\n }\n const coverageOnly = {\n summary: result.summary,\n coverage: result.coverage,\n }\n const continuationOnly = {\n coverage: {\n complete: result.coverage.complete,\n nextCursor: result.coverage.nextCursor,\n truncated: true,\n truncatedReasons: result.coverage.truncatedReasons,\n },\n }\n const candidates: unknown[] = [\n compactLabels,\n withAnchorLimit(2),\n withAnchorLimit(1),\n withAnchorLimit(0),\n identityFacts,\n coverageOnly,\n continuationOnly,\n { truncated: true, truncatedReasons: ['tool_result_budget'] },\n {},\n ]\n return candidates.find((candidate) => countTokens(JSON.stringify(candidate)) <= maxToolResultTokens) ?? {}\n}\n\nfunction truncateModelLabel(value: string): string {\n const chars = Array.from(value)\n return chars.length > MODEL_LABEL_MAX_LENGTH ? `${chars.slice(0, MODEL_LABEL_MAX_LENGTH).join('')}…` : value\n}\n\nasync function preprocessBySession(\n context: CrossChatToolExecutionContext,\n messages: CrossChatMessageSource[]\n): Promise<CrossChatMessageSource[]> {\n const bySession = new Map<string, CrossChatMessageSource[]>()\n for (const message of messages) {\n const group = bySession.get(message.sessionId) ?? []\n group.push({ ...message })\n bySession.set(message.sessionId, group)\n }\n const safe: CrossChatMessageSource[] = []\n const processedBySession = new Map<string, Map<number, CrossChatMessageSource>>()\n for (const [sessionId, group] of bySession) {\n const processed = await context.preprocessMessagesBySession(sessionId, group)\n const byMessageId = new Map<number, CrossChatMessageSource>()\n for (const message of processed) {\n if (message.sessionId === sessionId) byMessageId.set(message.messageId, message)\n }\n processedBySession.set(sessionId, byMessageId)\n }\n for (const message of messages) {\n const processed = processedBySession.get(message.sessionId)?.get(message.messageId)\n if (processed) safe.push(processed)\n }\n return safe\n}\n\nfunction limitMessagesToBudget(\n messages: CrossChatMessageSource[],\n maxToolResultTokens: number | undefined,\n buildPayload: (messages: CrossChatMessageSource[], truncated: boolean) => unknown,\n options: {\n priorityIndexes?: number[]\n continueAfterOverflow?: boolean\n countTokens?: (text: string) => number\n } = {}\n): { messages: CrossChatMessageSource[]; truncated: boolean } {\n const prepared = messages.map((message) => ({\n ...message,\n content: message.content.length > 500 ? `${message.content.slice(0, 500)}…` : message.content,\n }))\n if (!maxToolResultTokens || maxToolResultTokens <= 0) {\n return { messages: prepared, truncated: false }\n }\n\n const countTokens = options.countTokens ?? estimatePayloadTokens\n const priorityIndexes = [...new Set(options.priorityIndexes ?? prepared.map((_, index) => index))].filter(\n (index) => index >= 0 && index < prepared.length\n )\n\n if (!options.continueAfterOverflow) {\n let low = 0\n let high = priorityIndexes.length\n // 普通搜索按优先级取连续前缀,使用二分将大结果集的完整序列化和 tokenizer 调用降到对数级。\n while (low < high) {\n const middle = Math.ceil((low + high) / 2)\n const candidateIndexes = priorityIndexes.slice(0, middle).sort((left, right) => left - right)\n const candidateMessages = candidateIndexes.map((candidateIndex) => prepared[candidateIndex])\n const truncated = candidateMessages.length < prepared.length\n const serializedCandidate = JSON.stringify(buildPayload(candidateMessages, truncated))\n if (countTokens(serializedCandidate) <= maxToolResultTokens) low = middle\n else high = middle - 1\n }\n const limitedIndexes = priorityIndexes.slice(0, low).sort((left, right) => left - right)\n const limited = limitedIndexes.map((index) => prepared[index])\n return { messages: limited, truncated: limited.length < prepared.length }\n }\n\n const selectedIndexes = new Set<number>()\n for (const index of priorityIndexes) {\n const candidateIndexes = [...selectedIndexes, index].sort((left, right) => left - right)\n const candidateMessages = candidateIndexes.map((candidateIndex) => prepared[candidateIndex])\n const truncated = candidateMessages.length < prepared.length\n const serializedCandidate = JSON.stringify(buildPayload(candidateMessages, truncated))\n if (countTokens(serializedCandidate) > maxToolResultTokens) {\n if (options.continueAfterOverflow) continue\n break\n }\n selectedIndexes.add(index)\n }\n const limited = [...selectedIndexes].sort((left, right) => left - right).map((index) => prepared[index])\n return { messages: limited, truncated: limited.length < prepared.length }\n}\n\ntype EntityResolutionScopeItem =\n | { kind: 'contact'; contactIndex: number; session: CrossChatResolvedContactSession }\n | { kind: 'session'; sessionIndex: number; session: CrossChatResolvedSession }\n\nfunction limitEntityResolutionToBudget(\n resolution: CrossChatEntityResolution,\n contactLookups: CrossChatContactLookupResult[],\n maxToolResultTokens: number | undefined,\n injectedCountTokens?: (text: string) => number\n): unknown {\n const fullData = { ...resolution, contactLookups }\n if (!maxToolResultTokens || maxToolResultTokens <= 0) return fullData\n\n const countTokens = injectedCountTokens ?? estimatePayloadTokens\n const scopeItems = buildEntityResolutionScopePriority(resolution)\n let includeLookupHints = true\n let emptyPayload = buildEntityResolutionPayload(resolution, contactLookups, scopeItems, 0, includeLookupHints)\n // 先舍弃只用于姓名消歧的来源提示,把预算优先留给后续工具真正需要的精确 scope。\n if (countTokens(JSON.stringify(emptyPayload)) > maxToolResultTokens) {\n includeLookupHints = false\n emptyPayload = buildEntityResolutionPayload(resolution, contactLookups, scopeItems, 0, includeLookupHints)\n }\n if (countTokens(JSON.stringify(emptyPayload)) > maxToolResultTokens) {\n return buildMinimalEntityResolutionPayload(resolution, contactLookups, maxToolResultTokens, countTokens)\n }\n\n let low = 0\n let high = scopeItems.length\n // 最终 JSON 每次都用平台 tokenizer 复核;二分前缀避免大量来源时反复编码完整增长数组。\n while (low < high) {\n const middle = Math.ceil((low + high) / 2)\n const candidate = buildEntityResolutionPayload(resolution, contactLookups, scopeItems, middle, includeLookupHints)\n if (countTokens(JSON.stringify(candidate)) <= maxToolResultTokens) low = middle\n else high = middle - 1\n }\n return buildEntityResolutionPayload(resolution, contactLookups, scopeItems, low, includeLookupHints)\n}\n\nfunction buildEntityResolutionScopePriority(resolution: CrossChatEntityResolution): EntityResolutionScopeItem[] {\n const items: EntityResolutionScopeItem[] = []\n // 用户显式选择的会话优先;联系人来源按最近时间轮询,避免第一个联系人耗尽全部预算。\n for (const [sessionIndex, session] of resolution.sessions.entries()) {\n if (session.status === 'resolved' && session.session) items.push({ kind: 'session', sessionIndex, session })\n }\n\n const contactSessions = resolution.contacts.map((contact) =>\n [...contact.sessions].sort(\n (left, right) =>\n (right.lastMessageTs ?? Number.NEGATIVE_INFINITY) - (left.lastMessageTs ?? Number.NEGATIVE_INFINITY)\n )\n )\n for (let depth = 0; ; depth++) {\n let added = false\n for (const [contactIndex, sessions] of contactSessions.entries()) {\n const session = sessions[depth]\n if (!session) continue\n items.push({ kind: 'contact', contactIndex, session })\n added = true\n }\n if (!added) break\n }\n return items\n}\n\nfunction buildEntityResolutionPayload(\n resolution: CrossChatEntityResolution,\n contactLookups: CrossChatContactLookupResult[],\n scopeItems: EntityResolutionScopeItem[],\n selectedScopeCount: number,\n includeLookupHints: boolean\n): Record<string, unknown> {\n const selectedContactSessions = new Map<number, CrossChatResolvedContactSession[]>()\n const selectedSessionIndexes = new Set<number>()\n for (const item of scopeItems.slice(0, selectedScopeCount)) {\n if (item.kind === 'session') {\n selectedSessionIndexes.add(item.sessionIndex)\n continue\n }\n const sessions = selectedContactSessions.get(item.contactIndex) ?? []\n sessions.push(item.session)\n selectedContactSessions.set(item.contactIndex, sessions)\n }\n\n const truncated = selectedScopeCount < scopeItems.length\n const contacts = resolution.contacts.map((contact, index) => {\n const sessions = selectedContactSessions.get(index) ?? []\n return {\n ref: contact.ref,\n status: contact.status,\n cacheStatus: contact.cacheStatus,\n sessionCount: contact.sessions.length,\n returnedSessions: sessions.length,\n sessions,\n unresolvedSessionCount: contact.unresolvedSessionIds.length,\n failedSessionCount: contact.failedSessionIds.length,\n }\n })\n const sessions = resolution.sessions.filter(\n (session, index) => session.status === 'unresolved' || selectedSessionIndexes.has(index)\n )\n\n return {\n contacts,\n sessions,\n unresolved: resolution.unresolved,\n coverage: {\n ...resolution.coverage,\n returnedContactEntities: contacts.length,\n returnedSessionEntities: sessions.length,\n returnedSourceScopes: selectedScopeCount,\n truncated,\n truncatedReasons: truncated ? ['tool_result_budget'] : [],\n },\n contactLookups: buildModelContactLookups(contactLookups, includeLookupHints),\n }\n}\n\nfunction buildModelContactLookups(\n contactLookups: CrossChatContactLookupResult[],\n includeHints: boolean\n): Array<Record<string, unknown>> {\n return contactLookups.map((lookup) => ({\n query: lookup.query,\n status: lookup.status,\n cacheStatus: lookup.cacheStatus,\n totalCandidates: lookup.totalCandidates,\n candidates: lookup.candidates.map((candidate) => {\n const hints = includeHints && lookup.status === 'ambiguous' ? candidate.sourceSessions.slice(0, 3) : []\n return {\n contactKey: candidate.contactKey,\n displayName: candidate.displayName,\n platform: candidate.platform,\n aliases: candidate.aliases.slice(0, 8),\n aliasCount: candidate.aliases.length,\n sourceSessionCount: candidate.sourceSessions.length,\n sourceSessionHintsReturned: hints.length,\n sourceSessionHintsTruncated: lookup.status === 'ambiguous' && hints.length < candidate.sourceSessions.length,\n ...(hints.length > 0\n ? {\n sourceSessionHints: hints,\n }\n : {}),\n }\n }),\n }))\n}\n\nfunction buildMinimalEntityResolutionPayload(\n resolution: CrossChatEntityResolution,\n contactLookups: CrossChatContactLookupResult[],\n maxToolResultTokens: number,\n countTokens: (text: string) => number\n): Record<string, unknown> {\n const coverage = {\n ...resolution.coverage,\n returnedContactEntities: 0,\n returnedSessionEntities: 0,\n returnedSourceScopes: 0,\n truncated: true,\n truncatedReasons: ['tool_result_budget'],\n }\n const candidates: Array<Record<string, unknown>> = [\n {\n contacts: [],\n sessions: [],\n unresolved: [],\n coverage,\n contactLookups: contactLookups.map((lookup) => ({\n query: lookup.query,\n status: lookup.status,\n totalCandidates: lookup.totalCandidates,\n })),\n },\n { coverage },\n { truncated: true, truncatedReasons: ['tool_result_budget'] },\n ]\n return (\n candidates.find((candidate) => countTokens(JSON.stringify(candidate)) <= maxToolResultTokens) ?? {\n truncated: true,\n }\n )\n}\n\nfunction estimatePayloadTokens(text: string): number {\n // Browser/MCP 等未注入 Node tokenizer 的调用方仍需避免按 ASCII 密度低估中文结果。\n let cjkChars = 0\n let otherChars = 0\n for (const char of text) {\n const codePoint = char.codePointAt(0) ?? 0\n if (\n (codePoint >= 0x3400 && codePoint <= 0x4dbf) ||\n (codePoint >= 0x4e00 && codePoint <= 0x9fff) ||\n (codePoint >= 0x3040 && codePoint <= 0x30ff) ||\n (codePoint >= 0xac00 && codePoint <= 0xd7af)\n ) {\n cjkChars++\n } else {\n otherChars++\n }\n }\n return Math.ceil(cjkChars / 1.6 + otherChars / 4)\n}\n\nfunction buildContextPriority(messages: CrossChatMessageSource[], anchorMessageId: number): number[] {\n const anchorIndex = messages.findIndex((message) => message.messageId === anchorMessageId)\n if (anchorIndex < 0) return messages.map((_, index) => index)\n\n const indexes = [anchorIndex]\n for (let distance = 1; indexes.length < messages.length; distance++) {\n const before = anchorIndex - distance\n const after = anchorIndex + distance\n if (before >= 0) indexes.push(before)\n if (after < messages.length) indexes.push(after)\n }\n return indexes\n}\n\nfunction toModelMessage(message: CrossChatMessageSource): Record<string, unknown> {\n return {\n sessionId: message.sessionId,\n sessionName: message.sessionName,\n sessionType: message.sessionType,\n messageId: message.messageId,\n senderId: message.senderId,\n senderName: message.senderName,\n timestamp: message.timestamp,\n content: message.content,\n evidenceRole: message.evidenceRole,\n }\n}\n\nfunction summarizeEvidenceSelection(messages: CrossChatMessageSource[]): Record<string, number> {\n let matchedMessages = 0\n let contextMessages = 0\n let privateMessages = 0\n let groupMessages = 0\n for (const message of messages) {\n if (message.evidenceRole === 'context') contextMessages++\n else matchedMessages++\n if (message.sessionType === 'private') privateMessages++\n else groupMessages++\n }\n return { matchedMessages, contextMessages, privateMessages, groupMessages }\n}\n\nfunction toEvidenceSource(message: CrossChatMessageSource): CrossChatEvidencePayload['sources'][number] {\n return {\n sessionId: message.sessionId,\n sessionName: message.sessionName,\n sessionType: message.sessionType,\n platform: message.platform,\n messageId: message.messageId,\n senderName: message.senderName,\n timestamp: message.timestamp,\n snippet: message.content,\n }\n}\n\nfunction parseStringArray(value: unknown): string[] {\n if (!Array.isArray(value)) throw new Error('keywords must be an array')\n return value.map((item) => requireString(item, 'keyword')).filter(Boolean)\n}\n\nfunction parseNumberArray(value: unknown): number[] {\n if (!Array.isArray(value)) throw new Error('memberIds must be an array')\n return value.map((item) => requireNumber(item, 'memberId'))\n}\n\nfunction requireString(value: unknown, name: string): string {\n if (typeof value !== 'string' || !value.trim()) throw new Error(`${name} is required`)\n return value.trim()\n}\n\nfunction requireNumber(value: unknown, name: string): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) throw new Error(`${name} must be a number`)\n return value\n}\n\nfunction requireBoolean(value: unknown): boolean {\n if (typeof value !== 'boolean') throw new Error('include_roster_only must be a boolean')\n return value\n}\n\nfunction parseOptionalNumber(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n","import type { AIMemoryEntry, AIMemoryScope, AIMemorySourceType, AIEntityRef } from '@openchatlab/shared-types'\nimport { ChatType } from '@openchatlab/shared-types'\nimport type { CrossChatToolExecutionContext, JsonSchema, ToolDefinition, ToolResult } from '../types'\n\nconst readSchema: JsonSchema = {\n type: 'object',\n properties: {\n scope_type: { type: 'string', enum: ['global', 'self', 'contact', 'group'] },\n scope_id: {\n type: 'string',\n description: 'Stable contactKey or group sessionId. Omit for global and self memory.',\n },\n query: {\n type: 'string',\n description: 'Current question or topic used to rank memories inside the authorized scope.',\n },\n limit: { type: 'number', minimum: 1, maximum: 50, default: 20 },\n },\n required: ['scope_type'],\n}\n\nconst writeSchema: JsonSchema = {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Stable memory ID. Provide it to update an existing memory.' },\n scope_type: { type: 'string', enum: ['global', 'self', 'contact', 'group'] },\n scope_id: {\n type: 'string',\n description: 'Stable contactKey or group sessionId. Omit for global and self memory.',\n },\n content: { type: 'string', description: 'One durable fact or preference, without chat transcripts.' },\n source_type: {\n type: 'string',\n enum: ['user', 'ai'],\n description: 'Use user only for explicit user-provided facts or corrections; use ai for derived conclusions.',\n },\n },\n required: ['scope_type', 'content', 'source_type'],\n}\n\nconst forgetSchema: JsonSchema = {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Stable memory ID returned by memory_read or memory_write.' },\n },\n required: ['id'],\n}\n\nexport const memoryReadTool: ToolDefinition<CrossChatToolExecutionContext> = {\n name: 'memory_read',\n description:\n 'Read durable global preferences, facts about the user, or memories for one resolved contact/group. Pass the current question or topic as query to rank relevant entries inside that authorized scope. Self memory is read on demand and is never injected automatically. AI-derived memories are leads and must be re-verified against current chat evidence.',\n inputSchema: readSchema,\n handler: memoryReadHandler,\n}\n\nexport const memoryWriteTool: ToolDefinition<CrossChatToolExecutionContext> = {\n name: 'memory_write',\n description:\n 'Create or update one durable memory. Read the target scope first, use stable entity IDs, and never store transcripts, temporary requests, or ordinary statistics.',\n inputSchema: writeSchema,\n executionMode: 'sequential',\n handler: memoryWriteHandler,\n}\n\nexport const memoryForgetTool: ToolDefinition<CrossChatToolExecutionContext> = {\n name: 'memory_forget',\n description:\n 'Permanently delete one memory by its stable ID after the user asks to forget or confirms it is invalid.',\n inputSchema: forgetSchema,\n executionMode: 'sequential',\n handler: memoryForgetHandler,\n}\n\nasync function memoryReadHandler(\n params: Record<string, unknown>,\n context: CrossChatToolExecutionContext\n): Promise<ToolResult> {\n const scope = parseScope(params)\n await assertResolvableEntityScope(scope, context)\n const limit = parseLimit(params.limit)\n const query = optionalString(params.query)\n const searchResult = query\n ? context.memoryService.search(scope, query, context.locale)\n : { entries: context.memoryService.list(scope), retrievalMode: 'recent_fallback' as const }\n const allEntries = searchResult.entries\n const entries = allEntries.slice(0, limit)\n const truncated = allEntries.length > entries.length\n const verificationGuidance = entries.some((entry) => entry.sourceType === 'ai')\n ? context.locale?.startsWith('zh')\n ? '标记为 ai 的记忆只是调查线索,使用前必须重新查询原始聊天证据。'\n : 'Memories marked ai are investigation leads. Re-query the original chat evidence before using them.'\n : null\n const data = { entries, truncated, retrievalMode: searchResult.retrievalMode, verificationGuidance }\n return { content: JSON.stringify(data), data }\n}\n\nasync function memoryWriteHandler(\n params: Record<string, unknown>,\n context: CrossChatToolExecutionContext\n): Promise<ToolResult> {\n const scope = parseScope(params)\n await assertResolvableEntityScope(scope, context)\n const content = requireString(params.content, 'content')\n const sourceType = parseSourceType(params.source_type)\n\n const id = optionalString(params.id)\n let entry: AIMemoryEntry\n if (id) {\n const current = context.memoryService.get(id)\n if (!current) throw new Error(`AI memory not found: ${id}`)\n if (current.scopeType !== scope.scopeType || current.scopeId !== scope.scopeId) {\n throw new Error('AI memory scope does not match the existing memory')\n }\n entry = context.memoryService.update(id, {\n content,\n sourceType,\n sourceAIChatId: context.aiChatId,\n sourceMessageId: null,\n })\n } else {\n entry = context.memoryService.create({\n ...scope,\n content,\n sourceType,\n sourceAIChatId: context.aiChatId,\n sourceMessageId: null,\n })\n }\n\n context.reportMemoryChange?.(entry.id)\n return { content: JSON.stringify(entry), data: entry }\n}\n\nasync function memoryForgetHandler(\n params: Record<string, unknown>,\n context: CrossChatToolExecutionContext\n): Promise<ToolResult> {\n const id = requireString(params.id, 'id')\n const current = context.memoryService.get(id)\n if (!current) {\n const data = { id, deleted: false }\n return { content: JSON.stringify(data), data }\n }\n await assertResolvableEntityScope(current, context, true)\n const data = { id, deleted: context.memoryService.forget(id) }\n return { content: JSON.stringify(data), data }\n}\n\nfunction parseScope(params: Record<string, unknown>): AIMemoryScope {\n const scopeType = params.scope_type\n if (scopeType !== 'global' && scopeType !== 'self' && scopeType !== 'contact' && scopeType !== 'group') {\n throw new Error('scope_type must be global, self, contact, or group')\n }\n const scopeId = optionalString(params.scope_id)\n if (scopeType === 'global' || scopeType === 'self') {\n if (scopeId) throw new Error(`${scopeType} memory does not accept scope_id`)\n return { scopeType, scopeId: null }\n }\n if (!scopeId) throw new Error(`${scopeType} memory requires a stable scope_id`)\n return { scopeType, scopeId }\n}\n\nfunction parseSourceType(value: unknown): AIMemorySourceType {\n if (value !== 'user' && value !== 'ai') throw new Error('source_type must be user or ai')\n return value\n}\n\nfunction parseLimit(value: unknown): number {\n if (value === undefined) return 20\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 1 || value > 50) {\n throw new Error('limit must be an integer between 1 and 50')\n }\n return value\n}\n\nfunction requireString(value: unknown, field: string): string {\n const normalized = optionalString(value)\n if (!normalized) throw new Error(`${field} is required`)\n return normalized\n}\n\nfunction optionalString(value: unknown): string | null {\n if (typeof value !== 'string') return null\n return value.trim() || null\n}\n\nasync function assertResolvableEntityScope(\n scope: AIMemoryScope,\n context: CrossChatToolExecutionContext,\n requireCurrentTurnEntity = false\n): Promise<void> {\n if (scope.scopeType === 'global' || scope.scopeType === 'self') return\n\n const currentTurnRefs = [...(context.entityRefs ?? []), ...(context.resolvedEntityRefs ?? [])]\n const matchesCurrentTurn = currentTurnRefs.some((ref) => matchesMemoryScope(ref, scope))\n if ((requireCurrentTurnEntity || currentTurnRefs.length > 0) && !matchesCurrentTurn) {\n throw new Error('scope_id must match an entity selected or resolved for the current turn')\n }\n\n const ref: AIEntityRef =\n scope.scopeType === 'contact'\n ? { type: 'contact', contactKey: scope.scopeId!, displayName: scope.scopeId! }\n : { type: 'session', sessionId: scope.scopeId!, displayName: scope.scopeId!, sessionType: ChatType.GROUP }\n const resolution = await context.analysisService.resolveEntities([ref], {\n signal: context.abortSignal,\n })\n\n if (scope.scopeType === 'contact') {\n const resolved = resolution.contacts.some(\n (item) => item.ref.contactKey === scope.scopeId && (item.status === 'resolved' || item.status === 'partial')\n )\n if (!resolved) throw new Error('scope_id must be a resolvable stable contact ID')\n return\n }\n\n const resolved = resolution.sessions.some(\n (item) =>\n item.ref.sessionId === scope.scopeId && item.status === 'resolved' && item.session?.sessionType === ChatType.GROUP\n )\n if (!resolved) throw new Error('scope_id must be a resolvable stable group ID')\n}\n\nfunction matchesMemoryScope(ref: AIEntityRef, scope: AIMemoryScope): boolean {\n return scope.scopeType === 'contact'\n ? ref.type === 'contact' && ref.contactKey === scope.scopeId\n : ref.type === 'session' && ref.sessionType === ChatType.GROUP && ref.sessionId === scope.scopeId\n}\n","/**\n * 内置 SQL 分析工具定义集合\n *\n * 声明式 SQL 工具:每个定义在 LLM 眼中是一个 Function Calling 工具,\n * 执行时通过参数化 SQL 查询数据库,将结果格式化为文本返回给 LLM。\n */\n\nimport type { SqlToolDef } from '../types'\n\nexport const SQL_TOOL_DEFS: SqlToolDef[] = [\n // ==================== 通用分析 ====================\n {\n name: 'message_type_breakdown',\n description: '按消息类型统计近 N 天的消息分布(文本、图片、语音、表情等各有多少条)。适用于了解沟通方式偏好。',\n parameters: {\n type: 'object',\n properties: {\n days: { type: 'number', description: '统计最近多少天的数据' },\n },\n required: ['days'],\n },\n execution: {\n type: 'sqlite',\n query:\n \"SELECT CASE type WHEN 0 THEN '文本' WHEN 1 THEN '图片' WHEN 2 THEN '语音' WHEN 3 THEN '视频' WHEN 4 THEN '文件' WHEN 5 THEN '表情' WHEN 7 THEN '链接' WHEN 20 THEN '红包' WHEN 22 THEN '拍一拍' WHEN 80 THEN '系统消息' WHEN 81 THEN '撤回' ELSE '其他' END AS type_name, COUNT(*) AS msg_count, ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 1) AS percentage FROM message WHERE ts > unixepoch('now', '-' || @days || ' days') GROUP BY type ORDER BY msg_count DESC\",\n rowTemplate: '{type_name}:{msg_count} 条(占 {percentage}%)',\n summaryTemplate: '消息类型分布(共 {rowCount} 种类型):',\n fallback: '该时间范围内没有消息记录',\n },\n },\n {\n name: 'peak_chat_hours_by_member',\n description:\n '分析指定成员在近 N 天内每小时的发言量分布,找出其最活跃的时段。需要先通过 get_members 获取 member_id。',\n parameters: {\n type: 'object',\n properties: {\n member_id: { type: 'number', description: '成员 ID(通过 get_members 获取)' },\n days: { type: 'number', description: '统计最近多少天的数据', default: 30 },\n },\n required: ['member_id'],\n },\n execution: {\n type: 'sqlite',\n query:\n \"SELECT CAST(strftime('%H', ts, 'unixepoch', 'localtime') AS INTEGER) AS hour, COUNT(*) AS msg_count FROM message WHERE sender_id = @member_id AND ts > unixepoch('now', '-' || @days || ' days') GROUP BY hour ORDER BY msg_count DESC\",\n rowTemplate: '{hour}:00 — {msg_count} 条消息',\n summaryTemplate: '该成员各时段发言量(共 {rowCount} 个活跃时段):',\n fallback: '该成员在指定时间范围内没有发言记录',\n },\n },\n\n // ==================== 社群分析 ====================\n {\n name: 'member_activity_trend',\n description:\n '查看指定成员近 N 天的每日发言数量变化趋势。适用于观察某人是否变得更活跃或更沉默。需要先通过 get_members 获取 member_id。',\n parameters: {\n type: 'object',\n properties: {\n member_id: { type: 'number', description: '成员 ID(通过 get_members 获取)' },\n days: { type: 'number', description: '查看最近多少天的趋势' },\n },\n required: ['member_id', 'days'],\n },\n execution: {\n type: 'sqlite',\n query:\n \"SELECT date(ts, 'unixepoch', 'localtime') AS day, COUNT(*) AS msg_count FROM message WHERE sender_id = @member_id AND ts > unixepoch('now', '-' || @days || ' days') GROUP BY day ORDER BY day\",\n rowTemplate: '{day}:{msg_count} 条',\n summaryTemplate: '该成员近 {rowCount} 天有发言记录:',\n fallback: '该成员在指定时间范围内没有发言记录',\n },\n },\n {\n name: 'silent_members',\n description: '检测超过 N 天未发言的「沉默成员」。适用于社群运营中发现流失风险用户。',\n parameters: {\n type: 'object',\n properties: {\n days: { type: 'number', description: '多少天未发言算沉默', default: 7 },\n },\n required: ['days'],\n },\n execution: {\n type: 'sqlite',\n query:\n \"SELECT m.id AS member_id, COALESCE(m.group_nickname, m.account_name, m.platform_id) AS name, MAX(msg.ts) AS last_msg_ts, CAST((unixepoch('now') - MAX(msg.ts)) / 86400 AS INTEGER) AS silent_days FROM member m JOIN message msg ON msg.sender_id = m.id GROUP BY m.id HAVING silent_days >= @days ORDER BY silent_days DESC LIMIT 30\",\n rowTemplate: '{name} — 已沉默 {silent_days} 天',\n summaryTemplate: '共发现 {rowCount} 位沉默成员:',\n fallback: '没有发现超过指定天数未发言的成员,社群活跃度良好!',\n },\n },\n {\n name: 'reply_interaction_ranking',\n description: '分析群内的回复互动关系排行,找出谁回复谁最多。适用于发现社群中的核心互动关系和意见领袖。',\n parameters: {\n type: 'object',\n properties: {\n days: { type: 'number', description: '统计最近多少天的数据' },\n limit: { type: 'number', description: '返回前多少对互动关系', default: 10 },\n },\n required: ['days'],\n },\n execution: {\n type: 'sqlite',\n query:\n \"SELECT COALESCE(replier.group_nickname, replier.account_name) AS replier_name, COALESCE(original.group_nickname, original.account_name) AS original_name, COUNT(*) AS reply_count FROM message reply_msg JOIN message orig_msg ON reply_msg.reply_to_message_id = CAST(orig_msg.id AS TEXT) JOIN member replier ON reply_msg.sender_id = replier.id JOIN member original ON orig_msg.sender_id = original.id WHERE reply_msg.reply_to_message_id IS NOT NULL AND reply_msg.ts > unixepoch('now', '-' || @days || ' days') GROUP BY reply_msg.sender_id, orig_msg.sender_id ORDER BY reply_count DESC LIMIT @limit\",\n rowTemplate: '{replier_name} → {original_name}:{reply_count} 次回复',\n summaryTemplate: '回复互动 Top {rowCount}:',\n fallback: '该时间范围内没有回复互动记录',\n },\n },\n\n // ==================== 情感分析 ====================\n {\n name: 'mutual_interaction_pairs',\n description:\n '找出互动最频繁的成员对,基于双向消息时间接近度(一方发言后 5 分钟内另一方也发言即视为一次互动)。适用于发现关系亲密的好友组合。',\n parameters: {\n type: 'object',\n properties: {\n days: { type: 'number', description: '统计最近多少天的数据' },\n limit: { type: 'number', description: '返回前多少对', default: 10 },\n },\n required: ['days'],\n },\n execution: {\n type: 'sqlite',\n query:\n \"WITH ordered_messages AS (SELECT id, sender_id, ts, LAG(sender_id) OVER (ORDER BY ts, id) AS prev_sender_id, LAG(ts) OVER (ORDER BY ts, id) AS prev_ts FROM message WHERE type = 0 AND ts > unixepoch('now', '-' || @days || ' days')), pairs AS (SELECT CASE WHEN prev_sender_id < sender_id THEN prev_sender_id ELSE sender_id END AS member_a_id, CASE WHEN prev_sender_id < sender_id THEN sender_id ELSE prev_sender_id END AS member_b_id FROM ordered_messages WHERE prev_sender_id IS NOT NULL AND prev_sender_id != sender_id AND prev_ts IS NOT NULL AND ts <= prev_ts + 300) SELECT COALESCE(m1.group_nickname, m1.account_name) AS member_a, COALESCE(m2.group_nickname, m2.account_name) AS member_b, COUNT(*) AS interaction_count FROM pairs JOIN member m1 ON pairs.member_a_id = m1.id JOIN member m2 ON pairs.member_b_id = m2.id GROUP BY member_a_id, member_b_id ORDER BY interaction_count DESC LIMIT @limit\",\n rowTemplate: '{member_a} ↔ {member_b}:{interaction_count} 次互动',\n summaryTemplate: '互动最频繁的 {rowCount} 对好友:',\n fallback: '该时间范围内没有检测到明显的互动关系',\n },\n },\n {\n name: 'member_message_length_stats',\n description: '统计各成员的平均消息长度(仅文本消息),长消息通常意味着更用心的交流。适用于发现深度交流者。',\n parameters: {\n type: 'object',\n properties: {\n days: { type: 'number', description: '统计最近多少天的数据' },\n top_n: { type: 'number', description: '返回前多少名', default: 10 },\n },\n required: ['days'],\n },\n execution: {\n type: 'sqlite',\n query:\n \"SELECT COALESCE(m.group_nickname, m.account_name) AS name, COUNT(*) AS msg_count, ROUND(AVG(LENGTH(msg.content)), 1) AS avg_length, MAX(LENGTH(msg.content)) AS max_length FROM message msg JOIN member m ON msg.sender_id = m.id WHERE msg.type = 0 AND msg.content IS NOT NULL AND LENGTH(msg.content) > 0 AND msg.ts > unixepoch('now', '-' || @days || ' days') GROUP BY msg.sender_id HAVING msg_count >= 5 ORDER BY avg_length DESC LIMIT @top_n\",\n rowTemplate: '{name} — 平均 {avg_length} 字/条(共 {msg_count} 条,最长 {max_length} 字)',\n summaryTemplate: '消息长度 Top {rowCount}(更长 = 更用心):',\n fallback: '该时间范围内没有足够的文本消息数据',\n },\n },\n\n // ==================== 活跃度趋势 ====================\n {\n name: 'daily_active_members',\n description:\n '统计每日独立发言人数(DAU)和消息量,用于观察群活力变化趋势。适用于\"群活跃度趋势怎么样\"、\"最近有多少人在说话\"。',\n parameters: {\n type: 'object',\n properties: {\n days: { type: 'number', description: '统计最近多少天的数据', default: 30 },\n },\n required: ['days'],\n },\n execution: {\n type: 'sqlite',\n query:\n \"SELECT date(ts, 'unixepoch', 'localtime') AS day, COUNT(DISTINCT sender_id) AS active_members, COUNT(*) AS msg_count FROM message WHERE ts > unixepoch('now', '-' || @days || ' days') GROUP BY day ORDER BY day\",\n rowTemplate: '{day}:{active_members} 人活跃,{msg_count} 条消息',\n summaryTemplate: '近 {rowCount} 天的每日活跃人数趋势:',\n fallback: '该时间范围内没有消息记录',\n },\n },\n {\n name: 'conversation_initiator_stats',\n description: '统计每个成员发起会话(作为会话首条消息的发送者)的次数,找出谁最常开启话题。',\n parameters: {\n type: 'object',\n properties: {\n days: { type: 'number', description: '统计最近多少天的数据', default: 30 },\n limit: { type: 'number', description: '返回前多少名', default: 10 },\n },\n required: ['days'],\n },\n execution: {\n type: 'sqlite',\n query:\n \"SELECT COALESCE(m.group_nickname, m.account_name) AS name, COUNT(*) AS initiated_count FROM segment cs JOIN message_context mc ON mc.segment_id = cs.id JOIN message msg ON msg.id = mc.message_id JOIN member m ON msg.sender_id = m.id WHERE msg.ts = cs.start_ts AND cs.start_ts > unixepoch('now', '-' || @days || ' days') GROUP BY msg.sender_id ORDER BY initiated_count DESC LIMIT @limit\",\n rowTemplate: '{name}:发起 {initiated_count} 次话题',\n summaryTemplate: '话题发起者 Top {rowCount}:',\n fallback: '该时间范围内没有会话记录,可能需要先生成会话索引',\n },\n },\n {\n name: 'activity_heatmap',\n description: '返回 星期×小时 的消息数矩阵,适合生成活跃度热力图。weekday: 0=周日, 1=周一, ..., 6=周六。',\n parameters: {\n type: 'object',\n properties: {\n days: { type: 'number', description: '统计最近多少天的数据', default: 30 },\n },\n required: ['days'],\n },\n execution: {\n type: 'sqlite',\n query:\n \"SELECT CAST(strftime('%w', ts, 'unixepoch', 'localtime') AS INTEGER) AS weekday, CAST(strftime('%H', ts, 'unixepoch', 'localtime') AS INTEGER) AS hour, COUNT(*) AS msg_count FROM message WHERE ts > unixepoch('now', '-' || @days || ' days') GROUP BY weekday, hour ORDER BY weekday, hour\",\n rowTemplate: '星期{weekday} {hour}:00 — {msg_count} 条',\n summaryTemplate: '活跃度热力图数据(共 {rowCount} 个时段有消息):',\n fallback: '该时间范围内没有消息记录',\n },\n },\n\n // ==================== 客服分析 ====================\n {\n name: 'unanswered_messages',\n description:\n '查找近 N 天内未被回复的消息,这些可能是未解决的客户问题。仅统计文本消息且内容超过 10 字的(过滤简短寒暄)。',\n parameters: {\n type: 'object',\n properties: {\n days: { type: 'number', description: '查找最近多少天的数据' },\n limit: { type: 'number', description: '最多返回多少条', default: 20 },\n },\n required: ['days'],\n },\n execution: {\n type: 'sqlite',\n query:\n \"SELECT COALESCE(m.group_nickname, m.account_name) AS sender_name, datetime(msg.ts, 'unixepoch', 'localtime') AS send_time, SUBSTR(msg.content, 1, 100) AS content_preview FROM message msg JOIN member m ON msg.sender_id = m.id WHERE msg.type = 0 AND msg.content IS NOT NULL AND LENGTH(msg.content) > 10 AND msg.ts > unixepoch('now', '-' || @days || ' days') AND NOT EXISTS (SELECT 1 FROM message reply WHERE reply.reply_to_message_id = CAST(msg.id AS TEXT)) AND NOT EXISTS (SELECT 1 FROM message next WHERE next.sender_id != msg.sender_id AND next.ts > msg.ts AND next.ts <= msg.ts + 1800) ORDER BY msg.ts DESC LIMIT @limit\",\n rowTemplate: '[{send_time}] {sender_name}:{content_preview}',\n summaryTemplate: '共发现 {rowCount} 条可能未被回复的消息:',\n fallback: '该时间范围内所有消息都已得到回复,服务质量很好!',\n },\n },\n]\n","/**\n * 声明式 SQL 工具执行器\n *\n * 将 SqlToolDef 转换为 ToolDefinition,通过 dataProvider.executeParameterizedSql 执行。\n */\n\nimport type { ToolDefinition, ToolExecutionContext, ToolResult, SqlToolDef } from '../types'\n\nfunction formatRow(template: string, row: Record<string, unknown>): string {\n return template.replace(/\\{(\\w+)\\}/g, (_, col) => {\n const val = row[col]\n return val !== null && val !== undefined ? String(val) : ''\n })\n}\n\nfunction resolveTemplate(\n toolName: string,\n key: string,\n fallback: string,\n translateFn?: (key: string) => string | undefined\n): string {\n if (!translateFn) return fallback\n const i18nKey = `ai.tools.${toolName}.${key}`\n return translateFn(i18nKey) ?? fallback\n}\n\nexport function createSqlToolDefinition(def: SqlToolDef): ToolDefinition {\n return {\n name: def.name,\n description: def.description,\n inputSchema: def.parameters,\n category: 'analysis',\n handler: async (params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> => {\n const rows = await context.dataProvider!.executeParameterizedSql(def.execution.query, params)\n\n const fallback = resolveTemplate(def.name, 'fallback', def.execution.fallback, context.translateTemplate)\n\n if (!rows || rows.length === 0) {\n return {\n content: fallback,\n data: { rows: [], rowCount: 0 },\n }\n }\n\n const rowTemplate = resolveTemplate(def.name, 'rowTemplate', def.execution.rowTemplate, context.translateTemplate)\n const summaryTemplate = def.execution.summaryTemplate\n ? resolveTemplate(def.name, 'summaryTemplate', def.execution.summaryTemplate, context.translateTemplate)\n : undefined\n\n const lines: string[] = []\n\n if (summaryTemplate) {\n lines.push(summaryTemplate.replace(/\\{rowCount\\}/g, String(rows.length)))\n lines.push('')\n }\n\n for (const row of rows) {\n lines.push(formatRow(rowTemplate, row as Record<string, unknown>))\n }\n\n return {\n content: lines.join('\\n'),\n data: { rows, rowCount: rows.length },\n }\n },\n }\n}\n\nexport function createAllSqlToolDefinitions(defs: SqlToolDef[]): ToolDefinition[] {\n return defs.map(createSqlToolDefinition)\n}\n","/**\n * Tool registries\n *\n * AGENT_TOOL_REGISTRY: full toolset for Server Agent / Electron Agent\n * (core + analysis + raw SQL + declarative SQL tools).\n * MCP_TOOL_REGISTRY: slim toolset for MCP Server — core + analysis + raw SQL\n * plus MCP-specific session-discovery tools. Omits declarative SQL tools\n * to keep tool-schema token cost low for external AI agents.\n */\n\nimport type { ToolDefinition } from './types'\n\nimport { sqlQueryTool, schemaTool } from './definitions/sql-query'\nimport { renderChartTool } from './definitions/render-chart'\nimport { sessionInfoTool } from './definitions/session-info'\nimport { sessionsListTool } from './definitions/sessions'\nimport { chatOverviewTool } from './definitions/chat-overview'\nimport { searchMessagesTool } from './definitions/search-messages'\nimport { deepSearchMessagesTool } from './definitions/deep-search-messages'\nimport { getMessageContextTool } from './definitions/get-message-context'\nimport { getSegmentMessagesTool } from './definitions/get-segment-messages'\nimport { getMembersTool } from './definitions/get-members'\nimport { memberStatsTool } from './definitions/member-stats'\nimport { timeStatsTool } from './definitions/time-stats'\nimport { recentMessagesTool } from './definitions/recent-messages'\nimport { getMemberNameHistoryTool } from './definitions/get-member-name-history'\nimport { getConversationBetweenTool } from './definitions/get-conversation-between'\nimport { getSegmentSummariesTool } from './definitions/get-segment-summaries'\nimport { responseTimeAnalysisTool } from './definitions/response-time-analysis'\nimport { keywordFrequencyTool } from './definitions/keyword-frequency'\nimport { semanticSearchCurrentChatTool } from './definitions/semantic-search-current-chat'\nimport { retrieveChatEvidenceTool } from './definitions/retrieve-chat-evidence'\nimport {\n getCrossChatMessageContextTool,\n getCrossChatOverviewTool,\n getGlobalActivitySummaryTool,\n inspectContactSessionsTool,\n inspectSharedInteractionsTool,\n rankGroupSessionsTool,\n rankPrivateContactsTool,\n readRecentSessionTool,\n resolveChatEntitiesTool,\n searchMessagesGloballyTool,\n} from './definitions/cross-chat-tools'\nimport { memoryForgetTool, memoryReadTool, memoryWriteTool } from './definitions/memory-tools'\nimport { SQL_TOOL_DEFS, createAllSqlToolDefinitions } from './sql'\n\n/**\n * Core + analysis + raw SQL — shared between Agent and MCP.\n * New non-SQL tools added here will automatically appear in both registries.\n */\nconst SHARED_TOOLS: ToolDefinition[] = [\n // Core\n chatOverviewTool,\n searchMessagesTool,\n deepSearchMessagesTool,\n recentMessagesTool,\n getMessageContextTool,\n getSegmentMessagesTool,\n getMembersTool,\n schemaTool,\n\n // Analysis\n memberStatsTool,\n timeStatsTool,\n getMemberNameHistoryTool,\n getConversationBetweenTool,\n getSegmentSummariesTool,\n responseTimeAnalysisTool,\n keywordFrequencyTool,\n renderChartTool,\n\n // Raw SQL\n sqlQueryTool,\n]\n\n/**\n * Agent full toolset (Server Agent / Electron Agent).\n * Includes declarative SQL convenience tools on top of the shared set.\n *\n * semantic_search_current_chat 仅在 AGENT registry,不进 MCP(语义片段外部访问的隐私/权限后续单独设计)。\n * runner 会按当前会话是否可检索动态过滤,未启用/无 chunk/需重建时不暴露给 LLM。\n */\nexport const AGENT_TOOL_REGISTRY: ToolDefinition[] = [\n ...SHARED_TOOLS,\n semanticSearchCurrentChatTool,\n retrieveChatEvidenceTool,\n ...createAllSqlToolDefinitions(SQL_TOOL_DEFS),\n]\n\n/** Dedicated global-analysis tools. Never merge this registry into session Agent or MCP registries. */\nexport const CROSS_CHAT_AGENT_TOOL_REGISTRY = [\n resolveChatEntitiesTool,\n readRecentSessionTool,\n searchMessagesGloballyTool,\n getCrossChatMessageContextTool,\n getCrossChatOverviewTool,\n rankPrivateContactsTool,\n rankGroupSessionsTool,\n getGlobalActivitySummaryTool,\n inspectContactSessionsTool,\n inspectSharedInteractionsTool,\n memoryReadTool,\n memoryWriteTool,\n memoryForgetTool,\n]\n\n/** 语义检索工具名(runner 动态过滤用) */\nexport const SEMANTIC_SEARCH_TOOL_NAME = semanticSearchCurrentChatTool.name\n\n/** 证据检索工具名(planner / runner 判断用) */\nexport const RETRIEVE_CHAT_EVIDENCE_TOOL_NAME = retrieveChatEvidenceTool.name\n\n/**\n * MCP Server toolset — slim registry optimised for external AI agents.\n *\n * Includes MCP-specific session-discovery tools + shared core/analysis tools.\n * Omits declarative SQL tools to reduce tool-schema token overhead (~40% saving).\n * LLMs can use execute_sql + get_schema for any custom query.\n */\nexport const MCP_TOOL_REGISTRY: ToolDefinition[] = [\n // MCP-specific: session discovery & schema\n sessionsListTool,\n sessionInfoTool,\n // Shared core + analysis + raw SQL\n ...SHARED_TOOLS,\n]\n\n/**\n * 按名称查找工具(在所有注册表中查找)\n */\nexport function getToolByName(name: string): ToolDefinition | undefined {\n return AGENT_TOOL_REGISTRY.find((t) => t.name === name) || MCP_TOOL_REGISTRY.find((t) => t.name === name)\n}\n","/**\n * CoreDataProvider\n *\n * ToolDataProvider implementation backed by @openchatlab/core query functions.\n * Used by Server / MCP, accessing SQLite through DatabaseAdapter.\n */\n\nimport type { DatabaseAdapter } from '@openchatlab/core'\nimport {\n searchMessagesByKeywords,\n queryMessages,\n getMemberActivity,\n getHourlyActivity,\n getWeekdayActivity,\n getDailyActivity,\n getMonthlyActivity,\n executeReadonlySql,\n getDatabaseSchema,\n getMessageContext as coreGetMessageContext,\n getSearchMessageContext as coreGetSearchMessageContext,\n getConversationBetween as coreGetConversationBetween,\n getMemberNameHistory as coreGetMemberNameHistory,\n getMembersWithAliases,\n executeParameterizedSql as coreExecuteParameterizedSql,\n getChatOverview as coreGetChatOverview,\n getSegmentMessages as coreGetSegmentMessages,\n getSegmentSummaries as coreGetSegmentSummaries,\n} from '@openchatlab/core'\nimport type {\n ToolDataProvider,\n SearchMessagesOptions,\n SearchMessagesResult,\n MemberStatItem,\n SchemaTableInfo,\n ToolTimeRange,\n ChatOverviewResult,\n MemberInfo,\n NameHistoryItem,\n SegmentMessagesResult,\n ConversationResult,\n SegmentSummaryItem,\n RawMessage,\n} from '../types'\n\nconst TOOL_MESSAGE_LIMIT_CAP = 50000\n\nexport class CoreDataProvider implements ToolDataProvider {\n constructor(private db: DatabaseAdapter) {}\n\n async searchMessages(keywords: string[], options?: SearchMessagesOptions): Promise<SearchMessagesResult> {\n const result = searchMessagesByKeywords(this.db, keywords, {\n startTs: options?.timeFilter?.startTs,\n endTs: options?.timeFilter?.endTs,\n senderId: options?.senderId,\n limit: options?.limit ?? 50,\n offset: options?.offset,\n matchMode: options?.matchMode,\n excludeKeywords: options?.excludeKeywords,\n sort: options?.sort,\n })\n return {\n messages: result.messages.map((m) => ({\n id: m.id,\n senderId: m.senderId,\n senderName: m.senderName,\n senderPlatformId: m.senderPlatformId,\n content: m.content,\n timestamp: m.timestamp,\n })),\n total: result.total ?? result.messages.length,\n }\n }\n\n async deepSearchMessages(keywords: string[], options?: SearchMessagesOptions): Promise<SearchMessagesResult> {\n return this.searchMessages(keywords, options)\n }\n\n async getSearchMessageContext(\n messageIds: number[],\n contextBefore: number,\n contextAfter: number\n ): Promise<RawMessage[]> {\n return coreGetSearchMessageContext(this.db, messageIds, contextBefore, contextAfter)\n }\n\n async getRecentMessages(options?: { timeFilter?: ToolTimeRange; limit?: number }): Promise<SearchMessagesResult> {\n const result = queryMessages(this.db, {\n limit: options?.limit ?? 50,\n maxLimit: TOOL_MESSAGE_LIMIT_CAP,\n startTs: options?.timeFilter?.startTs,\n endTs: options?.timeFilter?.endTs,\n })\n return {\n messages: result.messages.map((m) => ({\n id: m.id,\n senderId: m.senderId,\n senderName: m.senderName,\n senderPlatformId: m.senderPlatformId,\n content: m.content,\n timestamp: m.timestamp,\n })),\n total: result.total,\n }\n }\n\n async getMessageContext(messageIds: number[], contextSize: number): Promise<RawMessage[]> {\n return coreGetMessageContext(this.db, messageIds, contextSize)\n }\n\n async getChatOverview(topN?: number): Promise<ChatOverviewResult | null> {\n return coreGetChatOverview(this.db, topN)\n }\n\n async getMembers(): Promise<MemberInfo[]> {\n return getMembersWithAliases(this.db)\n }\n\n async getMemberStats(options?: { timeFilter?: ToolTimeRange; top?: number }): Promise<MemberStatItem[]> {\n const top = options?.top ?? 20\n const members = getMemberActivity(this.db, options?.timeFilter)\n return members.slice(0, top).map((m) => ({\n name: m.name,\n messageCount: m.messageCount,\n percentage: m.percentage,\n }))\n }\n\n async getMemberNameHistory(memberId: number): Promise<NameHistoryItem[]> {\n return coreGetMemberNameHistory(this.db, memberId)\n }\n\n async getTimeStats(\n type: 'hourly' | 'weekday' | 'daily' | 'monthly',\n options?: { timeFilter?: ToolTimeRange }\n ): Promise<unknown[]> {\n const filter = options?.timeFilter\n switch (type) {\n case 'weekday':\n return getWeekdayActivity(this.db, filter)\n case 'daily':\n return getDailyActivity(this.db, filter)\n case 'monthly':\n return getMonthlyActivity(this.db, filter)\n case 'hourly':\n default:\n return getHourlyActivity(this.db, filter)\n }\n }\n\n async getSegmentMessages(segmentId: number, limit?: number): Promise<SegmentMessagesResult | null> {\n return coreGetSegmentMessages(this.db, segmentId, limit)\n }\n\n async getSegmentSummaries(options?: { limit?: number; timeFilter?: ToolTimeRange }): Promise<SegmentSummaryItem[]> {\n return coreGetSegmentSummaries(this.db, options)\n }\n\n async getConversationBetween(\n memberId1: number,\n memberId2: number,\n timeFilter?: ToolTimeRange,\n limit?: number\n ): Promise<ConversationResult> {\n return coreGetConversationBetween(this.db, memberId1, memberId2, timeFilter, limit)\n }\n\n async executeSql(sql: string, options?: { maxRows?: number }): Promise<unknown> {\n return executeReadonlySql(this.db, sql, options?.maxRows)\n }\n\n async executeParameterizedSql<T = Record<string, unknown>>(\n query: string,\n params: Record<string, unknown>\n ): Promise<T[]> {\n return coreExecuteParameterizedSql<T>(this.db, query, params)\n }\n\n async getSchema(): Promise<SchemaTableInfo[]> {\n return getDatabaseSchema(this.db)\n }\n}\n","import type { JsonSchema, ToolDefinition } from './types'\nimport { isChineseLocale } from './utils/format'\n\ninterface EnglishToolMetadata {\n /** Omitted when the definition description is already English. */\n description?: string\n properties?: Record<string, string>\n}\n\n/**\n * English tool/parameter descriptions handed to the LLM on non-Chinese locales.\n *\n * Only translates text the definitions write in Chinese: tools whose definition description and\n * parameter descriptions are already English have no entry here, and a tool with an English\n * description but Chinese parameters lists only `properties`. Copying English text into this table\n * would let the two copies drift apart (tool-metadata.test.ts enforces both rules).\n */\nexport const ENGLISH_TOOL_METADATA: Record<string, EnglishToolMetadata> = {\n get_chat_overview: {\n description:\n 'Get a chat overview including its name, platform, message and member counts, time range, and most active members.',\n properties: { top_n: 'Number of most active members to return. Defaults to 10.' },\n },\n search_messages: {\n description:\n 'Search chat messages by keywords, with optional time-range and sender filters. Use this for topic or keyword lookup.',\n properties: {\n keywords: 'Keywords to search for.',\n sender_id: 'Filter by sender ID obtained from get_members.',\n limit: 'Maximum number of messages to return.',\n start_time: 'Start time in YYYY-MM-DD HH:mm format.',\n end_time: 'End time in YYYY-MM-DD HH:mm format.',\n },\n },\n deep_search_messages: {\n description:\n 'Search messages using slower substring matching. Use this for exact phrase matches or when regular search misses results.',\n properties: {\n keywords: 'Keywords to search for.',\n sender_id: 'Filter by sender ID obtained from get_members.',\n limit: 'Maximum number of messages to return.',\n start_time: 'Start time in YYYY-MM-DD HH:mm format.',\n end_time: 'End time in YYYY-MM-DD HH:mm format.',\n },\n },\n get_recent_messages: {\n description:\n 'Get messages from a specified time range. Use this for questions such as what people have discussed recently.',\n properties: {\n limit: 'Maximum number of messages to return.',\n start_time: 'Start time in YYYY-MM-DD HH:mm format.',\n end_time: 'End time in YYYY-MM-DD HH:mm format.',\n },\n },\n get_message_context: {\n description: 'Get the surrounding chat messages for one or more message IDs.',\n properties: {\n message_ids: 'Message IDs whose surrounding context should be returned.',\n context_size: 'Number of messages to include before and after each message. Defaults to 20.',\n },\n },\n get_segment_messages: {\n description: 'Get the complete message list for a conversation segment found with get_segment_summaries.',\n properties: {\n segment_id: 'Segment ID obtained from get_segment_summaries.',\n limit: 'Maximum number of messages to return.',\n },\n },\n get_members: {\n description: 'Get chat members with their basic information, aliases, and message counts.',\n properties: {\n search: 'Filter members by name, alias, or platform ID.',\n limit: 'Maximum number of members to return.',\n },\n },\n get_member_stats: {\n description: 'Get the member activity ranking with message counts and percentages.',\n properties: { top: 'Number of most active members to return.' },\n },\n get_time_stats: {\n description: 'Get chat activity grouped by hour, weekday, day, or month.',\n properties: {\n type: 'Grouping type: hourly, weekday, daily, or monthly.',\n start_time: 'Start time in YYYY-MM-DD HH:mm format.',\n end_time: 'End time in YYYY-MM-DD HH:mm format.',\n },\n },\n get_conversation_between: {\n description:\n 'Get messages exchanged between two members. Obtain both member IDs from get_members before calling this tool.',\n properties: {\n member_id_1: 'First member ID obtained from get_members.',\n member_id_2: 'Second member ID obtained from get_members.',\n limit: 'Maximum number of messages to return.',\n start_time: 'Start time in YYYY-MM-DD HH:mm format.',\n end_time: 'End time in YYYY-MM-DD HH:mm format.',\n },\n },\n get_member_name_history: {\n description: \"Get a member's nickname change history.\",\n properties: { member_id: 'Member ID obtained from get_members.' },\n },\n get_schema: {\n description: 'Get the chat database schema as CREATE TABLE statements.',\n },\n execute_sql: {\n description:\n 'Run a read-only SELECT query against the chat database. Use get_schema first when needed and add an explicit LIMIT.',\n properties: {\n sql: 'Read-only SELECT query to execute. Add an explicit LIMIT when possible.',\n max_rows: 'Maximum rows to return. Defaults to 1000 and is also capped by the execution context.',\n },\n },\n get_segment_summaries: {\n description:\n 'Get the list of segment summaries for a quick view of the topics discussed in the chat history. Topics that have been discussed can be searched by keyword.',\n properties: {\n keywords: 'Filter summary content by keywords.',\n limit: 'Maximum number of segments to return. Defaults to 20.',\n start_time: 'Start time in YYYY-MM-DD HH:mm format.',\n end_time: 'End time in YYYY-MM-DD HH:mm format.',\n },\n },\n response_time_analysis: {\n description:\n 'Analyze the response-speed ranking of chat members, based on the median and mean of their reply intervals.',\n properties: {\n days: 'Number of most recent days of data to analyze. Defaults to 30.',\n top_n: 'Number of top-ranked members to return. Defaults to 10.',\n },\n },\n keyword_frequency: {\n description:\n 'Count the most frequent keywords in the chat, analyzing message content through NLP word segmentation.',\n properties: {\n days: 'Number of most recent days of data to analyze. Defaults to 30.',\n top_n: 'Number of top frequent words to return. Defaults to 50.',\n },\n },\n semantic_search_current_chat: {\n properties: {\n query:\n 'Semantic search query. Rewrite it into a natural-language description suited to searching the current chat history (centred on the facts/people/places/events/past mentions that need to be confirmed).',\n max_results:\n 'Expected number of relevant excerpts to return; optional. When omitted, the default configured by the user is used; it may be raised according to question complexity, with a hard limit of 20.',\n },\n },\n retrieve_chat_evidence: {\n properties: {\n query:\n 'The question or retrieval target that has to be confirmed with chat evidence, for example \"how many times have we travelled to Leshan\".',\n criteria:\n 'Judgement criteria: what counts and what does not. Counting or judgement questions should fill this in, for example \"counts: evidence of an actual trip/arrival/stay; does not count: plans only, travel guides, other people\\'s experiences, general chatter\".',\n keywords:\n 'Keyword list, given explicitly by you (the tool does not expand synonyms). Used by the hybrid/keyword modes for exact recall.',\n mode: 'auto (default)/hybrid (semantic + keyword)/semantic (semantic only)/keyword (keyword only). Counting historical facts usually uses hybrid.',\n max_results: 'Expected number of excerpts returned by the semantic path, with a hard limit of 20.',\n start_time: 'Start time in YYYY-MM-DD HH:mm format.',\n end_time: 'End time in YYYY-MM-DD HH:mm format.',\n },\n },\n message_type_breakdown: {\n description:\n 'Break the messages of the last N days down by message type (how many text, image, voice, sticker and other messages there are). Use this to understand communication-style preferences.',\n properties: { days: 'Number of most recent days of data to count.' },\n },\n peak_chat_hours_by_member: {\n description:\n \"Analyze the hourly distribution of a given member's messages over the last N days to find their most active hours. Obtain member_id from get_members before calling this tool.\",\n properties: {\n member_id: 'Member ID obtained from get_members.',\n days: 'Number of most recent days of data to count.',\n },\n },\n member_activity_trend: {\n description:\n \"View the trend of a given member's daily message counts over the last N days. Use this to observe whether someone has become more active or more silent. Obtain member_id from get_members before calling this tool.\",\n properties: {\n member_id: 'Member ID obtained from get_members.',\n days: 'Number of most recent days of trend to view.',\n },\n },\n silent_members: {\n description:\n 'Detect \"silent members\" who have not spoken for more than N days. Use this in community management to find users at risk of churn.',\n properties: { days: 'Number of days without speaking that counts as silent.' },\n },\n reply_interaction_ranking: {\n description:\n 'Analyze the ranking of reply interactions in the chat to find who replies to whom the most. Use this to discover the core interaction relationships and the opinion leaders in the community.',\n properties: {\n days: 'Number of most recent days of data to count.',\n limit: 'Number of top interaction pairs to return.',\n },\n },\n mutual_interaction_pairs: {\n description:\n 'Find the member pairs that interact most frequently, based on the temporal proximity of two-way messages (one interaction is counted when the other party also speaks within 5 minutes of one party speaking). Use this to discover closely connected friend pairs.',\n properties: {\n days: 'Number of most recent days of data to count.',\n limit: 'Number of top pairs to return.',\n },\n },\n member_message_length_stats: {\n description:\n 'Count the average message length of each member (text messages only); long messages usually mean more thoughtful communication. Use this to discover members who communicate in depth.',\n properties: {\n days: 'Number of most recent days of data to count.',\n top_n: 'Number of top-ranked members to return.',\n },\n },\n daily_active_members: {\n description:\n 'Count the daily unique speakers (DAU) and message volume, used to observe how the vitality of the chat changes. Use this for questions such as \"what is the chat activity trend\" and \"how many people have been talking recently\".',\n properties: { days: 'Number of most recent days of data to count.' },\n },\n conversation_initiator_stats: {\n description:\n \"Count how many times each member starts a conversation (as the sender of the conversation's first message) to find who opens topics most often.\",\n properties: {\n days: 'Number of most recent days of data to count.',\n limit: 'Number of top-ranked members to return.',\n },\n },\n activity_heatmap: {\n description:\n 'Return a weekday × hour matrix of message counts, suitable for generating an activity heatmap. weekday: 0=Sunday, 1=Monday, ..., 6=Saturday.',\n properties: { days: 'Number of most recent days of data to count.' },\n },\n unanswered_messages: {\n description:\n 'Find messages from the last N days that were never replied to; these may be unresolved customer questions. Only text messages whose content is longer than 10 characters are counted (short greetings are filtered out).',\n properties: {\n days: 'Number of most recent days of data to search.',\n limit: 'Maximum number of messages to return.',\n },\n },\n list_sessions: {\n description:\n 'List all available chat sessions, returning basic information such as session name, platform, and message count.',\n properties: { keyword: 'Filter sessions by name (optional).' },\n },\n get_session_info: {\n description:\n 'Get detailed information about the current session, including its name, platform, total message count, member count, and time range.',\n properties: { include_members: 'Whether to include the member list (defaults to false).' },\n },\n search_messages_globally: {\n properties: {\n start_time: 'Start time in YYYY-MM-DD HH:mm format.',\n end_time: 'End time in YYYY-MM-DD HH:mm format.',\n },\n },\n get_cross_chat_overview: {\n properties: {\n start_time: 'Start time in YYYY-MM-DD HH:mm format.',\n end_time: 'End time in YYYY-MM-DD HH:mm format.',\n },\n },\n rank_private_contacts: {\n properties: {\n start_time: 'Start time in YYYY-MM-DD HH:mm format.',\n end_time: 'End time in YYYY-MM-DD HH:mm format.',\n },\n },\n rank_group_sessions: {\n properties: {\n start_time: 'Start time in YYYY-MM-DD HH:mm format.',\n end_time: 'End time in YYYY-MM-DD HH:mm format.',\n },\n },\n inspect_contact_sessions: {\n properties: {\n start_time: 'Start time in YYYY-MM-DD HH:mm format.',\n end_time: 'End time in YYYY-MM-DD HH:mm format.',\n },\n },\n inspect_shared_interactions: {\n properties: {\n start_time: 'Start time in YYYY-MM-DD HH:mm format.',\n end_time: 'End time in YYYY-MM-DD HH:mm format.',\n },\n },\n}\n\nfunction localizeInputSchema(schema: JsonSchema, properties?: Record<string, string>): JsonSchema {\n if (!properties) return schema\n return {\n ...schema,\n properties: Object.fromEntries(\n Object.entries(schema.properties).map(([name, definition]) => [\n name,\n properties[name] ? { ...definition, description: properties[name] } : definition,\n ])\n ),\n }\n}\n\n/** Reads only the locale-independent fields, so tools bound to any execution context can be localized. */\nexport function getLocalizedToolMetadata(\n tool: Pick<ToolDefinition, 'name' | 'description' | 'inputSchema'>,\n locale?: string\n): Pick<ToolDefinition, 'description' | 'inputSchema'> {\n if (isChineseLocale(locale)) return { description: tool.description, inputSchema: tool.inputSchema }\n const metadata = ENGLISH_TOOL_METADATA[tool.name]\n if (!metadata) return { description: tool.description, inputSchema: tool.inputSchema }\n return {\n description: metadata.description ?? tool.description,\n inputSchema: localizeInputSchema(tool.inputSchema, metadata.properties),\n }\n}\n","import { CROSS_CHAT_AGENT_TOOL_REGISTRY } from './registry'\nimport { getLocalizedToolMetadata } from './tool-metadata'\nimport type { CrossChatToolExecutionContext, JsonSchema, ToolDefinition, ToolProgress, ToolResult } from './types'\n\ninterface AgentToolParameters {\n type: 'object'\n properties: Record<string, unknown>\n required: string[]\n}\n\ninterface AgentToolExecutionResult {\n content: Array<{ type: 'text'; text: string }>\n details: unknown\n isError?: boolean\n}\n\n/** 将平台无关的工具输入 schema 转成 Agent SDK 接受的参数结构,并避免共享原对象引用。 */\nexport function toAgentToolParameters(schema: JsonSchema): AgentToolParameters {\n return {\n type: 'object',\n properties: Object.fromEntries(Object.entries(schema.properties).map(([key, value]) => [key, { ...value }])),\n required: schema.required ?? [],\n }\n}\n\n/** 统一把工具返回的数据、图表和原始消息整理成 CLI/Desktop 共用的 Agent 结果结构。 */\nfunction toAgentToolResult(result: ToolResult): AgentToolExecutionResult {\n const chartDetails = {\n ...(result.chart ? { chart: result.chart } : {}),\n ...(result.charts ? { charts: result.charts } : {}),\n }\n\n if (result.rawMessages?.length) {\n const data = typeof result.data === 'object' && result.data !== null ? result.data : {}\n const { rawMessages: _ignored, ...details } = data as Record<string, unknown>\n return {\n content: [{ type: 'text', text: result.content }],\n details: { ...details, ...chartDetails, rawMessages: result.rawMessages },\n }\n }\n\n const details =\n typeof result.data === 'object' && result.data !== null\n ? (result.data as Record<string, unknown>)\n : result.data === undefined\n ? null\n : { value: result.data }\n\n return {\n content: [{ type: 'text', text: result.content }],\n details: Object.keys(chartDetails).length > 0 ? { ...(details ?? {}), ...chartDetails } : details,\n }\n}\n\n/** 执行共享工具并把异常收敛成 Agent 可直接返回给模型的文本结果。 */\nexport async function executeToolForAgent<TContext>(\n tool: ToolDefinition<TContext>,\n params: unknown,\n context: TContext\n): Promise<AgentToolExecutionResult> {\n const toolParams = (params && typeof params === 'object' ? params : {}) as Record<string, unknown>\n try {\n return toAgentToolResult(await tool.handler(toolParams, context))\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return { content: [{ type: 'text', text: `Error: ${message}` }], details: null, isError: true }\n }\n}\n\n/** Desktop 与 CLI Web 共用同一套跨会话工具装配,避免平台 wrapper 漏注册或产生 schema 漂移。 */\nexport function createCrossChatAgentToolAdapters(\n context: Omit<CrossChatToolExecutionContext, 'abortSignal' | 'reportProgress'>\n) {\n const runContext = {\n ...context,\n resolvedEntityRefs: context.resolvedEntityRefs ?? [],\n }\n return CROSS_CHAT_AGENT_TOOL_REGISTRY.map((tool) => {\n const { description, inputSchema } = getLocalizedToolMetadata(tool, context.locale)\n return {\n name: tool.name,\n label: tool.name,\n description,\n parameters: toAgentToolParameters(inputSchema),\n executionMode: tool.executionMode,\n execute: async (\n _toolCallId: string,\n params: unknown,\n signal: AbortSignal,\n onUpdate?: (update: { content: []; details: { progress: ToolProgress } }) => void\n ) =>\n executeToolForAgent(tool, params, {\n ...runContext,\n abortSignal: signal,\n reportProgress: (progress) => onUpdate?.({ content: [], details: { progress } }),\n }),\n }\n })\n}\n"],"mappings":"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","names":["inputSchema","handler","inputSchema","handler","inputSchema","handler","inputSchema","handler","inputSchema","handler","inputSchema","handler","inputSchema","handler","data","inputSchema","handler","data","inputSchema","handler","inputSchema","handler","inputSchema","handler","inputSchema","handler","inputSchema","handler","data","inputSchema","handler","data","inputSchema","handler","data","inputSchema","handler","inputSchema","handler","inputSchema","handler","inputSchema","t","handler","limited","scopeItems","sessions","requireString","data","ref","resolved","details","inputSchema"]}
|