weflow-cli 1.7.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/ARCHITECTURE.md +3 -2
  2. package/CHANGELOG.md +2108 -2
  3. package/OPERATIONS.md +810 -1
  4. package/README.en.md +96 -10
  5. package/README.md +34 -9
  6. package/bin/weflow-cli.ts +937 -28
  7. package/dist/bin/weflow-cli.js +955 -28
  8. package/dist/bin/weflow-cli.js.map +1 -1
  9. package/dist/mcp-server/index.js +39 -13
  10. package/dist/mcp-server/index.js.map +1 -1
  11. package/dist/src/core/appMsgFormat.d.ts +37 -0
  12. package/dist/src/core/appMsgFormat.d.ts.map +1 -0
  13. package/dist/src/core/appMsgFormat.js +106 -0
  14. package/dist/src/core/appMsgFormat.js.map +1 -0
  15. package/dist/src/core/ntCore.d.ts +19 -2
  16. package/dist/src/core/ntCore.d.ts.map +1 -1
  17. package/dist/src/core/ntCore.js +11 -1
  18. package/dist/src/core/ntCore.js.map +1 -1
  19. package/dist/src/core/sqlcipherCore.d.ts +0 -12
  20. package/dist/src/core/sqlcipherCore.d.ts.map +1 -1
  21. package/dist/src/core/sqlcipherCore.js +5 -64
  22. package/dist/src/core/sqlcipherCore.js.map +1 -1
  23. package/dist/src/core/wcdbCore.d.ts +1 -1
  24. package/dist/src/core/wcdbCore.d.ts.map +1 -1
  25. package/dist/src/core/wcdbCore.js +5 -1
  26. package/dist/src/core/wcdbCore.js.map +1 -1
  27. package/dist/src/panel/client.d.ts +25 -0
  28. package/dist/src/panel/client.d.ts.map +1 -0
  29. package/dist/src/panel/client.js +34 -0
  30. package/dist/src/panel/client.js.map +1 -0
  31. package/dist/src/panel/endpoint.d.ts +45 -0
  32. package/dist/src/panel/endpoint.d.ts.map +1 -0
  33. package/dist/src/panel/endpoint.js +132 -0
  34. package/dist/src/panel/endpoint.js.map +1 -0
  35. package/dist/src/panel/launch.d.ts +50 -0
  36. package/dist/src/panel/launch.d.ts.map +1 -0
  37. package/dist/src/panel/launch.js +74 -0
  38. package/dist/src/panel/launch.js.map +1 -0
  39. package/dist/src/panel/server.d.ts +23 -0
  40. package/dist/src/panel/server.d.ts.map +1 -0
  41. package/dist/src/panel/server.js +413 -0
  42. package/dist/src/panel/server.js.map +1 -0
  43. package/dist/src/panel/userId.d.ts +37 -0
  44. package/dist/src/panel/userId.d.ts.map +1 -0
  45. package/dist/src/panel/userId.js +56 -0
  46. package/dist/src/panel/userId.js.map +1 -0
  47. package/dist/src/services/assistantDaemon.d.ts +20 -3
  48. package/dist/src/services/assistantDaemon.d.ts.map +1 -1
  49. package/dist/src/services/assistantDaemon.js +46 -9
  50. package/dist/src/services/assistantDaemon.js.map +1 -1
  51. package/dist/src/services/assistantEval.d.ts +141 -0
  52. package/dist/src/services/assistantEval.d.ts.map +1 -0
  53. package/dist/src/services/assistantEval.js +497 -0
  54. package/dist/src/services/assistantEval.js.map +1 -0
  55. package/dist/src/services/assistantMemory.d.ts +106 -4
  56. package/dist/src/services/assistantMemory.d.ts.map +1 -1
  57. package/dist/src/services/assistantMemory.js +396 -61
  58. package/dist/src/services/assistantMemory.js.map +1 -1
  59. package/dist/src/services/assistantPrivacy.d.ts +15 -2
  60. package/dist/src/services/assistantPrivacy.d.ts.map +1 -1
  61. package/dist/src/services/assistantPrivacy.js +25 -6
  62. package/dist/src/services/assistantPrivacy.js.map +1 -1
  63. package/dist/src/services/assistantRouter.d.ts +41 -0
  64. package/dist/src/services/assistantRouter.d.ts.map +1 -0
  65. package/dist/src/services/assistantRouter.js +151 -0
  66. package/dist/src/services/assistantRouter.js.map +1 -0
  67. package/dist/src/services/assistantService.d.ts +209 -3
  68. package/dist/src/services/assistantService.d.ts.map +1 -1
  69. package/dist/src/services/assistantService.js +599 -75
  70. package/dist/src/services/assistantService.js.map +1 -1
  71. package/dist/src/services/assistantTools.d.ts +217 -1
  72. package/dist/src/services/assistantTools.d.ts.map +1 -1
  73. package/dist/src/services/assistantTools.js +1116 -59
  74. package/dist/src/services/assistantTools.js.map +1 -1
  75. package/dist/src/services/assistantTrace.d.ts +47 -0
  76. package/dist/src/services/assistantTrace.d.ts.map +1 -0
  77. package/dist/src/services/assistantTrace.js +150 -0
  78. package/dist/src/services/assistantTrace.js.map +1 -0
  79. package/dist/src/services/chatService.d.ts +1 -1
  80. package/dist/src/services/chatService.d.ts.map +1 -1
  81. package/dist/src/services/chatService.js +5 -2
  82. package/dist/src/services/chatService.js.map +1 -1
  83. package/dist/src/services/configService.d.ts +9 -0
  84. package/dist/src/services/configService.d.ts.map +1 -1
  85. package/dist/src/services/configService.js +15 -8
  86. package/dist/src/services/configService.js.map +1 -1
  87. package/dist/src/services/pythonBridge.d.ts +41 -0
  88. package/dist/src/services/pythonBridge.d.ts.map +1 -0
  89. package/dist/src/services/pythonBridge.js +119 -0
  90. package/dist/src/services/pythonBridge.js.map +1 -0
  91. package/dist/src/services/syncService.d.ts +8 -2
  92. package/dist/src/services/syncService.d.ts.map +1 -1
  93. package/dist/src/services/syncService.js +26 -7
  94. package/dist/src/services/syncService.js.map +1 -1
  95. package/dist/src/services/wechatMessageService.d.ts +25 -0
  96. package/dist/src/services/wechatMessageService.d.ts.map +1 -1
  97. package/dist/src/services/wechatMessageService.js +69 -7
  98. package/dist/src/services/wechatMessageService.js.map +1 -1
  99. package/dist/src/services/wereadService.d.ts +33 -6
  100. package/dist/src/services/wereadService.d.ts.map +1 -1
  101. package/dist/src/services/wereadService.js +27 -2
  102. package/dist/src/services/wereadService.js.map +1 -1
  103. package/dist/src/utils/atomicWrite.d.ts +4 -0
  104. package/dist/src/utils/atomicWrite.d.ts.map +1 -0
  105. package/dist/src/utils/atomicWrite.js +60 -0
  106. package/dist/src/utils/atomicWrite.js.map +1 -0
  107. package/dist/src/utils/dateRange.d.ts +15 -0
  108. package/dist/src/utils/dateRange.d.ts.map +1 -1
  109. package/dist/src/utils/dateRange.js +47 -0
  110. package/dist/src/utils/dateRange.js.map +1 -1
  111. package/dist/src/utils/text.d.ts +18 -0
  112. package/dist/src/utils/text.d.ts.map +1 -0
  113. package/dist/src/utils/text.js +20 -0
  114. package/dist/src/utils/text.js.map +1 -0
  115. package/docs/AI_INTERFACE.md +2 -0
  116. package/docs/BRANCHES.md +13 -4
  117. package/docs/DECISIONS.md +1424 -0
  118. package/docs/EXTENDING.md +187 -0
  119. package/docs/JEV/345/272/224/347/224/250/346/226/275/345/267/245/346/226/207/346/241/243.md +310 -0
  120. package/docs/MCP.md +23 -4
  121. package/docs/PROJECT_STATE.md +210 -9
  122. package/docs/SETUP.md +22 -0
  123. package/docs/SYNC_CONTRACT.md +31 -3
  124. package/mcp-server/index.ts +681 -657
  125. package/package.json +84 -83
  126. package/resources/panel/ball-position.cjs +153 -0
  127. package/resources/panel/index.html +46 -0
  128. package/resources/panel/main.cjs +483 -0
  129. package/resources/panel/mascot-happy.png +0 -0
  130. package/resources/panel/mascot-sorry.png +0 -0
  131. package/resources/panel/mascot-thinking.png +0 -0
  132. package/resources/panel/mascot-tired.png +0 -0
  133. package/resources/panel/mascot.png +0 -0
  134. package/resources/panel/package.json +7 -0
  135. package/resources/panel/panel.css +415 -0
  136. package/resources/panel/preload.cjs +79 -0
  137. package/resources/panel/quick-menu.cjs +197 -0
  138. package/resources/panel/renderer.js +470 -0
  139. package/resources/panel/tray-menu.cjs +40 -0
  140. package/resources/panel/tray.png +0 -0
  141. package/scripts/_utils.py +425 -54
  142. package/scripts/annual_report.py +4 -2
  143. package/scripts/article_notes.py +423 -0
  144. package/scripts/backfill_articles.py +438 -0
  145. package/scripts/biz_daily.py +590 -105
  146. package/scripts/chat_notes.py +470 -0
  147. package/scripts/classify_daily.py +10 -18
  148. package/scripts/compile_wiki.py +1060 -46
  149. package/scripts/create_reading_notes.py +199 -14
  150. package/scripts/decide.py +253 -0
  151. package/scripts/draft_reply.py +671 -0
  152. package/scripts/export_chat_html.py +35 -33
  153. package/scripts/extract_todos.py +31 -5
  154. package/scripts/fav_notes.py +318 -0
  155. package/scripts/fix_topics.py +2 -1
  156. package/scripts/generate_ai_report.py +214 -9
  157. package/scripts/generate_html.py +18 -3
  158. package/scripts/generate_review.py +2 -2
  159. package/scripts/jev_client.py +294 -0
  160. package/scripts/jev_probe.py +440 -0
  161. package/scripts/nt_common.py +82 -0
  162. package/scripts/nt_decrypt.py +1755 -1460
  163. package/scripts/pipeline.py +27 -2
  164. package/scripts/promote_ideas.py +19 -4
  165. package/scripts/quality_eval.py +707 -0
  166. package/scripts/rag_chat.py +4 -4
  167. package/scripts/read_image.py +187 -0
  168. package/scripts/reply_debt.py +488 -0
  169. package/scripts/route_cards.py +453 -0
  170. package/scripts/semantic_search.py +208 -49
  171. package/scripts/user_notes.py +315 -0
  172. package/scripts/vault_rag.py +13 -7
  173. package/scripts/vault_search.py +21 -4
  174. package/scripts/wiki_lint.py +429 -0
  175. package/src/core/appMsgFormat.ts +117 -0
  176. package/src/core/ntCore.ts +27 -2
  177. package/src/core/sqlcipherCore.ts +5 -61
  178. package/src/core/wcdbCore.ts +6 -2
  179. package/src/panel/client.ts +49 -0
  180. package/src/panel/endpoint.ts +144 -0
  181. package/src/panel/launch.ts +101 -0
  182. package/src/panel/server.ts +424 -0
  183. package/src/panel/userId.ts +72 -0
  184. package/src/services/assistantDaemon.ts +57 -9
  185. package/src/services/assistantEval.ts +611 -0
  186. package/src/services/assistantMemory.ts +413 -57
  187. package/src/services/assistantPrivacy.ts +25 -6
  188. package/src/services/assistantRouter.ts +191 -0
  189. package/src/services/assistantService.ts +681 -74
  190. package/src/services/assistantTools.ts +1149 -58
  191. package/src/services/assistantTrace.ts +175 -0
  192. package/src/services/chatService.ts +6 -2
  193. package/src/services/configService.ts +403 -385
  194. package/src/services/pythonBridge.ts +139 -0
  195. package/src/services/syncService.ts +37 -9
  196. package/src/services/wechatMessageService.ts +73 -7
  197. package/src/services/wereadService.ts +43 -7
  198. package/src/utils/atomicWrite.ts +56 -0
  199. package/src/utils/dateRange.ts +46 -0
  200. package/src/utils/text.ts +20 -0
@@ -7,9 +7,14 @@
7
7
  * - 本地推理引擎 (Ollama 等) 不出境, 跳过脱敏以保留完整能力
8
8
  *
9
9
  * 模式 (config: assistantPrivacy):
10
- * - open 不脱敏 (自担风险)
11
- * - balanced 默认; 工具输出中的 PII (电话/证件/邮箱/密钥/链接) 打码
10
+ * - open 不脱敏 (自担风险)
11
+ * - balanced 工具输出中的 PII (电话/证件/邮箱/密钥/链接) 打码
12
12
  * - strict balanced 基础上, 第三方聊天正文不出境 (仅保留时间/方向/类型)
13
+ *
14
+ * **实测(2026-09-28):新装用户的默认是 `strict`,不是 `balanced`。** 这个键由
15
+ * `configService` 出厂就写成 `'strict'`(`configService.ts` 的默认表与迁移那行都是),
16
+ * 下面 `mode()` 里的 `balanced` 只是**值缺失或不认识时**的兜底。原注释写成「balanced 默认」,
17
+ * 与出厂值矛盾——README 两版跟着写成「strict 可加强」,读起来像默认更弱。两处都已按实际改写。
13
18
  */
14
19
  import { join } from 'path';
15
20
  import { existsSync, mkdirSync, appendFileSync } from 'fs';
@@ -34,10 +39,24 @@ export function redactText(text, mode, localInference) {
34
39
  }
35
40
  return { safe, redactions: count };
36
41
  }
37
- export function maskMessageBodyText(body, mode, localInference) {
42
+ /**
43
+ * strict 模式:**保留类型标签、丢掉载荷**。
44
+ *
45
+ * 契约是"仅保留时间/方向/类型",而类型标签正是那个"类型":非文本消息的正文本来就是
46
+ * `[图片]` / `[文件] Base.csv` / `[引用] 回复 | 引:原文` 这种形态,整条遮掉会把
47
+ * "这是一张图片"一起抹掉——模型从此分不出图片和文本消息,而它**一个字都没有多知道**。
48
+ * 载荷(文件名、被引原文、撤回提示里的名字)照旧不出境。
49
+ *
50
+ * `isText` 由调用方给:只有读取器说的"非文本消息"才配当作标签。用户自己敲的
51
+ * `[图片] 这是我拍的` 是正文,按正文遮——否则就是一个把用户的话放出去的口子。
52
+ */
53
+ export function maskMessageBodyText(body, mode, localInference, isText = true) {
38
54
  if (mode !== 'strict' || localInference)
39
55
  return body;
40
- return `[内容${body.length}字已按严格模式屏蔽]`;
56
+ if (isText)
57
+ return `[内容${body.length}字已按严格模式屏蔽]`;
58
+ const label = body.match(/^\[[^\]]{1,20}\]/)?.[0];
59
+ return label ? `${label}(内容已按严格模式屏蔽)` : `[内容${body.length}字已按严格模式屏蔽]`;
41
60
  }
42
61
  export class PrivacyGate {
43
62
  mode() {
@@ -57,8 +76,8 @@ export class PrivacyGate {
57
76
  return redactText(text, this.mode(), this.isLocalInference());
58
77
  }
59
78
  /** strict 模式: 第三方聊天正文不出境, 只保留元数据形态 */
60
- maskMessageBody(body) {
61
- return maskMessageBodyText(body, this.mode(), this.isLocalInference());
79
+ maskMessageBody(body, opts = {}) {
80
+ return maskMessageBodyText(body, this.mode(), this.isLocalInference(), opts.isText !== false);
62
81
  }
63
82
  /** 审计日志 — 只记事件与字节量, 绝不记内容 */
64
83
  audit(event, bytes = 0, extra = '') {
@@ -1 +1 @@
1
- {"version":3,"file":"assistantPrivacy.js","sourceRoot":"","sources":["../../../src/services/assistantPrivacy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"assistantPrivacy.js","sourceRoot":"","sources":["../../../src/services/assistantPrivacy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ export type FastRouteMode = 'off' | 'log' | 'on';
2
+ /** 能力 = 工具 + 一组固定参数。名字要能在日志与审计里一眼看懂 */
3
+ export interface RouteCapability {
4
+ name: string;
5
+ tool: string;
6
+ args: Record<string, unknown>;
7
+ /** 写进 criteria 的判据:**同时说明它假定了什么查法**(参数表就藏在这句话里) */
8
+ when: string;
9
+ }
10
+ export declare const NO_CAPABILITY = "none";
11
+ export declare const FAST_ROUTE_CAPABILITIES: RouteCapability[];
12
+ /** 两次概率都过线才算路由成功;改这两个数等于改行为,测试会盯着 */
13
+ export declare const MIN_NEEDS_TOOL = 0.5;
14
+ export declare const MIN_CONFIDENCE = 0.6;
15
+ export declare function buildRouteRequest(message: string, capabilities?: RouteCapability[]): unknown;
16
+ export interface RouteDecision {
17
+ /** 定下来的能力;null 表示回退到正常循环 */
18
+ capability: RouteCapability | null;
19
+ needsTool: number;
20
+ confidence: number;
21
+ /** 实际服务我们的判断模型版本(来自 decide.py 的返回),落进日志 */
22
+ model: string;
23
+ /** 为什么路由 / 为什么回退——日志与审计里要看的就是这句 */
24
+ reason: string;
25
+ }
26
+ interface RouterOptions {
27
+ /** 注入的判断调用(测试用)。默认走本机 decide.py */
28
+ runDecide?: (request: unknown) => Promise<any>;
29
+ capabilities?: RouteCapability[];
30
+ minNeedsTool?: number;
31
+ minConfidence?: number;
32
+ }
33
+ /**
34
+ * 问一次:这条消息该不该走快路径。
35
+ *
36
+ * **任何不确定都回退**:判断层报错、概率不是数、能力名不认识、`choice` 与概率不一致——
37
+ * 全部返回 `capability: null`,让调用方走原本的循环。回退不是降级路径,它就是今天的行为。
38
+ */
39
+ export declare function decideRoute(message: string, options?: RouterOptions): Promise<RouteDecision>;
40
+ export {};
41
+ //# sourceMappingURL=assistantRouter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assistantRouter.d.ts","sourceRoot":"","sources":["../../../src/services/assistantRouter.ts"],"names":[],"mappings":"AAuBA,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,CAAA;AAEhD,uCAAuC;AACvC,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAA;CACb;AAED,eAAO,MAAM,aAAa,SAAS,CAAA;AAEnC,eAAO,MAAM,uBAAuB,EAAE,eAAe,EAmBpD,CAAA;AAED,qCAAqC;AACrC,eAAO,MAAM,cAAc,MAAM,CAAA;AACjC,eAAO,MAAM,cAAc,MAAM,CAAA;AAEjC,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,oBAA0B,GAAG,OAAO,CAuBlG;AAED,MAAM,WAAW,aAAa;IAC5B,4BAA4B;IAC5B,UAAU,EAAE,eAAe,GAAG,IAAI,CAAA;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAA;IACb,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAA;CACf;AAED,UAAU,aAAa;IACrB,mCAAmC;IACnC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;IAC9C,YAAY,CAAC,EAAE,eAAe,EAAE,CAAA;IAChC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AA8BD;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAmDtG"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * 单轮快路径的路由(D-035)。
3
+ *
4
+ * ReAct 循环对"从本地数据答一句"这类问题要两次往返:第一轮挑工具与参数,第二轮拿结果组织
5
+ * 回答。这里在循环之前先用一次判断层调用把 `{要不要工具, 哪个能力}` 定下来,执行掉那一个
6
+ * 工具,于是循环的第一轮就已经看得到结果——**两次往返变一次**。
7
+ *
8
+ * 三条边界,都是刻意的:
9
+ *
10
+ * 1. **只路由参数封闭或为空的工具**。"查我和某某的聊天"里的联系人、"搜收藏里的关键词"里的
11
+ * 关键词都是自由文本,判断层给不出来(它只能从封闭集合里选)。硬拿用户整句话当参数,
12
+ * 正好制造 D-035 点名的那个失败模式:**工具挑错,模型拿着一份不相关的结果自信地作答**。
13
+ * 所以能力表里只有 6 个工具、9 个"能力",其余一律回退到循环。
14
+ * 2. **拿不准就回退**。回退路径必须与今天逐字段一致(有测试断言这一点),而不是"一个更差的
15
+ * 新兜底"。
16
+ * 3. **判断走本机既有的 `scripts/decide.py`**,不在 TS 里再写一个判断层客户端——同一份契约
17
+ * 两份实现,这个仓库已经被咬过(`noul` 被当成布尔的教训)。
18
+ *
19
+ * 隐私:出境的是**用户这条消息本身**加一份固定的能力表说明。消息本来就会发给配置的 LLM
20
+ * (生成回答时),所以这不是新的出境类别;但这里的 state **不含**历史对话与任何本地数据。
21
+ */
22
+ import { runPythonJson } from './pythonBridge.js';
23
+ export const NO_CAPABILITY = 'none';
24
+ export const FAST_ROUTE_CAPABILITIES = [
25
+ { name: 'list_sessions', tool: 'list_sessions', args: {},
26
+ when: '用户想知道最近在和谁聊天、有哪些会话' },
27
+ { name: 'get_stats', tool: 'get_stats', args: {},
28
+ when: '用户问本机数据的统计概览(会话数、收藏总数)' },
29
+ { name: 'get_daily_report', tool: 'get_daily_report', args: {},
30
+ when: '用户问今天或最近公众号推了哪些文章、日报里有什么' },
31
+ { name: 'sns_timeline', tool: 'get_sns', args: { mode: 'timeline' },
32
+ when: '用户问朋友圈最近有什么动态' },
33
+ { name: 'sns_stats', tool: 'get_sns', args: { mode: 'stats' },
34
+ when: '用户问朋友圈的统计(发了多少、多少人发)' },
35
+ { name: 'weread_shelf', tool: 'get_weread', args: { mode: 'shelf' },
36
+ when: '用户问自己在读什么书、书架有什么' },
37
+ { name: 'weread_notebooks', tool: 'get_weread', args: { mode: 'notebooks' },
38
+ when: '用户问自己的读书笔记' },
39
+ { name: 'todos_pending', tool: 'get_todos', args: { status: 'pending' },
40
+ when: '用户问有什么待办、要做的事' },
41
+ { name: 'todos_done', tool: 'get_todos', args: { status: 'done' },
42
+ when: '用户问已经完成的事' },
43
+ ];
44
+ /** 两次概率都过线才算路由成功;改这两个数等于改行为,测试会盯着 */
45
+ export const MIN_NEEDS_TOOL = 0.5;
46
+ export const MIN_CONFIDENCE = 0.6;
47
+ export function buildRouteRequest(message, capabilities = FAST_ROUTE_CAPABILITIES) {
48
+ const criteria = {};
49
+ for (const capability of capabilities)
50
+ criteria[capability.name] = capability.when;
51
+ criteria[NO_CAPABILITY] =
52
+ '上面那些都不对:要么不需要查本机数据(闲聊、常识、写作、翻译、先问清楚),'
53
+ + '要么需要查但不在这几种查法里(例如要点名某个人、某个关键词,而上面每一项都没有这个参数)';
54
+ return {
55
+ state: `用户发来的消息:${message}`,
56
+ questions: {
57
+ needs_local_data: {
58
+ type: 'noul',
59
+ instructions: '要回答这条消息,是否必须去查本机保存的数据(聊天记录、朋友圈、'
60
+ + '读书数据、待办、公众号日报)?仅凭常识或对话本身就能回答的不算。',
61
+ },
62
+ capability: {
63
+ type: 'choice',
64
+ instructions: '假设这条消息必须查本机数据:要查的是哪一项?每一项都写明了它假定的查法;'
65
+ + '拿不准、或消息还需要先问清楚,就选 ' + NO_CAPABILITY + '。',
66
+ criteria,
67
+ },
68
+ },
69
+ };
70
+ }
71
+ /** 本机判断层的默认出口:request 从 stdin 进,答案从 stdout 出,路径里没有密钥。
72
+ *
73
+ * 走 pythonBridge(唯一的脚本调用入口)——此前这里自己 spawn 了一遍,与 get_todos 那份
74
+ * 各写一套超时与错误处理,正是"同一件事两处实现"的老毛病。
75
+ */
76
+ async function runDecideViaPython(request) {
77
+ const result = await runPythonJson('decide.py', ['--request', '-'], { stdin: JSON.stringify(request), timeoutMs: 60_000 });
78
+ if (!result.ok) {
79
+ // 调用方(decideRoute)用抛错来表达"判断层不可用",这里保持那个契约
80
+ throw new Error(`${result.error}${result.stderr ? " · " + result.stderr : ""}`);
81
+ }
82
+ return result.data;
83
+ }
84
+ function asProbability(value) {
85
+ // `noul` 是**概率浮点**,不是布尔。两种读错都要挡:
86
+ // `Number(true)` 是 1 —— 布尔会被当成"概率 1.0",于是**确定地**路由,比读成否更危险;
87
+ // `Number('')` 是 0 —— 空串会被当成"确定不需要"。
88
+ // 所以只认数字与像数字的字符串,别的一律当"契约变了",由调用方回退。
89
+ if (typeof value === 'number')
90
+ return Number.isFinite(value) ? value : null;
91
+ if (typeof value === 'string' && value.trim() !== '') {
92
+ const parsed = Number(value);
93
+ return Number.isFinite(parsed) ? parsed : null;
94
+ }
95
+ return null;
96
+ }
97
+ /**
98
+ * 问一次:这条消息该不该走快路径。
99
+ *
100
+ * **任何不确定都回退**:判断层报错、概率不是数、能力名不认识、`choice` 与概率不一致——
101
+ * 全部返回 `capability: null`,让调用方走原本的循环。回退不是降级路径,它就是今天的行为。
102
+ */
103
+ export async function decideRoute(message, options = {}) {
104
+ const capabilities = options.capabilities ?? FAST_ROUTE_CAPABILITIES;
105
+ const minNeedsTool = options.minNeedsTool ?? MIN_NEEDS_TOOL;
106
+ const minConfidence = options.minConfidence ?? MIN_CONFIDENCE;
107
+ const run = options.runDecide ?? runDecideViaPython;
108
+ const fallback = (reason, needsTool = 0, confidence = 0, model = '') => ({ capability: null, needsTool, confidence, model, reason });
109
+ let response;
110
+ try {
111
+ response = await run(buildRouteRequest(message, capabilities));
112
+ }
113
+ catch (error) {
114
+ return fallback(`判断层不可用: ${error?.message?.slice(0, 120) ?? error}`);
115
+ }
116
+ if (!response || response.success === false) {
117
+ return fallback(`判断层返回失败: ${String(response?.error ?? '未知').slice(0, 120)}`);
118
+ }
119
+ const answers = response.answers ?? {};
120
+ const model = String(response.model ?? '');
121
+ const needsTool = asProbability(answers.needs_local_data?.noul);
122
+ if (needsTool === null) {
123
+ return fallback('判断层没给出「要不要查本机数据」的概率', 0, 0, model);
124
+ }
125
+ if (needsTool < minNeedsTool) {
126
+ return fallback(`不需要查本机数据 (${needsTool.toFixed(2)})`, needsTool, 0, model);
127
+ }
128
+ const capabilityAnswer = answers.capability ?? {};
129
+ const picked = String(capabilityAnswer.choice ?? '');
130
+ const confidence = asProbability(capabilityAnswer.confidence) ?? 0;
131
+ if (picked === NO_CAPABILITY || !picked) {
132
+ return fallback(`判断层认为不需要工具 (${picked || '空'})`, needsTool, confidence, model);
133
+ }
134
+ const capability = capabilities.find(item => item.name === picked);
135
+ if (!capability) {
136
+ // 能力表是封闭的:出现陌生名字说明契约变了,回退而不是猜
137
+ return fallback(`判断层给了一个不在能力表里的名字: ${picked}`, needsTool, confidence, model);
138
+ }
139
+ if (confidence < minConfidence) {
140
+ return fallback(`路由置信度不足 (${confidence.toFixed(2)} < ${minConfidence})`, needsTool, confidence, model);
141
+ }
142
+ return {
143
+ capability,
144
+ needsTool,
145
+ confidence,
146
+ model,
147
+ reason: `路由到 ${capability.name}(${capability.tool},needs_tool=${needsTool.toFixed(2)},`
148
+ + `confidence=${confidence.toFixed(2)})`,
149
+ };
150
+ }
151
+ //# sourceMappingURL=assistantRouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assistantRouter.js","sourceRoot":"","sources":["../../../src/services/assistantRouter.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,90 @@
1
- import type { Message } from '../types.js';
1
+ import type { AttachedImage } from './assistantTools.js';
2
+ import type { Message, WechatInboundMessage } from '../types.js';
3
+ /**
4
+ * 消息通道。**不是新抽象,是把既有的隐式契约写出来**——`AssistantService` 一直只用
5
+ * `WechatMessageService` 的这四个方法,测试也是靠替换这四个方法驱动整条循环的
6
+ * (`test/assistant-loop.test.ts` 的 `installFakeChannel`)。写成接口是为了让"通道可以不是微信"
7
+ * 这件事在类型上成立,而不是靠"反正 `svc` 可空"。
8
+ *
9
+ * `stop` 写成 `Promise<void> | void`:`WechatMessageService.stop()` 返回 Promise,
10
+ * 而 `AssistantService.stop()` 并不 await 它(`:668`),两边都收。
11
+ */
12
+ export interface AssistantChannel {
13
+ onMessage(cb: (msg: WechatInboundMessage) => void): void;
14
+ startPolling(): Promise<void>;
15
+ sendText(conversationId: string, text: string): Promise<boolean>;
16
+ stop(): Promise<void> | void;
17
+ /**
18
+ * 服务端是否已判这个 token 失效。**可选**:它是"通道实况"的一部分,而通道是可以被替身实现的
19
+ * (测试里的假通道、将来的别的入口),没这个方法的通道一律当成没过期。
20
+ */
21
+ isTokenExpired?(): boolean;
22
+ }
23
+ /** 一轮从哪来。**决定要不要过白名单**,见 `runTurn` */
24
+ export type TurnOrigin = 'wechat' | 'panel';
25
+ export interface TurnInput {
26
+ sessionId: string;
27
+ text: string;
28
+ kind: string;
29
+ origin: TurnOrigin;
30
+ /** 微信来源才有:白名单判定要它的 senderId / conversationType / mentionedBot */
31
+ message?: WechatInboundMessage;
32
+ }
33
+ /**
34
+ * 一轮的结果。**"回什么"与"往哪回"分开**:这里只说回什么,往哪回由调用方的 `deliver` 决定。
35
+ *
36
+ * 这么分的直接原因是修一个真 bug:泵里原先是 `this.svc!.sendText(...)`,而 `svc` 在没有
37
+ * 微信通道时是 `null`——那个 `!` 只是给 TS 看的。于是"配额用尽"那一次会抛 TypeError,
38
+ * 调用方永远收不到响应(挂到超时)。任何"没有通道的宿主"都会踩到。
39
+ */
40
+ export type TurnOutcome = {
41
+ status: 'replied';
42
+ text: string;
43
+ }
44
+ /** 微信来源且不在白名单里。**故意不回复**(回一句就等于告诉陌生人这号是活的) */
45
+ | {
46
+ status: 'denied';
47
+ reason: string;
48
+ } | {
49
+ status: 'ignored';
50
+ reason: string;
51
+ } | {
52
+ status: 'quota-exceeded';
53
+ text: string;
54
+ } | {
55
+ status: 'not-running';
56
+ } | {
57
+ status: 'error';
58
+ message: string;
59
+ };
60
+ interface ApiMessage {
61
+ role: 'system' | 'user' | 'assistant' | 'tool';
62
+ content: string;
63
+ tool_calls?: any[];
64
+ tool_call_id?: string;
65
+ /** 多模态附件:只会由 `look_at_image` 产生,展开见 `toApiMessages` */
66
+ images?: AttachedImage[];
67
+ }
68
+ /**
69
+ * 把内部消息展开成请求要的形状——**图片只在这一处**变成多模态数组。
70
+ *
71
+ * 其余所有环节(记忆、脱敏、审计、配额)继续按文本 `content` 工作,所以加图片没有把
72
+ * `ApiMessage.content` 变成一个到处都要判类型的联合体。
73
+ *
74
+ * `allowImages` 为假时图片**不发**,并在正文里留下一句说明:静默少发一张图,和"模型
75
+ * 看不见"在下游无法区分——这是这个仓库反复踩过的那类坑。
76
+ *
77
+ * 纯函数,不读配置。是否允许由调用方(`callLLM`)按隐私模式判定。
78
+ */
79
+ export declare function toApiMessages(messages: ApiMessage[], allowImages: boolean): {
80
+ messages: ApiMessage[];
81
+ imagesSent: number;
82
+ imagesDropped: number;
83
+ };
2
84
  export declare class AssistantService {
85
+ constructor(options?: {
86
+ routeDecider?: (request: unknown) => Promise<any>;
87
+ });
3
88
  private svc;
4
89
  private memory;
5
90
  private running;
@@ -8,6 +93,23 @@ export declare class AssistantService {
8
93
  /** 每日用量计数 (内存态, 重启重置 — 配额护栏防烧钱, 无需持久精确) */
9
94
  private dailyCount;
10
95
  private dailyDate;
96
+ /** 快路径的判断调用。留出注入点:测试用假判断层驱动,不联网、不 spawn Python */
97
+ private routeDecider;
98
+ /**
99
+ * `handleMessage` 的重入护栏。
100
+ *
101
+ * `turnCalls` / `lastReasoning` / `lastNeedsLocalData` 是**实例字段**,它们的正确性只依赖
102
+ * "handleMessage 被串行调用"这个不变式——而那个不变式今天只写在注释里。第二个入口
103
+ * (本机面板)一出现,早晚有人想加一条直连的快速路径。重入就直接抛,
104
+ * 把"记忆窗口悄悄错乱"换成一声巨响。
105
+ */
106
+ private inFlight;
107
+ /** `start()` 给的日志出口。本机入口不经过那个调用点传参,所以存一份 */
108
+ private logSink;
109
+ /** 本机入口的回环端点(见 src/panel/server.ts 的信任边界) */
110
+ private panelServer;
111
+ /** 本机入口用哪个记忆桶。与微信直聊同一个 id 时才是"共用一个大脑" */
112
+ private memoryBucket;
11
113
  private engineConfig;
12
114
  /**
13
115
  * Direct messages require an explicit sender allowlist. Groups are disabled
@@ -24,14 +126,118 @@ export declare class AssistantService {
24
126
  localInference: boolean;
25
127
  redactions: number;
26
128
  }>;
27
- /** 组装系统提示: 基础人格 + L2 摘要 + L3 事实 */
129
+ /** 当前的隐私状态,作为**事实**写进系统提示。
130
+ *
131
+ * 曾经这里是一段写死的假设句(「若因严格模式读不到正文…」),实测撞了车:模型把它当成
132
+ * 当前状态,于是**一次工具都没调**就回用户"我调了工具,但内容被严格模式挡掉了"——
133
+ * 审计里 `tools=0`,是编造。现在按实际档位说,且与"没调工具不许下结论"那条配套。
134
+ */
135
+ private privacyStateLine;
136
+ /** 组装系统提示: 基础人格 + 隐私状态 + L2 摘要 + L3 事实。
137
+ *
138
+ * 两个纪律:
139
+ * 1. **事实按相关度取一部分**,而不是 30 条全塞——无关的那些是噪声,不只是花钱;
140
+ * 2. 本地数据(摘要、事实)一律**加帧 + 转义框标签**:它们的内容里完全可能写着
141
+ * `</weflow-local-data>` 再跟一段像系统指令的话,不转义就等于让数据自己把框关上。
142
+ */
28
143
  private buildSystemPrompt;
29
- /** 单条消息处理: 指令路由 → ReAct 循环 → 记忆更新 */
144
+ /** 白名单为空的首次配置提示是否已经打过了(只打一次,别把日志刷满) */
145
+ private firstRunHintShown;
146
+ /** 最近一次路由认为「这条消息需要查本机数据」的概率(0 = 没问过) */
147
+ private lastNeedsLocalData;
148
+ /** 最近一次模型调用里**真返回**的推理内容(`reasoning_content`)。默认模型不返回,所以常是空串 */
149
+ private lastReasoning;
150
+ /** 每个用户最近一轮的轨迹:微信里发「轨迹」看的就是它(跨进程的历史在文件里,见 assistantTrace) */
151
+ private traces;
152
+ /**
153
+ * 本轮已经调过的「工具名 + 参数」。同一条消息里重复调用**同样的参数**不会得到新信息,
154
+ * 而实测(评测的 ambiguous-contact 用例)模型会连着调三次 list_sessions。
155
+ * 消息是串行处理的(queue),所以实例字段在这里是安全的。
156
+ */
157
+ private turnCalls;
158
+ /** 白名单为空时,把"该把谁加进去"连同**完整**的发送者 ID 打一行。
159
+ *
160
+ * 为什么可以打完整的 ID:填白名单用的就是这个值,而它只在入站消息里出现——登录响应给的
161
+ * `ilink_user_id` 与它是不是同一个值**没有验证过**,所以不能拿登录来猜(猜错的后果是
162
+ * "白名单非空、看着配好了、却仍然拒你")。启发式在这里正好用得上:真值自己会来。
163
+ *
164
+ * 三条自我约束:白名单非空时不提示(那时人已经配过了)、只对**直聊**提示(群里的
165
+ * sender_id 是群成员,把它加进白名单是错的)、只提示一次。
166
+ * `assistant log --json` 照旧只回元数据,不返回日志内容。
167
+ */
168
+ private maybeAnnounceWhitelistBootstrap;
169
+ /** 快路径开关。默认 `off`:不改行为,直到有人愿意盯着它(D-035) */
170
+ private fastRouteMode;
171
+ /** ReAct 主循环:一轮一轮问模型,直到它给出不带工具调用的答复。
172
+ *
173
+ * 抽成方法是因为守卫(见 handleMessage)要在"顶回去一次"之后**再跑一遍同一条循环**——
174
+ * 两处各写一份,早晚有一处会漏掉既有的容错(参数解析、工具审计、轮数上限)。
175
+ */
176
+ private runReactLoop;
177
+ /** 执行一次工具调用:脱敏、审计、把结果塞回对话。
178
+ *
179
+ * 快路径与 ReAct 循环**共用这一份**:D-035 里那条不可回归的安全属性是「没有审计行就不得
180
+ * 派发工具」,两条路各写一遍,早晚有一条会漏。
181
+ */
182
+ private runToolCall;
183
+ /** 快路径:先问一次「该查哪个能力」,把这一个工具执行掉,于是循环第一轮就看得到结果。
184
+ *
185
+ * 返回派发了几个工具(0 = 回退)。**任何不确定都回退**,而回退就是原样跑循环——不是
186
+ * 「另一个更差的兜底」。`log` 模式下只算不派发,用来在真实流量上观察它本来会怎么走。
187
+ */
188
+ private maybeFastRoute;
189
+ /**
190
+ * 单条消息处理: 指令路由 → ReAct 循环 → 记忆更新。
191
+ *
192
+ * **外部只许经由 `enqueueTurn` 调用**(它保证串行);直接调会被 `inFlight` 挡下——
193
+ * 见那个字段的注释。
194
+ */
30
195
  handleMessage(userId: string, text: string, kind: string): Promise<string>;
196
+ private handleMessageInner;
197
+ /**
198
+ * 一轮的处理。**这是唯一一处**——微信通道与本机面板都走这里。
199
+ *
200
+ * 抽出来的理由是这个仓库付过学费的老毛病:判定逻辑两处各写一份,早晚有一处漏掉既有的容错
201
+ * (同样的判词写在本文件 `:319` 与 `:361` 附近的注释里)。配额、忽略非文本、异常兜底
202
+ * 这些行为**只该有一份**。
203
+ *
204
+ * `origin` 决定要不要过白名单:微信来的必须过;**本机入口的门是端点 token,不是白名单**。
205
+ * 把白名单套到"坐在机器前的人"身上是错的——空名单时会把面板自己拒掉,而且
206
+ * `maybeAnnounceWhitelistBootstrap` 还会打出一条**教用户把自己的面板 id 加进微信白名单**的错提示。
207
+ *
208
+ * 本方法**不负责"往哪回"**:结果交给调用方(微信是 `sendText`,面板是 HTTP 响应)。
209
+ */
210
+ private runTurn;
211
+ /**
212
+ * 串行入队 + 投递。**投递在队列里做**,不在队列外——微信那边"先回复完再处理下一条"
213
+ * 是既有行为,把它挪到队列外会让两条消息的回复有乱序的可能(前一条发出慢一点就反超)。
214
+ *
215
+ * 返回的 Promise 在这个请求**处理且投递完**之后 resolve,调用方可以直接 await 它去写响应。
216
+ */
217
+ private enqueueTurn;
31
218
  /** 启动常驻监听 */
32
219
  start(onLog?: (line: string) => void): Promise<void>;
220
+ /** 本机入口用:投一条消息进同一条队列,返回这一轮的结果 */
221
+ ask(sessionId: string, text: string, onLog?: (line: string) => void): Promise<TurnOutcome>;
222
+ /** 消息通道接上了吗(未登录时是 false)。status 要靠它区分两种"没通道" */
223
+ /**
224
+ * 微信通道**现在**是否可用。
225
+ *
226
+ * 原来是 `this.svc !== null`——那只是"启动时配了 token",于是 token 失效之后它照样报 true,
227
+ * 面板与状态页都在说"微信 + 本机"而通道其实已经死了(用户看不到任何异常)。
228
+ * 现在把长轮询那边的实况算进来:服务端判过期时,这里如实变 false(面板就会显示"仅本机入口")。
229
+ */
230
+ isChannelActive(): boolean;
231
+ /** 配额用量。**内存态**(重启归零),所以它不是"今天一共花了多少"的账本,是护栏的余量 */
232
+ quotaState(): {
233
+ used: number;
234
+ limit: number;
235
+ };
33
236
  stop(): void;
237
+ /** 本机入口的实际监听端口;没起来就是 null */
238
+ panelPort(): number | null;
34
239
  isRunning(): boolean;
35
240
  memoryUserCount(): number;
36
241
  }
242
+ export {};
37
243
  //# sourceMappingURL=assistantService.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"assistantService.d.ts","sourceRoot":"","sources":["../../../src/services/assistantService.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAAwB,MAAM,aAAa,CAAA;AAyBhE,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,GAAG,CAAoC;IAC/C,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,OAAO,CAAQ;IACvB,+CAA+C;IAC/C,OAAO,CAAC,KAAK,CAAmC;IAChD,2CAA2C;IAC3C,OAAO,CAAC,UAAU,CAAI;IACtB,OAAO,CAAC,SAAS,CAA4B;IAE7C,OAAO,CAAC,YAAY;IAgBpB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,cAAc;IAMtB,wBAAwB;YACV,OAAO;IA0BrB,iCAAiC;IAC3B,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,UAAU,UAAQ,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IA8BrJ,mCAAmC;IACnC,OAAO,CAAC,iBAAiB;IAWzB,qCAAqC;IAC/B,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiFhF,aAAa;IACP,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAiD1D,IAAI,IAAI,IAAI;IAKZ,SAAS,IAAI,OAAO;IACpB,eAAe,IAAI,MAAM;CAC1B"}
1
+ {"version":3,"file":"assistantService.d.ts","sourceRoot":"","sources":["../../../src/services/assistantService.ts"],"names":[],"mappings":"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"}