evolcore 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (379) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/LICENSE +21 -0
  3. package/MIGRATION-0.5.0.md +378 -0
  4. package/README.md +318 -14
  5. package/ROLE_ACCESS_CONTROL.md +174 -0
  6. package/assets/.env.template +4 -0
  7. package/bin/ec-safe-output.js +161 -0
  8. package/bin/ec.js +29 -0
  9. package/dist/agents/baseagent.js +163 -0
  10. package/dist/agents/claude-runner.js +2565 -0
  11. package/dist/agents/codex-app-server-client.js +448 -0
  12. package/dist/agents/codex-runner.js +2682 -0
  13. package/dist/agents/gemini-runner.js +666 -0
  14. package/dist/agents/runner-types.js +75 -0
  15. package/dist/aun/aid/agentmd.js +216 -0
  16. package/dist/aun/aid/client.js +132 -0
  17. package/dist/aun/aid/control-aid.js +91 -0
  18. package/dist/aun/aid/identity.js +518 -0
  19. package/dist/aun/aid/index.js +4 -0
  20. package/dist/aun/aid/store.js +74 -0
  21. package/dist/aun/aid/types.js +1 -0
  22. package/dist/aun/aid/validation.js +21 -0
  23. package/dist/aun/group-identity.js +10 -0
  24. package/dist/aun/msg/group-index.js +6 -0
  25. package/dist/aun/msg/group.js +1231 -0
  26. package/dist/aun/msg/history.js +123 -0
  27. package/dist/aun/msg/index.js +5 -0
  28. package/dist/aun/msg/p2p.js +393 -0
  29. package/dist/aun/msg/payload-type.js +27 -0
  30. package/dist/aun/msg/upload.js +137 -0
  31. package/dist/aun/outbox.js +168 -0
  32. package/dist/aun/rpc/caller.js +42 -0
  33. package/dist/aun/rpc/connection.js +25 -0
  34. package/dist/aun/rpc/index.js +2 -0
  35. package/dist/aun/service-proxy.js +225 -0
  36. package/dist/aun/storage/download.js +29 -0
  37. package/dist/aun/storage/index.js +3 -0
  38. package/dist/aun/storage/manage.js +10 -0
  39. package/dist/aun/storage/upload.js +68 -0
  40. package/dist/channels/aun.js +4164 -0
  41. package/dist/channels/contact-bind-code.js +134 -0
  42. package/dist/channels/daemon.js +422 -0
  43. package/dist/channels/dingtalk.js +1479 -0
  44. package/dist/channels/feishu.js +1865 -0
  45. package/dist/channels/qqbot.js +409 -0
  46. package/dist/channels/wechat.js +817 -0
  47. package/dist/channels/wecom-card.js +101 -0
  48. package/dist/channels/wecom-onboarding.js +82 -0
  49. package/dist/channels/wecom-state.js +191 -0
  50. package/dist/channels/wecom.js +1157 -0
  51. package/dist/cli/agent-command.js +642 -0
  52. package/dist/cli/agent.js +1059 -0
  53. package/dist/cli/aun-commands.js +2003 -0
  54. package/dist/cli/bench.js +1228 -0
  55. package/dist/cli/cli-argv.js +66 -0
  56. package/dist/cli/code-stats.js +329 -0
  57. package/dist/cli/command-log.js +82 -0
  58. package/dist/cli/config-selector.js +69 -0
  59. package/dist/cli/config.js +261 -0
  60. package/dist/cli/contact.js +71 -0
  61. package/dist/cli/ctl-command.js +62 -0
  62. package/dist/cli/daemon-commands.js +2750 -0
  63. package/dist/cli/fs-command.js +1447 -0
  64. package/dist/cli/handoff-command.js +302 -0
  65. package/dist/cli/help.js +35 -0
  66. package/dist/cli/index.js +374 -0
  67. package/dist/cli/init-channel.js +1372 -0
  68. package/dist/cli/init.js +590 -0
  69. package/dist/cli/link-rules.js +240 -0
  70. package/dist/cli/model.js +591 -0
  71. package/dist/cli/net-check.js +723 -0
  72. package/dist/cli/queue-command.js +150 -0
  73. package/dist/cli/raw-key-input.js +25 -0
  74. package/dist/cli/response.js +344 -0
  75. package/dist/cli/restart-monitor.js +480 -0
  76. package/dist/cli/stats.js +609 -0
  77. package/dist/cli/task-context.js +80 -0
  78. package/dist/cli/trigger-command.js +545 -0
  79. package/dist/cli/version.js +93 -0
  80. package/dist/cli/watch-logs.js +33 -0
  81. package/dist/cli/watch-msg.js +673 -0
  82. package/dist/config/boot-log.js +266 -0
  83. package/dist/config/builtin-role-templates.js +42 -0
  84. package/dist/config/builtin-roles.js +91 -0
  85. package/dist/config/config-batch-get.js +11 -0
  86. package/dist/config/config-field-policy.js +261 -0
  87. package/dist/config/config-manager.js +1120 -0
  88. package/dist/config/config-operation-service.js +384 -0
  89. package/dist/config/contact-alias.js +68 -0
  90. package/dist/config/contact-book-store.js +454 -0
  91. package/dist/config/contact-book-v2-startup.js +35 -0
  92. package/dist/config/contact-book.js +224 -0
  93. package/dist/config/contact-operation-service.js +110 -0
  94. package/dist/config/gateway-config.js +858 -0
  95. package/dist/config/lifecycle.js +17 -0
  96. package/dist/config/mention-mode.js +27 -0
  97. package/dist/config/merge.js +161 -0
  98. package/dist/config/owner-policy.js +4 -0
  99. package/dist/config/peer-role-resolver.js +218 -0
  100. package/dist/config/resolved-config-op.js +483 -0
  101. package/dist/config/role-config-v4-startup.js +32 -0
  102. package/dist/config/role-config-v5-startup.js +27 -0
  103. package/dist/config/role-ranks.js +18 -0
  104. package/dist/config/role-schema.js +105 -0
  105. package/dist/config/role-service.js +156 -0
  106. package/dist/config/role-store.js +215 -0
  107. package/dist/config/roles.js +64 -0
  108. package/dist/config/schema-registry.js +154 -0
  109. package/dist/config/snapshot.js +598 -0
  110. package/dist/config-store.js +501 -0
  111. package/dist/core/auth/agent-delegation.js +111 -0
  112. package/dist/core/auth/auth-gateway.js +166 -0
  113. package/dist/core/auth/authenticated-actor.js +6 -0
  114. package/dist/core/auth/authorization-audit.js +119 -0
  115. package/dist/core/auth/operation-authorizer.js +720 -0
  116. package/dist/core/auth/operation-catalog.js +731 -0
  117. package/dist/core/baseagent-loader.js +54 -0
  118. package/dist/core/bootstrap-service.js +175 -0
  119. package/dist/core/capability/capability-manager.js +316 -0
  120. package/dist/core/capability/providers/claude-capability-provider.js +176 -0
  121. package/dist/core/capability/providers/codex-capability-provider.js +148 -0
  122. package/dist/core/capability/providers/gemini-capability-provider.js +10 -0
  123. package/dist/core/capability/types.js +27 -0
  124. package/dist/core/causation/audit.js +103 -0
  125. package/dist/core/causation/aun-association.js +111 -0
  126. package/dist/core/causation/context.js +93 -0
  127. package/dist/core/causation/index.js +4 -0
  128. package/dist/core/causation/types.js +2 -0
  129. package/dist/core/channel-loader.js +277 -0
  130. package/dist/core/command/agent-control.js +616 -0
  131. package/dist/core/command/cli-intent-parser.js +225 -0
  132. package/dist/core/command/command-handler.js +1733 -0
  133. package/dist/core/command/connect-menu.js +374 -0
  134. package/dist/core/command/menu-handler.js +3452 -0
  135. package/dist/core/command/menu-protocol.js +247 -0
  136. package/dist/core/command/role-menu.js +1623 -0
  137. package/dist/core/command/slash-gate.js +148 -0
  138. package/dist/core/command/slash-handler.js +3066 -0
  139. package/dist/core/daemon-file-cache.js +222 -0
  140. package/dist/core/event-bus.js +32 -0
  141. package/dist/core/event-catalog.js +810 -0
  142. package/dist/core/evolagent-registry.js +545 -0
  143. package/dist/core/evolagent.js +342 -0
  144. package/dist/core/handoff/dispatcher.js +229 -0
  145. package/dist/core/handoff/mutex.js +46 -0
  146. package/dist/core/handoff/runtime.js +324 -0
  147. package/dist/core/handoff/store.js +537 -0
  148. package/dist/core/handoff/types.js +12 -0
  149. package/dist/core/inference/text-inference.js +173 -0
  150. package/dist/core/interaction-registration.js +10 -0
  151. package/dist/core/interaction-router.js +278 -0
  152. package/dist/core/message/create-status.js +67 -0
  153. package/dist/core/message/im-renderer.js +659 -0
  154. package/dist/core/message/items-formatter.js +76 -0
  155. package/dist/core/message/logical-queue-bridge.js +123 -0
  156. package/dist/core/message/message-bridge.js +874 -0
  157. package/dist/core/message/message-cache.js +56 -0
  158. package/dist/core/message/message-log.js +339 -0
  159. package/dist/core/message/message-processor.js +4 -0
  160. package/dist/core/message/message-queue.js +1446 -0
  161. package/dist/core/message/message-utils.js +76 -0
  162. package/dist/core/message/peer-mode.js +105 -0
  163. package/dist/core/message/pending-hints.js +232 -0
  164. package/dist/core/message/response-depth.js +33 -0
  165. package/dist/core/message/response-engine.js +4020 -0
  166. package/dist/core/message/response-snapshot.js +83 -0
  167. package/dist/core/message/send-receipt.js +24 -0
  168. package/dist/core/message/stream-debouncer.js +139 -0
  169. package/dist/core/message/stream-idle-monitor.js +124 -0
  170. package/dist/core/model/config-scope.js +162 -0
  171. package/dist/core/model/field-scope.js +78 -0
  172. package/dist/core/model/model-catalog.js +227 -0
  173. package/dist/core/model/model-diagnostics.js +182 -0
  174. package/dist/core/model/model-permission.js +90 -0
  175. package/dist/core/permission/approval-gateway.js +1017 -0
  176. package/dist/core/permission/ec-command-parser.js +347 -0
  177. package/dist/core/permission/execution-sandbox.js +16 -0
  178. package/dist/core/permission/index.js +6 -0
  179. package/dist/core/permission/mode.js +24 -0
  180. package/dist/core/permission/sandbox-runtime.js +265 -0
  181. package/dist/core/permission/tool-policy.js +1019 -0
  182. package/dist/core/permission/unix-socket-policy.js +99 -0
  183. package/dist/core/protected-paths.js +332 -0
  184. package/dist/core/relation/peer-identity.js +222 -0
  185. package/dist/core/relation/peer-key.js +1 -0
  186. package/dist/core/role/runtime-policy.js +141 -0
  187. package/dist/core/session/adapters/claude-session-file-adapter.js +218 -0
  188. package/dist/core/session/adapters/codex-session-file-adapter.js +333 -0
  189. package/dist/core/session/adapters/gemini-session-file-adapter.js +181 -0
  190. package/dist/core/session/session-file-adapter.js +7 -0
  191. package/dist/core/session/session-file-health.js +45 -0
  192. package/dist/core/session/session-fs-store.js +273 -0
  193. package/dist/core/session/session-key.js +24 -0
  194. package/dist/core/session/session-manager.js +1643 -0
  195. package/dist/core/session/session-mapper.js +100 -0
  196. package/dist/core/session/session-renew.js +314 -0
  197. package/dist/core/session/session-title.js +128 -0
  198. package/dist/core/session/session-turn-coordinator.js +205 -0
  199. package/dist/core/session/session-turns.js +67 -0
  200. package/dist/core/system-channels.js +29 -0
  201. package/dist/eck/baseagent-caps.js +18 -0
  202. package/dist/eck/detect.js +47 -0
  203. package/dist/eck/group-rules-sync.js +345 -0
  204. package/dist/eck/init.js +77 -0
  205. package/dist/eck/kit-renderer.js +359 -0
  206. package/dist/eck/manifest-engine.js +446 -0
  207. package/dist/eck/message-renderer.js +199 -0
  208. package/dist/eck/rules-loader.js +28 -0
  209. package/dist/index.js +2926 -4
  210. package/dist/ipc.js +777 -0
  211. package/dist/paths.js +262 -0
  212. package/dist/product.js +18 -0
  213. package/dist/response-system/context-builder.js +71 -0
  214. package/dist/response-system/coordinator.js +117 -0
  215. package/dist/response-system/decision-executor.js +86 -0
  216. package/dist/response-system/engines/v1/index.js +21 -0
  217. package/dist/response-system/engines/v1/interactive-flow.js +27 -0
  218. package/dist/response-system/engines/v1/proactive-flow.js +137 -0
  219. package/dist/response-system/engines/v1/types.js +1 -0
  220. package/dist/response-system/extensions.js +41 -0
  221. package/dist/response-system/index.js +6 -0
  222. package/dist/response-system/modes/index.js +7 -0
  223. package/dist/response-system/modes/single-session/index.js +72 -0
  224. package/dist/response-system/queues/fifo-queue.js +44 -0
  225. package/dist/response-system/queues/index.js +6 -0
  226. package/dist/response-system/queues/lifo-queue.js +42 -0
  227. package/dist/response-system/queues/priority-queue.js +63 -0
  228. package/dist/response-system/registry.js +97 -0
  229. package/dist/response-system/resolver.js +37 -0
  230. package/dist/response-system/selector.js +23 -0
  231. package/dist/response-system/types.js +7 -0
  232. package/dist/stats/billing.js +163 -0
  233. package/dist/stats/budget.js +93 -0
  234. package/dist/stats/db.js +403 -0
  235. package/dist/stats/eck-vars.js +89 -0
  236. package/dist/stats/index.js +11 -0
  237. package/dist/stats/normalizer.js +80 -0
  238. package/dist/stats/price-resolver.js +138 -0
  239. package/dist/stats/query.js +763 -0
  240. package/dist/stats/role-budget.js +168 -0
  241. package/dist/stats/writer.js +151 -0
  242. package/dist/trigger/anomaly-store.js +258 -0
  243. package/dist/trigger/audit.js +152 -0
  244. package/dist/trigger/event-source.js +119 -0
  245. package/dist/trigger/feedback.js +685 -0
  246. package/dist/trigger/history.js +290 -0
  247. package/dist/trigger/manager.js +294 -0
  248. package/dist/trigger/parser.js +595 -0
  249. package/dist/trigger/patch.js +155 -0
  250. package/dist/trigger/scheduler.js +1602 -0
  251. package/dist/trigger/script-executor.js +155 -0
  252. package/dist/trigger/state.js +145 -0
  253. package/dist/trigger/types.js +1 -0
  254. package/dist/trigger/validation.js +634 -0
  255. package/dist/types.js +12 -0
  256. package/dist/utils/aid-bind.js +313 -0
  257. package/dist/utils/atomic-write.js +95 -0
  258. package/dist/utils/avatar-upload.js +123 -0
  259. package/dist/utils/cross-platform.js +297 -0
  260. package/dist/utils/ecweb-utils.js +73 -0
  261. package/dist/utils/error-dict.json +153 -0
  262. package/dist/utils/error-utils.js +349 -0
  263. package/dist/utils/instance-registry.js +444 -0
  264. package/dist/utils/locale.js +21 -0
  265. package/dist/utils/log-writer.js +270 -0
  266. package/dist/utils/logger.js +89 -0
  267. package/dist/utils/markdown-to-plain-text.js +20 -0
  268. package/dist/utils/media-cache.js +274 -0
  269. package/dist/utils/model-prices.jsonl +20 -0
  270. package/dist/utils/npm-ops.js +210 -0
  271. package/dist/utils/process-introspect.js +133 -0
  272. package/dist/utils/process-tree-stats.js +271 -0
  273. package/dist/utils/project-path.js +74 -0
  274. package/dist/utils/restart-safety.js +31 -0
  275. package/dist/utils/stats.js +410 -0
  276. package/dist/utils/system-memory.js +62 -0
  277. package/dist/utils/tool-summary.js +284 -0
  278. package/dist/utils/welcome.js +268 -0
  279. package/kits/docs/GUIDE.md +20 -0
  280. package/kits/docs/INDEX.md +66 -0
  281. package/kits/docs/aun/CHEATSHEET.md +19 -0
  282. package/kits/docs/aun/SYNC_PROTOCOL.md +15 -0
  283. package/kits/docs/channels/aun.md +65 -0
  284. package/kits/docs/channels/feishu.md +56 -0
  285. package/kits/docs/context-assembly.md +366 -0
  286. package/kits/docs/eck_templates/GUIDE.template.md +22 -0
  287. package/kits/docs/eck_templates/INDEX.template.md +28 -0
  288. package/kits/docs/eck_templates/path-registry.template.md +33 -0
  289. package/kits/docs/eck_templates/runtime.template.md +19 -0
  290. package/kits/docs/evolcore/INDEX.md +68 -0
  291. package/kits/docs/evolcore/agent.md +77 -0
  292. package/kits/docs/evolcore/aid.md +52 -0
  293. package/kits/docs/evolcore/config.md +149 -0
  294. package/kits/docs/evolcore/contact.md +57 -0
  295. package/kits/docs/evolcore/ctl.md +46 -0
  296. package/kits/docs/evolcore/event.md +216 -0
  297. package/kits/docs/evolcore/fs-architecture.md +1215 -0
  298. package/kits/docs/evolcore/fs.md +110 -0
  299. package/kits/docs/evolcore/group-fs.md +17 -0
  300. package/kits/docs/evolcore/group-rules.md +226 -0
  301. package/kits/docs/evolcore/group.md +150 -0
  302. package/kits/docs/evolcore/model.md +50 -0
  303. package/kits/docs/evolcore/msg.md +136 -0
  304. package/kits/docs/evolcore/response.md +75 -0
  305. package/kits/docs/evolcore/rpc.md +37 -0
  306. package/kits/docs/evolcore/self-summary.md +29 -0
  307. package/kits/docs/evolcore/stats.md +83 -0
  308. package/kits/docs/evolcore/storage.md +50 -0
  309. package/kits/docs/evolcore/trigger.md +539 -0
  310. package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -0
  311. package/kits/docs/identity/PATH_OPS.md +16 -0
  312. package/kits/docs/identity/ROLE_DETAIL.md +23 -0
  313. package/kits/docs/identity/identity-tools.md +26 -0
  314. package/kits/docs/path-registry.md +43 -0
  315. package/kits/docs/prompt-loading-architecture.md +266 -0
  316. package/kits/docs/venues/aun-group.md +45 -0
  317. package/kits/docs/venues/aun-private.md +10 -0
  318. package/kits/docs/venues/client-desktop.md +10 -0
  319. package/kits/docs/venues/client-mobile.md +10 -0
  320. package/kits/docs/venues/feishu-group.md +13 -0
  321. package/kits/docs/venues/feishu-private.md +9 -0
  322. package/kits/docs/venues/group.md +25 -0
  323. package/kits/docs/venues/private.md +10 -0
  324. package/kits/eck_manifest.auxiliary.json +43 -0
  325. package/kits/eck_manifest.json +203 -0
  326. package/kits/eck_message_manifest.json +63 -0
  327. package/kits/migrations/README-role-config-v4.md +32 -0
  328. package/kits/migrations/migrate-contact-book-v2.mjs +747 -0
  329. package/kits/migrations/migrate-role-config-v4.mjs +623 -0
  330. package/kits/migrations/migrate-role-config-v5.mjs +346 -0
  331. package/kits/migrations/rename-config-file.mjs +99 -0
  332. package/kits/rules/01-overview.md +142 -0
  333. package/kits/rules/02-navigation.md +76 -0
  334. package/kits/rules/03-identity.md +34 -0
  335. package/kits/rules/04-relation.md +59 -0
  336. package/kits/rules/05-venue.md +44 -0
  337. package/kits/rules/06-channel.md +59 -0
  338. package/kits/schemas/_meta.json +32 -0
  339. package/kits/schemas/agent-config.schema.1.json +177 -0
  340. package/kits/schemas/agent-config.schema.2.json +239 -0
  341. package/kits/schemas/agent-config.schema.3.json +119 -0
  342. package/kits/schemas/agent-config.schema.4.json +208 -0
  343. package/kits/schemas/agent-config.schema.5.json +326 -0
  344. package/kits/schemas/agent-config.schema.6.json +322 -0
  345. package/kits/schemas/contact-book.schema.1.json +36 -0
  346. package/kits/schemas/contact-book.schema.2.json +43 -0
  347. package/kits/schemas/daemon.schema.1.json +90 -0
  348. package/kits/schemas/defaults.schema.1.json +81 -0
  349. package/kits/schemas/menu-exec-schema-commands.md +208 -0
  350. package/kits/schemas/migrations/README.md +28 -0
  351. package/kits/schemas/relation-config.schema.1.json +158 -0
  352. package/kits/schemas/relation-config.schema.2.json +73 -0
  353. package/kits/schemas/relation-config.schema.3.json +50 -0
  354. package/kits/schemas/relation-config.schema.4.json +47 -0
  355. package/kits/schemas/relation-config.schema.5.json +47 -0
  356. package/kits/schemas/role-config.schema.1.json +201 -0
  357. package/kits/schemas/role-registry.schema.1.json +35 -0
  358. package/kits/schemas/single-session.schema.1.json +31 -0
  359. package/kits/templates/bootstrap-welcome.md +15 -0
  360. package/kits/templates/message-fragments/handoff-request-to-target.md +13 -0
  361. package/kits/templates/message-fragments/handoff-response-to-origin.md +10 -0
  362. package/kits/templates/message-fragments/inject-default.md +2 -0
  363. package/kits/templates/message-fragments/item.md +2 -0
  364. package/kits/templates/roles/admin.json +9 -0
  365. package/kits/templates/roles/member.json +41 -0
  366. package/kits/templates/roles/owner.json +9 -0
  367. package/kits/templates/roles/visitor.json +40 -0
  368. package/kits/templates/system-fragments/baseagent.md +14 -0
  369. package/kits/templates/system-fragments/bootstrap.md +16 -0
  370. package/kits/templates/system-fragments/channel.md +48 -0
  371. package/kits/templates/system-fragments/commands.md +28 -0
  372. package/kits/templates/system-fragments/identity.md +11 -0
  373. package/kits/templates/system-fragments/relation.md +19 -0
  374. package/kits/templates/system-fragments/session.md +53 -0
  375. package/kits/templates/system-fragments/venue.md +31 -0
  376. package/package.json +50 -15
  377. package/dist/index.d.ts +0 -7
  378. package/dist/index.d.ts.map +0 -1
  379. package/dist/index.js.map +0 -1
@@ -0,0 +1,76 @@
1
+ /**
2
+ * 消息处理工具函数
3
+ *
4
+ * 从 message-processor.ts 提取的独立工具函数,供 ResponseEngine 和其他模块使用。
5
+ */
6
+ import { renderCommandCardAsText, renderActionAsText } from '../interaction-router.js';
7
+ /**
8
+ * 构造出站消息信封
9
+ */
10
+ export function buildEnvelope(opts) {
11
+ const taskId = opts.taskId ?? `interaction-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
12
+ return {
13
+ taskId,
14
+ operationId: opts.operationId ?? taskId,
15
+ sessionId: opts.sessionId,
16
+ channel: opts.channel,
17
+ channelId: opts.channelId,
18
+ agentName: opts.agentName ?? '<unknown>',
19
+ chatmode: opts.chatmode ?? 'interactive',
20
+ replyContext: opts.replyContext,
21
+ causation: opts.causation,
22
+ timestamp: opts.timestamp ?? Date.now(),
23
+ };
24
+ }
25
+ /**
26
+ * 交互请求的默认回退文本
27
+ * 当调用方未显式提供时使用,根据交互类型选择合适的渲染器。
28
+ */
29
+ export function defaultFallbackText(interaction) {
30
+ const kind = interaction.kind;
31
+ if (kind.kind === 'command-card') {
32
+ return renderCommandCardAsText(kind);
33
+ }
34
+ if (kind.kind === 'action') {
35
+ try {
36
+ return renderActionAsText(interaction);
37
+ }
38
+ catch {
39
+ // ActionInteraction without fallback metadata — produce a minimal hint
40
+ const action = kind;
41
+ const lines = [action.title];
42
+ if (action.body)
43
+ lines.push(action.body);
44
+ return lines.join('\n');
45
+ }
46
+ }
47
+ return '';
48
+ }
49
+ /**
50
+ * 通过统一的 adapter.send 入口发送交互负载
51
+ *
52
+ * 通过 adapter.send(envelope, { kind: 'interaction', ... }) 发送交互。
53
+ * 成功返回 'sent',失败返回 false。
54
+ */
55
+ export async function sendInteractionPayload(adapter, envelope, interaction, fallbackText, replyCtx) {
56
+ const text = fallbackText ?? defaultFallbackText(interaction);
57
+ const payload = {
58
+ kind: 'interaction',
59
+ interaction,
60
+ fallbackText: text || undefined,
61
+ };
62
+ try {
63
+ const enriched = replyCtx
64
+ ? { ...envelope, replyContext: replyCtx }
65
+ : envelope;
66
+ const receipt = await adapter.send(enriched, payload);
67
+ if (receipt?.status === 'suppressed')
68
+ return false;
69
+ if (receipt?.status === 'sent')
70
+ return receipt.messages[0]?.messageId || false;
71
+ return 'sent';
72
+ }
73
+ catch {
74
+ return false;
75
+ }
76
+ }
@@ -0,0 +1,105 @@
1
+ import { loadSchema } from '../../config/schema-registry.js';
2
+ import { resolveEffective } from '../../config/config-manager.js';
3
+ import { resolveRuntimeStringField } from '../role/runtime-policy.js';
4
+ /** Resolve the effective chat mode from the ConfigManager layering context. */
5
+ export function resolveChatMode(params) {
6
+ let configured;
7
+ try {
8
+ configured = resolveEffective({
9
+ self: params.self,
10
+ peerKey: params.peerKey,
11
+ }, { cache: true }).chatmode;
12
+ }
13
+ catch {
14
+ configured = undefined;
15
+ }
16
+ const kind = normalizePeerType(params.peerType);
17
+ if (kind === 'system' || kind === 'service')
18
+ return 'interactive';
19
+ const field = chatmodeFieldForPeer(params.chatType, params.peerType);
20
+ const decision = resolveRuntimeStringField({
21
+ selfAid: params.self,
22
+ role: params.role,
23
+ field: `chatmode.${field}`,
24
+ configuredValue: configured?.[field],
25
+ });
26
+ const effectiveValue = decision.effectiveValue;
27
+ return effectiveValue === 'interactive' || effectiveValue === 'proactive'
28
+ ? effectiveValue
29
+ : chatmodeFactoryDefaults()[field];
30
+ }
31
+ export function resolveChatModeForField(params) {
32
+ return resolveChatMode({
33
+ ...params,
34
+ chatType: params.field === 'group' ? 'group' : 'private',
35
+ peerType: params.field === 'nothuman' ? 'agent' : 'human',
36
+ });
37
+ }
38
+ export function normalizePeerType(value) {
39
+ if (typeof value !== 'string')
40
+ return undefined;
41
+ const raw = value.trim();
42
+ if (!raw)
43
+ return undefined;
44
+ const key = raw.toLowerCase();
45
+ if (key === 'human' || key === 'person' || key === 'user')
46
+ return 'human';
47
+ if (key === 'group' || key === 'room' || key === 'venue')
48
+ return 'group';
49
+ if (key === 'system' || key === 'trigger' || key === 'scheduler')
50
+ return 'system';
51
+ if (key === 'service' || key === 'daemon' || key === 'tool')
52
+ return 'service';
53
+ if (key === 'unknown')
54
+ return 'unknown';
55
+ return 'agent';
56
+ }
57
+ export function isSystemOrServicePeer(peerType) {
58
+ const kind = normalizePeerType(peerType);
59
+ return kind === 'system' || kind === 'service';
60
+ }
61
+ /**
62
+ * 解析某会话对端的 chatMode。优先级(高→低):
63
+ * 1. 运行时硬约束:system/service 对端始终 interactive(非配置项)
64
+ * 2. 合并后的 chatmode 场景表 `configured`(chatmode.{private|group|nothuman})——
65
+ * 关系级与 agent 级同名字典,已由 ConfigManager 按 x-merge:dict 逐键合并
66
+ * 3. schema 出厂默认表 `chatmodeFactoryDefaults()`
67
+ *
68
+ * chatmode 是顶层字典参数(agent 级与关系级形态相同),实际生效值由对端类型选键。
69
+ * 详见 config-reference.md §三。
70
+ */
71
+ export function resolveChatModeForPeer(params) {
72
+ const kind = normalizePeerType(params.peerType);
73
+ // 运行时硬约束(非配置项):system/service 对端始终同步交互
74
+ if (kind === 'system' || kind === 'service')
75
+ return 'interactive';
76
+ // 合并后的场景表 → 出厂默认表
77
+ const field = chatmodeFieldForPeer(params.chatType, params.peerType);
78
+ return params.configured?.[field] ?? chatmodeFactoryDefaults()[field];
79
+ }
80
+ let _factoryChatmode = null;
81
+ /**
82
+ * chatMode 出厂默认表 —— 唯一来源是 agent-config schema 的 chatmode.default
83
+ * (配置数据,非代码分支)。agent 级配置改默认表、关系级按键覆盖,均经
84
+ * ConfigManager 合并后以 `configured` 传入;此表仅在配置链完全未设值时兜底。
85
+ */
86
+ export function chatmodeFactoryDefaults() {
87
+ if (!_factoryChatmode) {
88
+ const d = loadSchema('agent-config').fields.get('chatmode')?.default;
89
+ if (!d?.private || !d?.group || !d?.nothuman) {
90
+ throw new Error('[peer-mode] agent-config schema 缺少 chatmode 出厂默认表(default.private/group/nothuman)');
91
+ }
92
+ _factoryChatmode = d;
93
+ }
94
+ return _factoryChatmode;
95
+ }
96
+ export function chatmodeFieldForPeer(chatType, peerType) {
97
+ const kind = normalizePeerType(peerType);
98
+ if (kind === 'system' || kind === 'service')
99
+ return 'private';
100
+ if (chatType === 'group' || kind === 'group')
101
+ return 'group';
102
+ if (kind === 'agent' || kind === 'unknown')
103
+ return 'nothuman';
104
+ return 'private';
105
+ }
@@ -0,0 +1,232 @@
1
+ // 观察者插话:待用提示(pending-hints)存储。
2
+ //
3
+ // owner 经 observer.inject 给「agent↔对端」会话预埋的提示,落盘为 append-only jsonl,
4
+ // 在下一条对端消息到达、渲染该轮 prompt 时一次性消费、注入渲染层。
5
+ // 详见 docs/observer-insert-design.md 第一部分(§1.3 文件生命周期 / §1.4 thread 作用域)。
6
+ //
7
+ // 文件:sessions/<channelType>/<selfAID>/<对端>/pending-hints.jsonl(与 messages.jsonl 同级)
8
+ // 每行一个事件:
9
+ // { action:'add', id, text, threadId, ownerAid, ts }
10
+ // { action:'remove', targetId?, threadId, ts } // 无 targetId = 撤该 thread 全部
11
+ //
12
+ // 生命周期 = 一个消费周期(按 (对端,thread) 维度):
13
+ // - add/remove 追加行(append-only,处理「加了又撤」的竞态:按时间序回放抵消)
14
+ // - consume(对端消息到达触发):回放算「该 thread」有效集 → 返回 → 清掉该 thread 的事件。
15
+ // · 若文件里其它 thread 仍有未消费提示 → 重写文件只留它们(不误删别的 thread)。
16
+ // · 否则(无其它 thread 残留)→ 删整个文件。
17
+ // - 因为 consume 一次性用掉该 thread 的全部有效提示,消费后该 thread 有效集必然归零,
18
+ // 未来状态不依赖消费前历史,故消费即清安全,无需 consume 事件行。
19
+ // - 任何让「整文件」有效集归零的操作都删文件:consume 后无残留即删;remove 把提示全撤光也删。
20
+ import fs from 'fs';
21
+ import path from 'path';
22
+ import { chatDirPath, appendJsonl, readAllJsonlLines } from '../session/session-fs-store.js';
23
+ import { logger } from '../../utils/logger.js';
24
+ const PENDING_HINTS_FILE = 'pending-hints.jsonl';
25
+ function hintsPath(sessionsDir, channelType, channelId, selfAID) {
26
+ return path.join(chatDirPath(sessionsDir, channelType, channelId, selfAID), PENDING_HINTS_FILE);
27
+ }
28
+ /** 归一 threadId:undefined/null → ''(主线程)。 */
29
+ function normThread(threadId) {
30
+ return threadId || '';
31
+ }
32
+ /**
33
+ * 追加一条 add 事件。返回是否写盘成功(供 ack 判定)。
34
+ * 写盘成功后才回 ack(accepted)——accepted 真正代表"已持久保存"。
35
+ */
36
+ export function appendHintAdd(sessionsDir, channelType, channelId, selfAID, hint) {
37
+ try {
38
+ const fp = hintsPath(sessionsDir, channelType, channelId, selfAID);
39
+ fs.mkdirSync(path.dirname(fp), { recursive: true });
40
+ const ev = {
41
+ action: 'add', id: hint.id, text: hint.text,
42
+ threadId: normThread(hint.threadId), ownerAid: hint.ownerAid, ts: hint.ts,
43
+ };
44
+ appendJsonl(fp, ev);
45
+ return true;
46
+ }
47
+ catch (e) {
48
+ logger.warn(`[PendingHints] appendHintAdd failed: ${e instanceof Error ? e.message : String(e)}`);
49
+ return false;
50
+ }
51
+ }
52
+ /**
53
+ * 追加一条 remove 事件。若该操作使 (对端,thread) 有效集归零,则删除整个文件。
54
+ * 返回是否写盘成功(供 ack 判定)。
55
+ */
56
+ export function appendHintRemove(sessionsDir, channelType, channelId, selfAID, rm) {
57
+ try {
58
+ const fp = hintsPath(sessionsDir, channelType, channelId, selfAID);
59
+ if (!fs.existsSync(fp))
60
+ return true; // 无文件 = 无可撤,幂等成功
61
+ fs.mkdirSync(path.dirname(fp), { recursive: true });
62
+ const ev = {
63
+ action: 'remove', threadId: normThread(rm.threadId), ts: rm.ts,
64
+ ...(rm.targetId ? { targetId: rm.targetId } : {}),
65
+ };
66
+ appendJsonl(fp, ev);
67
+ // 撤销后:若全部 thread 的有效集都归零,删文件(不堆死文件)。
68
+ if (!hasAnyEffective(fp))
69
+ deleteFile(fp);
70
+ return true;
71
+ }
72
+ catch (e) {
73
+ logger.warn(`[PendingHints] appendHintRemove failed: ${e instanceof Error ? e.message : String(e)}`);
74
+ return false;
75
+ }
76
+ }
77
+ /** 回放整个文件,返回是否还存在任意 thread 的有效提示。 */
78
+ function hasAnyEffective(fp) {
79
+ const events = readAllJsonlLines(fp);
80
+ // 按 thread 分组回放
81
+ const byThread = new Map();
82
+ for (const ev of events) {
83
+ const t = normThread(ev.threadId);
84
+ (byThread.get(t) ?? byThread.set(t, []).get(t)).push(ev);
85
+ }
86
+ for (const [, evs] of byThread) {
87
+ if (replayEffective(evs).length > 0)
88
+ return true;
89
+ }
90
+ return false;
91
+ }
92
+ /** 对单个 thread 的事件序列回放,算出有效提示集(已 add、未被 remove,按 ts 升序)。 */
93
+ function replayEffective(events) {
94
+ const sorted = events.slice().sort((a, b) => a.ts - b.ts);
95
+ const active = new Map(); // id → hint,保插入序
96
+ for (const ev of sorted) {
97
+ if (ev.action === 'add') {
98
+ active.set(ev.id, { id: ev.id, text: ev.text, ownerAid: ev.ownerAid, ts: ev.ts });
99
+ }
100
+ else {
101
+ if (ev.targetId)
102
+ active.delete(ev.targetId);
103
+ else
104
+ active.clear(); // 无 targetId = 撤该 thread 全部
105
+ }
106
+ }
107
+ return [...active.values()].sort((a, b) => a.ts - b.ts);
108
+ }
109
+ /**
110
+ * 消费 (对端, thread) 的有效提示:回放算「该 thread」有效集 → 返回 → 清掉该 thread。
111
+ *
112
+ * thread 隔离:只消费传入 threadId(归一后)的提示。若文件里其它 thread 仍有未消费提示,
113
+ * 重写文件保留它们;只有当整文件再无任何有效提示时才删除文件。
114
+ * 返回空数组表示该 thread 无有效提示(调用方据此决定是否注入)。
115
+ */
116
+ export function consumeHints(sessionsDir, channelType, channelId, selfAID, threadId) {
117
+ const fp = hintsPath(sessionsDir, channelType, channelId, selfAID);
118
+ if (!fs.existsSync(fp))
119
+ return [];
120
+ let all;
121
+ try {
122
+ all = readAllJsonlLines(fp);
123
+ }
124
+ catch (e) {
125
+ logger.warn(`[PendingHints] consume read failed: ${e instanceof Error ? e.message : String(e)}`);
126
+ return [];
127
+ }
128
+ const wantThread = normThread(threadId);
129
+ const sameThread = all.filter(ev => normThread(ev.threadId) === wantThread);
130
+ const effective = replayEffective(sameThread);
131
+ // 其它 thread 仍有未消费提示?若有,重写文件只留它们;否则删整个文件。
132
+ const otherThreadEvents = all.filter(ev => normThread(ev.threadId) !== wantThread);
133
+ if (otherThreadEvents.length > 0 && hasEffectiveInEvents(otherThreadEvents)) {
134
+ rewriteFile(fp, otherThreadEvents);
135
+ }
136
+ else {
137
+ deleteFile(fp);
138
+ }
139
+ return effective;
140
+ }
141
+ /** events(可能跨多 thread)中是否存在任意有效提示。 */
142
+ function hasEffectiveInEvents(events) {
143
+ const byThread = new Map();
144
+ for (const ev of events) {
145
+ const t = normThread(ev.threadId);
146
+ (byThread.get(t) ?? byThread.set(t, []).get(t)).push(ev);
147
+ }
148
+ for (const [, evs] of byThread) {
149
+ if (replayEffective(evs).length > 0)
150
+ return true;
151
+ }
152
+ return false;
153
+ }
154
+ function rewriteFile(fp, events) {
155
+ try {
156
+ const body = events.map(e => JSON.stringify(e)).join('\n') + '\n';
157
+ fs.writeFileSync(fp, body);
158
+ }
159
+ catch (e) {
160
+ logger.warn(`[PendingHints] rewriteFile failed: ${e instanceof Error ? e.message : String(e)}`);
161
+ }
162
+ }
163
+ function deleteFile(fp) {
164
+ try {
165
+ if (fs.existsSync(fp))
166
+ fs.unlinkSync(fp);
167
+ }
168
+ catch (e) {
169
+ logger.warn(`[PendingHints] deleteFile failed: ${e instanceof Error ? e.message : String(e)}`);
170
+ }
171
+ }
172
+ /** 仅供 watch / 调试:读出当前 (对端,thread) 有效提示,不消费、不删文件。 */
173
+ export function peekHints(sessionsDir, channelType, channelId, selfAID, threadId) {
174
+ const fp = hintsPath(sessionsDir, channelType, channelId, selfAID);
175
+ if (!fs.existsSync(fp))
176
+ return [];
177
+ try {
178
+ const all = readAllJsonlLines(fp);
179
+ const wantThread = normThread(threadId);
180
+ return replayEffective(all.filter(ev => normThread(ev.threadId) === wantThread));
181
+ }
182
+ catch {
183
+ return [];
184
+ }
185
+ }
186
+ // ── 渲染接线纯函数(无 IO,便于单测) ──────────────────────────
187
+ /** 把有效提示转成 owner-hint SubMessage(排在对端真实 item 之前,走 inject 渲染模式)。 */
188
+ export function hintsToSubMessages(hints) {
189
+ return hints.map(h => ({
190
+ kind: 'owner-hint',
191
+ content: h.text,
192
+ ownerAid: h.ownerAid,
193
+ injectTime: h.ts,
194
+ timestamp: h.ts,
195
+ }));
196
+ }
197
+ /**
198
+ * 渲染失败兜底:把已消费的 owner-hint(提示已从 pending 删除、不可恢复)以纯文本前缀
199
+ * 拼到对端原文之前,避免提示被静默丢弃。仅在 renderMessageBody 抛错或产出空时使用。
200
+ */
201
+ export function composeHintFallback(hintItems, content) {
202
+ if (!hintItems || hintItems.length === 0)
203
+ return content;
204
+ const lines = hintItems.map(h => `‹owner 提示·已验证›(仅你可见,对端无感)\n${h.content}`);
205
+ return [...lines, content].join('\n\n');
206
+ }
207
+ /**
208
+ * 解析 observer.inject payload:鉴权(from∈owners)+ 校验(add 需 channel_id+text;remove 需 channel_id)
209
+ * + 归一字段。纯函数,无副作用——落盘 / ack / watch 由调用方按结果执行。
210
+ * @param ts 用于 add 缺省 id(`inj-<ts>`);由调用方传入便于测试确定性。
211
+ */
212
+ export function parseInjectRequest(payload, fromAid, owners, ts) {
213
+ const p = (payload && typeof payload === 'object') ? payload : {};
214
+ const injectId = typeof p.id === 'string' ? p.id : undefined;
215
+ const action = p.action === 'remove' ? 'remove' : 'add';
216
+ if (!owners.includes(fromAid)) {
217
+ return { kind: 'reject', code: 'NOT_OWNER', message: '仅 owner 可插话', action, injectId };
218
+ }
219
+ const target = (p.target && typeof p.target === 'object') ? p.target : undefined;
220
+ const channelId = target && typeof target.channel_id === 'string' ? target.channel_id : undefined;
221
+ const text = typeof p.text === 'string' ? p.text : '';
222
+ if (!channelId || (action === 'add' && !text.trim())) {
223
+ return { kind: 'reject', code: 'INVALID_TARGET', message: 'target.channel_id 必填;add 还需 text', action, injectId };
224
+ }
225
+ const chatType = target?.chat_type === 'group' ? 'group' : 'private';
226
+ const threadId = typeof target?.thread_id === 'string' ? target.thread_id : undefined;
227
+ const targetId = typeof p.target_id === 'string' ? p.target_id : undefined;
228
+ if (action === 'remove') {
229
+ return { kind: 'remove', injectId, channelId, chatType, threadId, targetId };
230
+ }
231
+ return { kind: 'add', injectId, id: injectId || `inj-${ts}`, text, channelId, chatType, threadId, ownerAid: fromAid };
232
+ }
@@ -0,0 +1,33 @@
1
+ import crypto from 'crypto';
2
+ export function computeTopicHash(content) {
3
+ const normalized = (content || '').trim().slice(0, 20);
4
+ return crypto.createHash('sha1').update(normalized).digest('hex').slice(0, 8);
5
+ }
6
+ export function resolveResponseDepth(input) {
7
+ const content = input.content || '';
8
+ const topicHash = computeTopicHash(content);
9
+ const previousRounds = input.topicRounds || 0;
10
+ const topicRounds = input.lastTopicHash === topicHash ? previousRounds + 1 : 1;
11
+ const isMentioned = !!input.selfAid && Array.isArray(input.mentionAids) && input.mentionAids.includes(input.selfAid);
12
+ if (input.chatType !== 'group') {
13
+ return { depth: 'standard', topicHash, topicRounds, isMentioned };
14
+ }
15
+ if (topicRounds >= 3) {
16
+ return { depth: 'deep', topicHash, topicRounds, isMentioned };
17
+ }
18
+ if (isMentioned) {
19
+ return { depth: 'standard', topicHash, topicRounds, isMentioned };
20
+ }
21
+ if (input.mentionMode === 'disabled' && isShortNonQuestion(content)) {
22
+ return { depth: 'lightweight', topicHash, topicRounds, isMentioned };
23
+ }
24
+ return { depth: 'standard', topicHash, topicRounds, isMentioned };
25
+ }
26
+ function isShortNonQuestion(content) {
27
+ const text = (content || '').trim();
28
+ if (text.length > 30)
29
+ return false;
30
+ if (/[??]$/.test(text))
31
+ return false;
32
+ return !/^(怎么|如何|为什么|为何|哪|谁|什么|是否|能否|可否|how\b|why\b|what\b|when\b|where\b|who\b|which\b|can\b|could\b|should\b|would\b|is\b|are\b|do\b|does\b|did\b)/i.test(text);
33
+ }