@xdxer/dingtalk-agent 0.1.4 → 0.1.5-beta.10

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 (186) hide show
  1. package/CHANGELOG.md +232 -0
  2. package/README.en.md +115 -89
  3. package/README.md +111 -86
  4. package/dist/bin/dingtalk-agent.js +742 -152
  5. package/dist/bin/dingtalk-agent.js.map +1 -1
  6. package/dist/src/actions.js +3 -2
  7. package/dist/src/actions.js.map +1 -1
  8. package/dist/src/agent-audit.js +202 -85
  9. package/dist/src/agent-audit.js.map +1 -1
  10. package/dist/src/agent-definition.js +7 -3
  11. package/dist/src/agent-definition.js.map +1 -1
  12. package/dist/src/agent-enhance.js +51 -32
  13. package/dist/src/agent-enhance.js.map +1 -1
  14. package/dist/src/agent-platform.js +4 -4
  15. package/dist/src/agent-platform.js.map +1 -1
  16. package/dist/src/bootstrap.js +6 -2
  17. package/dist/src/bootstrap.js.map +1 -1
  18. package/dist/src/development-workspace.js +210 -34
  19. package/dist/src/development-workspace.js.map +1 -1
  20. package/dist/src/doctor.js +65 -9
  21. package/dist/src/doctor.js.map +1 -1
  22. package/dist/src/dws.js +67 -3
  23. package/dist/src/dws.js.map +1 -1
  24. package/dist/src/init.js +2 -1
  25. package/dist/src/init.js.map +1 -1
  26. package/dist/src/memory/noop-receipt.js +306 -0
  27. package/dist/src/memory/noop-receipt.js.map +1 -0
  28. package/dist/src/memory/operational.js +27 -3
  29. package/dist/src/memory/operational.js.map +1 -1
  30. package/dist/src/memory/remote-state.js +2 -1
  31. package/dist/src/memory/remote-state.js.map +1 -1
  32. package/dist/src/multica-deploy.js +692 -125
  33. package/dist/src/multica-deploy.js.map +1 -1
  34. package/dist/src/multica-provider.js +303 -25
  35. package/dist/src/multica-provider.js.map +1 -1
  36. package/dist/src/multica-runtime-vocabulary.js +110 -0
  37. package/dist/src/multica-runtime-vocabulary.js.map +1 -0
  38. package/dist/src/opencode-evals.js +6 -6
  39. package/dist/src/opencode-evals.js.map +1 -1
  40. package/dist/src/opencode-provider.js +21 -7
  41. package/dist/src/opencode-provider.js.map +1 -1
  42. package/dist/src/opencode-workspace.js +3 -3
  43. package/dist/src/opencode-workspace.js.map +1 -1
  44. package/dist/src/personal-event-evals.js +4 -2
  45. package/dist/src/personal-event-evals.js.map +1 -1
  46. package/dist/src/promotion.js +2 -1
  47. package/dist/src/promotion.js.map +1 -1
  48. package/dist/src/remote-semantic-state-live-evals.js +14 -8
  49. package/dist/src/remote-semantic-state-live-evals.js.map +1 -1
  50. package/dist/src/remote-state-evals.js +2 -2
  51. package/dist/src/remote-state-evals.js.map +1 -1
  52. package/dist/src/robot-evals.js +3 -3
  53. package/dist/src/robot-evals.js.map +1 -1
  54. package/dist/src/schedule-plan.js +380 -0
  55. package/dist/src/schedule-plan.js.map +1 -0
  56. package/dist/src/sessions.js +1 -1
  57. package/dist/src/sessions.js.map +1 -1
  58. package/dist/src/skill-manager.js +145 -13
  59. package/dist/src/skill-manager.js.map +1 -1
  60. package/dist/src/skills.js +2 -0
  61. package/dist/src/skills.js.map +1 -1
  62. package/dist/src/tui.js +369 -0
  63. package/dist/src/tui.js.map +1 -0
  64. package/dist/src/upgrade.js +113 -33
  65. package/dist/src/upgrade.js.map +1 -1
  66. package/dist/src/waits.js +2 -1
  67. package/dist/src/waits.js.map +1 -1
  68. package/dist/src/workspace.js +12 -7
  69. package/dist/src/workspace.js.map +1 -1
  70. package/docs/AGENT-IN-PRODUCTION.md +255 -0
  71. package/docs/ARCHITECTURE.md +366 -0
  72. package/docs/INSTALLATION.md +8 -8
  73. package/docs/PLATFORM-GUARDRAILS.md +188 -0
  74. package/docs/PRIOR-ART.md +126 -0
  75. package/docs/SELF-TEST.md +182 -0
  76. package/docs/architecture/agent-platform-connection-layer.svg +120 -0
  77. package/docs/architecture/digital-employee-composition.svg +92 -0
  78. package/docs/architecture/dingtalk-agent-architecture.svg +125 -0
  79. package/docs/assets/digital-employee-at-work.svg +77 -0
  80. package/docs/schemas/multica-deployment-plan.schema.json +3 -1
  81. package/docs/schemas/multica-deployment-receipt.schema.json +17 -3
  82. package/docs/schemas/multica-deployment-status.schema.json +6 -2
  83. package/docs/schemas/multica-workspace-inspection.schema.json +16 -0
  84. package/docs/schemas/multica-workspace-run-plan.schema.json +31 -0
  85. package/docs/schemas/multica-workspace-run.schema.json +161 -0
  86. package/docs/schemas/multica-workspace-status.schema.json +2 -0
  87. package/docs/schemas/project.schema.json +54 -3
  88. package/docs/schemas/workspace-scaffold.schema.json +38 -0
  89. package/examples/agents/README.md +45 -0
  90. package/examples/agents/fde-coach/AGENTS.md +2 -25
  91. package/examples/agents/fde-coach/agent/AGENTS.md +35 -0
  92. package/examples/agents/fde-coach/agent.bindings.json +10 -0
  93. package/examples/agents/release-manager/AGENTS.md +2 -25
  94. package/examples/agents/release-manager/agent/AGENTS.md +35 -0
  95. package/examples/agents/release-manager/agent.bindings.json +10 -0
  96. package/lab/agent-eval/catalog.json +5 -5
  97. package/lab/agent-eval/classic-failures.json +4 -4
  98. package/lab/agent-eval/completion-gate-regression.json +9 -9
  99. package/lab/agent-eval/personal-event-live.example.json +3 -3
  100. package/lab/agent-eval/remote-semantic-state-live.example.json +1 -1
  101. package/lab/agent-eval/workspace/opencode.json +2 -2
  102. package/lab/project-workspace/fake-multica-provider.mjs +171 -17
  103. package/lab/project-workspace/multica-deploy.fixture.json +2 -2
  104. package/lab/project-workspace/multica-readonly.fixture.json +4 -16
  105. package/lab/project-workspace/opencode-provider-suite.json +3 -3
  106. package/lab/project-workspace/project.fixture.json +2 -6
  107. package/lab/robot-eval/suite.json +1 -1
  108. package/lab/robot-eval/workspace/AGENTS.md +1 -1
  109. package/lab/robot-eval/workspace/opencode.json +2 -2
  110. package/lab/schemas/personal-event-eval.schema.json +1 -1
  111. package/package.json +18 -11
  112. package/skills/README.md +10 -8
  113. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/SKILL.md +49 -24
  114. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/AGENTS.template.md +1 -1
  115. package/skills/core/dta-agent-compose/assets/REPOSITORY.template.md +10 -0
  116. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/agent.bindings.dingtalk-doc.template.json +2 -2
  117. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/agent.bindings.local.template.json +2 -2
  118. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/hosts/opencode/opencode.template.json +3 -2
  119. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/evals/evals.json +4 -4
  120. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/agent-definition-contract.md +7 -7
  121. package/skills/core/dta-agent-compose/references/drive-and-schedules.md +166 -0
  122. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/host-loading-contract.md +11 -13
  123. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/hosts/claude-code.md +13 -12
  124. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/hosts/opencode.md +14 -13
  125. package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/SKILL.md +28 -3
  126. package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/assets/eval-catalog.template.json +1 -1
  127. package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/evals/evals.json +1 -1
  128. package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/eval-topology.md +3 -3
  129. package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/interactive-debug-channels.md +10 -4
  130. package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/SKILL.md +21 -5
  131. package/skills/core/dta-basic-behavior/references/event-to-behavior.md +38 -0
  132. package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/memory-and-evolution.md +3 -1
  133. package/skills/core/dta-basic-behavior/references/perception-and-gates.md +87 -0
  134. package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/risk-authority-and-privacy.md +12 -0
  135. package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/truth-and-recovery.md +4 -2
  136. package/skills/core/dta-people-group-memory/COMPLETENESS.md +36 -0
  137. package/skills/core/dta-people-group-memory/SKILL.md +69 -0
  138. package/skills/core/dta-people-group-memory/references/adapters.md +273 -0
  139. package/skills/core/dta-people-group-memory/references/assembly-guidance.md +40 -0
  140. package/skills/core/dta-people-group-memory/references/binding.md +110 -0
  141. package/skills/core/dta-people-group-memory/references/cold-start.md +70 -0
  142. package/skills/core/dta-people-group-memory/references/config-binding.md +89 -0
  143. package/skills/core/dta-people-group-memory/references/consent-and-visibility.md +83 -0
  144. package/skills/core/dta-people-group-memory/references/consolidation.md +162 -0
  145. package/skills/core/dta-people-group-memory/references/event-ingest.md +103 -0
  146. package/skills/core/dta-people-group-memory/references/guided-setup.md +70 -0
  147. package/skills/core/dta-people-group-memory/references/model.md +148 -0
  148. package/skills/core/dta-people-group-memory/references/storage-port.md +107 -0
  149. package/skills/platforms/deap/PLATFORM.md +30 -1
  150. package/skills/platforms/multica-dingtalk/PLATFORM.md +35 -9
  151. package/skills/platforms/multica-dingtalk/{dingtalk-agent-deploy-multica → dta-deploy-multica}/SKILL.md +10 -8
  152. package/skills/platforms/multica-dingtalk/dta-deploy-multica/references/multica-deployment-contract.md +67 -0
  153. package/skills/platforms/multica-dingtalk/{multica-external → dta-ops-multica}/SKILL.md +81 -11
  154. package/skills/platforms/multica-dingtalk/{multica-external → dta-ops-multica}/scripts/bootstrap.sh +2 -2
  155. package/skills/platforms/multica-dingtalk/{multica-external → dta-ops-multica}/scripts/multica_ext.py +264 -16
  156. package/dist/src/map.js +0 -157
  157. package/dist/src/map.js.map +0 -1
  158. package/docs/SECOND-AGENT-ACCEPTANCE.md +0 -62
  159. package/docs/architecture/agent-memory-topology.png +0 -0
  160. package/docs/architecture/agent-memory-topology.svg +0 -132
  161. package/docs/architecture/dingtalk-agent-blueprint.png +0 -0
  162. package/docs/architecture/durable-async-agent-runtime.png +0 -0
  163. package/docs/architecture/general-agent-kernel-topology.png +0 -0
  164. package/docs/architecture/provider-bound-development-workspace.png +0 -0
  165. package/docs/architecture/task-completion-gate.png +0 -0
  166. package/docs/assets/agent-delivery-lifecycle.svg +0 -103
  167. package/skills/core/dingtalk-basic-behavior/references/event-to-behavior.md +0 -24
  168. package/skills/core/dingtalk-basic-behavior/references/perception-and-gates.md +0 -28
  169. package/skills/platforms/deap/README.md +0 -3
  170. package/skills/platforms/multica-dingtalk/dingtalk-agent-boot-multica/SKILL.md +0 -40
  171. package/skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica/references/multica-deployment-contract.md +0 -49
  172. /package/examples/agents/fde-coach/{skills → agent/skills}/fde-coach/SKILL.md +0 -0
  173. /package/examples/agents/release-manager/{skills → agent/skills}/release-manager/SKILL.md +0 -0
  174. /package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/role-skill.template.md +0 -0
  175. /package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/storage-routing.md +0 -0
  176. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/evidence-contract.md +0 -0
  177. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/failure-to-case.md +0 -0
  178. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/local-connector-smoke.md +0 -0
  179. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/scenario-taxonomy.md +0 -0
  180. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/storage-modes.md +0 -0
  181. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/assets/memory-candidate-proposal.json +0 -0
  182. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/assets/task-checkpoint.json +0 -0
  183. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/action-contract.md +0 -0
  184. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/runtime-modes.md +0 -0
  185. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/task-lifecycle.md +0 -0
  186. /package/skills/platforms/multica-dingtalk/{dingtalk-agent-deploy-multica → dta-deploy-multica}/references/promotion-observation-contract.md +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/init.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,gEAAgE;AAEhE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,KAAK,GAAG,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EACL,eAAe,EAAE,aAAa,GAC/B,MAAM,gBAAgB,CAAA;AAEvB,MAAM,GAAG,GAAG,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAE/C,MAAM,UAAU,IAAI,CAAC,IAAY,EAAE,UAAgC,EAAE;IACnE,MAAM,cAAc,GAAG,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAA;IACtD,MAAM,cAAc,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACrC,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IAEhD,kDAAkD;IAClD,8CAA8C;IAC9C,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAA;IACzE,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAA;IACnE,KAAK,MAAM,GAAG,IAAI;QAChB,0BAA0B,EAAE,6BAA6B;QACzD,uBAAuB,EAAE,uBAAuB;KACjD;QAAE,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAClD,IAAI,CAAC,cAAc;QAAE,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IAEhD,OAAO,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,0BAA0B;;aAE/E,SAAS,CAAC,SAAS;;aAEnB,SAAS,CAAC,MAAM,CAAC,MAAM,MAAM,SAAS,CAAC,MAAM,CAAC,SAAS;aACvD,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;;;;mBAIrB,CAAC,CAAA;IAClB,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,SAAS,WAAW,CAAC,IAAY,EAAE,EAAU;IAC3C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAM;IAC7B,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAA;AAC1E,CAAC","sourcesContent":["// init 只为“需要持久 Workspace / Prepared Run runtime”的目录建立最小骨架。\n// 普通 Claude Code/Codex Session 只需全局 Skill + bootstrap,不需要 init。\n\nimport { cpSync, existsSync, mkdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport * as cfg from './config.js'\nimport { resolvePackageRoot } from './package-root.js'\nimport {\n ensureWorkspace, workspacePath, type WorkspaceInitOptions,\n} from './workspace.js'\n\nconst PKG = resolvePackageRoot(import.meta.url)\n\nexport function init(root: string, options: WorkspaceInitOptions = {}) {\n const wasInitialized = existsSync(workspacePath(root))\n const existingConfig = cfg.load(root)\n const workspace = ensureWorkspace(root, options)\n\n // Runtime 的机器策略仍需本地存在;只补缺失项,不复制全局 Skill、Ontology,\n // 也不修改项目的 AGENTS.md / CLAUDE.md / .gitignore。\n copyMissing(join(PKG, 'templates', 'behaviors'), join(root, 'behaviors'))\n copyMissing(join(PKG, 'templates', 'fields'), join(root, 'fields'))\n for (const dir of [\n '.dingtalk-agent/sessions', '.dingtalk-agent/event-index',\n '.dingtalk-agent/waits', '.dingtalk-agent/cache',\n ]) mkdirSync(join(root, dir), { recursive: true })\n if (!existingConfig) cfg.save(root, cfg.DEFAULT)\n\n console.log(`${wasInitialized ? '✅ Workspace 已存在;检查完成,未重新初始化' : '✅ 已初始化最小 Agent Workspace'}\n\n Context: ${workspace.contextId}(未显式指定时由目录名稳定派生)\n 配置: .dingtalk-agent/workspace.json\n Storage: ${workspace.mounts.memory} / ${workspace.mounts.knowledge}\n Skill: ${workspace.skills.join(', ')}(按名称解析;不复制进当前项目)\n\n 会话水合: dingtalk-agent bootstrap\n 事件运行时: dingtalk-agent prepare --event-file <event.json>\n 环境检查: dta doctor`)\n return workspace\n}\n\nfunction copyMissing(from: string, to: string): void {\n if (!existsSync(from)) return\n cpSync(from, to, { recursive: true, force: false, errorOnExist: false })\n}\n"]}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/init.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,gEAAgE;AAEhE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,KAAK,GAAG,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EACL,eAAe,EAAE,aAAa,GAC/B,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAE9B,MAAM,GAAG,GAAG,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAE/C,MAAM,UAAU,IAAI,CAAC,IAAY,EAAE,UAAgC,EAAE;IACnE,MAAM,cAAc,GAAG,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAA;IACtD,MAAM,cAAc,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACrC,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IAEhD,kDAAkD;IAClD,8CAA8C;IAC9C,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAA;IACzE,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAA;IACnE,KAAK,MAAM,GAAG,IAAI;QAChB,0BAA0B,EAAE,6BAA6B;QACzD,uBAAuB,EAAE,uBAAuB;KACjD;QAAE,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAClD,IAAI,CAAC,cAAc;QAAE,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IAEhD,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,0BAA0B,CAAC;;aAEpG,SAAS,CAAC,SAAS;;aAEnB,SAAS,CAAC,MAAM,CAAC,MAAM,MAAM,SAAS,CAAC,MAAM,CAAC,SAAS;aACvD,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;;;;mBAIrB,CAAC,CAAA;IAClB,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,SAAS,WAAW,CAAC,IAAY,EAAE,EAAU;IAC3C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAM;IAC7B,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAA;AAC1E,CAAC","sourcesContent":["// init 只为“需要持久 Workspace / Prepared Run runtime”的目录建立最小骨架。\n// 普通 Claude Code/Codex Session 只需全局 Skill + bootstrap,不需要 init。\n\nimport { cpSync, existsSync, mkdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport * as cfg from './config.js'\nimport { resolvePackageRoot } from './package-root.js'\nimport {\n ensureWorkspace, workspacePath, type WorkspaceInitOptions,\n} from './workspace.js'\nimport { out } from './tui.js'\n\nconst PKG = resolvePackageRoot(import.meta.url)\n\nexport function init(root: string, options: WorkspaceInitOptions = {}) {\n const wasInitialized = existsSync(workspacePath(root))\n const existingConfig = cfg.load(root)\n const workspace = ensureWorkspace(root, options)\n\n // Runtime 的机器策略仍需本地存在;只补缺失项,不复制全局 Skill、Ontology,\n // 也不修改项目的 AGENTS.md / CLAUDE.md / .gitignore。\n copyMissing(join(PKG, 'templates', 'behaviors'), join(root, 'behaviors'))\n copyMissing(join(PKG, 'templates', 'fields'), join(root, 'fields'))\n for (const dir of [\n '.dingtalk-agent/sessions', '.dingtalk-agent/event-index',\n '.dingtalk-agent/waits', '.dingtalk-agent/cache',\n ]) mkdirSync(join(root, dir), { recursive: true })\n if (!existingConfig) cfg.save(root, cfg.DEFAULT)\n\n console.log(`${out().theme.success(wasInitialized ? '✅ Workspace 已存在;检查完成,未重新初始化' : '✅ 已初始化最小 Agent Workspace')}\n\n Context: ${workspace.contextId}(未显式指定时由目录名稳定派生)\n 配置: .dingtalk-agent/workspace.json\n Storage: ${workspace.mounts.memory} / ${workspace.mounts.knowledge}\n Skill: ${workspace.skills.join(', ')}(按名称解析;不复制进当前项目)\n\n 会话水合: dingtalk-agent bootstrap\n 事件运行时: dingtalk-agent prepare --event-file <event.json>\n 环境检查: dta doctor`)\n return workspace\n}\n\nfunction copyMissing(from: string, to: string): void {\n if (!existsSync(from)) return\n cpSync(from, to, { recursive: true, force: false, errorOnExist: false })\n}\n"]}
@@ -0,0 +1,306 @@
1
+ import { existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join, relative, resolve, sep } from 'node:path';
3
+ import { digest, stableStringify } from '../events.js';
4
+ import { acquireLease } from '../lease.js';
5
+ /**
6
+ * no-op / nothing-to-save Receipt(issue #25)。
7
+ *
8
+ * dta-basic-behavior 要求「判存步骤跑过、判了没什么可存,也要留一条痕迹」,但此前
9
+ * 没有定义写到哪、什么 schema、怎么回读——Agent 只能自行发明日志格式,运维侧依旧
10
+ * 分不清「跑了判空」和「压根没跑」。本模块把这条痕迹变成宿主状态里的类型化 Receipt:
11
+ *
12
+ * - **身份 = (step, scopeId, occurrence)**:occurrence 是这次判定挂靠的事件锚
13
+ * (Prepared Run 用 run:<runId>,Direct 模式由调用方显式给 eventId/心跳拍号)。
14
+ * 同一 occurrence 重放幂等返回既有 Receipt;内容不一致则响亮报冲突,不静默覆盖。
15
+ * - **脱敏红线**:reason 只收枚举,被判定过的内容只能以 sha256 digest 入档
16
+ * (consideredDigest),自由文本字段在校验层直接拒绝——痕迹文件不携带原文。
17
+ * - **回读即合同**:traceMemoryNoop 对 (scopeId, occurrence) 给出二值判定
18
+ * ran-empty / no-trace,这正是运维要区分的那两个状态。
19
+ *
20
+ * 信任边界(issue #42,说清楚不装伪):Receipt 里的 hash 是【无密钥完整性校验】,
21
+ * 不是宿主签名——任何能写 state 目录的调用方都能重算它。真实性边界 = 「state 目录
22
+ * 归宿主所有、Prepared Run 的沙箱写不进来」这一部署事实;本模块能保证的是
23
+ * fail-closed 的结构合同:结构不合法/身份对不上的文件绝不折成 ran-empty,
24
+ * Prepared issuer 只认 canonical Session/runs 树里 run↔session 身份互证的 run,
25
+ * 环境变量指向的任意目录冒充不了。需要密码学可验证签发时,走宿主密钥/MAC 或
26
+ * 控制面回执机制,不要把这里的 digest 说成 signature。
27
+ */
28
+ export const MEMORY_SAVE_DECISION_STEP = 'memory-save-decision';
29
+ export const MEMORY_NOOP_REASONS = [
30
+ 'no-durable-content',
31
+ 'below-confidence',
32
+ 'duplicate-of-existing',
33
+ 'out-of-scope',
34
+ 'ephemeral-only',
35
+ ];
36
+ const STEP_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
37
+ const DIGEST_PATTERN = /^[a-f0-9]{64}$/;
38
+ const RECEIPT_ID_PATTERN = /^nop_[a-f0-9]{24}$/;
39
+ export function recordMemoryNoop(root, value, options = {}) {
40
+ const claim = validateClaim(value);
41
+ const run = issuerContext(root, options.runPath, options.sessionPath, options.sessionRoot);
42
+ if (run && claim.scopeId !== run.contextId) {
43
+ throw new Error(`Memory no-op scopeId=${claim.scopeId} 与 Prepared Run contextId=${run.contextId} 不一致`);
44
+ }
45
+ // Prepared Run 的 occurrence 从受信 run 状态推导,不采纳正文声称的锚点;
46
+ // Direct 模式没有受信锚可推,必须由调用方显式给出,缺了就拒绝——
47
+ // 没有 occurrence 的痕迹回答不了「哪一拍判过」,等于没留。
48
+ const derived = run ? `run:${run.id}` : '';
49
+ if (run) {
50
+ if (claim.occurrence && claim.occurrence !== derived) {
51
+ throw new Error(`Memory no-op occurrence=${claim.occurrence} 与 Prepared Run 推导值 ${derived} 不一致`);
52
+ }
53
+ }
54
+ else if (!claim.occurrence) {
55
+ throw new Error('Direct 模式的 memory no-op 需要显式 occurrence(eventId / 心跳拍号等事件锚)');
56
+ }
57
+ const occurrence = run ? derived : String(claim.occurrence);
58
+ const id = `nop_${digest(stableStringify({
59
+ step: claim.step, scopeId: claim.scopeId, occurrence,
60
+ })).slice(0, 24)}`;
61
+ const path = join(receiptRoot(root, options.stateDir, Boolean(run)), `${id}.json`);
62
+ const release = acquireLease(`${path}.lock`, `Memory no-op Receipt ${id} 正在写入`, {
63
+ waitMs: 3_000, staleAfterMs: 2 * 60_000,
64
+ });
65
+ try {
66
+ if (existsSync(path)) {
67
+ const existing = readReceipt(path);
68
+ if (existing.reason !== claim.reason ||
69
+ existing.consideredDigest !== (claim.consideredDigest || '')) {
70
+ throw new Error(`同一 occurrence(${occurrence}) 已有内容不一致的 no-op 痕迹(${existing.id}):` +
71
+ '不静默覆盖,请先人工核对两次判定为何不同');
72
+ }
73
+ return { $schema: 'dingtalk-agent/memory-noop-result@1', duplicate: true, path,
74
+ receipt: existing };
75
+ }
76
+ const unsigned = {
77
+ $schema: 'dingtalk-agent/memory-noop-receipt@1',
78
+ id,
79
+ step: claim.step,
80
+ scopeId: claim.scopeId,
81
+ occurrence,
82
+ reason: claim.reason,
83
+ consideredDigest: claim.consideredDigest || '',
84
+ issuer: run ? {
85
+ mode: 'prepared', runId: run.id, eventId: run.eventId || '',
86
+ definitionHash: run.definition?.hash || '',
87
+ } : { mode: 'direct', runId: '', eventId: '', definitionHash: '' },
88
+ recordedAt: parseNow(options.now).toISOString(),
89
+ };
90
+ const receipt = { ...unsigned, hash: digest(stableStringify(unsigned)) };
91
+ writeJsonAtomic(path, receipt);
92
+ return { $schema: 'dingtalk-agent/memory-noop-result@1', duplicate: false, path,
93
+ receipt: readReceipt(path) };
94
+ }
95
+ finally {
96
+ release();
97
+ }
98
+ }
99
+ export function listMemoryNoops(root, filter = {}, options = {}) {
100
+ const dir = receiptRoot(root, options.stateDir, false);
101
+ const receipts = readdirSync(dir)
102
+ .filter((name) => /^nop_[a-f0-9]{24}\.json$/.test(name))
103
+ .map((name) => readReceipt(join(dir, name)))
104
+ .filter((receipt) => (!filter.scopeId || receipt.scopeId === filter.scopeId) &&
105
+ (!filter.step || receipt.step === filter.step) &&
106
+ (!filter.occurrence || receipt.occurrence === filter.occurrence))
107
+ .sort((a, b) => a.recordedAt.localeCompare(b.recordedAt) || a.id.localeCompare(b.id));
108
+ return { $schema: 'dingtalk-agent/memory-noop-list@1', count: receipts.length, receipts };
109
+ }
110
+ /** 运维侧要的那个二值判定:这一拍的判存步骤——跑了判空,还是没有任何痕迹。 */
111
+ export function traceMemoryNoop(root, query, options = {}) {
112
+ const scopeId = clean(query.scopeId);
113
+ const occurrence = clean(query.occurrence);
114
+ if (!scopeId || !occurrence)
115
+ throw new Error('memory noop trace 需要 scopeId 和 occurrence');
116
+ const step = clean(query.step) || MEMORY_SAVE_DECISION_STEP;
117
+ const { receipts } = listMemoryNoops(root, { scopeId, occurrence, step }, options);
118
+ return {
119
+ $schema: 'dingtalk-agent/memory-noop-trace@1',
120
+ verdict: receipts.length ? 'ran-empty' : 'no-trace',
121
+ scopeId, occurrence, step,
122
+ receiptId: receipts[0]?.id || '',
123
+ };
124
+ }
125
+ export function isMemoryNoopReceiptId(value) {
126
+ return RECEIPT_ID_PATTERN.test(value);
127
+ }
128
+ function validateClaim(value) {
129
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
130
+ throw new Error('Memory no-op claim 必须是 JSON object');
131
+ }
132
+ const input = value;
133
+ const allowed = new Set(['$schema', 'step', 'scopeId', 'reason', 'occurrence', 'consideredDigest']);
134
+ const extra = Object.keys(input).filter((key) => !allowed.has(key));
135
+ if (extra.length) {
136
+ // 脱敏红线的执行点:note/detail 之类的自由文本字段在这里被结构性拒绝,
137
+ // 被判定过的内容只能以 consideredDigest(sha256)入档。
138
+ throw new Error(`Memory no-op claim 含未知字段: ${extra.join(', ')}(原文不入痕迹文件,只收 digest)`);
139
+ }
140
+ if (input.$schema !== 'dingtalk-agent/memory-noop-claim@1') {
141
+ throw new Error('Memory no-op claim schema 非法');
142
+ }
143
+ const step = clean(input.step);
144
+ if (!STEP_PATTERN.test(step)) {
145
+ throw new Error(`Memory no-op step 必须是 kebab-case(如 ${MEMORY_SAVE_DECISION_STEP}): ${step || '-'}`);
146
+ }
147
+ if (!clean(input.scopeId))
148
+ throw new Error('Memory no-op claim 缺少 scopeId');
149
+ if (!MEMORY_NOOP_REASONS.includes(input.reason)) {
150
+ throw new Error(`Memory no-op reason 必须是枚举之一: ${MEMORY_NOOP_REASONS.join(' / ')}`);
151
+ }
152
+ if (input.occurrence !== undefined) {
153
+ const occurrence = clean(input.occurrence);
154
+ if (!occurrence || occurrence.length > 128) {
155
+ throw new Error('Memory no-op occurrence 必须是 ≤128 字符的非空字符串');
156
+ }
157
+ }
158
+ if (input.consideredDigest !== undefined &&
159
+ !DIGEST_PATTERN.test(String(input.consideredDigest))) {
160
+ throw new Error('Memory no-op consideredDigest 必须是 64 位 sha256 hex');
161
+ }
162
+ return JSON.parse(JSON.stringify(input));
163
+ }
164
+ function receiptRoot(root, stateDir = '', prepared = false) {
165
+ const base = resolve(root, stateDir || process.env.DTA_STATE_DIR || '.dingtalk-agent');
166
+ // Prepared 的安全边界是「Agent root 内的宿主管理状态目录」,不是字面 `.dingtalk-agent`:
167
+ // bindings/enhance 合同允许自定义私有 stateDir(如 .agent-private),把它拒了会让
168
+ // 合法隔离配置签不出 Receipt,运维把「配置不兼容」误读成「步骤没跑」(issue #47)。
169
+ if (prepared)
170
+ assertInside(resolve(root), base, 'Prepared no-op stateDir');
171
+ const path = join(base, 'memory', 'noop-receipts');
172
+ mkdirSync(path, { recursive: true });
173
+ return path;
174
+ }
175
+ /**
176
+ * Prepared issuer 只认 canonical Session/Run 树(issue #42):DTA_RUN 是调用方可覆盖
177
+ * 的环境变量,「project root 内存在一个 run.json」不构成宿主证明。这里复用
178
+ * task-checkpoints 的解析纪律:run 必须位于对应 Session 的 runs/ 之下,且
179
+ * run↔session 的身份(sessionId/contextId)互证一致。
180
+ */
181
+ function issuerContext(root, runInput = '', sessionInput = '', sessionRoot = '') {
182
+ const value = clean(runInput || process.env.DTA_RUN);
183
+ if (!value)
184
+ return null;
185
+ const sessionValue = clean(sessionInput || process.env.DTA_SESSION);
186
+ if (!sessionValue) {
187
+ throw new Error('Prepared memory no-op 需要 DTA_SESSION(run 必须挂在 canonical Session 之下)');
188
+ }
189
+ const configuredRoot = resolve(root, sessionRoot || '.dingtalk-agent/sessions');
190
+ if (!existsSync(configuredRoot)) {
191
+ throw new Error('当前 Workspace 还没有 Session state root,无法验证 Prepared Run');
192
+ }
193
+ const sessionPath = realpathSync(resolve(sessionValue));
194
+ assertInside(realpathSync(configuredRoot), sessionPath, 'No-op Session');
195
+ const session = JSON.parse(readFileSync(join(sessionPath, 'session.json'), 'utf8'));
196
+ if (!session.id || !session.contextId)
197
+ throw new Error('No-op Session 缺少 id/contextId');
198
+ const runPath = realpathSync(resolve(value));
199
+ assertInside(join(sessionPath, 'runs'), runPath, 'No-op Run');
200
+ const run = JSON.parse(readFileSync(join(runPath, 'run.json'), 'utf8'));
201
+ if (!run.id || !run.contextId || !run.definition?.hash) {
202
+ throw new Error('Prepared Run 缺少 id/contextId/definition hash');
203
+ }
204
+ if (run.sessionId !== session.id || run.contextId !== session.contextId) {
205
+ throw new Error('No-op Run 与 Session 身份不一致');
206
+ }
207
+ return run;
208
+ }
209
+ const RECEIPT_KEYS = [
210
+ '$schema', 'id', 'step', 'scopeId', 'occurrence', 'reason',
211
+ 'consideredDigest', 'issuer', 'recordedAt', 'hash',
212
+ ];
213
+ const ISSUER_KEYS = ['mode', 'runId', 'eventId', 'definitionHash'];
214
+ /**
215
+ * 严格结构校验(issue #42):hash 只证完整性、证不了签发方,所以形状合同必须自己
216
+ * 站住——缺字段但 hash 自洽的手写文件、id 与文件名/三元组不一致的文件,一律
217
+ * fail-closed 抛错,绝不折成一条「有效痕迹」去支撑 ran-empty。
218
+ */
219
+ function readReceipt(path) {
220
+ if (!existsSync(path))
221
+ throw new Error(`找不到 Memory no-op Receipt: ${path}`);
222
+ const bad = (why) => {
223
+ throw new Error(`Memory no-op Receipt 非法(${why}): ${path} —— ` +
224
+ '结构不合法的痕迹文件不参与 trace 判定,先人工核对来源');
225
+ };
226
+ const value = JSON.parse(readFileSync(path, 'utf8'));
227
+ if (!value || typeof value !== 'object' || Array.isArray(value))
228
+ bad('不是 object');
229
+ const keys = Object.keys(value);
230
+ if (keys.length !== RECEIPT_KEYS.length || RECEIPT_KEYS.some((key) => !(key in value))) {
231
+ bad(`字段集必须恰为 ${RECEIPT_KEYS.join('/')}`);
232
+ }
233
+ if (value.$schema !== 'dingtalk-agent/memory-noop-receipt@1')
234
+ bad('$schema 不符');
235
+ if (!RECEIPT_ID_PATTERN.test(value.id))
236
+ bad('id 文法不符');
237
+ if (!STEP_PATTERN.test(clean(value.step)))
238
+ bad('step 文法不符');
239
+ if (!clean(value.scopeId))
240
+ bad('scopeId 为空');
241
+ const occurrence = clean(value.occurrence);
242
+ if (!occurrence || occurrence.length > 128)
243
+ bad('occurrence 文法不符');
244
+ if (!MEMORY_NOOP_REASONS.includes(value.reason))
245
+ bad('reason 不在枚举内');
246
+ if (value.consideredDigest !== '' && !DIGEST_PATTERN.test(String(value.consideredDigest))) {
247
+ bad('consideredDigest 文法不符');
248
+ }
249
+ const issuer = value.issuer;
250
+ if (!issuer || typeof issuer !== 'object' || Array.isArray(issuer) ||
251
+ Object.keys(issuer).length !== ISSUER_KEYS.length ||
252
+ ISSUER_KEYS.some((key) => !(key in issuer))) {
253
+ bad(`issuer 字段集必须恰为 ${ISSUER_KEYS.join('/')}`);
254
+ }
255
+ if (issuer.mode === 'prepared') {
256
+ if (!clean(issuer.runId) || `run:${issuer.runId}` !== occurrence) {
257
+ bad('prepared issuer 的 runId 必须非空且与 occurrence(run:<runId>) 一致');
258
+ }
259
+ }
260
+ else if (issuer.mode === 'direct') {
261
+ if (issuer.runId !== '' || issuer.eventId !== '' || issuer.definitionHash !== '') {
262
+ bad('direct issuer 的 runId/eventId/definitionHash 必须为空串');
263
+ }
264
+ }
265
+ else
266
+ bad('issuer.mode 不在枚举内');
267
+ if (Number.isNaN(new Date(String(value.recordedAt)).getTime()))
268
+ bad('recordedAt 不是合法时间');
269
+ const { hash, ...unsigned } = value;
270
+ if (!hash || hash !== digest(stableStringify(unsigned)))
271
+ bad('完整性 hash 不一致');
272
+ // id 必须能从三元组重推导,且与文件名一致——身份即内容,改一处就露馅
273
+ const derived = `nop_${digest(stableStringify({
274
+ step: value.step, scopeId: value.scopeId, occurrence,
275
+ })).slice(0, 24)}`;
276
+ if (value.id !== derived)
277
+ bad('id 与 (step,scopeId,occurrence) 重推导不一致');
278
+ if (!path.endsWith(`${sep}${value.id}.json`) && !path.endsWith(`/${value.id}.json`)) {
279
+ bad('id 与文件名不一致');
280
+ }
281
+ return value;
282
+ }
283
+ function writeJsonAtomic(path, value) {
284
+ mkdirSync(dirname(path), { recursive: true });
285
+ const temp = `${path}.${process.pid}.${Date.now()}.tmp`;
286
+ writeFileSync(temp, JSON.stringify(value, null, 2) + '\n', { flag: 'wx' });
287
+ renameSync(temp, path);
288
+ }
289
+ function assertInside(root, path, label) {
290
+ const rel = relative(resolve(root), resolve(path));
291
+ if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`)) {
292
+ throw new Error(`${label} 必须位于允许的 root 内`);
293
+ }
294
+ }
295
+ function parseNow(value) {
296
+ if (!value)
297
+ return new Date();
298
+ const parsed = new Date(value);
299
+ if (Number.isNaN(parsed.getTime()))
300
+ throw new Error(`非法时间: ${value}`);
301
+ return parsed;
302
+ }
303
+ function clean(value) {
304
+ return typeof value === 'string' ? value.trim() : '';
305
+ }
306
+ //# sourceMappingURL=noop-receipt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"noop-receipt.js","sourceRoot":"","sources":["../../../src/memory/noop-receipt.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, writeFileSync } from 'node:fs'\nimport { dirname, join, relative, resolve, sep } from 'node:path'\nimport { digest, stableStringify } from '../events.js'\nimport { acquireLease } from '../lease.js'\n\n/**\n * no-op / nothing-to-save Receipt(issue #25)。\n *\n * dta-basic-behavior 要求「判存步骤跑过、判了没什么可存,也要留一条痕迹」,但此前\n * 没有定义写到哪、什么 schema、怎么回读——Agent 只能自行发明日志格式,运维侧依旧\n * 分不清「跑了判空」和「压根没跑」。本模块把这条痕迹变成宿主状态里的类型化 Receipt:\n *\n * - **身份 = (step, scopeId, occurrence)**:occurrence 是这次判定挂靠的事件锚\n * (Prepared Run 用 run:<runId>,Direct 模式由调用方显式给 eventId/心跳拍号)。\n * 同一 occurrence 重放幂等返回既有 Receipt;内容不一致则响亮报冲突,不静默覆盖。\n * - **脱敏红线**:reason 只收枚举,被判定过的内容只能以 sha256 digest 入档\n * (consideredDigest),自由文本字段在校验层直接拒绝——痕迹文件不携带原文。\n * - **回读即合同**:traceMemoryNoop 对 (scopeId, occurrence) 给出二值判定\n * ran-empty / no-trace,这正是运维要区分的那两个状态。\n *\n * 信任边界(issue #42,说清楚不装伪):Receipt 里的 hash 是【无密钥完整性校验】,\n * 不是宿主签名——任何能写 state 目录的调用方都能重算它。真实性边界 = 「state 目录\n * 归宿主所有、Prepared Run 的沙箱写不进来」这一部署事实;本模块能保证的是\n * fail-closed 的结构合同:结构不合法/身份对不上的文件绝不折成 ran-empty,\n * Prepared issuer 只认 canonical Session/runs 树里 run↔session 身份互证的 run,\n * 环境变量指向的任意目录冒充不了。需要密码学可验证签发时,走宿主密钥/MAC 或\n * 控制面回执机制,不要把这里的 digest 说成 signature。\n */\n\nexport const MEMORY_SAVE_DECISION_STEP = 'memory-save-decision'\n\nexport const MEMORY_NOOP_REASONS = [\n 'no-durable-content',\n 'below-confidence',\n 'duplicate-of-existing',\n 'out-of-scope',\n 'ephemeral-only',\n] as const\n\nexport type MemoryNoopReason = typeof MEMORY_NOOP_REASONS[number]\n\nexport interface MemoryNoopClaim {\n $schema: 'dingtalk-agent/memory-noop-claim@1'\n step: string\n scopeId: string\n reason: MemoryNoopReason\n occurrence?: string\n consideredDigest?: string\n}\n\nexport interface MemoryNoopReceipt {\n $schema: 'dingtalk-agent/memory-noop-receipt@1'\n id: string\n step: string\n scopeId: string\n occurrence: string\n reason: MemoryNoopReason\n consideredDigest: string\n issuer: {\n mode: 'prepared' | 'direct'\n runId: string\n eventId: string\n definitionHash: string\n }\n recordedAt: string\n hash: string\n}\n\nexport interface MemoryNoopOptions {\n stateDir?: string\n runPath?: string\n sessionPath?: string\n // Session state root(cfg.runtime.sessionRoot);Prepared issuer 校验用\n sessionRoot?: string\n now?: string\n}\n\nexport interface MemoryNoopRecordResult {\n $schema: 'dingtalk-agent/memory-noop-result@1'\n duplicate: boolean\n path: string\n receipt: MemoryNoopReceipt\n}\n\nexport interface MemoryNoopListResult {\n $schema: 'dingtalk-agent/memory-noop-list@1'\n count: number\n receipts: MemoryNoopReceipt[]\n}\n\nexport interface MemoryNoopTraceResult {\n $schema: 'dingtalk-agent/memory-noop-trace@1'\n verdict: 'ran-empty' | 'no-trace'\n scopeId: string\n occurrence: string\n step: string\n receiptId: string\n}\n\nconst STEP_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/\nconst DIGEST_PATTERN = /^[a-f0-9]{64}$/\nconst RECEIPT_ID_PATTERN = /^nop_[a-f0-9]{24}$/\n\nexport function recordMemoryNoop(\n root: string,\n value: unknown,\n options: MemoryNoopOptions = {},\n): MemoryNoopRecordResult {\n const claim = validateClaim(value)\n const run = issuerContext(root, options.runPath, options.sessionPath, options.sessionRoot)\n if (run && claim.scopeId !== run.contextId) {\n throw new Error(\n `Memory no-op scopeId=${claim.scopeId} 与 Prepared Run contextId=${run.contextId} 不一致`,\n )\n }\n // Prepared Run 的 occurrence 从受信 run 状态推导,不采纳正文声称的锚点;\n // Direct 模式没有受信锚可推,必须由调用方显式给出,缺了就拒绝——\n // 没有 occurrence 的痕迹回答不了「哪一拍判过」,等于没留。\n const derived = run ? `run:${run.id}` : ''\n if (run) {\n if (claim.occurrence && claim.occurrence !== derived) {\n throw new Error(\n `Memory no-op occurrence=${claim.occurrence} 与 Prepared Run 推导值 ${derived} 不一致`,\n )\n }\n } else if (!claim.occurrence) {\n throw new Error('Direct 模式的 memory no-op 需要显式 occurrence(eventId / 心跳拍号等事件锚)')\n }\n const occurrence = run ? derived : String(claim.occurrence)\n\n const id = `nop_${digest(stableStringify({\n step: claim.step, scopeId: claim.scopeId, occurrence,\n })).slice(0, 24)}`\n const path = join(receiptRoot(root, options.stateDir, Boolean(run)), `${id}.json`)\n const release = acquireLease(`${path}.lock`, `Memory no-op Receipt ${id} 正在写入`, {\n waitMs: 3_000, staleAfterMs: 2 * 60_000,\n })\n try {\n if (existsSync(path)) {\n const existing = readReceipt(path)\n if (existing.reason !== claim.reason ||\n existing.consideredDigest !== (claim.consideredDigest || '')) {\n throw new Error(\n `同一 occurrence(${occurrence}) 已有内容不一致的 no-op 痕迹(${existing.id}):` +\n '不静默覆盖,请先人工核对两次判定为何不同',\n )\n }\n return { $schema: 'dingtalk-agent/memory-noop-result@1', duplicate: true, path,\n receipt: existing }\n }\n const unsigned: Omit<MemoryNoopReceipt, 'hash'> = {\n $schema: 'dingtalk-agent/memory-noop-receipt@1',\n id,\n step: claim.step,\n scopeId: claim.scopeId,\n occurrence,\n reason: claim.reason,\n consideredDigest: claim.consideredDigest || '',\n issuer: run ? {\n mode: 'prepared', runId: run.id, eventId: run.eventId || '',\n definitionHash: run.definition?.hash || '',\n } : { mode: 'direct', runId: '', eventId: '', definitionHash: '' },\n recordedAt: parseNow(options.now).toISOString(),\n }\n const receipt: MemoryNoopReceipt = { ...unsigned, hash: digest(stableStringify(unsigned)) }\n writeJsonAtomic(path, receipt)\n return { $schema: 'dingtalk-agent/memory-noop-result@1', duplicate: false, path,\n receipt: readReceipt(path) }\n } finally {\n release()\n }\n}\n\nexport function listMemoryNoops(\n root: string,\n filter: { scopeId?: string; step?: string; occurrence?: string } = {},\n options: MemoryNoopOptions = {},\n): MemoryNoopListResult {\n const dir = receiptRoot(root, options.stateDir, false)\n const receipts = readdirSync(dir)\n .filter((name) => /^nop_[a-f0-9]{24}\\.json$/.test(name))\n .map((name) => readReceipt(join(dir, name)))\n .filter((receipt) => (!filter.scopeId || receipt.scopeId === filter.scopeId) &&\n (!filter.step || receipt.step === filter.step) &&\n (!filter.occurrence || receipt.occurrence === filter.occurrence))\n .sort((a, b) => a.recordedAt.localeCompare(b.recordedAt) || a.id.localeCompare(b.id))\n return { $schema: 'dingtalk-agent/memory-noop-list@1', count: receipts.length, receipts }\n}\n\n/** 运维侧要的那个二值判定:这一拍的判存步骤——跑了判空,还是没有任何痕迹。 */\nexport function traceMemoryNoop(\n root: string,\n query: { scopeId: string; occurrence: string; step?: string },\n options: MemoryNoopOptions = {},\n): MemoryNoopTraceResult {\n const scopeId = clean(query.scopeId)\n const occurrence = clean(query.occurrence)\n if (!scopeId || !occurrence) throw new Error('memory noop trace 需要 scopeId 和 occurrence')\n const step = clean(query.step) || MEMORY_SAVE_DECISION_STEP\n const { receipts } = listMemoryNoops(root, { scopeId, occurrence, step }, options)\n return {\n $schema: 'dingtalk-agent/memory-noop-trace@1',\n verdict: receipts.length ? 'ran-empty' : 'no-trace',\n scopeId, occurrence, step,\n receiptId: receipts[0]?.id || '',\n }\n}\n\nexport function isMemoryNoopReceiptId(value: string): boolean {\n return RECEIPT_ID_PATTERN.test(value)\n}\n\nfunction validateClaim(value: unknown): MemoryNoopClaim {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Memory no-op claim 必须是 JSON object')\n }\n const input = value as Record<string, any>\n const allowed = new Set(['$schema', 'step', 'scopeId', 'reason', 'occurrence', 'consideredDigest'])\n const extra = Object.keys(input).filter((key) => !allowed.has(key))\n if (extra.length) {\n // 脱敏红线的执行点:note/detail 之类的自由文本字段在这里被结构性拒绝,\n // 被判定过的内容只能以 consideredDigest(sha256)入档。\n throw new Error(`Memory no-op claim 含未知字段: ${extra.join(', ')}(原文不入痕迹文件,只收 digest)`)\n }\n if (input.$schema !== 'dingtalk-agent/memory-noop-claim@1') {\n throw new Error('Memory no-op claim schema 非法')\n }\n const step = clean(input.step)\n if (!STEP_PATTERN.test(step)) {\n throw new Error(`Memory no-op step 必须是 kebab-case(如 ${MEMORY_SAVE_DECISION_STEP}): ${step || '-'}`)\n }\n if (!clean(input.scopeId)) throw new Error('Memory no-op claim 缺少 scopeId')\n if (!MEMORY_NOOP_REASONS.includes(input.reason)) {\n throw new Error(`Memory no-op reason 必须是枚举之一: ${MEMORY_NOOP_REASONS.join(' / ')}`)\n }\n if (input.occurrence !== undefined) {\n const occurrence = clean(input.occurrence)\n if (!occurrence || occurrence.length > 128) {\n throw new Error('Memory no-op occurrence 必须是 ≤128 字符的非空字符串')\n }\n }\n if (input.consideredDigest !== undefined &&\n !DIGEST_PATTERN.test(String(input.consideredDigest))) {\n throw new Error('Memory no-op consideredDigest 必须是 64 位 sha256 hex')\n }\n return JSON.parse(JSON.stringify(input)) as MemoryNoopClaim\n}\n\nfunction receiptRoot(root: string, stateDir = '', prepared = false): string {\n const base = resolve(root, stateDir || process.env.DTA_STATE_DIR || '.dingtalk-agent')\n // Prepared 的安全边界是「Agent root 内的宿主管理状态目录」,不是字面 `.dingtalk-agent`:\n // bindings/enhance 合同允许自定义私有 stateDir(如 .agent-private),把它拒了会让\n // 合法隔离配置签不出 Receipt,运维把「配置不兼容」误读成「步骤没跑」(issue #47)。\n if (prepared) assertInside(resolve(root), base, 'Prepared no-op stateDir')\n const path = join(base, 'memory', 'noop-receipts')\n mkdirSync(path, { recursive: true })\n return path\n}\n\n/**\n * Prepared issuer 只认 canonical Session/Run 树(issue #42):DTA_RUN 是调用方可覆盖\n * 的环境变量,「project root 内存在一个 run.json」不构成宿主证明。这里复用\n * task-checkpoints 的解析纪律:run 必须位于对应 Session 的 runs/ 之下,且\n * run↔session 的身份(sessionId/contextId)互证一致。\n */\nfunction issuerContext(\n root: string,\n runInput = '',\n sessionInput = '',\n sessionRoot = '',\n): Record<string, any> | null {\n const value = clean(runInput || process.env.DTA_RUN)\n if (!value) return null\n const sessionValue = clean(sessionInput || process.env.DTA_SESSION)\n if (!sessionValue) {\n throw new Error('Prepared memory no-op 需要 DTA_SESSION(run 必须挂在 canonical Session 之下)')\n }\n const configuredRoot = resolve(root, sessionRoot || '.dingtalk-agent/sessions')\n if (!existsSync(configuredRoot)) {\n throw new Error('当前 Workspace 还没有 Session state root,无法验证 Prepared Run')\n }\n const sessionPath = realpathSync(resolve(sessionValue))\n assertInside(realpathSync(configuredRoot), sessionPath, 'No-op Session')\n const session = JSON.parse(readFileSync(join(sessionPath, 'session.json'), 'utf8'))\n if (!session.id || !session.contextId) throw new Error('No-op Session 缺少 id/contextId')\n const runPath = realpathSync(resolve(value))\n assertInside(join(sessionPath, 'runs'), runPath, 'No-op Run')\n const run = JSON.parse(readFileSync(join(runPath, 'run.json'), 'utf8'))\n if (!run.id || !run.contextId || !run.definition?.hash) {\n throw new Error('Prepared Run 缺少 id/contextId/definition hash')\n }\n if (run.sessionId !== session.id || run.contextId !== session.contextId) {\n throw new Error('No-op Run 与 Session 身份不一致')\n }\n return run\n}\n\nconst RECEIPT_KEYS = [\n '$schema', 'id', 'step', 'scopeId', 'occurrence', 'reason',\n 'consideredDigest', 'issuer', 'recordedAt', 'hash',\n] as const\nconst ISSUER_KEYS = ['mode', 'runId', 'eventId', 'definitionHash'] as const\n\n/**\n * 严格结构校验(issue #42):hash 只证完整性、证不了签发方,所以形状合同必须自己\n * 站住——缺字段但 hash 自洽的手写文件、id 与文件名/三元组不一致的文件,一律\n * fail-closed 抛错,绝不折成一条「有效痕迹」去支撑 ran-empty。\n */\nfunction readReceipt(path: string): MemoryNoopReceipt {\n if (!existsSync(path)) throw new Error(`找不到 Memory no-op Receipt: ${path}`)\n const bad = (why: string): never => {\n throw new Error(`Memory no-op Receipt 非法(${why}): ${path} —— ` +\n '结构不合法的痕迹文件不参与 trace 判定,先人工核对来源')\n }\n const value = JSON.parse(readFileSync(path, 'utf8'))\n if (!value || typeof value !== 'object' || Array.isArray(value)) bad('不是 object')\n const keys = Object.keys(value)\n if (keys.length !== RECEIPT_KEYS.length || RECEIPT_KEYS.some((key) => !(key in value))) {\n bad(`字段集必须恰为 ${RECEIPT_KEYS.join('/')}`)\n }\n if (value.$schema !== 'dingtalk-agent/memory-noop-receipt@1') bad('$schema 不符')\n if (!RECEIPT_ID_PATTERN.test(value.id)) bad('id 文法不符')\n if (!STEP_PATTERN.test(clean(value.step))) bad('step 文法不符')\n if (!clean(value.scopeId)) bad('scopeId 为空')\n const occurrence = clean(value.occurrence)\n if (!occurrence || occurrence.length > 128) bad('occurrence 文法不符')\n if (!MEMORY_NOOP_REASONS.includes(value.reason)) bad('reason 不在枚举内')\n if (value.consideredDigest !== '' && !DIGEST_PATTERN.test(String(value.consideredDigest))) {\n bad('consideredDigest 文法不符')\n }\n const issuer = value.issuer\n if (!issuer || typeof issuer !== 'object' || Array.isArray(issuer) ||\n Object.keys(issuer).length !== ISSUER_KEYS.length ||\n ISSUER_KEYS.some((key) => !(key in issuer))) {\n bad(`issuer 字段集必须恰为 ${ISSUER_KEYS.join('/')}`)\n }\n if (issuer.mode === 'prepared') {\n if (!clean(issuer.runId) || `run:${issuer.runId}` !== occurrence) {\n bad('prepared issuer 的 runId 必须非空且与 occurrence(run:<runId>) 一致')\n }\n } else if (issuer.mode === 'direct') {\n if (issuer.runId !== '' || issuer.eventId !== '' || issuer.definitionHash !== '') {\n bad('direct issuer 的 runId/eventId/definitionHash 必须为空串')\n }\n } else bad('issuer.mode 不在枚举内')\n if (Number.isNaN(new Date(String(value.recordedAt)).getTime())) bad('recordedAt 不是合法时间')\n const { hash, ...unsigned } = value\n if (!hash || hash !== digest(stableStringify(unsigned))) bad('完整性 hash 不一致')\n // id 必须能从三元组重推导,且与文件名一致——身份即内容,改一处就露馅\n const derived = `nop_${digest(stableStringify({\n step: value.step, scopeId: value.scopeId, occurrence,\n })).slice(0, 24)}`\n if (value.id !== derived) bad('id 与 (step,scopeId,occurrence) 重推导不一致')\n if (!path.endsWith(`${sep}${value.id}.json`) && !path.endsWith(`/${value.id}.json`)) {\n bad('id 与文件名不一致')\n }\n return value as MemoryNoopReceipt\n}\n\nfunction writeJsonAtomic(path: string, value: unknown): void {\n mkdirSync(dirname(path), { recursive: true })\n const temp = `${path}.${process.pid}.${Date.now()}.tmp`\n writeFileSync(temp, JSON.stringify(value, null, 2) + '\\n', { flag: 'wx' })\n renameSync(temp, path)\n}\n\nfunction assertInside(root: string, path: string, label: string): void {\n const rel = relative(resolve(root), resolve(path))\n if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\\\' : '/'}`)) {\n throw new Error(`${label} 必须位于允许的 root 内`)\n }\n}\n\nfunction parseNow(value?: string): Date {\n if (!value) return new Date()\n const parsed = new Date(value)\n if (Number.isNaN(parsed.getTime())) throw new Error(`非法时间: ${value}`)\n return parsed\n}\n\nfunction clean(value: unknown): string {\n return typeof value === 'string' ? value.trim() : ''\n}\n"]}
@@ -48,9 +48,14 @@ export function upsertOperationalMemory(providerValue, recordValue, options = {}
48
48
  { operator: 'eq', operands: [provider.fields.scopeId, recorded.scopeId] },
49
49
  ],
50
50
  };
51
- let matches = dws.queryAiTableRecords({
51
+ // 完整性消费(issue #23):unique key 合同下 bounded-filter 读可用,但两种存疑态
52
+ // 必须挡下——window-full(命中打满窗口,可能被静默截断)与 records-null(截断/
53
+ // 软超时信号)。这里若把「没读到」当「没有」,下一步就会创建重复记录。
54
+ const lookup = dws.queryAiTableRecords({
52
55
  baseId: provider.baseId, tableId: provider.tableId, filters, profile,
53
56
  });
57
+ assertBoundedLookup(lookup, 'Operational Memory key/scope 查询');
58
+ let matches = lookup.records;
54
59
  if (matches.length > 1) {
55
60
  throw new Error(`Operational Memory key/scope 命中 ${matches.length} 条,拒绝猜测或批量覆盖`);
56
61
  }
@@ -67,9 +72,11 @@ export function upsertOperationalMemory(providerValue, recordValue, options = {}
67
72
  accepted = write.accepted;
68
73
  recordId = write.recordIds[0] || '';
69
74
  if (!recordId) {
70
- matches = dws.queryAiTableRecords({
75
+ const requery = dws.queryAiTableRecords({
71
76
  baseId: provider.baseId, tableId: provider.tableId, filters, profile,
72
77
  });
78
+ assertBoundedLookup(requery, 'Operational Memory 创建回查');
79
+ matches = requery.records;
73
80
  if (matches.length === 1)
74
81
  recordId = clean(matches[0]?.recordId);
75
82
  else if (matches.length > 1) {
@@ -87,12 +94,14 @@ export function upsertOperationalMemory(providerValue, recordValue, options = {}
87
94
  identity: { profile, expectedUserId, actualUserId },
88
95
  };
89
96
  }
90
- const readbackRows = dws.queryAiTableRecords({
97
+ const readbackRead = dws.queryAiTableRecords({
91
98
  baseId: provider.baseId,
92
99
  tableId: provider.tableId,
93
100
  recordIds: [recordId],
94
101
  profile,
95
102
  });
103
+ // recordId 有界读 → completeness proven('record-ids');行数仍由本合同校验。
104
+ const readbackRows = readbackRead.records;
96
105
  const readback = readbackRows.length === 1 ? readbackRows[0] : null;
97
106
  const mismatches = compareCells(provider, cells, readback?.cells);
98
107
  if (!readback || mismatches.length)
@@ -260,4 +269,19 @@ function validTime(value) {
260
269
  function clean(value) {
261
270
  return typeof value === 'string' ? value.trim() : '';
262
271
  }
272
+ /**
273
+ * bounded-filter 读的完整性守卫:unique-key 合同下「窗口未打满」可用;window-full
274
+ * (可能被静默截断)与 records-null(截断/软超时信号)都属「读没读全存疑」——
275
+ * 此时把空结果当「不存在」会直接造出重复记录,必须响亮地停。
276
+ */
277
+ function assertBoundedLookup(read, label) {
278
+ if (read.completeness.proven)
279
+ return;
280
+ if (read.completeness.reason === 'window-full') {
281
+ throw new Error(`${label}:命中打满查询窗口,可能被静默截断——读没读全存疑,拒绝继续`);
282
+ }
283
+ if (read.completeness.reason === 'records-null') {
284
+ throw new Error(`${label}:records:null(截断/软超时信号)——不是空表,重读后再继续`);
285
+ }
286
+ }
263
287
  //# sourceMappingURL=operational.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"operational.js","sourceRoot":"","sources":["../../../src/memory/operational.ts"],"names":[],"mappings":"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","sourcesContent":["import { digest, stableStringify } from '../events.js'\nimport * as dws from '../dws.js'\n\nexport interface OperationalMemoryRecord {\n $schema: 'dingtalk-agent/operational-memory-record@1'\n key: string\n scopeId: string\n kind: 'summary' | 'interaction' | 'task' | 'calendar' | 'fact'\n subjectId: string\n summary: string\n sourceRefs: string[]\n occurredAt: string | null\n recordedAt: string\n confidence: number\n attributes: Record<string, unknown>\n}\n\nexport interface OperationalMemoryProvider {\n $schema: 'dingtalk-agent/operational-memory-provider@1'\n provider: 'dingtalk-aitable'\n baseId: string\n tableId: string\n profile?: string\n expectedUserId?: string\n fields: {\n key: string\n scopeId: string\n kind: string\n subjectId: string\n summary: string\n sourceRefs: string\n occurredAt: string\n recordedAt: string\n confidence: string\n attributes: string\n }\n}\n\nexport interface OperationalUpsertResult {\n $schema: 'dingtalk-agent/operational-memory-result@1'\n mode: 'dry-run' | 'created' | 'updated' | 'uncertain'\n sideEffect: boolean\n verified: boolean\n verification: string\n recordId: string\n inputHash: string\n identity: { profile: string; expectedUserId: string; actualUserId: string }\n cells: Record<string, unknown>\n readback: unknown\n mismatches: string[]\n}\n\nexport function upsertOperationalMemory(\n providerValue: unknown,\n recordValue: unknown,\n options: { execute?: boolean; yes?: boolean } = {},\n): OperationalUpsertResult {\n const provider = validateProvider(providerValue)\n const record = validateRecord(recordValue)\n const profile = clean(provider.profile || process.env.DTA_DWS_PROFILE)\n const expectedUserId = clean(provider.expectedUserId || process.env.DTA_EXPECTED_USER_ID)\n if (!profile || profile.includes(',')) {\n throw new Error('Operational Memory 必须固定单一 DWS profile')\n }\n if (!expectedUserId) throw new Error('Operational Memory 必须固定 expectedUserId')\n const recorded: OperationalMemoryRecord = {\n ...record,\n recordedAt: new Date().toISOString(),\n }\n const cells = toCells(provider, recorded)\n const base = {\n $schema: 'dingtalk-agent/operational-memory-result@1' as const,\n sideEffect: false,\n verified: false,\n verification: 'dry-run-no-dws-call',\n recordId: '',\n inputHash: digest(stableStringify(recorded)),\n identity: { profile, expectedUserId, actualUserId: '' },\n cells,\n readback: null,\n mismatches: [] as string[],\n }\n if (!options.execute) return { ...base, mode: 'dry-run' }\n if (!options.yes) throw new Error('Operational Memory 真实写入必须显式 --live --yes')\n if (process.env.DTA_RUN) {\n throw new Error(\n 'Prepared Run 禁止绕过 Action Gate 直接写 Operational Memory;请由宿主 typed Broker 执行',\n )\n }\n\n const identityData = dws.getSelf(profile)\n const actualUserId = String(findValue(identityData, ['userId', 'user_id', 'userid']) || '')\n if (!actualUserId) throw new Error('dws contact user get-self 没有返回 userId,禁止写业务记忆')\n if (actualUserId !== expectedUserId) {\n throw new Error(`DWS 执行身份不符:expected=${expectedUserId}, actual=${actualUserId}`)\n }\n\n const filters = {\n operator: 'and',\n operands: [\n { operator: 'eq', operands: [provider.fields.key, recorded.key] },\n { operator: 'eq', operands: [provider.fields.scopeId, recorded.scopeId] },\n ],\n }\n let matches = dws.queryAiTableRecords({\n baseId: provider.baseId, tableId: provider.tableId, filters, profile,\n })\n if (matches.length > 1) {\n throw new Error(\n `Operational Memory key/scope 命中 ${matches.length} 条,拒绝猜测或批量覆盖`,\n )\n }\n const existing = matches[0] || null\n let recordId = clean(existing?.recordId)\n let mode: OperationalUpsertResult['mode'] = existing ? 'updated' : 'created'\n let accepted = false\n if (existing) {\n const write = dws.updateAiTableRecord(\n provider.baseId, provider.tableId, recordId, cells, profile,\n )\n accepted = write.accepted\n } else {\n const write = dws.createAiTableRecord(provider.baseId, provider.tableId, cells, profile)\n accepted = write.accepted\n recordId = write.recordIds[0] || ''\n if (!recordId) {\n matches = dws.queryAiTableRecords({\n baseId: provider.baseId, tableId: provider.tableId, filters, profile,\n })\n if (matches.length === 1) recordId = clean(matches[0]?.recordId)\n else if (matches.length > 1) {\n throw new Error('Operational Memory 创建回查命中多条,进入人工 reconcile')\n }\n }\n }\n if (!recordId) {\n return {\n ...base,\n mode: 'uncertain',\n sideEffect: true,\n verification: accepted\n ? 'write-accepted-but-no-record-id' : 'write-error-and-key-readback-miss',\n identity: { profile, expectedUserId, actualUserId },\n }\n }\n const readbackRows = dws.queryAiTableRecords({\n baseId: provider.baseId,\n tableId: provider.tableId,\n recordIds: [recordId],\n profile,\n })\n const readback = readbackRows.length === 1 ? readbackRows[0] : null\n const mismatches = compareCells(provider, cells, readback?.cells)\n if (!readback || mismatches.length) mode = 'uncertain'\n return {\n ...base,\n mode,\n sideEffect: true,\n verified: Boolean(readback) && mismatches.length === 0,\n verification: readback && !mismatches.length\n ? 'record-id-independent-readback' : 'record-readback-mismatch',\n recordId,\n identity: { profile, expectedUserId, actualUserId },\n readback,\n mismatches,\n }\n}\n\nfunction validateProvider(value: unknown): OperationalMemoryProvider {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Operational Memory provider 必须是 JSON object')\n }\n const input = value as Record<string, any>\n const allowed = new Set([\n '$schema', 'provider', 'baseId', 'tableId', 'profile', 'expectedUserId', 'fields',\n ])\n const extra = Object.keys(input).filter((key) => !allowed.has(key))\n if (extra.length) throw new Error(`Operational Memory provider 含未知字段: ${extra.join(', ')}`)\n if (input.$schema !== 'dingtalk-agent/operational-memory-provider@1' ||\n input.provider !== 'dingtalk-aitable') {\n throw new Error('Operational Memory provider schema/type 非法')\n }\n for (const key of ['baseId', 'tableId']) {\n if (!clean(input[key])) throw new Error(`Operational Memory provider 缺少 ${key}`)\n }\n const fieldNames = [\n 'key', 'scopeId', 'kind', 'subjectId', 'summary', 'sourceRefs', 'occurredAt',\n 'recordedAt', 'confidence', 'attributes',\n ]\n if (!input.fields || fieldNames.some((name) => !clean(input.fields[name]))) {\n throw new Error(`Operational Memory fields 必须包含 ${fieldNames.join(' / ')}`)\n }\n const fieldIds = fieldNames.map((name) => clean(input.fields[name]))\n if (new Set(fieldIds).size !== fieldIds.length) {\n throw new Error('Operational Memory fields 不能复用同一个 fieldId')\n }\n return JSON.parse(JSON.stringify(input)) as OperationalMemoryProvider\n}\n\nfunction validateRecord(value: unknown): OperationalMemoryRecord {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Operational Memory record 必须是 JSON object')\n }\n const input = value as Record<string, any>\n const allowed = new Set([\n '$schema', 'key', 'scopeId', 'kind', 'subjectId', 'summary', 'sourceRefs',\n 'occurredAt', 'recordedAt', 'confidence', 'attributes',\n ])\n const extra = Object.keys(input).filter((key) => !allowed.has(key))\n if (extra.length) throw new Error(`Operational Memory record 含未知字段: ${extra.join(', ')}`)\n if (input.$schema !== 'dingtalk-agent/operational-memory-record@1') {\n throw new Error('Operational Memory record schema 非法')\n }\n for (const key of ['key', 'scopeId', 'subjectId', 'summary']) {\n if (!clean(input[key])) throw new Error(`Operational Memory record 缺少 ${key}`)\n }\n if (!['summary', 'interaction', 'task', 'calendar', 'fact'].includes(input.kind)) {\n throw new Error(`Operational Memory kind 非法: ${input.kind || '-'}`)\n }\n if (!Array.isArray(input.sourceRefs) || !input.sourceRefs.length ||\n input.sourceRefs.some((item: unknown) => !clean(item))) {\n throw new Error('Operational Memory sourceRefs 必须至少包含一条非空来源')\n }\n if (input.occurredAt !== null && !validTime(input.occurredAt)) {\n throw new Error('Operational Memory occurredAt 必须是 RFC3339 或 null')\n }\n if (typeof input.recordedAt !== 'string') {\n throw new Error('Operational Memory recordedAt 必须是 string(由 CLI 重写)')\n }\n if (typeof input.confidence !== 'number' || input.confidence < 0 || input.confidence > 1) {\n throw new Error('Operational Memory confidence 必须在 0..1')\n }\n if (!input.attributes || typeof input.attributes !== 'object' || Array.isArray(input.attributes)) {\n throw new Error('Operational Memory attributes 必须是 JSON object')\n }\n return JSON.parse(JSON.stringify(input)) as OperationalMemoryRecord\n}\n\nfunction toCells(\n provider: OperationalMemoryProvider,\n record: OperationalMemoryRecord,\n): Record<string, unknown> {\n const fields = provider.fields\n const cells: Record<string, unknown> = {\n [fields.key]: record.key,\n [fields.scopeId]: record.scopeId,\n [fields.kind]: record.kind,\n [fields.subjectId]: record.subjectId,\n [fields.summary]: record.summary,\n [fields.sourceRefs]: stableStringify(record.sourceRefs),\n [fields.recordedAt]: record.recordedAt,\n [fields.confidence]: record.confidence,\n [fields.attributes]: stableStringify(record.attributes),\n }\n if (record.occurredAt) cells[fields.occurredAt] = record.occurredAt\n return cells\n}\n\nfunction compareCells(\n provider: OperationalMemoryProvider,\n expected: Record<string, unknown>,\n actualValue: unknown,\n): string[] {\n if (!actualValue || typeof actualValue !== 'object' || Array.isArray(actualValue)) {\n return ['cells:missing']\n }\n const actual = actualValue as Record<string, unknown>\n const mismatches: string[] = []\n for (const [name, fieldId] of Object.entries(provider.fields)) {\n const wanted = expected[fieldId]\n const seen = normalizeCell(actual[fieldId])\n if (name === 'confidence') {\n if (Number(seen) !== Number(wanted)) mismatches.push(name)\n } else if (name === 'occurredAt' || name === 'recordedAt') {\n if (!sameTimeOrText(seen, wanted)) mismatches.push(name)\n } else if (String(seen ?? '') !== String(wanted ?? '')) mismatches.push(name)\n }\n return mismatches\n}\n\nfunction normalizeCell(value: unknown): unknown {\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n const item = value as Record<string, unknown>\n return item.name ?? item.text ?? item.value ?? value\n }\n return value\n}\n\nfunction sameTimeOrText(actual: unknown, expected: unknown): boolean {\n const left = String(actual ?? '')\n const right = String(expected ?? '')\n if (!left || !right) return left === right\n const leftTime = Date.parse(left)\n const rightTime = Date.parse(right)\n return Number.isFinite(leftTime) && Number.isFinite(rightTime)\n ? leftTime === rightTime : left === right\n}\n\nfunction findValue(value: unknown, keys: string[]): unknown {\n if (!value || typeof value !== 'object') return null\n for (const [key, child] of Object.entries(value)) {\n if (keys.includes(key) && child !== undefined && child !== null && child !== '') return child\n }\n for (const child of Object.values(value)) {\n const found = findValue(child, keys)\n if (found !== null) return found\n }\n return null\n}\n\nfunction validTime(value: unknown): string | null {\n if (typeof value !== 'string' || !value.trim() || !Number.isFinite(Date.parse(value))) return null\n return new Date(value).toISOString()\n}\n\nfunction clean(value: unknown): string {\n return typeof value === 'string' ? value.trim() : ''\n}\n"]}
1
+ {"version":3,"file":"operational.js","sourceRoot":"","sources":["../../../src/memory/operational.ts"],"names":[],"mappings":"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","sourcesContent":["import { digest, stableStringify } from '../events.js'\nimport * as dws from '../dws.js'\n\nexport interface OperationalMemoryRecord {\n $schema: 'dingtalk-agent/operational-memory-record@1'\n key: string\n scopeId: string\n kind: 'summary' | 'interaction' | 'task' | 'calendar' | 'fact'\n subjectId: string\n summary: string\n sourceRefs: string[]\n occurredAt: string | null\n recordedAt: string\n confidence: number\n attributes: Record<string, unknown>\n}\n\nexport interface OperationalMemoryProvider {\n $schema: 'dingtalk-agent/operational-memory-provider@1'\n provider: 'dingtalk-aitable'\n baseId: string\n tableId: string\n profile?: string\n expectedUserId?: string\n fields: {\n key: string\n scopeId: string\n kind: string\n subjectId: string\n summary: string\n sourceRefs: string\n occurredAt: string\n recordedAt: string\n confidence: string\n attributes: string\n }\n}\n\nexport interface OperationalUpsertResult {\n $schema: 'dingtalk-agent/operational-memory-result@1'\n mode: 'dry-run' | 'created' | 'updated' | 'uncertain'\n sideEffect: boolean\n verified: boolean\n verification: string\n recordId: string\n inputHash: string\n identity: { profile: string; expectedUserId: string; actualUserId: string }\n cells: Record<string, unknown>\n readback: unknown\n mismatches: string[]\n}\n\nexport function upsertOperationalMemory(\n providerValue: unknown,\n recordValue: unknown,\n options: { execute?: boolean; yes?: boolean } = {},\n): OperationalUpsertResult {\n const provider = validateProvider(providerValue)\n const record = validateRecord(recordValue)\n const profile = clean(provider.profile || process.env.DTA_DWS_PROFILE)\n const expectedUserId = clean(provider.expectedUserId || process.env.DTA_EXPECTED_USER_ID)\n if (!profile || profile.includes(',')) {\n throw new Error('Operational Memory 必须固定单一 DWS profile')\n }\n if (!expectedUserId) throw new Error('Operational Memory 必须固定 expectedUserId')\n const recorded: OperationalMemoryRecord = {\n ...record,\n recordedAt: new Date().toISOString(),\n }\n const cells = toCells(provider, recorded)\n const base = {\n $schema: 'dingtalk-agent/operational-memory-result@1' as const,\n sideEffect: false,\n verified: false,\n verification: 'dry-run-no-dws-call',\n recordId: '',\n inputHash: digest(stableStringify(recorded)),\n identity: { profile, expectedUserId, actualUserId: '' },\n cells,\n readback: null,\n mismatches: [] as string[],\n }\n if (!options.execute) return { ...base, mode: 'dry-run' }\n if (!options.yes) throw new Error('Operational Memory 真实写入必须显式 --live --yes')\n if (process.env.DTA_RUN) {\n throw new Error(\n 'Prepared Run 禁止绕过 Action Gate 直接写 Operational Memory;请由宿主 typed Broker 执行',\n )\n }\n\n const identityData = dws.getSelf(profile)\n const actualUserId = String(findValue(identityData, ['userId', 'user_id', 'userid']) || '')\n if (!actualUserId) throw new Error('dws contact user get-self 没有返回 userId,禁止写业务记忆')\n if (actualUserId !== expectedUserId) {\n throw new Error(`DWS 执行身份不符:expected=${expectedUserId}, actual=${actualUserId}`)\n }\n\n const filters = {\n operator: 'and',\n operands: [\n { operator: 'eq', operands: [provider.fields.key, recorded.key] },\n { operator: 'eq', operands: [provider.fields.scopeId, recorded.scopeId] },\n ],\n }\n // 完整性消费(issue #23):unique key 合同下 bounded-filter 读可用,但两种存疑态\n // 必须挡下——window-full(命中打满窗口,可能被静默截断)与 records-null(截断/\n // 软超时信号)。这里若把「没读到」当「没有」,下一步就会创建重复记录。\n const lookup = dws.queryAiTableRecords({\n baseId: provider.baseId, tableId: provider.tableId, filters, profile,\n })\n assertBoundedLookup(lookup, 'Operational Memory key/scope 查询')\n let matches = lookup.records\n if (matches.length > 1) {\n throw new Error(\n `Operational Memory key/scope 命中 ${matches.length} 条,拒绝猜测或批量覆盖`,\n )\n }\n const existing = matches[0] || null\n let recordId = clean(existing?.recordId)\n let mode: OperationalUpsertResult['mode'] = existing ? 'updated' : 'created'\n let accepted = false\n if (existing) {\n const write = dws.updateAiTableRecord(\n provider.baseId, provider.tableId, recordId, cells, profile,\n )\n accepted = write.accepted\n } else {\n const write = dws.createAiTableRecord(provider.baseId, provider.tableId, cells, profile)\n accepted = write.accepted\n recordId = write.recordIds[0] || ''\n if (!recordId) {\n const requery = dws.queryAiTableRecords({\n baseId: provider.baseId, tableId: provider.tableId, filters, profile,\n })\n assertBoundedLookup(requery, 'Operational Memory 创建回查')\n matches = requery.records\n if (matches.length === 1) recordId = clean(matches[0]?.recordId)\n else if (matches.length > 1) {\n throw new Error('Operational Memory 创建回查命中多条,进入人工 reconcile')\n }\n }\n }\n if (!recordId) {\n return {\n ...base,\n mode: 'uncertain',\n sideEffect: true,\n verification: accepted\n ? 'write-accepted-but-no-record-id' : 'write-error-and-key-readback-miss',\n identity: { profile, expectedUserId, actualUserId },\n }\n }\n const readbackRead = dws.queryAiTableRecords({\n baseId: provider.baseId,\n tableId: provider.tableId,\n recordIds: [recordId],\n profile,\n })\n // recordId 有界读 → completeness proven('record-ids');行数仍由本合同校验。\n const readbackRows = readbackRead.records\n const readback = readbackRows.length === 1 ? readbackRows[0] : null\n const mismatches = compareCells(provider, cells, readback?.cells)\n if (!readback || mismatches.length) mode = 'uncertain'\n return {\n ...base,\n mode,\n sideEffect: true,\n verified: Boolean(readback) && mismatches.length === 0,\n verification: readback && !mismatches.length\n ? 'record-id-independent-readback' : 'record-readback-mismatch',\n recordId,\n identity: { profile, expectedUserId, actualUserId },\n readback,\n mismatches,\n }\n}\n\nfunction validateProvider(value: unknown): OperationalMemoryProvider {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Operational Memory provider 必须是 JSON object')\n }\n const input = value as Record<string, any>\n const allowed = new Set([\n '$schema', 'provider', 'baseId', 'tableId', 'profile', 'expectedUserId', 'fields',\n ])\n const extra = Object.keys(input).filter((key) => !allowed.has(key))\n if (extra.length) throw new Error(`Operational Memory provider 含未知字段: ${extra.join(', ')}`)\n if (input.$schema !== 'dingtalk-agent/operational-memory-provider@1' ||\n input.provider !== 'dingtalk-aitable') {\n throw new Error('Operational Memory provider schema/type 非法')\n }\n for (const key of ['baseId', 'tableId']) {\n if (!clean(input[key])) throw new Error(`Operational Memory provider 缺少 ${key}`)\n }\n const fieldNames = [\n 'key', 'scopeId', 'kind', 'subjectId', 'summary', 'sourceRefs', 'occurredAt',\n 'recordedAt', 'confidence', 'attributes',\n ]\n if (!input.fields || fieldNames.some((name) => !clean(input.fields[name]))) {\n throw new Error(`Operational Memory fields 必须包含 ${fieldNames.join(' / ')}`)\n }\n const fieldIds = fieldNames.map((name) => clean(input.fields[name]))\n if (new Set(fieldIds).size !== fieldIds.length) {\n throw new Error('Operational Memory fields 不能复用同一个 fieldId')\n }\n return JSON.parse(JSON.stringify(input)) as OperationalMemoryProvider\n}\n\nfunction validateRecord(value: unknown): OperationalMemoryRecord {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Operational Memory record 必须是 JSON object')\n }\n const input = value as Record<string, any>\n const allowed = new Set([\n '$schema', 'key', 'scopeId', 'kind', 'subjectId', 'summary', 'sourceRefs',\n 'occurredAt', 'recordedAt', 'confidence', 'attributes',\n ])\n const extra = Object.keys(input).filter((key) => !allowed.has(key))\n if (extra.length) throw new Error(`Operational Memory record 含未知字段: ${extra.join(', ')}`)\n if (input.$schema !== 'dingtalk-agent/operational-memory-record@1') {\n throw new Error('Operational Memory record schema 非法')\n }\n for (const key of ['key', 'scopeId', 'subjectId', 'summary']) {\n if (!clean(input[key])) throw new Error(`Operational Memory record 缺少 ${key}`)\n }\n if (!['summary', 'interaction', 'task', 'calendar', 'fact'].includes(input.kind)) {\n throw new Error(`Operational Memory kind 非法: ${input.kind || '-'}`)\n }\n if (!Array.isArray(input.sourceRefs) || !input.sourceRefs.length ||\n input.sourceRefs.some((item: unknown) => !clean(item))) {\n throw new Error('Operational Memory sourceRefs 必须至少包含一条非空来源')\n }\n if (input.occurredAt !== null && !validTime(input.occurredAt)) {\n throw new Error('Operational Memory occurredAt 必须是 RFC3339 或 null')\n }\n if (typeof input.recordedAt !== 'string') {\n throw new Error('Operational Memory recordedAt 必须是 string(由 CLI 重写)')\n }\n if (typeof input.confidence !== 'number' || input.confidence < 0 || input.confidence > 1) {\n throw new Error('Operational Memory confidence 必须在 0..1')\n }\n if (!input.attributes || typeof input.attributes !== 'object' || Array.isArray(input.attributes)) {\n throw new Error('Operational Memory attributes 必须是 JSON object')\n }\n return JSON.parse(JSON.stringify(input)) as OperationalMemoryRecord\n}\n\nfunction toCells(\n provider: OperationalMemoryProvider,\n record: OperationalMemoryRecord,\n): Record<string, unknown> {\n const fields = provider.fields\n const cells: Record<string, unknown> = {\n [fields.key]: record.key,\n [fields.scopeId]: record.scopeId,\n [fields.kind]: record.kind,\n [fields.subjectId]: record.subjectId,\n [fields.summary]: record.summary,\n [fields.sourceRefs]: stableStringify(record.sourceRefs),\n [fields.recordedAt]: record.recordedAt,\n [fields.confidence]: record.confidence,\n [fields.attributes]: stableStringify(record.attributes),\n }\n if (record.occurredAt) cells[fields.occurredAt] = record.occurredAt\n return cells\n}\n\nfunction compareCells(\n provider: OperationalMemoryProvider,\n expected: Record<string, unknown>,\n actualValue: unknown,\n): string[] {\n if (!actualValue || typeof actualValue !== 'object' || Array.isArray(actualValue)) {\n return ['cells:missing']\n }\n const actual = actualValue as Record<string, unknown>\n const mismatches: string[] = []\n for (const [name, fieldId] of Object.entries(provider.fields)) {\n const wanted = expected[fieldId]\n const seen = normalizeCell(actual[fieldId])\n if (name === 'confidence') {\n if (Number(seen) !== Number(wanted)) mismatches.push(name)\n } else if (name === 'occurredAt' || name === 'recordedAt') {\n if (!sameTimeOrText(seen, wanted)) mismatches.push(name)\n } else if (String(seen ?? '') !== String(wanted ?? '')) mismatches.push(name)\n }\n return mismatches\n}\n\nfunction normalizeCell(value: unknown): unknown {\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n const item = value as Record<string, unknown>\n return item.name ?? item.text ?? item.value ?? value\n }\n return value\n}\n\nfunction sameTimeOrText(actual: unknown, expected: unknown): boolean {\n const left = String(actual ?? '')\n const right = String(expected ?? '')\n if (!left || !right) return left === right\n const leftTime = Date.parse(left)\n const rightTime = Date.parse(right)\n return Number.isFinite(leftTime) && Number.isFinite(rightTime)\n ? leftTime === rightTime : left === right\n}\n\nfunction findValue(value: unknown, keys: string[]): unknown {\n if (!value || typeof value !== 'object') return null\n for (const [key, child] of Object.entries(value)) {\n if (keys.includes(key) && child !== undefined && child !== null && child !== '') return child\n }\n for (const child of Object.values(value)) {\n const found = findValue(child, keys)\n if (found !== null) return found\n }\n return null\n}\n\nfunction validTime(value: unknown): string | null {\n if (typeof value !== 'string' || !value.trim() || !Number.isFinite(Date.parse(value))) return null\n return new Date(value).toISOString()\n}\n\nfunction clean(value: unknown): string {\n return typeof value === 'string' ? value.trim() : ''\n}\n\n/**\n * bounded-filter 读的完整性守卫:unique-key 合同下「窗口未打满」可用;window-full\n * (可能被静默截断)与 records-null(截断/软超时信号)都属「读没读全存疑」——\n * 此时把空结果当「不存在」会直接造出重复记录,必须响亮地停。\n */\nfunction assertBoundedLookup(read: dws.CompletenessRead, label: string): void {\n if (read.completeness.proven) return\n if (read.completeness.reason === 'window-full') {\n throw new Error(`${label}:命中打满查询窗口,可能被静默截断——读没读全存疑,拒绝继续`)\n }\n if (read.completeness.reason === 'records-null') {\n throw new Error(`${label}:records:null(截断/软超时信号)——不是空表,重读后再继续`)\n }\n}\n"]}
@@ -273,12 +273,13 @@ function readRemoteDocument(uri, profile, slot) {
273
273
  }
274
274
  function readStructuredHotState(provider) {
275
275
  const layer = provider.layers.l2;
276
+ // recordId 有界读 → completeness proven('record-ids');行数与 recordId 由本合同校验。
276
277
  const rows = dws.queryAiTableRecords({
277
278
  baseId: layer.baseId,
278
279
  tableId: layer.tableId,
279
280
  recordIds: [layer.recordId],
280
281
  profile: provider.authority.profile,
281
- });
282
+ }).records;
282
283
  if (rows.length !== 1 || clean(rows[0]?.recordId) !== layer.recordId) {
283
284
  throw new Error(`Remote Semantic State l2 recordId=${layer.recordId} 必须精确回读一条记录`);
284
285
  }