chatlab-cli 0.25.1 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/{chat-command-5XMRLXZM.mjs → chat-command-ZP4WJVWC.mjs} +144 -6
  2. package/dist/chat-command-ZP4WJVWC.mjs.map +1 -0
  3. package/dist/{chunk-YZYP5ST6.mjs → chunk-6G7AIF7I.mjs} +12 -11
  4. package/dist/chunk-6G7AIF7I.mjs.map +1 -0
  5. package/dist/{chunk-WYHGWTA4.mjs → chunk-ILGSSXOG.mjs} +92 -28
  6. package/dist/chunk-ILGSSXOG.mjs.map +1 -0
  7. package/dist/{chunk-JE3FOFF7.mjs → chunk-IRZRIHIT.mjs} +49 -12
  8. package/dist/chunk-IRZRIHIT.mjs.map +1 -0
  9. package/dist/{chunk-7VG6QGQ2.mjs → chunk-QY67NN65.mjs} +841 -79
  10. package/dist/chunk-QY67NN65.mjs.map +1 -0
  11. package/dist/{chunk-GTCTDD2Z.mjs → chunk-SJIOPSMM.mjs} +8 -8
  12. package/dist/{chunk-PDQFSQO6.mjs → chunk-TC74HESZ.mjs} +2 -2
  13. package/dist/{chunk-FDK6SPCG.mjs → chunk-UB4XBM4R.mjs} +2 -2
  14. package/dist/{chunk-CUCDRAY6.mjs → chunk-WXC6RZCX.mjs} +2 -2
  15. package/dist/cli.mjs +3 -3
  16. package/dist/{http-C3CGXUBU.mjs → http-J3IOFFIA.mjs} +8 -8
  17. package/dist/{import-VS7L5JDX.mjs → import-POYG5LOX.mjs} +4 -4
  18. package/dist/index.mjs +8 -8
  19. package/dist/{mcp-6VXDPUQK.mjs → mcp-7HH7UMXT.mjs} +4 -4
  20. package/dist/{stream-import-TFDBNVIW.mjs → stream-import-O3H3FGV2.mjs} +3 -3
  21. package/dist-web/assets/{DebugToolsPanel-vn-bnUxn.css → DebugToolsPanel-CrqULdXp.css} +1 -1
  22. package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-BTJxEma5.js +182 -0
  23. package/dist-web/assets/{EChartWordcloud-CzhfrEF_.js → EChartWordcloud-B_YisOW5.js} +1 -1
  24. package/dist-web/assets/{MessageExportModal-B79pPBL9.js → MessageExportModal-C7NgEL8T.js} +1 -1
  25. package/dist-web/assets/{electron-DRkrjeIl.js → electron-B3DFm1cC.js} +1 -1
  26. package/dist-web/assets/electron-BMM4Nfty.js +1 -0
  27. package/dist-web/assets/{fetch-DfgdagMN.js → fetch-ArMjdMcy.js} +1 -1
  28. package/dist-web/assets/{fetch-BqLy63aj.js → fetch-BFtuJaa1.js} +1 -1
  29. package/dist-web/assets/{fetch-CDamdvtb.js → fetch-BGfaAqO9.js} +1 -1
  30. package/dist-web/assets/{fetch-Drk9dLaF.js → fetch-BaJDB31c.js} +1 -1
  31. package/dist-web/assets/{fetch-BmZIm6mS.js → fetch-BjDJgdN0.js} +1 -1
  32. package/dist-web/assets/{fetch-DWg-2kOp.js → fetch-C5CLcpQW.js} +1 -1
  33. package/dist-web/assets/{fetch-ph2_d79v.js → fetch-DQZvdHnG.js} +1 -1
  34. package/dist-web/assets/{fetch-Y-_WsCuk.js → fetch-Dhfbt1BQ.js} +3 -3
  35. package/dist-web/assets/{fetch-BstX-wd4.js → fetch-DnEP0uyF.js} +1 -1
  36. package/dist-web/assets/{fetch-Bvcxe5PI.js → fetch-SYrb-sZe.js} +1 -1
  37. package/dist-web/assets/index-CWfkrx37.js +173 -0
  38. package/dist-web/assets/index-D3N4NDFx.css +1 -0
  39. package/dist-web/assets/{index-DMWf5On7.js → index-D7_ch4zf.js} +1 -1
  40. package/dist-web/assets/{index-9urfJP1r.js → index-DK9LEEzT.js} +1 -1
  41. package/dist-web/assets/index-DqDa_on9.js +9 -0
  42. package/dist-web/assets/{index-D_hHm7bQ.js → index-DrN1G9bl.js} +2 -2
  43. package/dist-web/assets/{index-deYDOVUa.js → index-MdYeovYo.js} +4 -4
  44. package/dist-web/assets/{vendor-nuxt-ui-C_8CsH6e.js → vendor-nuxt-ui-Zy8txNdC.js} +1 -1
  45. package/dist-web/assets/{vendor-reka-ui-CIMXwvEp.js → vendor-reka-ui-mMvma1EP.js} +1 -1
  46. package/dist-web/assets/{web-XJV6Vj5t.js → web-zEXsvoZW.js} +1 -1
  47. package/dist-web/index.html +4 -4
  48. package/package.json +1 -1
  49. package/dist/chat-command-5XMRLXZM.mjs.map +0 -1
  50. package/dist/chunk-7VG6QGQ2.mjs.map +0 -1
  51. package/dist/chunk-JE3FOFF7.mjs.map +0 -1
  52. package/dist/chunk-WYHGWTA4.mjs.map +0 -1
  53. package/dist/chunk-YZYP5ST6.mjs.map +0 -1
  54. package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-B1xZmp9r.js +0 -161
  55. package/dist-web/assets/electron-Dv8jdn_2.js +0 -1
  56. package/dist-web/assets/index-CfKjh0Jr.js +0 -9
  57. package/dist-web/assets/index-CprJOAB1.css +0 -1
  58. package/dist-web/assets/index-MCdpiX_O.js +0 -173
  59. /package/dist/{chunk-GTCTDD2Z.mjs.map → chunk-SJIOPSMM.mjs.map} +0 -0
  60. /package/dist/{chunk-PDQFSQO6.mjs.map → chunk-TC74HESZ.mjs.map} +0 -0
  61. /package/dist/{chunk-FDK6SPCG.mjs.map → chunk-UB4XBM4R.mjs.map} +0 -0
  62. /package/dist/{chunk-CUCDRAY6.mjs.map → chunk-WXC6RZCX.mjs.map} +0 -0
  63. /package/dist/{http-C3CGXUBU.mjs.map → http-J3IOFFIA.mjs.map} +0 -0
  64. /package/dist/{import-VS7L5JDX.mjs.map → import-POYG5LOX.mjs.map} +0 -0
  65. /package/dist/{mcp-6VXDPUQK.mjs.map → mcp-7HH7UMXT.mjs.map} +0 -0
  66. /package/dist/{stream-import-TFDBNVIW.mjs.map → stream-import-O3H3FGV2.mjs.map} +0 -0
@@ -2158,6 +2158,7 @@ function getChatOverview(db, topN = 10) {
2158
2158
  if (!meta) return null;
2159
2159
  const overview = getSessionOverview(db);
2160
2160
  const members = getMemberActivity(db);
2161
+ const summaryCount = getSummaryCount(db);
2161
2162
  const topMembers = members.slice(0, topN).map((m) => ({
2162
2163
  id: m.memberId,
2163
2164
  name: m.name,
@@ -2171,7 +2172,8 @@ function getChatOverview(db, topN = 10) {
2171
2172
  totalMembers: overview.totalMembers,
2172
2173
  firstMessageTs: overview.firstMessageTs,
2173
2174
  lastMessageTs: overview.lastMessageTs,
2174
- topMembers
2175
+ topMembers,
2176
+ summaryCount
2175
2177
  };
2176
2178
  }
2177
2179
  function searchSegments(db, keywords, timeFilter, limit = 20, previewCount = 5, ftsMatchExpression) {
@@ -11779,6 +11781,10 @@ function isDuplicate(msg, existingPlatformMsgIds, existingKeys) {
11779
11781
  existingKeys.add(key);
11780
11782
  return false;
11781
11783
  }
11784
+ function normalizeTimestamp(timestamp) {
11785
+ const value = typeof timestamp === "string" && timestamp.trim() !== "" ? Number(timestamp) : timestamp;
11786
+ return typeof value === "number" && value > 0 && Number.isFinite(value) ? value : null;
11787
+ }
11782
11788
  async function analyzeIncrementalImport(sessionId, filePath, deps) {
11783
11789
  const formatFeature = detectFormat(filePath);
11784
11790
  if (!formatFeature) {
@@ -11806,7 +11812,9 @@ async function analyzeIncrementalImport(sessionId, filePath, deps) {
11806
11812
  onMessageBatch: (batch) => {
11807
11813
  for (const msg of batch) {
11808
11814
  totalInFile++;
11809
- if (isDuplicate(msg, existingPlatformMsgIds, existingKeys)) {
11815
+ const timestamp = normalizeTimestamp(msg.timestamp);
11816
+ if (timestamp === null) continue;
11817
+ if (isDuplicate({ ...msg, timestamp }, existingPlatformMsgIds, existingKeys)) {
11810
11818
  duplicateCount++;
11811
11819
  } else {
11812
11820
  newMessageCount++;
@@ -11929,11 +11937,12 @@ async function incrementalImport(sessionId, filePath, deps, options) {
11929
11937
  trackError2(processedCount, "MISSING_TIMESTAMP", "timestamp field is missing");
11930
11938
  continue;
11931
11939
  }
11932
- if (typeof msg.timestamp !== "number" || msg.timestamp <= 0 || !isFinite(msg.timestamp)) {
11940
+ const timestamp = normalizeTimestamp(msg.timestamp);
11941
+ if (timestamp === null) {
11933
11942
  trackError2(processedCount, "INVALID_TIMESTAMP", `timestamp value: ${msg.timestamp}`);
11934
11943
  continue;
11935
11944
  }
11936
- if (isDuplicate(msg, existingPlatformMsgIds, existingKeys)) {
11945
+ if (isDuplicate({ ...msg, timestamp }, existingPlatformMsgIds, existingKeys)) {
11937
11946
  duplicateCount++;
11938
11947
  continue;
11939
11948
  }
@@ -11957,7 +11966,7 @@ async function incrementalImport(sessionId, filePath, deps, options) {
11957
11966
  memberId,
11958
11967
  msg.senderAccountName || null,
11959
11968
  msg.senderGroupNickname || null,
11960
- msg.timestamp,
11969
+ timestamp,
11961
11970
  msg.type,
11962
11971
  msg.content || null,
11963
11972
  msg.replyToMessageId || null,
@@ -12584,11 +12593,7 @@ var AIChatManager = class {
12584
12593
  siblingGroupId,
12585
12594
  branchIndex
12586
12595
  );
12587
- db.prepare("UPDATE ai_chat SET active_message_id = ?, updated_at = ? WHERE id = ?").run(
12588
- id,
12589
- now,
12590
- aiChatId
12591
- );
12596
+ db.prepare("UPDATE ai_chat SET active_message_id = ?, updated_at = ? WHERE id = ?").run(id, now, aiChatId);
12592
12597
  return {
12593
12598
  id,
12594
12599
  aiChatId,
@@ -12626,11 +12631,7 @@ var AIChatManager = class {
12626
12631
  db.prepare(`DELETE FROM ai_message WHERE id IN (${placeholders})`).run(...idsToDelete);
12627
12632
  const newLeafId = targetIndex > 0 ? activePath[targetIndex - 1].id : null;
12628
12633
  const now = Math.floor(Date.now() / 1e3);
12629
- db.prepare("UPDATE ai_chat SET active_message_id = ?, updated_at = ? WHERE id = ?").run(
12630
- newLeafId,
12631
- now,
12632
- aiChatId
12633
- );
12634
+ db.prepare("UPDATE ai_chat SET active_message_id = ?, updated_at = ? WHERE id = ?").run(newLeafId, now, aiChatId);
12634
12635
  }
12635
12636
  forkAIChat(sourceAIChatId, upToMessageId, title) {
12636
12637
  const db = this.getDb();
@@ -12749,11 +12750,7 @@ var AIChatManager = class {
12749
12750
  db.prepare("UPDATE ai_message SET parent_id = ? WHERE id = ?").run(id, childRow.id);
12750
12751
  db.prepare("UPDATE ai_chat SET updated_at = ? WHERE id = ?").run(now, aiChatId);
12751
12752
  } else {
12752
- db.prepare("UPDATE ai_chat SET active_message_id = ?, updated_at = ? WHERE id = ?").run(
12753
- id,
12754
- now,
12755
- aiChatId
12756
- );
12753
+ db.prepare("UPDATE ai_chat SET active_message_id = ?, updated_at = ? WHERE id = ?").run(id, now, aiChatId);
12757
12754
  }
12758
12755
  return {
12759
12756
  id,
@@ -14034,10 +14031,38 @@ function shouldUseChartCapabilityForMessage(message) {
14034
14031
  normalized
14035
14032
  );
14036
14033
  }
14034
+ function shouldOfferChartCapabilityForAnalyticalMessage(message) {
14035
+ const normalized = message.trim().toLowerCase();
14036
+ if (!normalized) return false;
14037
+ if (shouldUseChartCapabilityForMessage(normalized)) return true;
14038
+ return /(?:趋势|变化|走势|排名|排行|前\s*\d+|top\s*\d*|最多|最少|高频|分布|占比|比例|构成|份额|活跃度|热度|按.{0,8}统计|统计.{0,8}按|trend|ranking|rank|top\s*\d*|distribution|ratio|share|percentage|breakdown)/i.test(
14039
+ normalized
14040
+ );
14041
+ }
14042
+ function getChartPlannerCapabilityForMessage(options) {
14043
+ const availableToolSet = new Set(options.availableTools);
14044
+ if (!availableToolSet.has("get_schema") || !availableToolSet.has("render_chart")) {
14045
+ return null;
14046
+ }
14047
+ const chartAutoMode = options.chartAutoMode ?? "suggest";
14048
+ const shouldOffer = chartAutoMode === "explicit" ? shouldUseChartCapabilityForMessage(options.userMessage) : shouldOfferChartCapabilityForAnalyticalMessage(options.userMessage);
14049
+ if (!shouldOffer) {
14050
+ return null;
14051
+ }
14052
+ const isZh = (options.locale ?? "zh-CN").startsWith("zh");
14053
+ return {
14054
+ id: "chart_generation",
14055
+ label: isZh ? "\u56FE\u8868\u751F\u6210" : "Chart generation",
14056
+ tools: ["get_schema", "render_chart"],
14057
+ guidance: isZh ? "\u7528\u6237\u660E\u786E\u8981\u6C42\u56FE\u8868\uFF0C\u6216\u8D8B\u52BF\u3001\u6392\u540D\u3001\u5206\u5E03\u3001\u5360\u6BD4\u7B49\u5206\u6790\u7528\u56FE\u66F4\u6E05\u695A\u65F6\uFF0C\u53EF\u4EE5\u5728\u8BA1\u5212\u4E2D\u52A0\u5165\u6700\u591A\u4E00\u5F20\u56FE\u8868\u6B65\u9AA4\uFF1B\u5FC5\u987B\u5148\u7528 get_schema \u786E\u8BA4 schema\uFF0C\u518D\u7528 render_chart \u751F\u6210\u56FE\u8868\uFF1B\u4E0D\u8981\u8F93\u51FA\u7ED8\u56FE\u4EE3\u7801\u3002" : "When the user explicitly asks for charts, or when trends, rankings, distributions, or ratios are clearer visually, you may add at most one chart step to the plan; call get_schema before render_chart; do not output chart-rendering code."
14058
+ };
14059
+ }
14037
14060
  function resolveChartRuntimeForRequest(options) {
14038
14061
  const locale = options.locale ?? "zh-CN";
14039
14062
  const isExplicitChartSkill = options.skillId === CHART_CAPABILITY_SKILL_ID;
14040
- const isAutoChartSkill = options.enableAutoDetection === true && !options.skillId && shouldUseChartCapabilityForMessage(options.userMessage ?? "");
14063
+ const allowAnalyticalAutoDetection = options.chartAutoMode !== void 0 ? options.chartAutoMode === "aggressive" : options.enableAnalyticalAutoDetection === true;
14064
+ const shouldAutoDetectChart = shouldUseChartCapabilityForMessage(options.userMessage ?? "") || allowAnalyticalAutoDetection && shouldOfferChartCapabilityForAnalyticalMessage(options.userMessage ?? "");
14065
+ const isAutoChartSkill = options.enableAutoDetection === true && !options.skillId && shouldAutoDetectChart;
14041
14066
  if (!isExplicitChartSkill && !isAutoChartSkill) {
14042
14067
  return { isChartCapability: false };
14043
14068
  }
@@ -14083,23 +14108,28 @@ function getSkillConfigWithBuiltinChart(id, locale = "zh-CN", getSkillConfig) {
14083
14108
  }
14084
14109
  var ZH_PROMPT = `\u4F60\u662F ChatLab \u7ED8\u56FE\u52A9\u624B\u3002\u672C\u8F6E\u7528\u6237\u5E0C\u671B\u4F60\u5728\u56DE\u7B54\u91CC\u81EA\u7136\u5D4C\u5165\u4E00\u5F20\u6216\u591A\u5F20\u56FE\u8868\u3002
14085
14110
 
14086
- \u4F60\u5FC5\u987B\u901A\u8FC7 render_chart \u5DE5\u5177\u751F\u6210\u56FE\u8868\u3002\u4E0D\u8981\u8F93\u51FA HTML\u3001JavaScript\u3001SVG\u3001Canvas\u3001ECharts option \u6216\u4EFB\u4F55\u6E32\u67D3\u4EE3\u7801\u3002
14111
+ \u4F60\u5FC5\u987B\u901A\u8FC7 render_chart \u5DE5\u5177\u751F\u6210\u56FE\u8868\u3002\u4E0D\u8981\u8F93\u51FA HTML\u3001JavaScript\u3001SVG\u3001Canvas\u3001ECharts option\u3001Markdown \u56FE\u7247\u94FE\u63A5\uFF08\u5982 ![\u56FE\u8868](chart1.png)\uFF09\u6216\u4EFB\u4F55\u6E32\u67D3\u4EE3\u7801\u3002
14087
14112
 
14088
14113
  \u786C\u6027\u89C4\u5219\uFF1A
14089
14114
  1. \u7B2C\u4E00\u6B21\u5199 SQL \u524D\u5FC5\u987B\u5148\u8C03\u7528 get_schema\u3002\u7981\u6B62\u731C\u6D4B\u8868\u540D\u3001\u5B57\u6BB5\u540D\u6216\u65F6\u95F4\u5B57\u6BB5\u3002
14090
- 2. \u201C\u6700\u8FD1\u201D\u201C\u5230\u73B0\u5728\u201D\u201C\u5230\u6700\u8FD1\u201D\u5FC5\u987B\u7528\u6570\u636E\u4E2D\u7684 MAX(ts) \u6216\u7B49\u4EF7\u5B57\u6BB5\u786E\u5B9A\u7ED3\u675F\u65E5\u671F\uFF1B\u4E0D\u8981\u624B\u7B97\u6216\u81C6\u6D4B\u65E5\u671F\u3002
14115
+ 2. \u201C\u6700\u8FD1\u201D\u201C\u8FC7\u53BB N \u5929/\u5E74\u201D\u7B49\u76F8\u5BF9\u65F6\u95F4\u4EE5\u7CFB\u7EDF\u63D0\u793A\u4E2D\u7684\u771F\u5B9E\u5F53\u524D\u65E5\u671F\u4E3A\u57FA\u51C6\uFF1B\u5982\u679C\u542F\u52A8\u4E0A\u4E0B\u6587\u663E\u793A\u6570\u636E\u5E93\u8986\u76D6\u4E0D\u8DB3\uFF0C\u53EA\u5206\u6790\u7528\u6237\u65F6\u95F4\u8303\u56F4\u4E0E\u6570\u636E\u5E93\u8986\u76D6\u8303\u56F4\u7684\u4EA4\u96C6\u5E76\u8BF4\u660E\u7F3A\u53E3\u3002
14091
14116
  3. ChatLab \u7684 message.ts \u662F\u79D2\u7EA7 Unix \u65F6\u95F4\u6233\uFF0C\u4F7F\u7528 date(ts, 'unixepoch', 'localtime')\uFF1B\u7981\u6B62\u5199 ts/1000\u3002
14092
14117
  4. \u201C\u6700\u8FD1\u7684 N \u4EBA/\u6210\u5458\u201D\u5FC5\u987B\u5148\u7528\u6570\u636E\u5B9A\u4E49\u5E76\u7B5B\u9009\u51FA N \u4E2A\u6210\u5458\uFF0C\u518D\u53EA\u7EDF\u8BA1\u8FD9\u4E9B\u6210\u5458\u3002
14093
14118
  5. \u6298\u7EBF\u56FE\u6709\u591A\u6761\u7EBF\u65F6\uFF0C\u6BCF\u6761\u7EBF\u5FC5\u987B\u6709\u660E\u786E series \u5B57\u6BB5\u542B\u4E49\uFF1B\u6309\u65E5\u671F\u7EDF\u8BA1\u65F6\u5E94\u8865\u9F50\u65E5\u671F \xD7 series \u7684 0 \u503C\uFF0C\u907F\u514D\u7F3A\u5931\u65E5\u671F\u5BFC\u81F4\u6298\u7EBF\u65AD\u88C2\u6216\u8BEF\u8FDE\u3002
14094
- 6. \u5DE5\u5177\u5931\u8D25\u3001SQL \u4FEE\u6B63\u3001schema \u63A2\u7D22\u8FC7\u7A0B\u4E0D\u8981\u5199\u8FDB\u6700\u7EC8\u56DE\u7B54\uFF1B\u6700\u7EC8\u53EA\u4FDD\u7559\u56FE\u8868\u548C\u7B80\u77ED\u7ED3\u8BBA\u3002
14095
- 7. \u56FE\u8868\u89E3\u91CA\u53EA\u80FD\u63CF\u8FF0\u6570\u636E\u76F4\u63A5\u652F\u6301\u7684\u8D8B\u52BF\u3001\u5CF0\u503C\u3001\u4F4E\u8C37\u3001\u5DEE\u5F02\u548C\u540C\u6B65\u6027\uFF0C\u7981\u6B62\u5938\u5F20\u62DF\u4EBA\u5316\u6216\u65E0\u6CD5\u4ECE\u56FE\u4E2D\u9A8C\u8BC1\u7684\u5173\u7CFB\u5224\u65AD\u3002
14119
+ 6. \u5DE5\u5177\u5931\u8D25\u3001SQL \u4FEE\u6B63\u3001schema \u63A2\u7D22\u8FC7\u7A0B\u4E0D\u8981\u5199\u8FDB\u6700\u7EC8\u56DE\u7B54\uFF1B\u6700\u7EC8\u53EA\u4FDD\u7559\u539F\u751F\u56FE\u8868\u548C\u7B80\u77ED\u7ED3\u8BBA\uFF0C\u7981\u6B62\u7528 chart1.png\u3001chart2.png \u7B49\u6587\u4EF6\u540D\u5F15\u7528\u56FE\u8868\u3002
14120
+ 7. \u8C03\u7528 render_chart \u65F6\uFF0CChatLab \u4F1A\u7ACB\u5373\u5728\u8BE5\u4F4D\u7F6E\u63D2\u5165\u539F\u751F\u56FE\u8868\uFF1B\u9700\u8981\u56FE\u8868\u5C31\u76F4\u63A5\u8C03\u7528\u5DE5\u5177\uFF0C\u4E0D\u8981\u5199 SQL \u6CE8\u91CA\u3001Markdown \u56FE\u7247\u6216\u201C\u5DF2\u751F\u6210\u56FE\u8868/\u89C1\u4E0A\u56FE\u201D\u8FD9\u7C7B\u6587\u672C\u5360\u4F4D\u3002
14121
+ 8. \u7528\u6237\u8981\u6C42\u591A\u5F20\u56FE\u65F6\uFF0C\u56FE\u8868\u5E94\u5206\u6563\u51FA\u73B0\u5728\u76F8\u5173\u603B\u7ED3\u6216\u89E3\u91CA\u9644\u8FD1\uFF1B\u4E0D\u8981\u628A\u6240\u6709\u56FE\u96C6\u4E2D\u751F\u6210\u540E\u518D\u5728\u6700\u540E\u7528\u6587\u5B57\u5F15\u7528\u3002
14122
+ 9. \u4E3A\u56FE\u8868\u51C6\u5907\u6570\u636E\u65F6\uFF0C\u4F18\u5148\u8C03\u7528\u9AD8\u5C42\u5DE5\u5177\uFF08\u5982 get_time_stats\u3001member_stats\uFF09\u800C\u975E\u81EA\u5DF1\u5199 SQL\uFF1B\u53EA\u6709\u9AD8\u5C42\u5DE5\u5177\u65E0\u6CD5\u8986\u76D6\u6240\u9700\u7B5B\u9009\u6216\u805A\u5408\u65F6\u624D\u7528 sql\u3002render_chart \u4E0D\u8981\u7528\u4E8E\u5143\u6570\u636E\u63A2\u6D4B\u3001\u6807\u91CF\u67E5\u8BE2\u3001\u5355\u884C\u65E5\u671F\u5B57\u7B26\u4E32\u6216\u7EAF\u8BF4\u660E\u6027\u7ED3\u679C\u3002
14123
+ 10. render_chart \u7684\u5DE5\u5177\u7ED3\u679C\u4F1A\u5305\u542B\u6570\u636E\u9884\u89C8\uFF08Data preview\uFF09\uFF1B\u7528\u5B83\u5206\u6790\u5CF0\u503C\u3001\u4F4E\u8C37\u548C\u5DEE\u5F02\uFF0C\u4E0D\u8981\u4E3A\u4E86\u8BFB\u53D6\u6570\u503C\u91CD\u590D\u751F\u6210\u7B49\u4EF7\u56FE\u8868\u3002
14124
+ 11. \u56FE\u8868\u89E3\u91CA\u53EA\u80FD\u63CF\u8FF0\u6570\u636E\u76F4\u63A5\u652F\u6301\u7684\u8D8B\u52BF\u3001\u5CF0\u503C\u3001\u4F4E\u8C37\u3001\u5DEE\u5F02\u548C\u540C\u6B65\u6027\uFF0C\u7981\u6B62\u5938\u5F20\u62DF\u4EBA\u5316\u6216\u65E0\u6CD5\u4ECE\u56FE\u4E2D\u9A8C\u8BC1\u7684\u5173\u7CFB\u5224\u65AD\u3002
14096
14125
 
14097
14126
  \u5DE5\u4F5C\u6D41\u7A0B\uFF1A
14098
14127
  1. \u8C03\u7528 get_schema\u3002
14099
- 2. \u6839\u636E schema \u548C\u7528\u6237\u8981\u6C42\u786E\u5B9A\u7EDF\u8BA1\u5BF9\u8C61\u3001\u65F6\u95F4\u8303\u56F4\u3001\u7EF4\u5EA6\u3001\u6307\u6807\u548C\u56FE\u8868\u7C7B\u578B\u3002
14100
- 3. \u5FC5\u8981\u65F6\u7528\u53EA\u8BFB SQL \u5728 render_chart \u4E2D\u5B8C\u6210\u6210\u5458\u7B5B\u9009\u3001\u65F6\u95F4\u8303\u56F4\u786E\u8BA4\u3001\u805A\u5408\u548C\u8865\u96F6\u3002
14101
- 4. \u8C03\u7528 render_chart\uFF0C\u63D0\u4EA4\u53EA\u8BFB SQL \u548C ChartSpec v1\u3002
14102
- 5. \u56FE\u8868\u751F\u6210\u540E\uFF0C\u7528 1-3 \u53E5\u7B80\u6D01\u6587\u5B57\u89E3\u91CA\u7ED3\u8BBA\u3002\u7528\u6237\u8981\u6C42\u591A\u5F20\u56FE\u65F6\uFF0C\u53EF\u4EE5\u591A\u6B21\u8C03\u7528 render_chart\u3002
14128
+ 2. \u6839\u636E schema\u3001\u7528\u6237\u8981\u6C42\u3001\u7CFB\u7EDF\u5F53\u524D\u65E5\u671F\u548C\u542F\u52A8\u4E0A\u4E0B\u6587\u786E\u5B9A\u7EDF\u8BA1\u5BF9\u8C61\u3001\u65F6\u95F4\u8303\u56F4\u3001\u7EF4\u5EA6\u3001\u6307\u6807\u548C\u56FE\u8868\u7C7B\u578B\u3002
14129
+ 3. \u5982\u9700\u8C03\u67E5\u4E8B\u5B9E\u3001\u5EFA\u7ACB\u8BDD\u9898\u5730\u56FE\u3001\u7B5B\u9009\u6210\u5458\u6216\u786E\u8BA4\u7EDF\u8BA1\u53E3\u5F84\uFF0C\u5148\u7528\u53EF\u7528\u7684\u666E\u901A\u5206\u6790\u5DE5\u5177\u5B8C\u6210\uFF1B\u4E0D\u8981\u4E3A\u4E86\u8C03\u67E5\u800C\u751F\u6210\u4E34\u65F6\u56FE\u8868\u3002
14130
+ 4. \u51C6\u5907\u56FE\u8868\u6570\u636E\u2014\u2014\u5148\u95EE\u81EA\u5DF1\uFF1A\u54EA\u4E2A\u53EF\u7528\u7684\u9AD8\u5C42\u5DE5\u5177\u80FD\u76F4\u63A5\u63D0\u4F9B\u8FD9\u5F20\u56FE\u6240\u9700\u7684\u6570\u636E\uFF1Fget_time_stats \u80FD\u7ED9\u65F6\u95F4\u5206\u5E03\u3001member_stats \u80FD\u7ED9\u6210\u5458\u6392\u540D\uFF1B\u80FD\u7528\u5C31\u8C03\u7528\uFF0C\u5C06 data \u6570\u7EC4\u4F5C\u4E3A rows \u4F20\u5165 render_chart\u3002\u53EA\u6709\u5728\u9AD8\u5C42\u5DE5\u5177\u65E0\u6CD5\u8986\u76D6\u6240\u9700\u7B5B\u9009\u6216\u805A\u5408\u65F6\uFF0C\u624D\u7F16\u5199 SQL\u3002
14131
+ 5. \u5728\u5E0C\u671B\u56FE\u8868\u51FA\u73B0\u7684\u4F4D\u7F6E\u8C03\u7528 render_chart\uFF0C\u63D0\u4EA4\u6570\u636E\uFF08rows \u6216 sql\uFF09\u548C ChartSpec v1\u3002
14132
+ 6. \u56FE\u8868\u751F\u6210\u540E\uFF0C\u7528 1-3 \u53E5\u7B80\u6D01\u6587\u5B57\u89E3\u91CA\u7ED3\u8BBA\u3002\u7528\u6237\u8981\u6C42\u591A\u5F20\u56FE\u65F6\uFF0C\u53EF\u4EE5\u591A\u6B21\u8C03\u7528 render_chart\uFF0C\u5E76\u628A\u6BCF\u5F20\u56FE\u653E\u5728\u6700\u76F8\u5173\u7684\u6BB5\u843D\u9644\u8FD1\u3002
14103
14133
 
14104
14134
  \u5E38\u7528\u8BED\u3001\u53E3\u5934\u7985\u3001\u9AD8\u9891\u77ED\u53E5\u7C7B\u56FE\u8868\u5FC5\u987B\u6392\u9664\u975E\u771F\u4EBA\u6587\u672C\uFF1A\u53D1\u9001\u8005\u4E3A\u7CFB\u7EDF\u6D88\u606F\u3001\u5A92\u4F53\u5360\u4F4D\uFF08\u5982 [\u8868\u60C5\u5305]\u3001[\u56FE\u7247]\u3001[\u8BED\u97F3]\u3001[\u89C6\u9891]\u3001[\u6587\u4EF6]\u3001[\u94FE\u63A5]\u3001[\u7EA2\u5305]\u3001[\u8F6C\u8D26]\uFF09\u4EE5\u53CA\u64A4\u56DE/\u5220\u9664\u63D0\u793A\u90FD\u4E0D\u80FD\u8FDB\u5165\u7EDF\u8BA1\u3002
14105
14135
 
@@ -14121,23 +14151,28 @@ ChartSpec \u793A\u4F8B\uFF1A
14121
14151
  \u7528\u6237\u660E\u786E\u8981\u6C42\u56FE\u8868\u65F6\u5FC5\u987B\u5C1D\u8BD5\u751F\u6210\u3002\u7528\u6237\u6CA1\u6709\u660E\u786E\u8981\u6C42\u65F6\uFF0C\u53EA\u6709\u6392\u540D\u3001\u8D8B\u52BF\u3001\u5206\u5E03\u3001\u5360\u6BD4\u6216\u4E8C\u7EF4\u5BC6\u5EA6\u660E\u663E\u66F4\u6E05\u695A\u65F6\u624D\u4E3B\u52A8\u751F\u6210\uFF0C\u4E14\u9ED8\u8BA4\u6700\u591A\u4E00\u5F20\u3002`;
14122
14152
  var EN_PROMPT = `You are the ChatLab Chart Assistant. In this turn, the user wants one or more charts embedded naturally in the answer.
14123
14153
 
14124
- You must generate charts through the render_chart tool. Do not output HTML, JavaScript, SVG, Canvas, ECharts options, or rendering code.
14154
+ You must generate charts through the render_chart tool. Do not output HTML, JavaScript, SVG, Canvas, ECharts options, Markdown image links such as ![Chart](chart1.png), or rendering code.
14125
14155
 
14126
14156
  Hard rules:
14127
14157
  1. Always call get_schema before writing the first SQL query. Do not guess table names, field names, or timestamp fields.
14128
- 2. For "latest", "until now", or "through the latest date", derive the end date from MAX(ts) or the equivalent timestamp field in the data. Do not hand-calculate or assume dates.
14158
+ 2. For relative ranges like "recent" or "past N days/years", use the real current date from the system prompt as the baseline. If startup context shows incomplete database coverage, analyze only the intersection between the requested range and database coverage, and state the gap.
14129
14159
  3. ChatLab message.ts is a Unix timestamp in seconds. Use date(ts, 'unixepoch', 'localtime'); never write ts/1000.
14130
14160
  4. For "latest N members" or "recent N people", first define and select those N members from the data, then count only those members.
14131
14161
  5. For multi-series line charts, every line must have an explicit series field. For daily counts, fill the date x series grid with zero values so missing days do not break or mislead the line.
14132
- 6. Do not include failed SQL attempts, schema exploration, or retry reasoning in the final answer. Final answer should contain only the chart and a short conclusion.
14133
- 7. Explain only trends, peaks, lows, differences, and synchrony directly supported by chart data. Do not make exaggerated personality or relationship claims.
14162
+ 6. Do not include failed SQL attempts, schema exploration, or retry reasoning in the final answer. Final answer should contain only native charts and a short conclusion; never reference charts with filenames like chart1.png or chart2.png.
14163
+ 7. When you call render_chart, ChatLab immediately inserts the native chart at that position. If a chart is needed, call the tool directly; do not write SQL-comment placeholders, Markdown images, or text such as "generated chart" or "see chart above".
14164
+ 8. If the user asks for multiple charts, place each chart near the relevant summary or explanation. Do not generate all charts together and then reference them later with text.
14165
+ 9. When preparing chart data, prefer calling a high-level tool (such as get_time_stats, member_stats) over writing SQL; only use sql when no high-level tool can satisfy the required filters or aggregations. Do not use render_chart for metadata inspection, scalar queries, single-row date strings, or purely explanatory results.
14166
+ 10. render_chart tool results include a Data preview; use it to identify peaks, lows, and differences. Do not generate equivalent charts again just to read values.
14167
+ 11. Explain only trends, peaks, lows, differences, and synchrony directly supported by chart data. Do not make exaggerated personality or relationship claims.
14134
14168
 
14135
14169
  Workflow:
14136
14170
  1. Call get_schema.
14137
- 2. Derive the target members, time range, dimensions, metrics, and chart type from schema and the user request.
14138
- 3. When needed, use read-only SQL inside render_chart to select members, determine time range, aggregate data, and fill zero rows.
14139
- 4. Call render_chart with read-only SQL and ChartSpec v1.
14140
- 5. After the chart is generated, explain the key finding in 1-3 concise sentences. If the user asks for multiple charts, call render_chart multiple times.
14171
+ 2. Derive the target members, time range, dimensions, metrics, and chart type from schema, the user request, system current date, and startup context.
14172
+ 3. If you need to investigate facts, build a topic map, select members, or confirm statistical definitions, use available ordinary analysis tools first; do not generate temporary charts for investigation.
14173
+ 4. Prepare chart data \u2014 ask yourself first: which available high-level tool can directly provide the data this chart needs? get_time_stats covers time distributions; member_stats covers member rankings. If one fits, call it and pass its data array as rows to render_chart. Only write SQL when no high-level tool can cover the required filters or aggregations.
14174
+ 5. Call render_chart at the position where the chart should appear, with data (rows or sql) and ChartSpec v1.
14175
+ 6. After the chart is generated, explain the key finding in 1-3 concise sentences. If the user asks for multiple charts, call render_chart multiple times and place each chart near its most relevant section.
14141
14176
 
14142
14177
  For catchphrase, common phrase, or frequent short-text charts, exclude non-human text from the SQL: system-message senders, media placeholders such as [Sticker], [Image], [Photo], [Voice], [Video], [File], [Link], and recall/deletion notices must not be counted.
14143
14178
 
@@ -14964,7 +14999,7 @@ import {
14964
14999
  } from "@earendil-works/pi-ai";
14965
15000
 
14966
15001
  // ../../packages/node-runtime/src/ai/agent/constants.ts
14967
- var DEFAULT_MAX_TOOL_ROUNDS = 10;
15002
+ var DEFAULT_MAX_TOOL_ROUNDS = 20;
14968
15003
 
14969
15004
  // ../../packages/node-runtime/src/ai/agent/core.ts
14970
15005
  function createEmptyPiUsage() {
@@ -15045,14 +15080,6 @@ async function runAgentCore(options) {
15045
15080
  return clampThinkingLevel(piModel, level);
15046
15081
  })();
15047
15082
  const finalThinkingLevel = resolvedThinkingLevel ?? (piModel.reasoning ? void 0 : "off");
15048
- console.debug("[agent-core] thinkingLevel resolution:", {
15049
- input: options.thinkingLevel,
15050
- modelId: piModel.id,
15051
- modelReasoning: effectiveModel.reasoning,
15052
- isDefault,
15053
- resolved: resolvedThinkingLevel,
15054
- final: finalThinkingLevel
15055
- });
15056
15083
  const coreAgent = new PiAgentCore({
15057
15084
  initialState: {
15058
15085
  systemPrompt,
@@ -15182,6 +15209,584 @@ async function runAgentCore(options) {
15182
15209
  }
15183
15210
  }
15184
15211
 
15212
+ // ../../packages/node-runtime/src/ai/agent/data-snapshot.ts
15213
+ function roundShare(value) {
15214
+ if (!Number.isFinite(value)) return 0;
15215
+ return Math.round(value * 10) / 10;
15216
+ }
15217
+ function formatNullableTimestamp(timestamp) {
15218
+ return typeof timestamp === "number" && Number.isFinite(timestamp) ? String(timestamp) : "null";
15219
+ }
15220
+ function formatSharePercent(share) {
15221
+ if (!Number.isFinite(share)) return "0%";
15222
+ const rounded = Math.round(share * 10) / 10;
15223
+ return Number.isInteger(rounded) ? `${rounded}%` : `${rounded.toFixed(1)}%`;
15224
+ }
15225
+ function createDataSnapshotFromOverview(overview) {
15226
+ if (!overview) return void 0;
15227
+ const topMembers = overview.topMembers ?? [];
15228
+ return {
15229
+ version: 2,
15230
+ name: overview.name,
15231
+ platform: overview.platform,
15232
+ type: overview.type,
15233
+ totalMessages: overview.totalMessages,
15234
+ totalMembers: overview.totalMembers,
15235
+ firstMessageTs: overview.firstMessageTs,
15236
+ lastMessageTs: overview.lastMessageTs,
15237
+ activeMemberHints: topMembers.slice(0, 10).map((member) => ({
15238
+ memberId: member.id,
15239
+ displayName: member.name,
15240
+ messageCount: member.count,
15241
+ share: overview.totalMessages > 0 ? roundShare(member.count / overview.totalMessages * 100) : 0
15242
+ })),
15243
+ segmentSummaries: {
15244
+ availableCount: overview.summaryCount ?? 0
15245
+ }
15246
+ };
15247
+ }
15248
+ function formatDataSnapshotForRouter(dataSnapshot) {
15249
+ if (!dataSnapshot) return "(none)";
15250
+ return [
15251
+ `name: ${dataSnapshot.name}`,
15252
+ `platform: ${dataSnapshot.platform}`,
15253
+ `type: ${dataSnapshot.type}`,
15254
+ `total_messages: ${dataSnapshot.totalMessages}`,
15255
+ `total_members: ${dataSnapshot.totalMembers}`,
15256
+ `first_message_ts: ${formatNullableTimestamp(dataSnapshot.firstMessageTs)}`,
15257
+ `last_message_ts: ${formatNullableTimestamp(dataSnapshot.lastMessageTs)}`,
15258
+ `segment_summaries_available: ${dataSnapshot.segmentSummaries?.availableCount ?? 0}`,
15259
+ `active_member_hint_count: ${dataSnapshot.activeMemberHints?.length ?? 0}`
15260
+ ].join("\n");
15261
+ }
15262
+ function formatDataSnapshotForPlanner(dataSnapshot) {
15263
+ if (!dataSnapshot) return "(none)";
15264
+ const memberHints = dataSnapshot.activeMemberHints ?? [];
15265
+ const memberHintLines = memberHints.length > 0 ? memberHints.map(
15266
+ (member, index) => `${index + 1}. member_id=${member.memberId} | display_name=${member.displayName} | messages=${member.messageCount} | share=${formatSharePercent(member.share)}`
15267
+ ).join("\n") : "(none)";
15268
+ return `${formatDataSnapshotForRouter(dataSnapshot)}
15269
+ active_member_hints:
15270
+ ${memberHintLines}
15271
+ notes:
15272
+ - member_id is a tool lookup hint; display_name may not be unique.
15273
+ - Active member hints reflect historical total message volume, not recent activity.
15274
+ - Use real current date for relative ranges; database bounds only describe data coverage.
15275
+ - Do not plan a tool call only to rediscover min/max timestamp.
15276
+ - When using default recent-day tools, choose a range that intersects database bounds instead of probing an empty real-current-date window first.`;
15277
+ }
15278
+
15279
+ // ../../packages/node-runtime/src/ai/agent/router.ts
15280
+ import {
15281
+ completeSimple as completeSimple2
15282
+ } from "@earendil-works/pi-ai";
15283
+ var DEFAULT_LLM_FALLBACK_CONFIDENCE_THRESHOLD = 0.6;
15284
+ function clampConfidence(value) {
15285
+ if (!Number.isFinite(value)) return 0;
15286
+ return Math.max(0, Math.min(1, value));
15287
+ }
15288
+ function normalizeText(text) {
15289
+ return text.trim().replace(/\s+/g, " ");
15290
+ }
15291
+ function matchAny(text, patterns) {
15292
+ return patterns.some((pattern) => pattern.test(text));
15293
+ }
15294
+ function isRoute(value) {
15295
+ return value === "direct_response" || value === "tool_assisted" || value === "planned_execution";
15296
+ }
15297
+ function resultToText(result) {
15298
+ return typeof result === "string" ? { text: result } : result;
15299
+ }
15300
+ function extractJsonObject3(text) {
15301
+ const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
15302
+ if (fenced?.[1]) return fenced[1].trim();
15303
+ const start = text.indexOf("{");
15304
+ const end = text.lastIndexOf("}");
15305
+ if (start >= 0 && end > start) return text.slice(start, end + 1);
15306
+ return text.trim();
15307
+ }
15308
+ function parseLlmDecision(rawText, usage) {
15309
+ try {
15310
+ const parsed = JSON.parse(extractJsonObject3(rawText));
15311
+ if (!isRoute(parsed.route)) return null;
15312
+ return {
15313
+ route: parsed.route,
15314
+ confidence: clampConfidence(typeof parsed.confidence === "number" ? parsed.confidence : 0.5),
15315
+ reason: typeof parsed.reason === "string" && parsed.reason.trim() ? parsed.reason.trim() : "LLM route decision.",
15316
+ source: "llm",
15317
+ usage
15318
+ };
15319
+ } catch {
15320
+ return null;
15321
+ }
15322
+ }
15323
+ function buildLlmRouterPrompt(input, ruleDecision2) {
15324
+ const toolNames = input.availableTools?.length ? input.availableTools.join(", ") : "(none)";
15325
+ const dataSnapshot = formatDataSnapshotForRouter(input.dataSnapshot);
15326
+ return `Classify the user's ChatLab request into exactly one route.
15327
+
15328
+ Routes:
15329
+ - direct_response: no local chat data/tools needed.
15330
+ - tool_assisted: local chat data/tools needed, but the task is simple.
15331
+ - planned_execution: complex analysis, multi-step evidence gathering, retries, long-range comparison, relationship analysis, or insufficient-evidence handling.
15332
+
15333
+ Return strict JSON only:
15334
+ {"route":"direct_response|tool_assisted|planned_execution","confidence":0.0,"reason":"short reason"}
15335
+
15336
+ Context:
15337
+ - locale: ${input.locale}
15338
+ - chatType: ${input.chatType}
15339
+ - availableTools: ${toolNames}
15340
+ - dataSnapshot: ${dataSnapshot}
15341
+ - assistantSummary: ${input.assistantSummary ?? "(none)"}
15342
+ - skillSummary: ${input.skillSummary ?? "(none)"}
15343
+ - recentIntentSummary: ${input.recentIntentSummary ?? "(none)"}
15344
+ - ruleDecision: ${ruleDecision2.route}, confidence=${ruleDecision2.confidence}, reason=${ruleDecision2.reason}
15345
+
15346
+ User request:
15347
+ ${input.userMessage}`;
15348
+ }
15349
+ function directRuleDecision(text) {
15350
+ if (matchAny(text, [/不用查聊天记录|不用查询|不用查数据|不用看本地数据/i, /润色|改写|翻译|polish|rewrite|translate/i])) {
15351
+ return {
15352
+ route: "direct_response",
15353
+ confidence: 0.95,
15354
+ reason: "User explicitly asked for a non-data response.",
15355
+ source: "rule"
15356
+ };
15357
+ }
15358
+ if (matchAny(text, [/什么是|解释一下|概念|区别|explain|briefly explain|why .*function calling|react/i])) {
15359
+ return {
15360
+ route: "direct_response",
15361
+ confidence: 0.86,
15362
+ reason: "Conceptual explanation without local chat-data dependency.",
15363
+ source: "rule"
15364
+ };
15365
+ }
15366
+ if (matchAny(text, [/日志在哪里|怎么配置|设置|帮助|help|where .*log/i])) {
15367
+ return {
15368
+ route: "direct_response",
15369
+ confidence: 0.84,
15370
+ reason: "Help or configuration request does not require chat tools.",
15371
+ source: "rule"
15372
+ };
15373
+ }
15374
+ if (matchAny(text, [/你觉得|闲聊|随便聊聊|建议我|should i/i])) {
15375
+ return {
15376
+ route: "direct_response",
15377
+ confidence: 0.78,
15378
+ reason: "Conversational request without clear data dependency.",
15379
+ source: "rule"
15380
+ };
15381
+ }
15382
+ return null;
15383
+ }
15384
+ function plannedRuleDecision(text) {
15385
+ if (matchAny(text, [/如果.*找不到.*继续查|换几个相关|换几个.*继续|search.*if.*not.*found/i])) {
15386
+ return {
15387
+ route: "planned_execution",
15388
+ confidence: 0.88,
15389
+ reason: "Request asks for search failure recovery and retry strategy.",
15390
+ source: "rule"
15391
+ };
15392
+ }
15393
+ const dimensions = [
15394
+ matchAny(text, [/分析|复盘|总结.*规律|趋势|变化|演变|compare|comparison/i]),
15395
+ matchAny(text, [
15396
+ /过去一年|最近一年|近一年|过去.*年|最近半年|今年|去年|上半年|下半年|长期|按季度|按月份|first half|second half/i
15397
+ ]),
15398
+ matchAny(text, [/关系|互动|影响力|核心成员|最强|最活跃|被忽略|主动|回应|turning point|转折点/i]),
15399
+ matchAny(text, [/证据|举出|例子|关键分歧|主要矛盾|evidence/i]),
15400
+ matchAny(text, [/并且|同时|以及|分别|每个阶段|按阶段|阶段|多条件|参与|回复|话题|主题|发言规律|topic|theme/i]),
15401
+ matchAny(text, [/证据不够|不足以|不够|uncertain|insufficient/i])
15402
+ ];
15403
+ const score = dimensions.filter(Boolean).length;
15404
+ if (score >= 2) {
15405
+ return {
15406
+ route: "planned_execution",
15407
+ confidence: Math.min(0.95, 0.72 + score * 0.04),
15408
+ reason: `Rule matched ${score} complex-analysis signals.`,
15409
+ source: "rule"
15410
+ };
15411
+ }
15412
+ return null;
15413
+ }
15414
+ function toolRuleDecision(text) {
15415
+ if (matchAny(text, [
15416
+ /一共有多少|多少成员|多少条消息|谁发言最多|前\s*\d+\s*名|top\s*\d+/i,
15417
+ /异常活跃|活跃度|发言最多|message count|member count/i
15418
+ ])) {
15419
+ return {
15420
+ route: "tool_assisted",
15421
+ confidence: 0.82,
15422
+ reason: "Simple statistics request can be answered by one or a few tools.",
15423
+ source: "rule"
15424
+ };
15425
+ }
15426
+ if (matchAny(text, [
15427
+ /找一下|查一下|有没有聊到|有没有提过|最近提到|昨天.*聊了什么|最近.*发言/i,
15428
+ /search|find|mentioned|talked about/i
15429
+ ])) {
15430
+ return {
15431
+ route: "tool_assisted",
15432
+ confidence: 0.78,
15433
+ reason: "Simple search or lookup request with a single clear target.",
15434
+ source: "rule"
15435
+ };
15436
+ }
15437
+ return null;
15438
+ }
15439
+ function ruleDecision(input) {
15440
+ const text = normalizeText(input.userMessage);
15441
+ return plannedRuleDecision(text) ?? toolRuleDecision(text) ?? directRuleDecision(text) ?? {
15442
+ route: "tool_assisted",
15443
+ confidence: 0.45,
15444
+ reason: "Ambiguous request; conservatively keep the existing tool-assisted Agent path.",
15445
+ source: "rule"
15446
+ };
15447
+ }
15448
+ async function decideRequestRoute(input, options = {}) {
15449
+ const decision = ruleDecision(input);
15450
+ const threshold = options.llmFallbackConfidenceThreshold ?? DEFAULT_LLM_FALLBACK_CONFIDENCE_THRESHOLD;
15451
+ if (decision.confidence >= threshold || !options.llmRouter) {
15452
+ return { ...decision, confidence: clampConfidence(decision.confidence) };
15453
+ }
15454
+ const llmDecision = await options.llmRouter(input, decision);
15455
+ return {
15456
+ ...llmDecision,
15457
+ confidence: clampConfidence(llmDecision.confidence)
15458
+ };
15459
+ }
15460
+ function createLlmRouteDecider(options) {
15461
+ return async (input, ruleDecision2) => {
15462
+ const prompt = buildLlmRouterPrompt(input, ruleDecision2);
15463
+ try {
15464
+ const rawResult = options.complete ? await options.complete(prompt, options.abortSignal) : await completeWithPiAi(prompt, options);
15465
+ const { text, usage } = resultToText(rawResult);
15466
+ const decision = parseLlmDecision(text, usage);
15467
+ if (decision) return decision;
15468
+ return {
15469
+ ...ruleDecision2,
15470
+ reason: `${ruleDecision2.reason} LLM fallback returned invalid route JSON.`
15471
+ };
15472
+ } catch (error) {
15473
+ const message = error instanceof Error ? error.message : String(error);
15474
+ return {
15475
+ ...ruleDecision2,
15476
+ reason: `${ruleDecision2.reason} LLM fallback failed: ${message}`
15477
+ };
15478
+ }
15479
+ };
15480
+ }
15481
+ async function completeWithPiAi(prompt, options) {
15482
+ if (!options.piModel || !options.apiKey) {
15483
+ throw new Error("LLM router requires piModel and apiKey");
15484
+ }
15485
+ const result = await completeSimple2(
15486
+ options.piModel,
15487
+ {
15488
+ systemPrompt: "You are a strict JSON classifier for ChatLab AI routing. Return JSON only.",
15489
+ messages: [{ role: "user", content: [{ type: "text", text: prompt }], timestamp: Date.now() }]
15490
+ },
15491
+ {
15492
+ apiKey: options.apiKey,
15493
+ maxTokens: options.maxTokens ?? 180,
15494
+ temperature: options.temperature ?? 0,
15495
+ signal: options.abortSignal
15496
+ }
15497
+ );
15498
+ const text = result.content.filter((item) => item.type === "text").map((item) => item.text).join("");
15499
+ return {
15500
+ text,
15501
+ usage: {
15502
+ promptTokens: result.usage?.input,
15503
+ completionTokens: result.usage?.output,
15504
+ totalTokens: result.usage?.totalTokens
15505
+ }
15506
+ };
15507
+ }
15508
+
15509
+ // ../../packages/node-runtime/src/ai/agent/planner.ts
15510
+ import {
15511
+ completeSimple as completeSimple3,
15512
+ streamSimple
15513
+ } from "@earendil-works/pi-ai";
15514
+ var PLAN_INTENTS = [
15515
+ "summary",
15516
+ "trend",
15517
+ "relationship",
15518
+ "search",
15519
+ "comparison",
15520
+ "mixed"
15521
+ ];
15522
+ var STREAM_MARKER_HOLDBACK_CHARS = Math.max("</draft>".length, "</plan>".length, "<json>".length) - 1;
15523
+ function isRecord2(value) {
15524
+ return typeof value === "object" && value !== null && !Array.isArray(value);
15525
+ }
15526
+ function isIntent(value) {
15527
+ return typeof value === "string" && PLAN_INTENTS.includes(value);
15528
+ }
15529
+ function normalizeString(value) {
15530
+ if (typeof value !== "string") return null;
15531
+ const text = value.trim();
15532
+ return text.length > 0 ? text : null;
15533
+ }
15534
+ function extractJsonObject4(text) {
15535
+ const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
15536
+ if (fenced?.[1]) return fenced[1].trim();
15537
+ const start = text.indexOf("{");
15538
+ const end = text.lastIndexOf("}");
15539
+ if (start >= 0 && end > start) return text.slice(start, end + 1);
15540
+ return text.trim();
15541
+ }
15542
+ function parsePlanJson(rawText, availableTools) {
15543
+ try {
15544
+ const parsed = JSON.parse(extractJsonObject4(rawText));
15545
+ if (!isRecord2(parsed)) return null;
15546
+ const title = normalizeString(parsed.title);
15547
+ if (!title || !isIntent(parsed.intent) || !Array.isArray(parsed.steps)) return null;
15548
+ const steps = parsed.steps.filter(isRecord2).map((step) => {
15549
+ const goal = normalizeString(step.goal);
15550
+ const evidenceNeeded = normalizeString(step.evidenceNeeded);
15551
+ if (!goal || !evidenceNeeded) return null;
15552
+ const suggestedTools = Array.isArray(step.suggestedTools) ? step.suggestedTools.filter((tool) => typeof tool === "string" && availableTools.has(tool)) : [];
15553
+ return { goal, suggestedTools: Array.from(new Set(suggestedTools)), evidenceNeeded };
15554
+ }).filter((step) => step !== null).slice(0, 5);
15555
+ if (steps.length === 0) return null;
15556
+ const successCriteria = Array.isArray(parsed.successCriteria) ? parsed.successCriteria.map(normalizeString).filter((item) => item !== null).slice(0, 5) : [];
15557
+ if (successCriteria.length === 0) return null;
15558
+ return {
15559
+ version: 1,
15560
+ title,
15561
+ route: "planned_execution",
15562
+ intent: parsed.intent,
15563
+ steps,
15564
+ successCriteria
15565
+ };
15566
+ } catch {
15567
+ return null;
15568
+ }
15569
+ }
15570
+ function resultToText2(result) {
15571
+ return typeof result === "string" ? result : result.text;
15572
+ }
15573
+ function buildPlannerPrompt(input) {
15574
+ const dataSnapshot = formatDataSnapshotForPlanner(input.dataSnapshot);
15575
+ const availableCapabilities = input.availableCapabilities && input.availableCapabilities.length > 0 ? input.availableCapabilities.map((capability) => {
15576
+ const tools = capability.tools.join(", ") || "none";
15577
+ return ` - ${capability.id} (${capability.label}; tools: ${tools}): ${capability.guidance}`;
15578
+ }).join("\n") : "(none)";
15579
+ return `Create a concise user-visible analysis plan for a ChatLab planned_execution request.
15580
+
15581
+ Return exactly three blocks:
15582
+ <draft>
15583
+ A brief user-visible planning note in the user's locale. Keep it high-level; do not reveal hidden chain-of-thought.
15584
+ </draft>
15585
+ <plan>
15586
+ A concise user-facing analysis approach in the user's locale. Do not include suggested tools, evidence fields, or success criteria; those details belong in <json>.
15587
+ </plan>
15588
+ <json>
15589
+ {
15590
+ "title": "short title",
15591
+ "intent": "summary|trend|relationship|search|comparison|mixed",
15592
+ "steps": [
15593
+ {"goal": "what to investigate", "suggestedTools": ["tool_name"], "evidenceNeeded": "what evidence is needed"}
15594
+ ],
15595
+ "successCriteria": ["criterion"]
15596
+ }
15597
+ </json>
15598
+
15599
+ Limits:
15600
+ - Max 5 steps.
15601
+ - Max 5 successCriteria.
15602
+ - suggestedTools must come only from availableTools.
15603
+ - If availableCapabilities are listed, you may plan steps that use their tools when the capability helps the user.
15604
+ - Do not reveal hidden chain-of-thought; draft and plan are user-readable summaries only.
15605
+ - The plan is soft guidance, not a mandatory execution script.
15606
+
15607
+ Planning strategy:
15608
+ - For open-ended topic, community profile, influence, interaction-pattern, or multi-dimensional retrospective analysis, first plan a lightweight reconnaissance step to build a topic/member activity map before drawing conclusions.
15609
+ - Prefer segment summaries, keyword frequency, time distribution, member activity, and representative message retrieval when available.
15610
+ - Do not create a dedicated step whose only purpose is finding max timestamp or confirming latest message time.
15611
+
15612
+ Context:
15613
+ - locale: ${input.locale}
15614
+ - chatType: ${input.chatType}
15615
+ - availableTools: ${input.availableTools.join(", ") || "(none)"}
15616
+ - availableCapabilities:
15617
+ ${availableCapabilities}
15618
+ - dataSnapshot: ${dataSnapshot}
15619
+ - assistantSummary: ${input.assistantSummary ?? "(none)"}
15620
+ - skillSummary: ${input.skillSummary ?? "(none)"}
15621
+ - recentIntentSummary: ${input.recentIntentSummary ?? "(none)"}
15622
+
15623
+ User request:
15624
+ ${input.userMessage}`;
15625
+ }
15626
+ function createAnalysisPlanner(options) {
15627
+ return async (input, signal) => {
15628
+ try {
15629
+ const prompt = buildPlannerPrompt(input);
15630
+ const callbacks = {
15631
+ onPlanDelta: options.onPlanDelta ?? (() => {
15632
+ }),
15633
+ onThinkingDelta: options.onThinkingDelta,
15634
+ onThinkingEnd: options.onThinkingEnd,
15635
+ onValidationDelta: options.onValidationDelta,
15636
+ onValidationEnd: options.onValidationEnd
15637
+ };
15638
+ const rawResult = options.stream ? await options.stream(prompt, callbacks, signal) : options.complete ? await options.complete(prompt, signal) : options.onPlanDelta ? await streamWithPiAi(prompt, options, signal) : await completeWithPiAi2(prompt, options, signal);
15639
+ return parsePlanJson(resultToText2(rawResult), new Set(input.availableTools));
15640
+ } catch {
15641
+ return null;
15642
+ }
15643
+ };
15644
+ }
15645
+ function createPlanContentBlock(plan, status = "created") {
15646
+ return {
15647
+ type: "plan",
15648
+ version: 1,
15649
+ status,
15650
+ plan
15651
+ };
15652
+ }
15653
+ function buildPlanGuidance(plan) {
15654
+ const steps = plan.steps.map((step, index) => {
15655
+ const tools = step.suggestedTools.length > 0 ? step.suggestedTools.join(", ") : "none";
15656
+ return `${index + 1}. ${step.goal}
15657
+ Evidence needed: ${step.evidenceNeeded}
15658
+ Suggested tools: ${tools}`;
15659
+ }).join("\n");
15660
+ const successCriteria = plan.successCriteria.map((item) => `- ${item}`).join("\n");
15661
+ return `A suggested analysis plan is available below. Use it as guidance when helpful, but do not follow it mechanically if the user's question can be answered more directly.
15662
+
15663
+ Plan title: ${plan.title}
15664
+ Intent: ${plan.intent}
15665
+
15666
+ Steps:
15667
+ ${steps}
15668
+
15669
+ Success criteria:
15670
+ ${successCriteria}`;
15671
+ }
15672
+ async function completeWithPiAi2(prompt, options, signal) {
15673
+ if (!options.piModel || !options.apiKey) {
15674
+ throw new Error("Planner requires piModel and apiKey");
15675
+ }
15676
+ const result = await completeSimple3(
15677
+ options.piModel,
15678
+ {
15679
+ systemPrompt: "You are a strict planner for ChatLab analysis. Return the requested blocks only.",
15680
+ messages: [{ role: "user", content: [{ type: "text", text: prompt }], timestamp: Date.now() }]
15681
+ },
15682
+ {
15683
+ apiKey: options.apiKey,
15684
+ maxTokens: options.maxTokens ?? 900,
15685
+ temperature: options.temperature ?? 0.2,
15686
+ signal
15687
+ }
15688
+ );
15689
+ return {
15690
+ text: result.content.filter((item) => item.type === "text").map((item) => item.text).join("")
15691
+ };
15692
+ }
15693
+ function extractTaggedBlockText(rawText, tag, nextTags) {
15694
+ const openTag = `<${tag}>`;
15695
+ const closeTag = `</${tag}>`;
15696
+ const blockStart = rawText.indexOf(openTag);
15697
+ if (blockStart < 0) return "";
15698
+ const bodyStart = blockStart + openTag.length;
15699
+ const closeStart = rawText.indexOf(closeTag, bodyStart);
15700
+ const nextStarts = nextTags.map((nextTag) => rawText.indexOf(nextTag, bodyStart)).filter((index) => index >= 0);
15701
+ const endCandidates = [closeStart, ...nextStarts].filter((index) => index >= 0);
15702
+ const bodyEnd = endCandidates.length > 0 ? Math.min(...endCandidates) : Math.max(bodyStart, rawText.length - STREAM_MARKER_HOLDBACK_CHARS);
15703
+ const text = rawText.slice(bodyStart, bodyEnd);
15704
+ return text.replace(/^\s+/, "");
15705
+ }
15706
+ async function streamWithPiAi(prompt, options, signal) {
15707
+ if (!options.piModel || !options.apiKey) {
15708
+ throw new Error("Planner requires piModel and apiKey");
15709
+ }
15710
+ const stream = streamSimple(
15711
+ options.piModel,
15712
+ {
15713
+ systemPrompt: "You are a strict planner for ChatLab analysis. Return the requested plan and JSON blocks only.",
15714
+ messages: [{ role: "user", content: [{ type: "text", text: prompt }], timestamp: Date.now() }]
15715
+ },
15716
+ {
15717
+ apiKey: options.apiKey,
15718
+ maxTokens: options.maxTokens ?? 900,
15719
+ temperature: options.temperature ?? 0.2,
15720
+ signal
15721
+ }
15722
+ );
15723
+ let text = "";
15724
+ let emittedDraftLength = 0;
15725
+ let emittedPlanLength = 0;
15726
+ let emittedJsonLength = 0;
15727
+ let thinkingStartedAt;
15728
+ let draftThinkingStartedAt;
15729
+ let draftThinkingEnded = false;
15730
+ let validationStartedAt;
15731
+ let validationEnded = false;
15732
+ for await (const event of stream) {
15733
+ if (signal?.aborted) break;
15734
+ if (event.type === "thinking_start") {
15735
+ thinkingStartedAt = Date.now();
15736
+ continue;
15737
+ }
15738
+ if (event.type === "thinking_delta") {
15739
+ options.onThinkingDelta?.(event.delta);
15740
+ continue;
15741
+ }
15742
+ if (event.type === "thinking_end") {
15743
+ const durationMs = thinkingStartedAt ? Date.now() - thinkingStartedAt : void 0;
15744
+ thinkingStartedAt = void 0;
15745
+ options.onThinkingEnd?.(durationMs);
15746
+ continue;
15747
+ }
15748
+ if (event.type !== "text_delta") continue;
15749
+ text += event.delta;
15750
+ const draftText = extractTaggedBlockText(text, "draft", ["<plan>", "<json>"]);
15751
+ if (draftText.length > emittedDraftLength) {
15752
+ if (!draftThinkingStartedAt) draftThinkingStartedAt = Date.now();
15753
+ const delta = draftText.slice(emittedDraftLength);
15754
+ emittedDraftLength = draftText.length;
15755
+ if (delta.trim().length > 0 || /\s/.test(delta)) {
15756
+ options.onThinkingDelta?.(delta);
15757
+ }
15758
+ }
15759
+ if (!draftThinkingEnded && emittedDraftLength > 0 && (text.includes("</draft>") || text.includes("<plan>"))) {
15760
+ draftThinkingEnded = true;
15761
+ const durationMs = draftThinkingStartedAt ? Date.now() - draftThinkingStartedAt : void 0;
15762
+ options.onThinkingEnd?.(durationMs);
15763
+ }
15764
+ const planText = extractTaggedBlockText(text, "plan", ["<json>"]);
15765
+ if (planText.length > emittedPlanLength) {
15766
+ const delta = planText.slice(emittedPlanLength);
15767
+ emittedPlanLength = planText.length;
15768
+ if (delta.trim().length > 0 || /\s/.test(delta)) {
15769
+ options.onPlanDelta?.(delta);
15770
+ }
15771
+ }
15772
+ const jsonText = extractTaggedBlockText(text, "json", []);
15773
+ if (jsonText.length > emittedJsonLength) {
15774
+ if (!validationStartedAt) validationStartedAt = Date.now();
15775
+ const delta = jsonText.slice(emittedJsonLength);
15776
+ emittedJsonLength = jsonText.length;
15777
+ if (delta.trim().length > 0 || /\s/.test(delta)) {
15778
+ options.onValidationDelta?.(delta);
15779
+ }
15780
+ }
15781
+ if (!validationEnded && emittedJsonLength > 0 && text.includes("</json>")) {
15782
+ validationEnded = true;
15783
+ const durationMs = validationStartedAt ? Date.now() - validationStartedAt : void 0;
15784
+ options.onValidationEnd?.(durationMs);
15785
+ }
15786
+ }
15787
+ return { text };
15788
+ }
15789
+
15185
15790
  // ../../packages/node-runtime/src/ai/agent/event-handler.ts
15186
15791
  function estimateTokensFromText(text) {
15187
15792
  if (!text) return 0;
@@ -15318,6 +15923,39 @@ var AgentEventHandler = class {
15318
15923
  function agentT(t2, key, locale, options) {
15319
15924
  return t2(key, { lng: locale, ...options });
15320
15925
  }
15926
+ function formatNullableTimestamp2(timestamp) {
15927
+ return typeof timestamp === "number" && Number.isFinite(timestamp) ? String(timestamp) : "null";
15928
+ }
15929
+ function formatSharePercent2(share) {
15930
+ if (!Number.isFinite(share)) return "0%";
15931
+ const rounded = Math.round(share * 10) / 10;
15932
+ return Number.isInteger(rounded) ? `${rounded}%` : `${rounded.toFixed(1)}%`;
15933
+ }
15934
+ function normalizeInlineText(text) {
15935
+ return text.replace(/\s+/g, " ").trim();
15936
+ }
15937
+ function formatDataSnapshotContext(t2, dataSnapshot, locale) {
15938
+ const memberHints = dataSnapshot.activeMemberHints ?? [];
15939
+ const memberHintTitle = memberHints.length === 0 ? agentT(t2, "ai.agent.dataSnapshotMemberHintsUnavailable", locale) : dataSnapshot.totalMembers <= 10 ? agentT(t2, "ai.agent.dataSnapshotMemberHintsAll", locale) : agentT(t2, "ai.agent.dataSnapshotMemberHintsTop", locale);
15940
+ const memberHintLines = memberHints.length > 0 ? memberHints.map((member, index) => {
15941
+ return `${index + 1}. member_id=${member.memberId} | display_name=${normalizeInlineText(member.displayName)} | messages=${member.messageCount} | share=${formatSharePercent2(member.share)}`;
15942
+ }).join("\n") : agentT(t2, "ai.agent.dataSnapshotMemberHintsEmpty", locale);
15943
+ return agentT(t2, "ai.agent.dataSnapshotContext", locale, {
15944
+ name: dataSnapshot.name,
15945
+ platform: dataSnapshot.platform,
15946
+ type: dataSnapshot.type,
15947
+ totalMessages: dataSnapshot.totalMessages,
15948
+ totalMembers: dataSnapshot.totalMembers,
15949
+ firstMessageTs: formatNullableTimestamp2(dataSnapshot.firstMessageTs),
15950
+ firstMessageTime: formatTimestamp(dataSnapshot.firstMessageTs, locale),
15951
+ lastMessageTs: formatNullableTimestamp2(dataSnapshot.lastMessageTs),
15952
+ lastMessageTime: formatTimestamp(dataSnapshot.lastMessageTs, locale),
15953
+ segmentSummaryCount: dataSnapshot.segmentSummaries?.availableCount ?? 0,
15954
+ memberHintTitle,
15955
+ memberHintLines,
15956
+ usageRules: agentT(t2, "ai.agent.dataSnapshotUsageRules", locale)
15957
+ });
15958
+ }
15321
15959
  function getLockedPromptSection(t2, chatType, ownerInfo, locale, mentionedMembers, dataSnapshot) {
15322
15960
  const now = /* @__PURE__ */ new Date();
15323
15961
  const dateLocale = locale.startsWith("zh") ? "zh-CN" : "en-US";
@@ -15342,14 +15980,7 @@ ${mentionedMembers.map((member) => {
15342
15980
  }).join("\n")}
15343
15981
  ` : "";
15344
15982
  const year = now.getFullYear();
15345
- const dataSnapshotNote = dataSnapshot ? `${agentT(t2, "ai.agent.dataSnapshotNote", locale, {
15346
- name: dataSnapshot.name,
15347
- platform: dataSnapshot.platform,
15348
- totalMessages: dataSnapshot.totalMessages,
15349
- totalMembers: dataSnapshot.totalMembers,
15350
- firstMessageDate: formatTimestamp(dataSnapshot.firstMessageTs, locale),
15351
- lastMessageDate: formatTimestamp(dataSnapshot.lastMessageTs, locale)
15352
- })}
15983
+ const dataSnapshotNote = dataSnapshot ? `${formatDataSnapshotContext(t2, dataSnapshot, locale)}
15353
15984
  ` : "";
15354
15985
  return `${agentT(t2, "ai.agent.currentDateIs", locale)} ${currentDate}\u3002
15355
15986
  ${ownerNote}
@@ -15463,7 +16094,7 @@ var zh_CN_default = {
15463
16094
  }
15464
16095
  },
15465
16096
  get_time_stats: {
15466
- desc: '\u83B7\u53D6\u7FA4\u804A\u7684\u65F6\u95F4\u5206\u5E03\u7EDF\u8BA1\u3002\u9002\u7528\u4E8E\u56DE\u7B54"\u4EC0\u4E48\u65F6\u5019\u6700\u6D3B\u8DC3"\u3001"\u5927\u5BB6\u4E00\u822C\u51E0\u70B9\u804A\u5929"\u7B49\u95EE\u9898\u3002',
16097
+ desc: '\u83B7\u53D6\u7FA4\u804A\u7684\u65F6\u95F4\u5206\u5E03\u7EDF\u8BA1\u3002\u9002\u7528\u4E8E\u56DE\u7B54"\u4EC0\u4E48\u65F6\u5019\u6700\u6D3B\u8DC3"\u3001"\u5927\u5BB6\u4E00\u822C\u51E0\u70B9\u804A\u5929"\u7B49\u95EE\u9898\u3002\u8FD4\u56DE\u7684 `data` \u6570\u7EC4\u53EF\u76F4\u63A5\u4F5C\u4E3A `render_chart` \u7684 `rows` \u53C2\u6570\u7528\u4E8E\u7ED8\u56FE\u3002',
15467
16098
  params: {
15468
16099
  type: "\u7EDF\u8BA1\u7C7B\u578B\uFF1Ahourly\uFF08\u6309\u5C0F\u65F6\uFF09\u3001weekday\uFF08\u6309\u661F\u671F\uFF09\u3001daily\uFF08\u6309\u65E5\u671F\uFF09"
15469
16100
  }
@@ -15653,9 +16284,10 @@ var zh_CN_default = {
15653
16284
  params: {}
15654
16285
  },
15655
16286
  render_chart: {
15656
- desc: "\u6839\u636E\u53EA\u8BFB SQL \u548C ChartSpec v1 \u751F\u6210 ChatLab \u539F\u751F\u56FE\u8868\u3002\u652F\u6301 bar\u3001line\u3001pie\u3001heatmap\u3002\u7981\u6B62\u8F93\u51FA HTML\u3001JavaScript\u3001SVG\u3001ECharts option \u6216\u6E32\u67D3\u4EE3\u7801\u3002",
16287
+ desc: "\u6839\u636E ChartSpec v1 \u751F\u6210 ChatLab \u539F\u751F\u56FE\u8868\u3002\u652F\u6301 bar\u3001line\u3001pie\u3001heatmap\u3002\u63D0\u4F9B `rows`\uFF08\u6765\u81EA\u9AD8\u5C42\u5DE5\u5177\u7684\u6570\u636E\u6570\u7EC4\uFF0C\u5982 get_time_stats \u7684 `data` \u5B57\u6BB5\uFF09\u6216 `sql`\uFF08\u53EA\u8BFB SELECT\uFF09\u4E8C\u9009\u4E00\uFF1B\u6709\u73B0\u6210\u6570\u636E\u65F6\u4F18\u5148\u7528 `rows`\uFF0C\u53EA\u6709\u9AD8\u5C42\u5DE5\u5177\u65E0\u6CD5\u6EE1\u8DB3\u65F6\u624D\u5199 `sql`\u3002\u7981\u6B62\u8F93\u51FA HTML\u3001JavaScript\u3001SVG\u3001ECharts option \u6216\u6E32\u67D3\u4EE3\u7801\u3002",
15657
16288
  params: {
15658
- sql: "\u53EA\u8BFB SELECT \u6216 WITH SELECT SQL\u3002\u5FC5\u987B\u8FD4\u56DE ChartSpec encoding \u4E2D\u5F15\u7528\u7684\u5B57\u6BB5\u3002",
16289
+ rows: "\u6765\u81EA\u9AD8\u5C42\u5DE5\u5177\u8FD4\u56DE\u7684\u6570\u636E\u6570\u7EC4\uFF08\u5982 get_time_stats \u7684 `data` \u5B57\u6BB5\uFF09\u3002\u6709\u73B0\u6210\u6570\u636E\u65F6\u4F18\u5148\u4F7F\u7528\uFF0C\u4E0E sql \u4E8C\u9009\u4E00\u3002",
16290
+ sql: "\u53EA\u8BFB SELECT \u6216 WITH SELECT SQL\u3002\u4EC5\u5728\u9AD8\u5C42\u5DE5\u5177\u65E0\u6CD5\u6EE1\u8DB3\u9700\u6C42\u65F6\u4F7F\u7528\uFF0C\u5FC5\u987B\u8FD4\u56DE ChartSpec encoding \u4E2D\u5F15\u7528\u7684\u5B57\u6BB5\u3002",
15659
16291
  params: "SQL \u547D\u540D\u53C2\u6570\u5BF9\u8C61\uFF1B\u4E0D\u9700\u8981\u53C2\u6570\u65F6\u4F20\u7A7A\u5BF9\u8C61\u3002",
15660
16292
  chartSpec: "ChartSpec v1\uFF0C\u5305\u542B version\u3001type\u3001title\u3001encoding\u3002",
15661
16293
  maxRows: "\u56FE\u8868\u67E5\u8BE2\u6700\u5927\u884C\u6570\uFF0C\u9ED8\u8BA4 1000\u3002"
@@ -15689,6 +16321,35 @@ var zh_CN_default = {
15689
16321
  timeParamsIntro: '\u65F6\u95F4\u53C2\u6570\uFF1A\u4F7F\u7528 start_time/end_time \u6307\u5B9A\u65F6\u95F4\u8303\u56F4\uFF0C\u683C\u5F0F "YYYY-MM-DD HH:mm"',
15690
16322
  defaultYearNote: "\u672A\u6307\u5B9A\u65F6\u95F4\u8303\u56F4\u65F6\u9ED8\u8BA4\u67E5\u8BE2\u5168\u90E8\u3002\u5F53\u524D\u5E74\u4EFD\u4E3A{{year}}\u5E74",
15691
16323
  dataSnapshotNote: "\u5F53\u524D\u804A\u5929\u6570\u636E\u5E93\u5FEB\u7167\uFF1A{{name}}\uFF08{{platform}}\uFF09\uFF0C\u603B\u6D88\u606F {{totalMessages}} \u6761\uFF0C\u6210\u5458 {{totalMembers}} \u4EBA\uFF0C\u65F6\u95F4\u8303\u56F4 {{firstMessageDate}} ~ {{lastMessageDate}}\u3002\u8BE5\u5FEB\u7167\u53EA\u7528\u4E8E\u5224\u65AD\u6570\u636E\u8303\u56F4\uFF1B\u56DE\u7B54\u5177\u4F53\u804A\u5929\u4E8B\u5B9E\u4ECD\u5FC5\u987B\u8C03\u7528\u5DE5\u5177\u68C0\u7D22\u5F53\u524D\u6570\u636E\u5E93\u3002",
16324
+ dataSnapshotContext: `\u5F53\u524D\u804A\u5929\u6570\u636E\u5E93\u542F\u52A8\u4E0A\u4E0B\u6587\uFF1A
16325
+ - name: {{name}}
16326
+ - platform: {{platform}}
16327
+ - type: {{type}}
16328
+ - total_messages: {{totalMessages}}
16329
+ - total_members: {{totalMembers}}
16330
+ - first_message_ts: {{firstMessageTs}}
16331
+ - first_message_time: {{firstMessageTime}}
16332
+ - last_message_ts: {{lastMessageTs}}
16333
+ - last_message_time: {{lastMessageTime}}
16334
+ - segment_summaries_available: {{segmentSummaryCount}}
16335
+
16336
+ {{memberHintTitle}}
16337
+ {{memberHintLines}}
16338
+
16339
+ \u4F7F\u7528\u89C4\u5219\uFF1A
16340
+ {{usageRules}}`,
16341
+ dataSnapshotMemberHintsAll: "\u6D3B\u8DC3\u6210\u5458\u67E5\u8BE2\u63D0\u793A\uFF08\u5168\u90E8\u6210\u5458\uFF09\uFF1A",
16342
+ dataSnapshotMemberHintsTop: "\u6D3B\u8DC3\u6210\u5458\u67E5\u8BE2\u63D0\u793A\uFF08\u6309\u5386\u53F2\u603B\u6D88\u606F\u91CF Top 10\uFF09\uFF1A",
16343
+ dataSnapshotMemberHintsUnavailable: "\u6D3B\u8DC3\u6210\u5458\u67E5\u8BE2\u63D0\u793A\uFF1A",
16344
+ dataSnapshotMemberHintsEmpty: "\u65E0\u53EF\u7528\u6210\u5458\u63D0\u793A\u3002",
16345
+ dataSnapshotUsageRules: `- member_id \u662F\u5DE5\u5177\u67E5\u8BE2\u63D0\u793A\uFF1Bdisplay_name \u4EC5\u7528\u4E8E\u4EBA\u7C7B\u8BC6\u522B\uFF0C\u53EF\u80FD\u4E0D\u552F\u4E00\u3002
16346
+ - \u4E0D\u8981\u5728\u6700\u7EC8\u56DE\u7B54\u4E2D\u4E3B\u52A8\u66B4\u9732 member_id \u6216\u542F\u52A8\u4E0A\u4E0B\u6587\u672C\u8EAB\uFF0C\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u6280\u672F\u7EC6\u8282\u3002
16347
+ - \u6D3B\u8DC3\u6210\u5458\u6392\u884C\u53EA\u4EE3\u8868\u5386\u53F2\u603B\u6D88\u606F\u91CF\uFF0C\u4E0D\u4EE3\u8868\u6700\u8FD1\u6D3B\u8DC3\u60C5\u51B5\uFF1B\u4E5F\u4E0D\u8DB3\u4EE5\u4F5C\u4E3A\u5F71\u54CD\u529B\u3001\u5173\u7CFB\u6216\u8FD1\u671F\u8D8B\u52BF\u7ED3\u8BBA\u7684\u8BC1\u636E\u3002
16348
+ - \u76F8\u5BF9\u65F6\u95F4\u8868\u8FBE\u4EE5\u771F\u5B9E\u5F53\u524D\u65E5\u671F\u4E3A\u57FA\u51C6\uFF0C\u800C\u4E0D\u662F\u6570\u636E\u5E93\u6700\u540E\u6D88\u606F\u65F6\u95F4\u3002
16349
+ - \u201C\u6700\u8FD1\u4E00\u5E74/\u8FC7\u53BB\u4E00\u5E74\u201D\u8868\u793A\u4ECE\u771F\u5B9E\u5F53\u524D\u65E5\u671F\u56DE\u63A8\u4E00\u5E74\u5230\u4ECA\u5929\uFF1B\u201C\u53BB\u5E74\u201D\u8868\u793A\u4E0A\u4E00\u81EA\u7136\u5E74\u3002
16350
+ - \u6570\u636E\u5E93\u65F6\u95F4\u8FB9\u754C\u53EA\u7528\u4E8E\u8BF4\u660E\u8986\u76D6\u8303\u56F4\uFF0C\u4E0D\u7528\u4E8E\u91CD\u5B9A\u4E49\u7528\u6237\u8981\u6C42\u7684\u65F6\u95F4\u8303\u56F4\u3002
16351
+ - \u4F7F\u7528\u9ED8\u8BA4\u201C\u8FD1 N \u5929\u201D\u7684\u5DE5\u5177\u65F6\uFF0C\u5148\u9009\u62E9\u4E0E\u6570\u636E\u5E93\u65F6\u95F4\u8FB9\u754C\u6709\u4EA4\u96C6\u7684\u8303\u56F4\uFF0C\u4E0D\u8981\u5148\u63A2\u6D4B\u771F\u5B9E\u5F53\u524D\u65E5\u671F\u7A97\u53E3\u5BFC\u81F4\u7A7A\u7ED3\u679C\u3002
16352
+ - \u4E0D\u8981\u53EA\u4E3A\u4E86\u91CD\u65B0\u53D1\u73B0 min/max timestamp \u8C03\u7528\u5DE5\u5177\uFF1B\u4F46\u56DE\u7B54\u5177\u4F53\u804A\u5929\u4E8B\u5B9E\u3001\u7EDF\u8BA1\u548C\u7ED3\u8BBA\u4ECD\u5FC5\u987B\u8C03\u7528\u5DE5\u5177\u83B7\u53D6\u8BC1\u636E\u3002`,
15692
16353
  evidencePolicy: `\u8BC1\u636E\u7B56\u7565\uFF1A
15693
16354
  - AI \u5BF9\u8BDD\u5386\u53F2\u3001\u5386\u53F2 AI \u56DE\u590D\u548C\u538B\u7F29\u6458\u8981\u53EA\u7528\u4E8E\u7406\u89E3\u7528\u6237\u610F\u56FE\uFF0C\u4E0D\u80FD\u4F5C\u4E3A\u804A\u5929\u8BB0\u5F55\u4E8B\u5B9E\u8BC1\u636E\u3002
15694
16355
  - \u53EA\u8981\u7528\u6237\u8BE2\u95EE\u804A\u5929\u8BB0\u5F55\u5185\u5BB9\u3001\u6700\u8FD1\u804A\u4EC0\u4E48\u3001\u67D0\u4EBA\u8BF4\u8FC7\u4EC0\u4E48\u3001\u7EDF\u8BA1\u6392\u884C\u3001\u662F\u5426\u51FA\u73B0\u8FC7\u67D0\u8BDD\u9898\u6216\u8981\u6C42\u5F15\u7528\u539F\u8BDD\uFF0C\u5FC5\u987B\u5148\u8C03\u7528\u5408\u9002\u7684\u6570\u636E\u5DE5\u5177\u68C0\u7D22\u5F53\u524D\u6570\u636E\u5E93\u3002
@@ -15797,7 +16458,7 @@ var en_US_default = {
15797
16458
  }
15798
16459
  },
15799
16460
  get_time_stats: {
15800
- desc: 'Get time distribution statistics of chat activity. Suitable for questions like "when is the group most active" or "what time do people usually chat".',
16461
+ desc: 'Get time distribution statistics of chat activity. Suitable for questions like "when is the group most active" or "what time do people usually chat". The returned `data` array can be passed directly as the `rows` parameter of render_chart for visualization.',
15801
16462
  params: {
15802
16463
  type: "Statistics type: hourly (by hour), weekday (by day of week), daily (by date)"
15803
16464
  }
@@ -15988,9 +16649,10 @@ Returned summaries are brief descriptions of each segment, helping quickly locat
15988
16649
  params: {}
15989
16650
  },
15990
16651
  render_chart: {
15991
- desc: "Generate a native ChatLab chart from read-only SQL and ChartSpec v1. Supports bar, line, pie, and heatmap. Do not output HTML, JavaScript, SVG, ECharts options, or rendering code.",
16652
+ desc: "Generate a native ChatLab chart from ChartSpec v1. Supports bar, line, pie, and heatmap. Provide either `rows` (pre-fetched data array from a tool result, e.g. the `data` field from get_time_stats) or `sql` (read-only SELECT) \u2014 prefer `rows` when data is already available; use `sql` only when high-level tools cannot satisfy the need. Do not output HTML, JavaScript, SVG, ECharts options, or rendering code.",
15992
16653
  params: {
15993
- sql: "Read-only SELECT or WITH SELECT SQL. It must return fields referenced by ChartSpec encoding.",
16654
+ rows: "Pre-fetched data array from a high-level tool result (e.g. the `data` field from get_time_stats). Prefer this over sql when data is already available. Mutually exclusive with sql.",
16655
+ sql: "Read-only SELECT or WITH SELECT SQL. Use only when high-level tools cannot satisfy the need. Must return fields referenced by ChartSpec encoding.",
15994
16656
  params: "Named SQL parameters. Use an empty object when no parameters are needed.",
15995
16657
  chartSpec: "ChartSpec v1 with version, type, title, and encoding.",
15996
16658
  maxRows: "Maximum chart query rows. Default 1000."
@@ -16025,6 +16687,35 @@ Returned summaries are brief descriptions of each segment, helping quickly locat
16025
16687
  timeParamsIntro: 'Time parameters: use start_time/end_time to specify the range, format "YYYY-MM-DD HH:mm"',
16026
16688
  defaultYearNote: "When no time range is specified, queries default to all data. Current year is {{year}}.",
16027
16689
  dataSnapshotNote: "Current chat database snapshot: {{name}} ({{platform}}), {{totalMessages}} total messages, {{totalMembers}} members, time range {{firstMessageDate}} ~ {{lastMessageDate}}. This snapshot only helps judge data coverage; concrete chat facts still require tool retrieval from the current database.",
16690
+ dataSnapshotContext: `Current chat database startup context:
16691
+ - name: {{name}}
16692
+ - platform: {{platform}}
16693
+ - type: {{type}}
16694
+ - total_messages: {{totalMessages}}
16695
+ - total_members: {{totalMembers}}
16696
+ - first_message_ts: {{firstMessageTs}}
16697
+ - first_message_time: {{firstMessageTime}}
16698
+ - last_message_ts: {{lastMessageTs}}
16699
+ - last_message_time: {{lastMessageTime}}
16700
+ - segment_summaries_available: {{segmentSummaryCount}}
16701
+
16702
+ {{memberHintTitle}}
16703
+ {{memberHintLines}}
16704
+
16705
+ Usage rules:
16706
+ {{usageRules}}`,
16707
+ dataSnapshotMemberHintsAll: "Active member lookup hints (all members):",
16708
+ dataSnapshotMemberHintsTop: "Active member lookup hints (top 10 by historical total messages):",
16709
+ dataSnapshotMemberHintsUnavailable: "Active member lookup hints:",
16710
+ dataSnapshotMemberHintsEmpty: "No member hints available.",
16711
+ dataSnapshotUsageRules: `- member_id is a tool lookup hint; display_name is only for human recognition and may not be unique.
16712
+ - Do not proactively expose member_id or the startup context in the final answer unless the user explicitly asks for technical details.
16713
+ - Active member ranking only reflects historical total message volume, not recent activity; it is also not evidence for influence, relationships, or recent trends.
16714
+ - Interpret relative time expressions using the real current date, not the database's last message time.
16715
+ - "recent year" / "past year" means one year back from the real current date to today; "last year" means the previous calendar year.
16716
+ - Database time bounds are only for explaining coverage, not for redefining the user's requested time range.
16717
+ - When using default recent-day tools, first choose a range that intersects database time bounds instead of probing an empty real-current-date window.
16718
+ - Do not call tools only to rediscover min/max timestamp; concrete chat facts, statistics, and conclusions still require tool evidence.`,
16028
16719
  evidencePolicy: `Evidence policy:
16029
16720
  - AI conversation history, prior AI replies, and compressed summaries are only for understanding the user's intent; they are not evidence for chat-record facts.
16030
16721
  - Whenever the user asks about chat content, recent topics, what someone said, rankings/statistics, whether a topic appeared, or asks for exact quotes, first call an appropriate data tool to retrieve the current database.
@@ -16129,7 +16820,7 @@ var ja_JP_default = {
16129
16820
  }
16130
16821
  },
16131
16822
  get_time_stats: {
16132
- desc: "\u30B0\u30EB\u30FC\u30D7\u30C1\u30E3\u30C3\u30C8\u306E\u6642\u9593\u5206\u5E03\u7D71\u8A08\u3092\u53D6\u5F97\u3059\u308B\u3002\u300C\u3044\u3064\u304C\u4E00\u756A\u30A2\u30AF\u30C6\u30A3\u30D6\uFF1F\u300D\u300C\u307F\u3093\u306A\u4F55\u6642\u306B\u30C1\u30E3\u30C3\u30C8\u3057\u3066\u3044\u308B\uFF1F\u300D\u306A\u3069\u306E\u8CEA\u554F\u306B\u9069\u3057\u3066\u3044\u308B\u3002",
16823
+ desc: "\u30B0\u30EB\u30FC\u30D7\u30C1\u30E3\u30C3\u30C8\u306E\u6642\u9593\u5206\u5E03\u7D71\u8A08\u3092\u53D6\u5F97\u3059\u308B\u3002\u300C\u3044\u3064\u304C\u4E00\u756A\u30A2\u30AF\u30C6\u30A3\u30D6\uFF1F\u300D\u300C\u307F\u3093\u306A\u4F55\u6642\u306B\u30C1\u30E3\u30C3\u30C8\u3057\u3066\u3044\u308B\uFF1F\u300D\u306A\u3069\u306E\u8CEA\u554F\u306B\u9069\u3057\u3066\u3044\u308B\u3002\u8FD4\u3055\u308C\u308B `data` \u914D\u5217\u306F render_chart \u306E `rows` \u30D1\u30E9\u30E1\u30FC\u30BF\u3068\u3057\u3066\u76F4\u63A5\u4F7F\u7528\u3067\u304D\u308B\u3002",
16133
16824
  params: {
16134
16825
  type: "\u7D71\u8A08\u30BF\u30A4\u30D7\uFF1Ahourly\uFF08\u6642\u9593\u5225\uFF09\u3001weekday\uFF08\u66DC\u65E5\u5225\uFF09\u3001daily\uFF08\u65E5\u5225\uFF09"
16135
16826
  }
@@ -16319,9 +17010,10 @@ var ja_JP_default = {
16319
17010
  params: {}
16320
17011
  },
16321
17012
  render_chart: {
16322
- desc: "\u8AAD\u307F\u53D6\u308A\u5C02\u7528 SQL \u3068 ChartSpec v1 \u304B\u3089 ChatLab \u30CD\u30A4\u30C6\u30A3\u30D6\u30C1\u30E3\u30FC\u30C8\u3092\u751F\u6210\u3057\u307E\u3059\u3002bar\u3001line\u3001pie\u3001heatmap \u3092\u30B5\u30DD\u30FC\u30C8\u3057\u307E\u3059\u3002HTML\u3001JavaScript\u3001SVG\u3001ECharts option\u3001\u63CF\u753B\u30B3\u30FC\u30C9\u306F\u51FA\u529B\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002",
17013
+ desc: "ChartSpec v1 \u304B\u3089 ChatLab \u30CD\u30A4\u30C6\u30A3\u30D6\u30C1\u30E3\u30FC\u30C8\u3092\u751F\u6210\u3057\u307E\u3059\u3002bar\u3001line\u3001pie\u3001heatmap \u3092\u30B5\u30DD\u30FC\u30C8\u3057\u307E\u3059\u3002`rows`\uFF08\u9AD8\u30EC\u30D9\u30EB\u30C4\u30FC\u30EB\u306E\u30C7\u30FC\u30BF\u914D\u5217\u3001\u4F8B\uFF1Aget_time_stats \u306E `data` \u30D5\u30A3\u30FC\u30EB\u30C9\uFF09\u307E\u305F\u306F `sql`\uFF08\u8AAD\u307F\u53D6\u308A\u5C02\u7528 SELECT\uFF09\u306E\u3044\u305A\u308C\u304B\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002\u30C7\u30FC\u30BF\u304C\u3059\u3067\u306B\u53D6\u5F97\u6E08\u307F\u306E\u5834\u5408\u306F `rows` \u3092\u512A\u5148\u3057\u3001\u9AD8\u30EC\u30D9\u30EB\u30C4\u30FC\u30EB\u3067\u5BFE\u5FDC\u3067\u304D\u306A\u3044\u5834\u5408\u306E\u307F `sql` \u3092\u4F7F\u7528\u3057\u307E\u3059\u3002HTML\u3001JavaScript\u3001SVG\u3001ECharts option\u3001\u63CF\u753B\u30B3\u30FC\u30C9\u306F\u51FA\u529B\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002",
16323
17014
  params: {
16324
- sql: "\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u306E SELECT \u307E\u305F\u306F WITH SELECT SQL\u3002ChartSpec encoding \u3067\u53C2\u7167\u3059\u308B\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u8FD4\u3059\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002",
17015
+ rows: "\u9AD8\u30EC\u30D9\u30EB\u30C4\u30FC\u30EB\u304B\u3089\u53D6\u5F97\u3057\u305F\u30C7\u30FC\u30BF\u914D\u5217\uFF08\u4F8B\uFF1Aget_time_stats \u306E `data` \u30D5\u30A3\u30FC\u30EB\u30C9\uFF09\u3002\u30C7\u30FC\u30BF\u304C\u53D6\u5F97\u6E08\u307F\u306E\u5834\u5408\u306F sql \u3088\u308A\u512A\u5148\u3057\u3066\u4F7F\u7528\u3057\u307E\u3059\u3002sql \u3068\u306F\u6392\u4ED6\u3002",
17016
+ sql: "\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u306E SELECT \u307E\u305F\u306F WITH SELECT SQL\u3002\u9AD8\u30EC\u30D9\u30EB\u30C4\u30FC\u30EB\u3067\u5BFE\u5FDC\u3067\u304D\u306A\u3044\u5834\u5408\u306E\u307F\u4F7F\u7528\u3057\u307E\u3059\u3002ChartSpec encoding \u3067\u53C2\u7167\u3059\u308B\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u8FD4\u3059\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002",
16325
17017
  params: "SQL \u306E\u540D\u524D\u4ED8\u304D\u30D1\u30E9\u30E1\u30FC\u30BF\u3002\u4E0D\u8981\u306A\u5834\u5408\u306F\u7A7A\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3092\u6E21\u3057\u307E\u3059\u3002",
16326
17018
  chartSpec: "version\u3001type\u3001title\u3001encoding \u3092\u542B\u3080 ChartSpec v1\u3002",
16327
17019
  maxRows: "\u30C1\u30E3\u30FC\u30C8\u30AF\u30A8\u30EA\u306E\u6700\u5927\u884C\u6570\u3002\u30C7\u30D5\u30A9\u30EB\u30C8\u306F 1000\u3002"
@@ -16355,6 +17047,35 @@ var ja_JP_default = {
16355
17047
  timeParamsIntro: '\u6642\u9593\u30D1\u30E9\u30E1\u30FC\u30BF\uFF1Astart_time/end_time \u3067\u7BC4\u56F2\u3092\u6307\u5B9A\u3002\u5F62\u5F0F\u306F "YYYY-MM-DD HH:mm"',
16356
17048
  defaultYearNote: "\u6642\u9593\u7BC4\u56F2\u3092\u6307\u5B9A\u3057\u306A\u3044\u5834\u5408\u306F\u5168\u671F\u9593\u304C\u5BFE\u8C61\u3002\u73FE\u5728\u306E\u5E74\u306F{{year}}\u5E74",
16357
17049
  dataSnapshotNote: "\u73FE\u5728\u306E\u30C1\u30E3\u30C3\u30C8\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\uFF1A{{name}}\uFF08{{platform}}\uFF09\u3001\u7DCF\u30E1\u30C3\u30BB\u30FC\u30B8 {{totalMessages}} \u4EF6\u3001\u30E1\u30F3\u30D0\u30FC {{totalMembers}} \u4EBA\u3001\u671F\u9593 {{firstMessageDate}} ~ {{lastMessageDate}}\u3002\u3053\u306E\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u306F\u30C7\u30FC\u30BF\u7BC4\u56F2\u306E\u5224\u65AD\u306B\u306E\u307F\u4F7F\u3044\u3001\u5177\u4F53\u7684\u306A\u30C1\u30E3\u30C3\u30C8\u4E8B\u5B9F\u306E\u56DE\u7B54\u306B\u306F\u5FC5\u305A\u73FE\u5728\u306E\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u30C4\u30FC\u30EB\u3067\u691C\u7D22\u3059\u308B\u3002",
17050
+ dataSnapshotContext: `\u73FE\u5728\u306E\u30C1\u30E3\u30C3\u30C8\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u8D77\u52D5\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\uFF1A
17051
+ - name: {{name}}
17052
+ - platform: {{platform}}
17053
+ - type: {{type}}
17054
+ - total_messages: {{totalMessages}}
17055
+ - total_members: {{totalMembers}}
17056
+ - first_message_ts: {{firstMessageTs}}
17057
+ - first_message_time: {{firstMessageTime}}
17058
+ - last_message_ts: {{lastMessageTs}}
17059
+ - last_message_time: {{lastMessageTime}}
17060
+ - segment_summaries_available: {{segmentSummaryCount}}
17061
+
17062
+ {{memberHintTitle}}
17063
+ {{memberHintLines}}
17064
+
17065
+ \u4F7F\u7528\u30EB\u30FC\u30EB\uFF1A
17066
+ {{usageRules}}`,
17067
+ dataSnapshotMemberHintsAll: "\u30A2\u30AF\u30C6\u30A3\u30D6\u30E1\u30F3\u30D0\u30FC\u691C\u7D22\u30D2\u30F3\u30C8\uFF08\u5168\u30E1\u30F3\u30D0\u30FC\uFF09\uFF1A",
17068
+ dataSnapshotMemberHintsTop: "\u30A2\u30AF\u30C6\u30A3\u30D6\u30E1\u30F3\u30D0\u30FC\u691C\u7D22\u30D2\u30F3\u30C8\uFF08\u904E\u53BB\u306E\u7DCF\u30E1\u30C3\u30BB\u30FC\u30B8\u6570 Top 10\uFF09\uFF1A",
17069
+ dataSnapshotMemberHintsUnavailable: "\u30A2\u30AF\u30C6\u30A3\u30D6\u30E1\u30F3\u30D0\u30FC\u691C\u7D22\u30D2\u30F3\u30C8\uFF1A",
17070
+ dataSnapshotMemberHintsEmpty: "\u5229\u7528\u53EF\u80FD\u306A\u30E1\u30F3\u30D0\u30FC\u30D2\u30F3\u30C8\u306F\u3042\u308A\u307E\u305B\u3093\u3002",
17071
+ dataSnapshotUsageRules: `- member_id \u306F\u30C4\u30FC\u30EB\u691C\u7D22\u7528\u306E\u30D2\u30F3\u30C8\u3067\u3059\u3002display_name \u306F\u4EBA\u9593\u304C\u8B58\u5225\u3059\u308B\u305F\u3081\u3060\u3051\u306E\u3082\u306E\u3067\u3001\u4E00\u610F\u3068\u306F\u9650\u308A\u307E\u305B\u3093\u3002
17072
+ - \u30E6\u30FC\u30B6\u30FC\u304C\u6280\u8853\u7684\u8A73\u7D30\u3092\u660E\u793A\u7684\u306B\u6C42\u3081\u306A\u3044\u9650\u308A\u3001\u6700\u7D42\u56DE\u7B54\u3067 member_id \u3084\u8D77\u52D5\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u81EA\u4F53\u3092\u7A4D\u6975\u7684\u306B\u958B\u793A\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
17073
+ - \u30A2\u30AF\u30C6\u30A3\u30D6\u30E1\u30F3\u30D0\u30FC\u9806\u4F4D\u306F\u904E\u53BB\u306E\u7DCF\u30E1\u30C3\u30BB\u30FC\u30B8\u91CF\u3060\u3051\u3092\u793A\u3057\u3001\u6700\u8FD1\u306E\u6D3B\u767A\u3055\u3092\u793A\u3059\u3082\u306E\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002\u307E\u305F\u3001\u5F71\u97FF\u529B\u3001\u95A2\u4FC2\u6027\u3001\u6700\u8FD1\u306E\u50BE\u5411\u306E\u7D50\u8AD6\u8A3C\u62E0\u306B\u3082\u306A\u308A\u307E\u305B\u3093\u3002
17074
+ - \u76F8\u5BFE\u7684\u306A\u6642\u9593\u8868\u73FE\u306F\u3001\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u6700\u7D42\u30E1\u30C3\u30BB\u30FC\u30B8\u6642\u523B\u3067\u306F\u306A\u304F\u3001\u5B9F\u969B\u306E\u73FE\u5728\u65E5\u4ED8\u3092\u57FA\u6E96\u306B\u89E3\u91C8\u3057\u3066\u304F\u3060\u3055\u3044\u3002
17075
+ - \u300C\u6700\u8FD1\u4E00\u5E74/\u904E\u53BB\u4E00\u5E74\u300D\u306F\u5B9F\u969B\u306E\u73FE\u5728\u65E5\u4ED8\u304B\u3089\u4ECA\u65E5\u307E\u3067\u306E1\u5E74\u9593\u3092\u6307\u3057\u3001\u300C\u53BB\u5E74\u300D\u306F\u524D\u306E\u66A6\u5E74\u3092\u6307\u3057\u307E\u3059\u3002
17076
+ - \u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u6642\u9593\u5883\u754C\u306F\u30AB\u30D0\u30EC\u30C3\u30B8\u8AAC\u660E\u306B\u306E\u307F\u4F7F\u3044\u3001\u30E6\u30FC\u30B6\u30FC\u304C\u6C42\u3081\u305F\u6642\u9593\u7BC4\u56F2\u3092\u518D\u5B9A\u7FA9\u3059\u308B\u305F\u3081\u306B\u4F7F\u308F\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
17077
+ - \u30C7\u30D5\u30A9\u30EB\u30C8\u306E\u300C\u76F4\u8FD1 N \u65E5\u300D\u30C4\u30FC\u30EB\u3092\u4F7F\u3046\u5834\u5408\u306F\u3001\u7A7A\u306E\u5B9F\u969B\u73FE\u5728\u65E5\u4ED8\u30A6\u30A3\u30F3\u30C9\u30A6\u3092\u8A66\u3059\u306E\u3067\u306F\u306A\u304F\u3001\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u6642\u9593\u5883\u754C\u3068\u4EA4\u5DEE\u3059\u308B\u7BC4\u56F2\u3092\u5148\u306B\u9078\u3093\u3067\u304F\u3060\u3055\u3044\u3002
17078
+ - min/max timestamp \u3092\u518D\u767A\u898B\u3059\u308B\u305F\u3081\u3060\u3051\u306B\u30C4\u30FC\u30EB\u3092\u547C\u3070\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002\u305F\u3060\u3057\u3001\u5177\u4F53\u7684\u306A\u30C1\u30E3\u30C3\u30C8\u4E8B\u5B9F\u3001\u7D71\u8A08\u3001\u7D50\u8AD6\u306B\u306F\u5F15\u304D\u7D9A\u304D\u30C4\u30FC\u30EB\u8A3C\u62E0\u304C\u5FC5\u8981\u3067\u3059\u3002`,
16358
17079
  evidencePolicy: `\u8A3C\u62E0\u30DD\u30EA\u30B7\u30FC\uFF1A
16359
17080
  - AI \u4F1A\u8A71\u5C65\u6B74\u3001\u904E\u53BB\u306E AI \u56DE\u7B54\u3001\u5727\u7E2E\u8981\u7D04\u306F\u30E6\u30FC\u30B6\u30FC\u610F\u56F3\u306E\u7406\u89E3\u306B\u306E\u307F\u4F7F\u7528\u3057\u3001\u30C1\u30E3\u30C3\u30C8\u8A18\u9332\u306E\u4E8B\u5B9F\u8A3C\u62E0\u3068\u3057\u3066\u6271\u308F\u306A\u3044\u3002
16360
17081
  - \u30E6\u30FC\u30B6\u30FC\u304C\u30C1\u30E3\u30C3\u30C8\u5185\u5BB9\u3001\u6700\u8FD1\u306E\u8A71\u984C\u3001\u8AB0\u304B\u306E\u767A\u8A00\u3001\u30E9\u30F3\u30AD\u30F3\u30B0/\u7D71\u8A08\u3001\u3042\u308B\u8A71\u984C\u304C\u51FA\u305F\u304B\u3069\u3046\u304B\u3001\u307E\u305F\u306F\u539F\u6587\u5F15\u7528\u3092\u6C42\u3081\u305F\u5834\u5408\u306F\u3001\u5FC5\u305A\u5148\u306B\u9069\u5207\u306A\u30C7\u30FC\u30BF\u30C4\u30FC\u30EB\u3067\u73FE\u5728\u306E\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u691C\u7D22\u3059\u308B\u3002
@@ -16461,7 +17182,7 @@ var zh_TW_default = {
16461
17182
  }
16462
17183
  },
16463
17184
  get_time_stats: {
16464
- desc: "\u53D6\u5F97\u7FA4\u804A\u7684\u6642\u9593\u5206\u4F48\u7D71\u8A08\u3002\u9069\u7528\u65BC\u56DE\u7B54\u300C\u4EC0\u9EBC\u6642\u5019\u6700\u6D3B\u8E8D\u300D\u3001\u300C\u5927\u5BB6\u4E00\u822C\u5E7E\u9EDE\u804A\u5929\u300D\u7B49\u554F\u984C\u3002",
17185
+ desc: "\u53D6\u5F97\u7FA4\u804A\u7684\u6642\u9593\u5206\u4F48\u7D71\u8A08\u3002\u9069\u7528\u65BC\u56DE\u7B54\u300C\u4EC0\u9EBC\u6642\u5019\u6700\u6D3B\u8E8D\u300D\u3001\u300C\u5927\u5BB6\u4E00\u822C\u5E7E\u9EDE\u804A\u5929\u300D\u7B49\u554F\u984C\u3002\u8FD4\u56DE\u7684 `data` \u9663\u5217\u53EF\u76F4\u63A5\u4F5C\u70BA `render_chart` \u7684 `rows` \u53C3\u6578\u7528\u65BC\u7E6A\u5716\u3002",
16465
17186
  params: {
16466
17187
  type: "\u7D71\u8A08\u985E\u578B\uFF1Ahourly\uFF08\u6309\u5C0F\u6642\uFF09\u3001weekday\uFF08\u6309\u661F\u671F\uFF09\u3001daily\uFF08\u6309\u65E5\u671F\uFF09"
16467
17188
  }
@@ -16651,9 +17372,10 @@ var zh_TW_default = {
16651
17372
  params: {}
16652
17373
  },
16653
17374
  render_chart: {
16654
- desc: "\u6839\u64DA\u552F\u8B80 SQL \u548C ChartSpec v1 \u751F\u6210 ChatLab \u539F\u751F\u5716\u8868\u3002\u652F\u63F4 bar\u3001line\u3001pie\u3001heatmap\u3002\u7981\u6B62\u8F38\u51FA HTML\u3001JavaScript\u3001SVG\u3001ECharts option \u6216\u6E32\u67D3\u7A0B\u5F0F\u78BC\u3002",
17375
+ desc: "\u6839\u64DA ChartSpec v1 \u751F\u6210 ChatLab \u539F\u751F\u5716\u8868\u3002\u652F\u63F4 bar\u3001line\u3001pie\u3001heatmap\u3002\u63D0\u4F9B `rows`\uFF08\u4F86\u81EA\u9AD8\u5C64\u5DE5\u5177\u7684\u8CC7\u6599\u9663\u5217\uFF0C\u5982 get_time_stats \u7684 `data` \u6B04\u4F4D\uFF09\u6216 `sql`\uFF08\u552F\u8B80 SELECT\uFF09\u4E8C\u64C7\u4E00\uFF1B\u6709\u73FE\u6210\u8CC7\u6599\u6642\u512A\u5148\u7528 `rows`\uFF0C\u50C5\u5728\u9AD8\u5C64\u5DE5\u5177\u7121\u6CD5\u6EFF\u8DB3\u9700\u6C42\u6642\u624D\u5BEB `sql`\u3002\u7981\u6B62\u8F38\u51FA HTML\u3001JavaScript\u3001SVG\u3001ECharts option \u6216\u6E32\u67D3\u7A0B\u5F0F\u78BC\u3002",
16655
17376
  params: {
16656
- sql: "\u552F\u8B80 SELECT \u6216 WITH SELECT SQL\u3002\u5FC5\u9808\u8FD4\u56DE ChartSpec encoding \u4E2D\u5F15\u7528\u7684\u6B04\u4F4D\u3002",
17377
+ rows: "\u4F86\u81EA\u9AD8\u5C64\u5DE5\u5177\u8FD4\u56DE\u7684\u8CC7\u6599\u9663\u5217\uFF08\u5982 get_time_stats \u7684 `data` \u6B04\u4F4D\uFF09\u3002\u6709\u73FE\u6210\u8CC7\u6599\u6642\u512A\u5148\u4F7F\u7528\uFF0C\u8207 sql \u4E8C\u64C7\u4E00\u3002",
17378
+ sql: "\u552F\u8B80 SELECT \u6216 WITH SELECT SQL\u3002\u50C5\u5728\u9AD8\u5C64\u5DE5\u5177\u7121\u6CD5\u6EFF\u8DB3\u9700\u6C42\u6642\u4F7F\u7528\uFF0C\u5FC5\u9808\u8FD4\u56DE ChartSpec encoding \u4E2D\u5F15\u7528\u7684\u6B04\u4F4D\u3002",
16657
17379
  params: "SQL \u547D\u540D\u53C3\u6578\u7269\u4EF6\uFF1B\u4E0D\u9700\u8981\u53C3\u6578\u6642\u50B3\u7A7A\u7269\u4EF6\u3002",
16658
17380
  chartSpec: "ChartSpec v1\uFF0C\u5305\u542B version\u3001type\u3001title\u3001encoding\u3002",
16659
17381
  maxRows: "\u5716\u8868\u67E5\u8A62\u6700\u5927\u884C\u6578\uFF0C\u9810\u8A2D 1000\u3002"
@@ -16687,6 +17409,35 @@ var zh_TW_default = {
16687
17409
  timeParamsIntro: '\u6642\u9593\u53C3\u6578\uFF1A\u4F7F\u7528 start_time/end_time \u6307\u5B9A\u6642\u9593\u7BC4\u570D\uFF0C\u683C\u5F0F "YYYY-MM-DD HH:mm"',
16688
17410
  defaultYearNote: "\u672A\u6307\u5B9A\u6642\u9593\u7BC4\u570D\u6642\u9810\u8A2D\u67E5\u8A62\u5168\u90E8\u3002\u7576\u524D\u5E74\u4EFD\u70BA{{year}}\u5E74",
16689
17411
  dataSnapshotNote: "\u76EE\u524D\u804A\u5929\u8CC7\u6599\u5EAB\u5FEB\u7167\uFF1A{{name}}\uFF08{{platform}}\uFF09\uFF0C\u7E3D\u8A0A\u606F {{totalMessages}} \u689D\uFF0C\u6210\u54E1 {{totalMembers}} \u4EBA\uFF0C\u6642\u9593\u7BC4\u570D {{firstMessageDate}} ~ {{lastMessageDate}}\u3002\u8A72\u5FEB\u7167\u53EA\u7528\u65BC\u5224\u65B7\u8CC7\u6599\u7BC4\u570D\uFF1B\u56DE\u7B54\u5177\u9AD4\u804A\u5929\u4E8B\u5BE6\u4ECD\u5FC5\u9808\u547C\u53EB\u5DE5\u5177\u6AA2\u7D22\u76EE\u524D\u8CC7\u6599\u5EAB\u3002",
17412
+ dataSnapshotContext: `\u76EE\u524D\u804A\u5929\u8CC7\u6599\u5EAB\u555F\u52D5\u4E0A\u4E0B\u6587\uFF1A
17413
+ - name: {{name}}
17414
+ - platform: {{platform}}
17415
+ - type: {{type}}
17416
+ - total_messages: {{totalMessages}}
17417
+ - total_members: {{totalMembers}}
17418
+ - first_message_ts: {{firstMessageTs}}
17419
+ - first_message_time: {{firstMessageTime}}
17420
+ - last_message_ts: {{lastMessageTs}}
17421
+ - last_message_time: {{lastMessageTime}}
17422
+ - segment_summaries_available: {{segmentSummaryCount}}
17423
+
17424
+ {{memberHintTitle}}
17425
+ {{memberHintLines}}
17426
+
17427
+ \u4F7F\u7528\u898F\u5247\uFF1A
17428
+ {{usageRules}}`,
17429
+ dataSnapshotMemberHintsAll: "\u6D3B\u8E8D\u6210\u54E1\u67E5\u8A62\u63D0\u793A\uFF08\u5168\u90E8\u6210\u54E1\uFF09\uFF1A",
17430
+ dataSnapshotMemberHintsTop: "\u6D3B\u8E8D\u6210\u54E1\u67E5\u8A62\u63D0\u793A\uFF08\u6309\u6B77\u53F2\u7E3D\u8A0A\u606F\u91CF Top 10\uFF09\uFF1A",
17431
+ dataSnapshotMemberHintsUnavailable: "\u6D3B\u8E8D\u6210\u54E1\u67E5\u8A62\u63D0\u793A\uFF1A",
17432
+ dataSnapshotMemberHintsEmpty: "\u7121\u53EF\u7528\u6210\u54E1\u63D0\u793A\u3002",
17433
+ dataSnapshotUsageRules: `- member_id \u662F\u5DE5\u5177\u67E5\u8A62\u63D0\u793A\uFF1Bdisplay_name \u50C5\u7528\u65BC\u4EBA\u985E\u8B58\u5225\uFF0C\u53EF\u80FD\u4E0D\u552F\u4E00\u3002
17434
+ - \u4E0D\u8981\u5728\u6700\u7D42\u56DE\u7B54\u4E2D\u4E3B\u52D5\u66B4\u9732 member_id \u6216\u555F\u52D5\u4E0A\u4E0B\u6587\u672C\u8EAB\uFF0C\u9664\u975E\u4F7F\u7528\u8005\u660E\u78BA\u8981\u6C42\u6280\u8853\u7D30\u7BC0\u3002
17435
+ - \u6D3B\u8E8D\u6210\u54E1\u6392\u884C\u53EA\u4EE3\u8868\u6B77\u53F2\u7E3D\u8A0A\u606F\u91CF\uFF0C\u4E0D\u4EE3\u8868\u8FD1\u671F\u6D3B\u8E8D\u60C5\u6CC1\uFF1B\u4E5F\u4E0D\u8DB3\u4EE5\u4F5C\u70BA\u5F71\u97FF\u529B\u3001\u95DC\u4FC2\u6216\u8FD1\u671F\u8DA8\u52E2\u7D50\u8AD6\u7684\u8B49\u64DA\u3002
17436
+ - \u76F8\u5C0D\u6642\u9593\u8868\u9054\u4EE5\u771F\u5BE6\u76EE\u524D\u65E5\u671F\u70BA\u57FA\u6E96\uFF0C\u800C\u4E0D\u662F\u8CC7\u6599\u5EAB\u6700\u5F8C\u8A0A\u606F\u6642\u9593\u3002
17437
+ -\u300C\u6700\u8FD1\u4E00\u5E74/\u904E\u53BB\u4E00\u5E74\u300D\u8868\u793A\u5F9E\u771F\u5BE6\u76EE\u524D\u65E5\u671F\u56DE\u63A8\u4E00\u5E74\u5230\u4ECA\u5929\uFF1B\u300C\u53BB\u5E74\u300D\u8868\u793A\u4E0A\u4E00\u81EA\u7136\u5E74\u3002
17438
+ - \u8CC7\u6599\u5EAB\u6642\u9593\u908A\u754C\u53EA\u7528\u65BC\u8AAA\u660E\u8986\u84CB\u7BC4\u570D\uFF0C\u4E0D\u7528\u65BC\u91CD\u5B9A\u7FA9\u4F7F\u7528\u8005\u8981\u6C42\u7684\u6642\u9593\u7BC4\u570D\u3002
17439
+ - \u4F7F\u7528\u9810\u8A2D\u300C\u8FD1 N \u5929\u300D\u7684\u5DE5\u5177\u6642\uFF0C\u5148\u9078\u64C7\u8207\u8CC7\u6599\u5EAB\u6642\u9593\u908A\u754C\u6709\u4EA4\u96C6\u7684\u7BC4\u570D\uFF0C\u4E0D\u8981\u5148\u63A2\u6E2C\u771F\u5BE6\u76EE\u524D\u65E5\u671F\u8996\u7A97\u5C0E\u81F4\u7A7A\u7D50\u679C\u3002
17440
+ - \u4E0D\u8981\u53EA\u70BA\u4E86\u91CD\u65B0\u767C\u73FE min/max timestamp \u547C\u53EB\u5DE5\u5177\uFF1B\u4F46\u56DE\u7B54\u5177\u9AD4\u804A\u5929\u4E8B\u5BE6\u3001\u7D71\u8A08\u548C\u7D50\u8AD6\u4ECD\u5FC5\u9808\u547C\u53EB\u5DE5\u5177\u53D6\u5F97\u8B49\u64DA\u3002`,
16690
17441
  evidencePolicy: `\u8B49\u64DA\u7B56\u7565\uFF1A
16691
17442
  - AI \u5C0D\u8A71\u6B77\u53F2\u3001\u6B77\u53F2 AI \u56DE\u8986\u548C\u58D3\u7E2E\u6458\u8981\u53EA\u7528\u65BC\u7406\u89E3\u4F7F\u7528\u8005\u610F\u5716\uFF0C\u4E0D\u80FD\u4F5C\u70BA\u804A\u5929\u7D00\u9304\u4E8B\u5BE6\u8B49\u64DA\u3002
16692
17443
  - \u53EA\u8981\u4F7F\u7528\u8005\u8A62\u554F\u804A\u5929\u7D00\u9304\u5167\u5BB9\u3001\u6700\u8FD1\u804A\u4EC0\u9EBC\u3001\u67D0\u4EBA\u8AAA\u904E\u4EC0\u9EBC\u3001\u7D71\u8A08\u6392\u884C\u3001\u662F\u5426\u51FA\u73FE\u904E\u67D0\u8A71\u984C\u6216\u8981\u6C42\u5F15\u7528\u539F\u8A71\uFF0C\u5FC5\u9808\u5148\u547C\u53EB\u5408\u9069\u7684\u8CC7\u6599\u5DE5\u5177\u6AA2\u7D22\u76EE\u524D\u8CC7\u6599\u5EAB\u3002
@@ -17127,7 +17878,7 @@ function buildPiModel(config, options) {
17127
17878
  }
17128
17879
 
17129
17880
  // ../../packages/node-runtime/src/ai/remote-api.ts
17130
- import { completeSimple as completeSimple2 } from "@earendil-works/pi-ai";
17881
+ import { completeSimple as completeSimple4 } from "@earendil-works/pi-ai";
17131
17882
  async function fetchRemoteModels(provider, apiKey, baseUrl, apiFormat, options) {
17132
17883
  const effectiveApiFormat = apiFormat || "openai-completions";
17133
17884
  if (effectiveApiFormat === "anthropic-messages") {
@@ -17211,7 +17962,7 @@ async function validateApiKey(provider, apiKey, baseUrl, model, apiFormat, optio
17211
17962
  const abortController = new AbortController();
17212
17963
  const timeout = setTimeout(() => abortController.abort(), 15e3);
17213
17964
  try {
17214
- const result = await completeSimple2(
17965
+ const result = await completeSimple4(
17215
17966
  piModel,
17216
17967
  { messages: [{ role: "user", content: "Hi", timestamp: Date.now() }] },
17217
17968
  { apiKey, maxTokens: 1, signal: abortController.signal }
@@ -17232,7 +17983,7 @@ async function validateApiKey(provider, apiKey, baseUrl, model, apiFormat, optio
17232
17983
  }
17233
17984
 
17234
17985
  // ../../packages/node-runtime/src/ai/llm-stream.ts
17235
- import { streamSimple } from "@earendil-works/pi-ai";
17986
+ import { streamSimple as streamSimple2 } from "@earendil-works/pi-ai";
17236
17987
  function toPiMessages(messages, timestamp) {
17237
17988
  return messages.map((m) => ({
17238
17989
  role: m.role,
@@ -17245,7 +17996,7 @@ async function runSimpleLlmStream(options) {
17245
17996
  const systemMsg = messages.find((m) => m.role === "system");
17246
17997
  const nonSystemMsgs = messages.filter((m) => m.role !== "system");
17247
17998
  const now = Date.now();
17248
- const eventStream = streamSimple(
17999
+ const eventStream = streamSimple2(
17249
18000
  piModel,
17250
18001
  {
17251
18002
  systemPrompt: systemMsg?.content,
@@ -17303,7 +18054,7 @@ async function runSimpleLlmStream(options) {
17303
18054
  }
17304
18055
 
17305
18056
  // ../../packages/node-runtime/src/ai/index.ts
17306
- import { Type, completeSimple as completeSimple4, streamSimple as streamSimple2 } from "@earendil-works/pi-ai";
18057
+ import { Type, completeSimple as completeSimple6, streamSimple as streamSimple3 } from "@earendil-works/pi-ai";
17307
18058
 
17308
18059
  // ../../packages/node-runtime/src/ai/rag/types.ts
17309
18060
  var noopLogger = {
@@ -17342,7 +18093,7 @@ var _logger6 = getNoopLogger();
17342
18093
  var _logger7 = getNoopLogger();
17343
18094
 
17344
18095
  // ../../packages/node-runtime/src/ai/rag/pipeline/semantic.ts
17345
- import { completeSimple as completeSimple3 } from "@earendil-works/pi-ai";
18096
+ import { completeSimple as completeSimple5 } from "@earendil-works/pi-ai";
17346
18097
  var _logger8 = getNoopLogger();
17347
18098
 
17348
18099
  // ../../packages/node-runtime/src/migrations/electron-data-migration.ts
@@ -17967,7 +18718,7 @@ function getMetaPath(userDataDir) {
17967
18718
  return path31.join(userDataDir, ".chatlab-meta.json");
17968
18719
  }
17969
18720
  function validateDataDirCompatibilityMeta(value, userDataDir, metaPath) {
17970
- if (!isRecord2(value)) {
18721
+ if (!isRecord3(value)) {
17971
18722
  throw createInvalidMetaError(userDataDir, metaPath, "Data directory compatibility meta must be an object.");
17972
18723
  }
17973
18724
  if (value.formatVersion !== 1) {
@@ -17978,7 +18729,7 @@ function validateDataDirCompatibilityMeta(value, userDataDir, metaPath) {
17978
18729
  const reasons = value.reasons;
17979
18730
  const updatedBy = value.updatedBy;
17980
18731
  const updatedAt = value.updatedAt;
17981
- if (!isStableSemver(minRuntimeVersion) || typeof dataCompatibilityVersion !== "number" || !Number.isInteger(dataCompatibilityVersion) || dataCompatibilityVersion < 0 || !Array.isArray(reasons) || !reasons.every(isNonEmptyString) || !isRecord2(updatedBy) || !isRuntimeKind(updatedBy.runtime) || !isNonEmptyString(updatedBy.module) || !isStableSemver(updatedBy.version) || typeof updatedAt !== "number" || !Number.isInteger(updatedAt) || updatedAt < 0) {
18732
+ if (!isStableSemver(minRuntimeVersion) || typeof dataCompatibilityVersion !== "number" || !Number.isInteger(dataCompatibilityVersion) || dataCompatibilityVersion < 0 || !Array.isArray(reasons) || !reasons.every(isNonEmptyString) || !isRecord3(updatedBy) || !isRuntimeKind(updatedBy.runtime) || !isNonEmptyString(updatedBy.module) || !isStableSemver(updatedBy.version) || typeof updatedAt !== "number" || !Number.isInteger(updatedAt) || updatedAt < 0) {
17982
18733
  throw createInvalidMetaError(userDataDir, metaPath, "Invalid data directory compatibility meta fields.");
17983
18734
  }
17984
18735
  return {
@@ -18036,7 +18787,7 @@ function writeMetaAtomic(userDataDir, metaPath, meta) {
18036
18787
  throw error;
18037
18788
  }
18038
18789
  }
18039
- function isRecord2(value) {
18790
+ function isRecord3(value) {
18040
18791
  return typeof value === "object" && value !== null && !Array.isArray(value);
18041
18792
  }
18042
18793
  function isNonEmptyString(value) {
@@ -18842,6 +19593,7 @@ var DEFAULTS = {
18842
19593
  exportFormat: "markdown",
18843
19594
  sqlExportFormat: "csv",
18844
19595
  enableAutoSkill: true,
19596
+ chartAutoMode: "suggest",
18845
19597
  searchContextBefore: 2,
18846
19598
  searchContextAfter: 2,
18847
19599
  contextCompression: {
@@ -18858,7 +19610,8 @@ var DEFAULTS = {
18858
19610
  defaultSchemeId: null,
18859
19611
  sessionSchemeOverrides: {}
18860
19612
  },
18861
- filterHistory: []
19613
+ filterHistory: [],
19614
+ thinkingLevels: {}
18862
19615
  };
18863
19616
  var PreferencesManager = class {
18864
19617
  filePath;
@@ -18926,7 +19679,8 @@ var PreferencesManager = class {
18926
19679
  customKeywordTemplates: partial.customKeywordTemplates ?? DEFAULTS.customKeywordTemplates,
18927
19680
  deletedPresetTemplateIds: partial.deletedPresetTemplateIds ?? DEFAULTS.deletedPresetTemplateIds,
18928
19681
  wordFilter: partial.wordFilter ? { ...DEFAULTS.wordFilter, ...partial.wordFilter } : { ...DEFAULTS.wordFilter },
18929
- filterHistory: partial.filterHistory ?? DEFAULTS.filterHistory
19682
+ filterHistory: partial.filterHistory ?? DEFAULTS.filterHistory,
19683
+ thinkingLevels: partial.thinkingLevels ?? DEFAULTS.thinkingLevels
18930
19684
  };
18931
19685
  }
18932
19686
  normalizeAiPreprocessConfig(partial) {
@@ -19549,7 +20303,7 @@ function buildSummaryDeps(db, llmConfig, deps) {
19549
20303
  return getSegmentSummary(db, segmentId);
19550
20304
  },
19551
20305
  async llmComplete(systemPrompt, userPrompt, options) {
19552
- const result = await completeSimple4(
20306
+ const result = await completeSimple6(
19553
20307
  piModel,
19554
20308
  {
19555
20309
  systemPrompt,
@@ -19836,6 +20590,8 @@ export {
19836
20590
  createActivateSkillTool,
19837
20591
  CHART_CAPABILITY_CORE_TOOLS,
19838
20592
  getAllowedBuiltinToolsForChartAutoSkill,
20593
+ shouldUseChartCapabilityForMessage,
20594
+ getChartPlannerCapabilityForMessage,
19839
20595
  resolveChartRuntimeForRequest,
19840
20596
  getChartCapabilitySkill,
19841
20597
  buildSkillMenuWithBuiltinChart,
@@ -19849,6 +20605,12 @@ export {
19849
20605
  applyPreprocessingPipeline,
19850
20606
  DEFAULT_MAX_TOOL_ROUNDS,
19851
20607
  runAgentCore,
20608
+ createDataSnapshotFromOverview,
20609
+ decideRequestRoute,
20610
+ createLlmRouteDecider,
20611
+ createAnalysisPlanner,
20612
+ createPlanContentBlock,
20613
+ buildPlanGuidance,
19852
20614
  AgentEventHandler,
19853
20615
  buildSystemPrompt,
19854
20616
  createAiTranslate,
@@ -19884,4 +20646,4 @@ export {
19884
20646
  createDatabaseManagerAdapter,
19885
20647
  MergeSessionCache
19886
20648
  };
19887
- //# sourceMappingURL=chunk-7VG6QGQ2.mjs.map
20649
+ //# sourceMappingURL=chunk-QY67NN65.mjs.map