@xdxer/dingtalk-agent 0.1.4-beta.8 → 0.1.4

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 (254) hide show
  1. package/CHANGELOG.md +233 -0
  2. package/README.en.md +167 -0
  3. package/README.md +101 -248
  4. package/dist/bin/dingtalk-agent.js +1255 -25
  5. package/dist/bin/dingtalk-agent.js.map +1 -1
  6. package/dist/src/actions.js +98 -14
  7. package/dist/src/actions.js.map +1 -1
  8. package/dist/src/agent-audit.js +1385 -0
  9. package/dist/src/agent-audit.js.map +1 -0
  10. package/dist/src/agent-bindings.js +132 -0
  11. package/dist/src/agent-bindings.js.map +1 -0
  12. package/dist/src/agent-definition.js +182 -0
  13. package/dist/src/agent-definition.js.map +1 -0
  14. package/dist/src/agent-enhance.js +711 -0
  15. package/dist/src/agent-enhance.js.map +1 -0
  16. package/dist/src/agent-platform.js +299 -0
  17. package/dist/src/agent-platform.js.map +1 -0
  18. package/dist/src/bootstrap.js +125 -17
  19. package/dist/src/bootstrap.js.map +1 -1
  20. package/dist/src/config.js +1 -7
  21. package/dist/src/config.js.map +1 -1
  22. package/dist/src/development-workspace.js +755 -0
  23. package/dist/src/development-workspace.js.map +1 -0
  24. package/dist/src/doctor.js +74 -15
  25. package/dist/src/doctor.js.map +1 -1
  26. package/dist/src/dws.js +145 -0
  27. package/dist/src/dws.js.map +1 -1
  28. package/dist/src/eval-evidence.js +193 -0
  29. package/dist/src/eval-evidence.js.map +1 -0
  30. package/dist/src/host-detect.js +146 -0
  31. package/dist/src/host-detect.js.map +1 -0
  32. package/dist/src/instruction-path.js +270 -0
  33. package/dist/src/instruction-path.js.map +1 -0
  34. package/dist/src/invocation.js +36 -0
  35. package/dist/src/invocation.js.map +1 -0
  36. package/dist/src/lab.js +679 -0
  37. package/dist/src/lab.js.map +1 -0
  38. package/dist/src/lease.js +100 -0
  39. package/dist/src/lease.js.map +1 -0
  40. package/dist/src/map.js +157 -0
  41. package/dist/src/map.js.map +1 -0
  42. package/dist/src/memory/candidates.js +451 -0
  43. package/dist/src/memory/candidates.js.map +1 -0
  44. package/dist/src/memory/completion-evidence.js +536 -0
  45. package/dist/src/memory/completion-evidence.js.map +1 -0
  46. package/dist/src/memory/operational.js +263 -0
  47. package/dist/src/memory/operational.js.map +1 -0
  48. package/dist/src/memory/remote-state.js +478 -0
  49. package/dist/src/memory/remote-state.js.map +1 -0
  50. package/dist/src/memory/task-checkpoints.js +204 -0
  51. package/dist/src/memory/task-checkpoints.js.map +1 -0
  52. package/dist/src/multica-deploy.js +1538 -0
  53. package/dist/src/multica-deploy.js.map +1 -0
  54. package/dist/src/multica-provider.js +685 -0
  55. package/dist/src/multica-provider.js.map +1 -0
  56. package/dist/src/opencode-evals.js +1547 -0
  57. package/dist/src/opencode-evals.js.map +1 -0
  58. package/dist/src/opencode-isolation.js +124 -0
  59. package/dist/src/opencode-isolation.js.map +1 -0
  60. package/dist/src/opencode-provider.js +532 -0
  61. package/dist/src/opencode-provider.js.map +1 -0
  62. package/dist/src/opencode-workspace.js +208 -0
  63. package/dist/src/opencode-workspace.js.map +1 -0
  64. package/dist/src/perception.js +225 -0
  65. package/dist/src/perception.js.map +1 -0
  66. package/dist/src/personal-event-evals.js +595 -0
  67. package/dist/src/personal-event-evals.js.map +1 -0
  68. package/dist/src/promotion.js +786 -0
  69. package/dist/src/promotion.js.map +1 -0
  70. package/dist/src/remote-semantic-state-live-evals.js +888 -0
  71. package/dist/src/remote-semantic-state-live-evals.js.map +1 -0
  72. package/dist/src/remote-semantic-state-worker.js +38 -0
  73. package/dist/src/remote-semantic-state-worker.js.map +1 -0
  74. package/dist/src/remote-state-evals.js +502 -0
  75. package/dist/src/remote-state-evals.js.map +1 -0
  76. package/dist/src/response-gate.js +51 -0
  77. package/dist/src/response-gate.js.map +1 -0
  78. package/dist/src/robot-evals.js +771 -0
  79. package/dist/src/robot-evals.js.map +1 -0
  80. package/dist/src/sessions.js +66 -105
  81. package/dist/src/sessions.js.map +1 -1
  82. package/dist/src/setup.js +6 -5
  83. package/dist/src/setup.js.map +1 -1
  84. package/dist/src/skill-manager.js +162 -24
  85. package/dist/src/skill-manager.js.map +1 -1
  86. package/dist/src/skills.js +2 -1
  87. package/dist/src/skills.js.map +1 -1
  88. package/dist/src/storage-evals.js +26 -0
  89. package/dist/src/storage-evals.js.map +1 -0
  90. package/dist/src/types.js.map +1 -1
  91. package/dist/src/upgrade.js +23 -27
  92. package/dist/src/upgrade.js.map +1 -1
  93. package/dist/src/version.js +73 -0
  94. package/dist/src/version.js.map +1 -0
  95. package/dist/src/waits.js +5 -1
  96. package/dist/src/waits.js.map +1 -1
  97. package/dist/src/workspace.js +28 -3
  98. package/dist/src/workspace.js.map +1 -1
  99. package/docs/INSTALLATION.md +50 -3
  100. package/docs/SECOND-AGENT-ACCEPTANCE.md +62 -0
  101. package/docs/architecture/agent-memory-topology.png +0 -0
  102. package/docs/architecture/agent-memory-topology.svg +132 -0
  103. package/docs/architecture/general-agent-kernel-topology.png +0 -0
  104. package/docs/architecture/general-agent-kernel-topology.svg +149 -0
  105. package/docs/architecture/provider-bound-development-workspace.png +0 -0
  106. package/docs/architecture/provider-bound-development-workspace.svg +141 -0
  107. package/docs/architecture/task-completion-gate.png +0 -0
  108. package/docs/architecture/task-completion-gate.svg +191 -0
  109. package/docs/assets/agent-delivery-lifecycle.svg +103 -0
  110. package/docs/schemas/agent-audit-load-evidence.schema.json +14 -0
  111. package/docs/schemas/agent-audit.schema.json +92 -0
  112. package/docs/schemas/agent-bindings.schema.json +54 -0
  113. package/docs/schemas/agent-definition.schema.json +78 -0
  114. package/docs/schemas/agent-enhancement-plan.schema.json +88 -0
  115. package/docs/schemas/agent-enhancement-receipt.schema.json +37 -0
  116. package/docs/schemas/agent-platform.schema.json +13 -0
  117. package/docs/schemas/enriched-invocation.schema.json +46 -0
  118. package/docs/schemas/eval-candidate-plan.schema.json +28 -0
  119. package/docs/schemas/eval-candidate-result.schema.json +20 -0
  120. package/docs/schemas/eval-candidate.schema.json +30 -0
  121. package/docs/schemas/invocation.schema.json +19 -0
  122. package/docs/schemas/memory-candidate-proposal.schema.json +18 -0
  123. package/docs/schemas/memory-candidate.schema.json +76 -0
  124. package/docs/schemas/memory-publish-target.schema.json +25 -0
  125. package/docs/schemas/multica-deployment-list.schema.json +29 -0
  126. package/docs/schemas/multica-deployment-operation.schema.json +51 -0
  127. package/docs/schemas/multica-deployment-plan.schema.json +70 -0
  128. package/docs/schemas/multica-deployment-receipt.schema.json +87 -0
  129. package/docs/schemas/multica-deployment-status.schema.json +23 -0
  130. package/docs/schemas/multica-workspace-inspection.schema.json +77 -0
  131. package/docs/schemas/multica-workspace-plan.schema.json +68 -0
  132. package/docs/schemas/multica-workspace-resource-list.schema.json +27 -0
  133. package/docs/schemas/multica-workspace-status.schema.json +34 -0
  134. package/docs/schemas/observation.schema.json +21 -0
  135. package/docs/schemas/operational-memory-provider.schema.json +36 -0
  136. package/docs/schemas/operational-memory-record.schema.json +24 -0
  137. package/docs/schemas/perception-input.schema.json +56 -0
  138. package/docs/schemas/project.schema.json +115 -0
  139. package/docs/schemas/promotion-list.schema.json +36 -0
  140. package/docs/schemas/promotion-plan.schema.json +60 -0
  141. package/docs/schemas/promotion-policy.schema.json +29 -0
  142. package/docs/schemas/promotion-receipt.schema.json +43 -0
  143. package/docs/schemas/promotion-status.schema.json +23 -0
  144. package/docs/schemas/release-readiness.schema.json +66 -0
  145. package/docs/schemas/remote-semantic-state-live-eval.schema.json +60 -0
  146. package/docs/schemas/remote-semantic-state-manifest.schema.json +79 -0
  147. package/docs/schemas/remote-semantic-state-provider.schema.json +98 -0
  148. package/docs/schemas/response-gate.schema.json +20 -0
  149. package/docs/schemas/task-checkpoint.schema.json +71 -0
  150. package/docs/schemas/task-completion-evidence.schema.json +154 -0
  151. package/docs/schemas/workspace-doctor.schema.json +56 -0
  152. package/docs/schemas/workspace-state.schema.json +39 -0
  153. package/evals/README.md +17 -0
  154. package/evals/baselines/2026-07-16/opencode-basic-010-completion-summary.json +123 -0
  155. package/evals/baselines/2026-07-16/opencode-basic-skill-required-summary.json +69 -0
  156. package/evals/baselines/2026-07-16/opencode-multi-surface-summary.json +63 -0
  157. package/evals/baselines/2026-07-16/remote-state-live-summary.json +70 -0
  158. package/evals/baselines/2026-07-17/agent-enhance-opencode-dogfood-summary.json +98 -0
  159. package/evals/baselines/2026-07-17/personal-event-live-readiness-summary.json +68 -0
  160. package/examples/agents/fde-coach/AGENTS.md +26 -0
  161. package/examples/agents/fde-coach/MEMORY.md +3 -0
  162. package/examples/agents/fde-coach/fields/default/field.json +24 -0
  163. package/examples/agents/fde-coach/knowledge/INDEX.md +4 -0
  164. package/examples/agents/fde-coach/skills/fde-coach/SKILL.md +13 -0
  165. package/examples/agents/release-manager/AGENTS.md +26 -0
  166. package/examples/agents/release-manager/MEMORY.md +3 -0
  167. package/examples/agents/release-manager/fields/default/field.json +24 -0
  168. package/examples/agents/release-manager/knowledge/INDEX.md +4 -0
  169. package/examples/agents/release-manager/skills/release-manager/SKILL.md +13 -0
  170. package/lab/README.md +109 -0
  171. package/lab/agent-eval/catalog.json +91 -0
  172. package/lab/agent-eval/classic-failures.json +177 -0
  173. package/lab/agent-eval/completion-gate-regression.json +99 -0
  174. package/lab/agent-eval/personal-event-live.example.json +94 -0
  175. package/lab/agent-eval/remote-semantic-state-live.example.json +70 -0
  176. package/lab/agent-eval/remote-semantic-state-provider.fixture.json +47 -0
  177. package/lab/agent-eval/remote-state-workspace/AGENTS.md +8 -0
  178. package/lab/agent-eval/remote-state-workspace/opencode.json +7 -0
  179. package/lab/agent-eval/remote-state-workspace/skills/remote-state-operator/SKILL.md +13 -0
  180. package/lab/agent-eval/remote-state.example.json +31 -0
  181. package/lab/agent-eval/workspace/AGENTS.md +7 -0
  182. package/lab/agent-eval/workspace/MEMORY.md +4 -0
  183. package/lab/agent-eval/workspace/artifacts/pending-review.md +3 -0
  184. package/lab/agent-eval/workspace/knowledge/INDEX.md +4 -0
  185. package/lab/agent-eval/workspace/opencode.json +20 -0
  186. package/lab/manifest.example.json +27 -0
  187. package/lab/manifest.personal-event.example.json +27 -0
  188. package/lab/project-workspace/README.md +11 -0
  189. package/lab/project-workspace/fake-multica-provider.mjs +277 -0
  190. package/lab/project-workspace/multica-deploy.fixture.json +29 -0
  191. package/lab/project-workspace/multica-readonly.fixture.json +69 -0
  192. package/lab/project-workspace/observation.fixture.json +14 -0
  193. package/lab/project-workspace/opencode-provider-suite.json +65 -0
  194. package/lab/project-workspace/project.fixture.json +44 -0
  195. package/lab/project-workspace/promotion-policy.fixture.json +15 -0
  196. package/lab/robot-eval/pool.example.json +30 -0
  197. package/lab/robot-eval/suite.json +123 -0
  198. package/lab/robot-eval/workspace/AGENTS.md +21 -0
  199. package/lab/robot-eval/workspace/MEMORY.md +3 -0
  200. package/lab/robot-eval/workspace/knowledge/INDEX.md +5 -0
  201. package/lab/robot-eval/workspace/opencode.json +22 -0
  202. package/lab/schemas/agent-eval-catalog.schema.json +47 -0
  203. package/lab/schemas/lab-manifest.schema.json +70 -0
  204. package/lab/schemas/personal-event-eval.schema.json +91 -0
  205. package/lab/schemas/remote-state-eval.schema.json +66 -0
  206. package/lab/schemas/robot-eval-suite.schema.json +184 -0
  207. package/lab/schemas/robot-pool.schema.json +56 -0
  208. package/package.json +28 -9
  209. package/skills/README.md +23 -0
  210. package/skills/core/dingtalk-agent-compose/SKILL.md +151 -0
  211. package/skills/core/dingtalk-agent-compose/assets/AGENTS.template.md +35 -0
  212. package/skills/core/dingtalk-agent-compose/assets/agent.bindings.dingtalk-doc.template.json +13 -0
  213. package/skills/core/dingtalk-agent-compose/assets/agent.bindings.local.template.json +13 -0
  214. package/skills/core/dingtalk-agent-compose/assets/hosts/opencode/opencode.template.json +12 -0
  215. package/skills/core/dingtalk-agent-compose/assets/role-skill.template.md +32 -0
  216. package/skills/core/dingtalk-agent-compose/evals/evals.json +129 -0
  217. package/skills/core/dingtalk-agent-compose/references/agent-definition-contract.md +55 -0
  218. package/skills/core/dingtalk-agent-compose/references/host-loading-contract.md +58 -0
  219. package/skills/core/dingtalk-agent-compose/references/hosts/claude-code.md +48 -0
  220. package/skills/core/dingtalk-agent-compose/references/hosts/opencode.md +77 -0
  221. package/skills/core/dingtalk-agent-compose/references/storage-routing.md +20 -0
  222. package/skills/core/dingtalk-agent-eval/SKILL.md +140 -0
  223. package/skills/core/dingtalk-agent-eval/assets/eval-catalog.template.json +18 -0
  224. package/skills/core/dingtalk-agent-eval/evals/evals.json +83 -0
  225. package/skills/core/dingtalk-agent-eval/references/eval-topology.md +48 -0
  226. package/skills/core/dingtalk-agent-eval/references/evidence-contract.md +52 -0
  227. package/skills/core/dingtalk-agent-eval/references/failure-to-case.md +35 -0
  228. package/skills/core/dingtalk-agent-eval/references/interactive-debug-channels.md +93 -0
  229. package/skills/core/dingtalk-agent-eval/references/local-connector-smoke.md +75 -0
  230. package/skills/core/dingtalk-agent-eval/references/scenario-taxonomy.md +25 -0
  231. package/skills/core/dingtalk-agent-eval/references/storage-modes.md +75 -0
  232. package/skills/core/dingtalk-basic-behavior/SKILL.md +87 -0
  233. package/skills/core/dingtalk-basic-behavior/assets/memory-candidate-proposal.json +10 -0
  234. package/skills/{dingtalk-basic-behavior/assets/task-checkpoint.md → core/dingtalk-basic-behavior/assets/task-checkpoint.json} +2 -21
  235. package/skills/{dingtalk-basic-behavior → core/dingtalk-basic-behavior}/references/action-contract.md +2 -0
  236. package/skills/core/dingtalk-basic-behavior/references/memory-and-evolution.md +53 -0
  237. package/skills/core/dingtalk-basic-behavior/references/perception-and-gates.md +28 -0
  238. package/skills/core/dingtalk-basic-behavior/references/risk-authority-and-privacy.md +62 -0
  239. package/skills/{dingtalk-basic-behavior → core/dingtalk-basic-behavior}/references/task-lifecycle.md +47 -10
  240. package/skills/core/dingtalk-basic-behavior/references/truth-and-recovery.md +65 -0
  241. package/skills/platforms/deap/PLATFORM.md +3 -0
  242. package/skills/platforms/deap/README.md +3 -0
  243. package/skills/platforms/multica-dingtalk/PLATFORM.md +40 -0
  244. package/skills/platforms/multica-dingtalk/dingtalk-agent-boot-multica/SKILL.md +40 -0
  245. package/skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica/SKILL.md +60 -0
  246. package/skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica/references/multica-deployment-contract.md +49 -0
  247. package/skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica/references/promotion-observation-contract.md +49 -0
  248. package/skills/platforms/multica-dingtalk/multica-external/SKILL.md +282 -0
  249. package/skills/platforms/multica-dingtalk/multica-external/scripts/bootstrap.sh +78 -0
  250. package/skills/platforms/multica-dingtalk/multica-external/scripts/multica_ext.py +1180 -0
  251. package/skills/dingtalk-basic-behavior/SKILL.md +0 -86
  252. package/skills/dingtalk-basic-behavior/references/memory-and-evolution.md +0 -27
  253. /package/skills/{dingtalk-basic-behavior → core/dingtalk-basic-behavior}/references/event-to-behavior.md +0 -0
  254. /package/skills/{dingtalk-basic-behavior → core/dingtalk-basic-behavior}/references/runtime-modes.md +0 -0
@@ -1,6 +1,6 @@
1
1
  // Agent Workspace:一个物理目录对应一个稳定 Context/Field。
2
2
  // 人和模型读取 Markdown;机器控制状态仍留在宿主私有 JSON 中。
3
- import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync, } from 'node:fs';
3
+ import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync, } from 'node:fs';
4
4
  import { basename, dirname, join, relative, resolve } from 'node:path';
5
5
  import { digest } from './events.js';
6
6
  import * as dws from './dws.js';
@@ -27,9 +27,10 @@ export function ensureWorkspace(root, options = {}) {
27
27
  dws: { profile: '', expectedUserId: '' },
28
28
  // 用 Skill name 声明,不把 Workspace 绑死到某个物理安装目录。
29
29
  // Resolver 依次查 Workspace override、全局安装和 npm 内置版本。
30
- skills: ['dingtalk-basic-behavior'],
30
+ skills: ['dingtalk-basic-behavior', ...discoverLocalSkillNames(root)],
31
31
  mounts: {
32
- profile: 'local-md:WORKSPACE.md',
32
+ profile: existsSync(join(root, 'AGENTS.md'))
33
+ ? 'local-md:AGENTS.md' : 'local-md:WORKSPACE.md',
33
34
  memory: options.memory || 'local-md:MEMORY.md',
34
35
  knowledge: options.knowledge || 'local-md:knowledge/INDEX.md',
35
36
  skills: 'local-dir:skills',
@@ -167,6 +168,30 @@ function writeDefaultMarkdown(root, spec) {
167
168
  function safeName(value) {
168
169
  return value.replace(/[^a-zA-Z0-9._-]+/g, '-');
169
170
  }
171
+ function discoverLocalSkillNames(root) {
172
+ const directory = join(root, 'skills');
173
+ if (!existsSync(directory) || !lstatSync(directory).isDirectory())
174
+ return [];
175
+ const names = [];
176
+ for (const entry of readdirSync(directory, { withFileTypes: true })) {
177
+ if (!entry.isDirectory())
178
+ continue;
179
+ const path = join(directory, entry.name, 'SKILL.md');
180
+ if (!existsSync(path))
181
+ continue;
182
+ const markdown = readFileSync(path, 'utf8');
183
+ const frontmatter = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1] || '';
184
+ const name = frontmatter.match(/^name:\s*['"]?([^'"\r\n]+)['"]?\s*$/m)?.[1]?.trim() || '';
185
+ if (!name)
186
+ throw new Error(`本地 Role Skill 缺少 frontmatter name: ${path}`);
187
+ if (name !== entry.name) {
188
+ throw new Error(`本地 Role Skill 目录名与 name 不一致: ${entry.name} != ${name}`);
189
+ }
190
+ if (name !== 'dingtalk-basic-behavior')
191
+ names.push(name);
192
+ }
193
+ return [...new Set(names)].sort();
194
+ }
170
195
  function clean(value) {
171
196
  return typeof value === 'string' ? value.trim() : '';
172
197
  }
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/workspace.ts"],"names":[],"mappings":"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","sourcesContent":["// Agent Workspace:一个物理目录对应一个稳定 Context/Field。\n// 人和模型读取 Markdown;机器控制状态仍留在宿主私有 JSON 中。\n\nimport {\n existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync,\n} from 'node:fs'\nimport { basename, dirname, join, relative, resolve } from 'node:path'\nimport { digest } from './events.js'\nimport * as dws from './dws.js'\n\nexport const WORKSPACE_FILE = '.dingtalk-agent/workspace.json'\n\nexport interface WorkspaceSpec {\n $schema: 'dingtalk-agent/workspace@1'\n id: string\n contextId: string\n fieldId: string\n dws: { profile: string; expectedUserId: string }\n skills: string[]\n mounts: Record<'profile' | 'memory' | 'knowledge' | 'skills', string>\n}\n\nexport interface WorkspaceInitOptions {\n contextId?: string\n id?: string\n memory?: string\n knowledge?: string\n}\n\nexport interface MountSnapshot {\n slot: string\n provider: 'local-md' | 'local-dir' | 'dingtalk-doc'\n source: string\n snapshotPath: string\n hash: string\n}\n\nexport function workspacePath(root: string): string {\n return join(root, WORKSPACE_FILE)\n}\n\nexport function ensureWorkspace(\n root: string,\n options: WorkspaceInitOptions = {},\n): WorkspaceSpec {\n const path = workspacePath(root)\n if (existsSync(path)) {\n const current = loadWorkspace(root)\n if (options.contextId && options.contextId !== current.contextId) {\n throw new Error(\n `当前目录已绑定 contextId=${current.contextId};一个物理 Workspace 不能重新绑定为 ${options.contextId}`,\n )\n }\n return current\n }\n\n const contextId = clean(options.contextId || basename(resolve(root)) || 'default')\n const id = clean(options.id || contextId)\n const spec: WorkspaceSpec = {\n $schema: 'dingtalk-agent/workspace@1',\n id,\n contextId,\n fieldId: 'default',\n dws: { profile: '', expectedUserId: '' },\n // 用 Skill name 声明,不把 Workspace 绑死到某个物理安装目录。\n // Resolver 依次查 Workspace override、全局安装和 npm 内置版本。\n skills: ['dingtalk-basic-behavior'],\n mounts: {\n profile: 'local-md:WORKSPACE.md',\n memory: options.memory || 'local-md:MEMORY.md',\n knowledge: options.knowledge || 'local-md:knowledge/INDEX.md',\n skills: 'local-dir:skills',\n },\n }\n\n mkdirSync(dirname(path), { recursive: true })\n writeFileSync(path, JSON.stringify(spec, null, 2) + '\\n', { flag: 'wx' })\n writeDefaultMarkdown(root, spec)\n for (const dir of ['.dingtalk-agent/cache', '.dingtalk-agent/pending']) {\n mkdirSync(join(root, dir), { recursive: true })\n }\n return spec\n}\n\nexport function loadWorkspace(root: string): WorkspaceSpec {\n const path = workspacePath(root)\n if (!existsSync(path)) {\n throw new Error(\n '缺少 .dingtalk-agent/workspace.json;只有 Prepared Run runtime 才需要 `dingtalk-agent init`。' +\n '普通 Agent Session 请使用全局 Skill,按需运行 `dingtalk-agent bootstrap`。',\n )\n }\n let value: unknown\n try { value = JSON.parse(readFileSync(path, 'utf8')) }\n catch (error) { throw new Error(`Workspace manifest 不是合法 JSON: ${error.message}`) }\n return validateWorkspace(value)\n}\n\nexport function resolveContextId(spec: WorkspaceSpec, supplied = ''): string {\n const contextId = clean(supplied || spec.contextId)\n if (contextId !== spec.contextId) {\n throw new Error(\n `contextId=${contextId} 不属于当前 Workspace(期望 ${spec.contextId});请由上游选择正确工作目录`,\n )\n }\n return contextId\n}\n\n/**\n * Provider 只负责把语义内容冻结成本地 Markdown;锁、Wait、去重和 Receipt 不走这里。\n * dingtalk-doc 只读显式 node,不搜索、不创建、不覆盖。\n */\nexport function snapshotWorkspaceMounts(\n root: string,\n runPath: string,\n spec: WorkspaceSpec,\n): MountSnapshot[] {\n const destination = join(runPath, 'context', 'mounts')\n mkdirSync(destination, { recursive: true })\n const snapshots: MountSnapshot[] = []\n\n for (const [slot, uri] of Object.entries(spec.mounts)) {\n const mount = parseMount(uri)\n if (mount.provider === 'local-dir') {\n // skills 是逻辑槽:实际内容由 Skill resolver 从 Workspace override、\n // 全局目录或 npm 内置版本解析并在 Session 创建时冻结。\n if (slot !== 'skills') safeLocalPath(root, mount.ref)\n snapshots.push({\n slot, provider: mount.provider, source: uri,\n // P0 的目录型 mount 只有 skills;真实内容由 Session 绑定并冻结到这里。\n snapshotPath: slot === 'skills' ? 'context/skills' : '', hash: '',\n })\n continue\n }\n\n const markdown = mount.provider === 'local-md'\n ? readFileSync(safeLocalPath(root, mount.ref), 'utf8')\n : String(dws.readDoc(mount.ref, spec.dws.profile))\n const path = join(destination, `${safeName(slot)}.md`)\n writeFileSync(path, markdown.endsWith('\\n') ? markdown : markdown + '\\n')\n snapshots.push({\n slot,\n provider: mount.provider,\n source: uri,\n snapshotPath: relative(runPath, path).split('\\\\').join('/'),\n hash: digest(markdown),\n })\n }\n\n writeFileSync(\n join(destination, 'manifest.json'),\n JSON.stringify({ $schema: 'dingtalk-agent/mount-snapshot@1', entries: snapshots }, null, 2) + '\\n',\n )\n return snapshots\n}\n\nfunction validateWorkspace(value: unknown): WorkspaceSpec {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Workspace manifest 必须是 JSON object')\n }\n const input = value as Record<string, any>\n if (input.$schema !== 'dingtalk-agent/workspace@1') {\n throw new Error('Workspace manifest 缺少 dingtalk-agent/workspace@1 schema')\n }\n for (const key of ['id', 'contextId', 'fieldId']) {\n if (!clean(input[key])) throw new Error(`Workspace manifest 缺少 ${key}`)\n }\n if (!Array.isArray(input.skills) || input.skills.some((item: unknown) => typeof item !== 'string')) {\n throw new Error('Workspace skills 必须是 string[]')\n }\n if (!input.dws || typeof input.dws.profile !== 'string' ||\n typeof input.dws.expectedUserId !== 'string') {\n throw new Error('Workspace dws 必须包含 string profile / expectedUserId')\n }\n const requiredSlots = ['profile', 'memory', 'knowledge', 'skills']\n if (!input.mounts || requiredSlots.some((slot) => typeof input.mounts[slot] !== 'string')) {\n throw new Error(`Workspace mounts 必须包含 ${requiredSlots.join(' / ')}`)\n }\n for (const uri of Object.values(input.mounts)) parseMount(String(uri))\n return input as WorkspaceSpec\n}\n\nfunction parseMount(uri: string): {\n provider: 'local-md' | 'local-dir' | 'dingtalk-doc'\n ref: string\n} {\n const separator = uri.indexOf(':')\n const provider = uri.slice(0, separator)\n const ref = separator >= 0 ? uri.slice(separator + 1).trim() : ''\n if (!['local-md', 'local-dir', 'dingtalk-doc'].includes(provider) || !ref) {\n throw new Error(`不支持的 Workspace mount: ${uri}`)\n }\n return { provider: provider as 'local-md' | 'local-dir' | 'dingtalk-doc', ref }\n}\n\nfunction safeLocalPath(root: string, ref: string): string {\n const rootReal = realpathSync(resolve(root))\n const candidate = resolve(rootReal, ref)\n if (!existsSync(candidate)) throw new Error(`Workspace mount 不存在: ${ref}`)\n const actual = realpathSync(candidate)\n const rel = relative(rootReal, actual)\n if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\\\' : '/'}`)) {\n throw new Error(`Workspace local mount 必须位于当前目录内: ${ref}`)\n }\n return actual\n}\n\nfunction writeDefaultMarkdown(root: string, spec: WorkspaceSpec): void {\n const files: Array<[string, string]> = [\n ['WORKSPACE.md', `# Agent Workspace\\n\\n- Context ID: ${spec.contextId}\\n- Workspace: ${spec.id}\\n- Field: ${spec.fieldId}\\n\\n这里定义稳定的身份、职责、协作边界和内容挂载。\\n`],\n ['MEMORY.md', '# Long-term Memory\\n\\n只保存经过筛选、带来源的长期记忆。当前事项放在 Session memory。\\n'],\n ['knowledge/INDEX.md', '# Knowledge Index\\n\\n按需列出本 Workspace 可用的知识入口。\\n'],\n ]\n for (const [rel, content] of files) {\n const path = join(root, rel)\n mkdirSync(dirname(path), { recursive: true })\n if (!existsSync(path)) writeFileSync(path, content)\n }\n}\n\nfunction safeName(value: string): string {\n return value.replace(/[^a-zA-Z0-9._-]+/g, '-')\n}\n\nfunction clean(value: unknown): string {\n return typeof value === 'string' ? value.trim() : ''\n}\n"]}
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/workspace.ts"],"names":[],"mappings":"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","sourcesContent":["// Agent Workspace:一个物理目录对应一个稳定 Context/Field。\n// 人和模型读取 Markdown;机器控制状态仍留在宿主私有 JSON 中。\n\nimport {\n existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync,\n} from 'node:fs'\nimport { basename, dirname, join, relative, resolve } from 'node:path'\nimport { digest } from './events.js'\nimport * as dws from './dws.js'\n\nexport const WORKSPACE_FILE = '.dingtalk-agent/workspace.json'\n\nexport interface WorkspaceSpec {\n $schema: 'dingtalk-agent/workspace@1'\n id: string\n contextId: string\n fieldId: string\n dws: { profile: string; expectedUserId: string }\n skills: string[]\n mounts: Record<'profile' | 'memory' | 'knowledge' | 'skills', string>\n}\n\nexport interface WorkspaceInitOptions {\n contextId?: string\n id?: string\n memory?: string\n knowledge?: string\n}\n\nexport interface MountSnapshot {\n slot: string\n provider: 'local-md' | 'local-dir' | 'dingtalk-doc'\n source: string\n snapshotPath: string\n hash: string\n}\n\nexport function workspacePath(root: string): string {\n return join(root, WORKSPACE_FILE)\n}\n\nexport function ensureWorkspace(\n root: string,\n options: WorkspaceInitOptions = {},\n): WorkspaceSpec {\n const path = workspacePath(root)\n if (existsSync(path)) {\n const current = loadWorkspace(root)\n if (options.contextId && options.contextId !== current.contextId) {\n throw new Error(\n `当前目录已绑定 contextId=${current.contextId};一个物理 Workspace 不能重新绑定为 ${options.contextId}`,\n )\n }\n return current\n }\n\n const contextId = clean(options.contextId || basename(resolve(root)) || 'default')\n const id = clean(options.id || contextId)\n const spec: WorkspaceSpec = {\n $schema: 'dingtalk-agent/workspace@1',\n id,\n contextId,\n fieldId: 'default',\n dws: { profile: '', expectedUserId: '' },\n // 用 Skill name 声明,不把 Workspace 绑死到某个物理安装目录。\n // Resolver 依次查 Workspace override、全局安装和 npm 内置版本。\n skills: ['dingtalk-basic-behavior', ...discoverLocalSkillNames(root)],\n mounts: {\n profile: existsSync(join(root, 'AGENTS.md'))\n ? 'local-md:AGENTS.md' : 'local-md:WORKSPACE.md',\n memory: options.memory || 'local-md:MEMORY.md',\n knowledge: options.knowledge || 'local-md:knowledge/INDEX.md',\n skills: 'local-dir:skills',\n },\n }\n\n mkdirSync(dirname(path), { recursive: true })\n writeFileSync(path, JSON.stringify(spec, null, 2) + '\\n', { flag: 'wx' })\n writeDefaultMarkdown(root, spec)\n for (const dir of ['.dingtalk-agent/cache', '.dingtalk-agent/pending']) {\n mkdirSync(join(root, dir), { recursive: true })\n }\n return spec\n}\n\nexport function loadWorkspace(root: string): WorkspaceSpec {\n const path = workspacePath(root)\n if (!existsSync(path)) {\n throw new Error(\n '缺少 .dingtalk-agent/workspace.json;只有 Prepared Run runtime 才需要 `dingtalk-agent init`。' +\n '普通 Agent Session 请使用全局 Skill,按需运行 `dingtalk-agent bootstrap`。',\n )\n }\n let value: unknown\n try { value = JSON.parse(readFileSync(path, 'utf8')) }\n catch (error) { throw new Error(`Workspace manifest 不是合法 JSON: ${error.message}`) }\n return validateWorkspace(value)\n}\n\nexport function resolveContextId(spec: WorkspaceSpec, supplied = ''): string {\n const contextId = clean(supplied || spec.contextId)\n if (contextId !== spec.contextId) {\n throw new Error(\n `contextId=${contextId} 不属于当前 Workspace(期望 ${spec.contextId});请由上游选择正确工作目录`,\n )\n }\n return contextId\n}\n\n/**\n * Provider 只负责把语义内容冻结成本地 Markdown;锁、Wait、去重和 Receipt 不走这里。\n * dingtalk-doc 只读显式 node,不搜索、不创建、不覆盖。\n */\nexport function snapshotWorkspaceMounts(\n root: string,\n runPath: string,\n spec: WorkspaceSpec,\n): MountSnapshot[] {\n const destination = join(runPath, 'context', 'mounts')\n mkdirSync(destination, { recursive: true })\n const snapshots: MountSnapshot[] = []\n\n for (const [slot, uri] of Object.entries(spec.mounts)) {\n const mount = parseMount(uri)\n if (mount.provider === 'local-dir') {\n // skills 是逻辑槽:实际内容由 Skill resolver 从 Workspace override、\n // 全局目录或 npm 内置版本解析并在 Session 创建时冻结。\n if (slot !== 'skills') safeLocalPath(root, mount.ref)\n snapshots.push({\n slot, provider: mount.provider, source: uri,\n // P0 的目录型 mount 只有 skills;真实内容由 Session 绑定并冻结到这里。\n snapshotPath: slot === 'skills' ? 'context/skills' : '', hash: '',\n })\n continue\n }\n\n const markdown = mount.provider === 'local-md'\n ? readFileSync(safeLocalPath(root, mount.ref), 'utf8')\n : String(dws.readDoc(mount.ref, spec.dws.profile))\n const path = join(destination, `${safeName(slot)}.md`)\n writeFileSync(path, markdown.endsWith('\\n') ? markdown : markdown + '\\n')\n snapshots.push({\n slot,\n provider: mount.provider,\n source: uri,\n snapshotPath: relative(runPath, path).split('\\\\').join('/'),\n hash: digest(markdown),\n })\n }\n\n writeFileSync(\n join(destination, 'manifest.json'),\n JSON.stringify({ $schema: 'dingtalk-agent/mount-snapshot@1', entries: snapshots }, null, 2) + '\\n',\n )\n return snapshots\n}\n\nfunction validateWorkspace(value: unknown): WorkspaceSpec {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Workspace manifest 必须是 JSON object')\n }\n const input = value as Record<string, any>\n if (input.$schema !== 'dingtalk-agent/workspace@1') {\n throw new Error('Workspace manifest 缺少 dingtalk-agent/workspace@1 schema')\n }\n for (const key of ['id', 'contextId', 'fieldId']) {\n if (!clean(input[key])) throw new Error(`Workspace manifest 缺少 ${key}`)\n }\n if (!Array.isArray(input.skills) || input.skills.some((item: unknown) => typeof item !== 'string')) {\n throw new Error('Workspace skills 必须是 string[]')\n }\n if (!input.dws || typeof input.dws.profile !== 'string' ||\n typeof input.dws.expectedUserId !== 'string') {\n throw new Error('Workspace dws 必须包含 string profile / expectedUserId')\n }\n const requiredSlots = ['profile', 'memory', 'knowledge', 'skills']\n if (!input.mounts || requiredSlots.some((slot) => typeof input.mounts[slot] !== 'string')) {\n throw new Error(`Workspace mounts 必须包含 ${requiredSlots.join(' / ')}`)\n }\n for (const uri of Object.values(input.mounts)) parseMount(String(uri))\n return input as WorkspaceSpec\n}\n\nfunction parseMount(uri: string): {\n provider: 'local-md' | 'local-dir' | 'dingtalk-doc'\n ref: string\n} {\n const separator = uri.indexOf(':')\n const provider = uri.slice(0, separator)\n const ref = separator >= 0 ? uri.slice(separator + 1).trim() : ''\n if (!['local-md', 'local-dir', 'dingtalk-doc'].includes(provider) || !ref) {\n throw new Error(`不支持的 Workspace mount: ${uri}`)\n }\n return { provider: provider as 'local-md' | 'local-dir' | 'dingtalk-doc', ref }\n}\n\nfunction safeLocalPath(root: string, ref: string): string {\n const rootReal = realpathSync(resolve(root))\n const candidate = resolve(rootReal, ref)\n if (!existsSync(candidate)) throw new Error(`Workspace mount 不存在: ${ref}`)\n const actual = realpathSync(candidate)\n const rel = relative(rootReal, actual)\n if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\\\' : '/'}`)) {\n throw new Error(`Workspace local mount 必须位于当前目录内: ${ref}`)\n }\n return actual\n}\n\nfunction writeDefaultMarkdown(root: string, spec: WorkspaceSpec): void {\n const files: Array<[string, string]> = [\n ['WORKSPACE.md', `# Agent Workspace\\n\\n- Context ID: ${spec.contextId}\\n- Workspace: ${spec.id}\\n- Field: ${spec.fieldId}\\n\\n这里定义稳定的身份、职责、协作边界和内容挂载。\\n`],\n ['MEMORY.md', '# Long-term Memory\\n\\n只保存经过筛选、带来源的长期记忆。当前事项放在 Session memory。\\n'],\n ['knowledge/INDEX.md', '# Knowledge Index\\n\\n按需列出本 Workspace 可用的知识入口。\\n'],\n ]\n for (const [rel, content] of files) {\n const path = join(root, rel)\n mkdirSync(dirname(path), { recursive: true })\n if (!existsSync(path)) writeFileSync(path, content)\n }\n}\n\nfunction safeName(value: string): string {\n return value.replace(/[^a-zA-Z0-9._-]+/g, '-')\n}\n\nfunction discoverLocalSkillNames(root: string): string[] {\n const directory = join(root, 'skills')\n if (!existsSync(directory) || !lstatSync(directory).isDirectory()) return []\n const names: string[] = []\n for (const entry of readdirSync(directory, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue\n const path = join(directory, entry.name, 'SKILL.md')\n if (!existsSync(path)) continue\n const markdown = readFileSync(path, 'utf8')\n const frontmatter = markdown.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---/)?.[1] || ''\n const name = frontmatter.match(/^name:\\s*['\"]?([^'\"\\r\\n]+)['\"]?\\s*$/m)?.[1]?.trim() || ''\n if (!name) throw new Error(`本地 Role Skill 缺少 frontmatter name: ${path}`)\n if (name !== entry.name) {\n throw new Error(`本地 Role Skill 目录名与 name 不一致: ${entry.name} != ${name}`)\n }\n if (name !== 'dingtalk-basic-behavior') names.push(name)\n }\n return [...new Set(names)].sort()\n}\n\nfunction clean(value: unknown): string {\n return typeof value === 'string' ? value.trim() : ''\n}\n"]}
@@ -42,6 +42,25 @@ npm view 解析目标版本
42
42
 
43
43
  `--force` 可用于重装当前版本和修复损坏安装;`--json` 可供自动化宿主读取。CLI 升级成功但 DWS 等环境检查未 ready 时,不会把升级回滚成旧代码,而会返回退出码 2 和明确的复核命令。
44
44
 
45
+ ## 发布前隔离验收
46
+
47
+ 在 checkout 中准备 beta 候选时运行:
48
+
49
+ ```bash
50
+ npm run release:check
51
+ ```
52
+
53
+ 这不是 `npm pack --dry-run` 的别名。它会:
54
+
55
+ 1. 核对 `package.json` / `package-lock.json` / CLI 版本;
56
+ 2. 生成真实 tarball,检查必需运行时、Schema、Skill、fixture 和 baseline,拒绝 state/results/凭据路径;
57
+ 3. 用 `npm install --offline` 安装到全新 HOME/prefix;
58
+ 4. 使用合成 DWS 与 skills installer 执行 setup/doctor,确认 Basic 只有一份 canonical copy,Claude Code 为相对链接,Codex/OpenCode 共享 canonical;
59
+ 5. 从安装包运行 direct bootstrap 和 plan-only OpenCode eval;
60
+ 6. 从同一 tarball 强制重装,再生成上一 beta 的显式 rollback dry-run。
61
+
62
+ 验收不联系真实 DWS/Multica,不创建机器人或 Trigger,也不执行 Tag、GitHub Release 或 npm publish。这些操作必须在 Live 缺口处理并获得用户单独授权后执行。
63
+
45
64
  npm 全局命令会被链接到 `{prefix}/bin`,但不同 Node 版本管理器可能使用不同 prefix;包已经安装不代表该目录已进入当前 shell 的 PATH。因此固定使用 `~/.local` prefix,并用绝对路径启动一次 setup,由它幂等补齐后续 shell PATH。
46
65
 
47
66
  ## setup 做什么
@@ -50,7 +69,7 @@ npm 全局命令会被链接到 `{prefix}/bin`,但不同 Node 版本管理器
50
69
  npm install → dta setup
51
70
  → 安装当前版本到 ~/.local/bin
52
71
  → 检查并幂等补充 ~/.zshrc / ~/.bashrc PATH
53
- → 安装 canonical Basic Behavior Skill
72
+ → 安装 canonical 内置 Skill(Basic Behavior + Compose)
54
73
  → 暴露给 Claude Code,验证 Codex/OpenCode 共享发现
55
74
  → 检查 DWS 版本和认证
56
75
  → 给出唯一下一条命令
@@ -105,7 +124,7 @@ dws auth login
105
124
 
106
125
  ```bash
107
126
  npx --yes --registry=https://registry.npmjs.org --package=skills@latest -- skills add \
108
- <package>/skills/dingtalk-basic-behavior \
127
+ <package>/skills/core/dingtalk-basic-behavior \
109
128
  --global --yes --agent claude-code codex opencode
110
129
  ```
111
130
 
@@ -140,7 +159,7 @@ npx skills add D1-2004/dingtalk-agent \
140
159
  --agent claude-code --agent codex --agent opencode
141
160
 
142
161
  # 本地 checkout
143
- npx skills add ./skills/dingtalk-basic-behavior \
162
+ npx skills add ./skills/core/dingtalk-basic-behavior \
144
163
  --global --yes --agent claude-code --agent codex --agent opencode
145
164
  ```
146
165
 
@@ -173,6 +192,34 @@ dta prepare --event-file event.json --json
173
192
  - `2`:至少一个必要条件不满足,同时输出确定的修复命令;
174
193
  - `--json`:输出 `dingtalk-agent/doctor@1`,供安装器、CI 或宿主解析。
175
194
 
195
+ ## 开发者 Golden Path
196
+
197
+ 安装完成后,一个岗位 Agent 只需要三组输入:本地 `AGENTS.md`、本地 `skills/<role>/SKILL.md`,以及从 compose Skill 模板创建的 `agent.bindings.json`。本地模板把 memory/knowledge 指向 Markdown;远端模板只把这两个语义槽路由到专用钉钉文档,产物与控制状态仍留在 Agent 根目录。
198
+
199
+ ```bash
200
+ # 在 Agent 根目录
201
+ dta agent enhance --project-name <agent-name> \
202
+ --role-skill <role-skill-name> --dry-run --json
203
+
204
+ # 审阅 plan 后执行其 apply.command(当前 plan-id + 显式 yes)
205
+ dta agent enhance --project-name <agent-name> \
206
+ --role-skill <role-skill-name> \
207
+ --plan-id <current-plan-id> --yes --json
208
+
209
+ # 把 AGENTS.md 与 Role Skill 的模板占位符替换为真实岗位语义后
210
+ dta bootstrap --bindings agent.bindings.json --json
211
+ dta agent audit --bindings agent.bindings.json \
212
+ --require-skill <role-skill-name> --json
213
+
214
+ # 静态项修复后,证明 Basic Skill 在 OpenCode 中真正加载
215
+ dta agent audit --bindings agent.bindings.json \
216
+ --require-skill <role-skill-name> --verify-load --yes --json
217
+ ```
218
+
219
+ `agent enhance` 默认只生成计划,不写文件、不访问 DWS、也不创建 Trigger;apply 更新旧文件前把原值备份到 gitignored state 目录,并在 source/config 漂移时拒绝旧 plan-id。第一次 `agent audit` 默认不访问 DWS、不调用模型。它分别检查 Definition、本地文件/产物目录、Role Skill 真实语义、OpenCode Basic instruction/exposure 和已有证据,缺口用稳定 check ID 与修复动作返回;`partial` 的退出码是 2。`--verify-load --yes` 只增加隔离 OpenCode 评测,并生成与当前 Definition、bindings、配置和 Skill hash 绑定的 load evidence。
220
+
221
+ 远端 memory/knowledge 需要另跑授权的 `dta lab eval --engine storage`,再把其报告传给 `--remote-report`。审计不会用旧缓存替代 DWS 身份、类型、hash 和独立回读,也不会把远端文档升级为 Wait、Receipt、锁或凭据介质。
222
+
176
223
  ## 错误提示约定
177
224
 
178
225
  CLI 错误统一包含两层信息:
@@ -0,0 +1,62 @@
1
+ # 一小时复制第二个岗位 Agent
2
+
3
+ ## 结论
4
+
5
+ 第二个 Agent 不复制运行时,只复制一份 Agent kit 并替换四类绑定:`AGENTS.md`、Role Skills、Field/存储、DWS authority。事件监听不在本流程内;没有事件时 Agent 仍以 Direct/Mounted Session 正常工作,有可信事件时再进入同一个 Prepared Runtime。
6
+
7
+ 仓库提供两份已通过同一合同的实例:
8
+
9
+ - `examples/agents/fde-coach`:FDE 教练;
10
+ - `examples/agents/release-manager`:发布经理。
11
+
12
+ 两者共享 Basic Behavior、Invocation、Session/Run/Wait、双半闸门与 Receipt;Definition、Role Skill、Field、Session state、记忆和权限完全隔离。
13
+
14
+ ## 60 分钟执行表
15
+
16
+ | 时间 | 开发者动作 | 验收标准 |
17
+ |---|---|---|
18
+ | 0–10 分钟 | 复制任一 example,改目录名 | 原 example 不被覆盖,新目录不含 `.dingtalk-agent` |
19
+ | 10–20 分钟 | 改 `AGENTS.md` 的身份、服务对象、职责、交付与拒绝边界 | 另一个 Agent 能回答“我是谁、负责什么、不做什么” |
20
+ | 20–30 分钟 | 新建/改名 `skills/<role>/SKILL.md` | 目录名等于 frontmatter `name`;只含岗位方法,不重复基础行为 |
21
+ | 30–40 分钟 | 配置 Field、存储路由和 DWS authority | 使用可信 ID;不同 Agent 不共用 state root、业务 scope 或生产权限 |
22
+ | 40–50 分钟 | 先 `dta bootstrap --json`,需要 Prepared Run 时再显式 `dta init` | Direct 默认 ready/partial 可解释;init 采用 `AGENTS.md` 并发现 Role Skill |
23
+ | 50–60 分钟 | 跑合同/mock Lab,检查冻结快照和隔离 | 无可信 target 不外发;两个 Agent 的 Definition/Session/记忆/权限不串 |
24
+
25
+ ## 最小操作
26
+
27
+ ```bash
28
+ cp -R examples/agents/release-manager /path/to/my-agent
29
+ cd /path/to/my-agent
30
+
31
+ # 先验证本体;这一步不要求 Workspace,也不产生钉钉副作用
32
+ dta bootstrap --json
33
+
34
+ # 只有需要可信事件和 Prepared Run 时才初始化一次
35
+ dta init
36
+ dta bootstrap --json
37
+ ```
38
+
39
+ 首次 `init` 会优先采用已有 `AGENTS.md`,发现 `skills/*/SKILL.md`,并保留已有 `fields/default/field.json`。初始化后新增 Skill 不会自动热启用:离线评审后把 Skill name 加入 `.dingtalk-agent/workspace.json#skills`,由新 Session 重新冻结。
40
+
41
+ ## 自动化验收
42
+
43
+ ```bash
44
+ npm run typecheck
45
+ npm run eval:contract
46
+ ```
47
+
48
+ 合同 42 会从两份 example 分别创建临时 Workspace,并检查:
49
+
50
+ 1. 初始化前 Direct bootstrap 可工作且没有可信 target;
51
+ 2. 初始化后 `AGENTS.md`、Role Skill 与显式 Field 被正确采用;
52
+ 3. 两个 Definition、DWS profile、Session ID 不同,共享 Basic Behavior hash;
53
+ 4. FDE 的 Task Checkpoint 与 Memory Candidate 在发布经理 state root 中不可见;
54
+ 5. 两者都通过同一 fake-DWS Lab 的 Action/Receipt/平台回读合同。
55
+
56
+ 2026-07-16 本地基线为 42/42,通过;双 Agent 合同自动执行约 2–3 秒。这个数字证明模板化装配和隔离可自动验证,不代表真实账号、专用群、AI 表格和钉钉文档已接通。真实 L4 仍需为每个 Agent 提供专用测试对象、allowlist 和明确 `--live --yes` 授权。
57
+
58
+ ## 验收边界
59
+
60
+ - 通过:开发者只改本体、岗位 Skill、存储/Field/authority,即可得到第二个结构完整、状态隔离的 Agent;
61
+ - 不包含:Webhook、定时器、personal-event listener 等触发端;
62
+ - 不冒充:mock 平台可见不等于真实钉钉送达,真实写入必须另走 Lab L3/L4 晋级门禁。
@@ -0,0 +1,132 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 900" width="1440" height="900" role="img" aria-labelledby="title desc">
2
+ <title id="title">dingtalk-agent 三层语义记忆与控制状态拓扑</title>
3
+ <desc id="desc">Agent Run 按需读写三层语义记忆:Session 工作记忆、钉钉原生业务记忆、长期知识;Wait、锁、generation、幂等和 Receipt 位于独立控制状态;Git 用于定义与 Skill 的版本发布,不作为运行时锁或 PCB。</desc>
4
+ <style>
5
+ text { font-family:'Helvetica Neue',Helvetica,Arial,'PingFang SC','Microsoft YaHei',sans-serif; }
6
+ .title { fill:#111827;font-size:28px;font-weight:700; }
7
+ .subtitle { fill:#6b7280;font-size:14px; }
8
+ .lane { fill:#475569;font-size:12px;font-weight:700;letter-spacing:.08em; }
9
+ .node-title { fill:#111827;font-size:16px;font-weight:700; }
10
+ .node-sub { fill:#4b5563;font-size:12px; }
11
+ .small { fill:#64748b;font-size:11px; }
12
+ .label { fill:#475569;font-size:11px;font-weight:600; }
13
+ </style>
14
+ <defs>
15
+ <marker id="blue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"><polygon points="0 0,10 3.5,0 7" fill="#2563eb"/></marker>
16
+ <marker id="green" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"><polygon points="0 0,10 3.5,0 7" fill="#059669"/></marker>
17
+ <marker id="purple" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"><polygon points="0 0,10 3.5,0 7" fill="#7c3aed"/></marker>
18
+ <marker id="rose" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"><polygon points="0 0,10 3.5,0 7" fill="#dc2626"/></marker>
19
+ <filter id="shadow" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="2" stdDeviation="3" flood-color="#0f172a" flood-opacity=".10"/></filter>
20
+ </defs>
21
+
22
+ <rect width="1440" height="900" fill="#ffffff"/>
23
+ <text x="40" y="48" class="title">三层语义记忆,各归各的介质</text>
24
+ <text x="40" y="75" class="subtitle">语义记忆服务“想起什么”;控制状态保证“只执行一次、从正确位置继续”。两者必须分开。</text>
25
+
26
+ <rect x="30" y="105" width="300" height="620" rx="14" fill="#eff6ff" stroke="#60a5fa" stroke-width="1.6"/>
27
+ <text x="50" y="132" class="lane">AGENT RUNTIME</text>
28
+
29
+ <rect x="70" y="180" width="220" height="122" rx="12" fill="#ffffff" stroke="#60a5fa" stroke-width="2.2" filter="url(#shadow)"/>
30
+ <rect x="74" y="184" width="212" height="114" rx="9" fill="none" stroke="#60a5fa" stroke-width=".8" opacity=".5"/>
31
+ <text x="180" y="218" text-anchor="middle" class="node-title">Agent Run</text>
32
+ <text x="180" y="243" text-anchor="middle" class="node-sub">一次事件唤醒</text>
33
+ <text x="180" y="265" text-anchor="middle" class="node-sub">推理 · 工具 · ActionRequest</text>
34
+ <text x="180" y="286" text-anchor="middle" class="small">沙箱可丢弃</text>
35
+
36
+ <rect x="70" y="355" width="220" height="132" rx="10" fill="#faf5ff" stroke="#c084fc" stroke-width="1.7"/>
37
+ <text x="180" y="388" text-anchor="middle" class="node-title">Session</text>
38
+ <text x="180" y="412" text-anchor="middle" class="node-sub">一件事的稳定语义边界</text>
39
+ <text x="180" y="435" text-anchor="middle" class="node-sub">goal · checkpoint · next</text>
40
+ <text x="180" y="457" text-anchor="middle" class="node-sub">waitFor · evidence</text>
41
+ <text x="180" y="478" text-anchor="middle" class="small">跨 Run,不跨事项</text>
42
+
43
+ <rect x="70" y="540" width="220" height="128" rx="10" fill="#fef2f2" stroke="#f87171" stroke-width="1.8" stroke-dasharray="6 4"/>
44
+ <text x="180" y="572" text-anchor="middle" class="node-title">Control State Client</text>
45
+ <text x="180" y="596" text-anchor="middle" class="node-sub">claim · resume · commit</text>
46
+ <text x="180" y="619" text-anchor="middle" class="node-sub">不暴露平台凭据</text>
47
+ <text x="180" y="643" text-anchor="middle" class="small">通过宿主原子接口读写</text>
48
+
49
+ <path d="M180 302 L180 355" fill="none" stroke="#2563eb" stroke-width="2" marker-end="url(#blue)"/>
50
+ <path d="M180 487 L180 540" fill="none" stroke="#dc2626" stroke-width="1.8" marker-end="url(#rose)"/>
51
+
52
+ <rect x="365" y="105" width="645" height="620" rx="14" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1.2" stroke-dasharray="7 5"/>
53
+ <text x="385" y="132" class="lane">THREE SEMANTIC MEMORY TIERS</text>
54
+
55
+ <rect x="405" y="165" width="565" height="138" rx="12" fill="#eff6ff" stroke="#93c5fd" stroke-width="1.8" filter="url(#shadow)"/>
56
+ <rect x="425" y="184" width="78" height="34" rx="17" fill="#2563eb"/><text x="464" y="207" text-anchor="middle" fill="#ffffff" font-size="13" font-weight="700">L1 短期</text>
57
+ <text x="525" y="205" class="node-title">Session 工作记忆</text>
58
+ <text x="425" y="242" class="node-sub">介质:宿主 state root / 原子本地存储;可生成 Markdown checkpoint 供人审阅</text>
59
+ <text x="425" y="267" class="node-sub">内容:当前目标、做到哪、下一步、在等什么、已有哪些证据</text>
60
+ <text x="425" y="289" class="small">高频更新 · 事项结束后归档/压缩 · 不承担锁和幂等</text>
61
+
62
+ <rect x="405" y="348" width="565" height="138" rx="12" fill="#f0fdfa" stroke="#5eead4" stroke-width="1.8" filter="url(#shadow)"/>
63
+ <rect x="425" y="367" width="78" height="34" rx="17" fill="#0f766e"/><text x="464" y="390" text-anchor="middle" fill="#ffffff" font-size="13" font-weight="700">L2 工作</text>
64
+ <text x="525" y="388" class="node-title">钉钉原生业务记忆</text>
65
+ <text x="425" y="425" class="node-sub">介质:AI 表格宽表 / Todo / Calendar / 业务系统的唯一事实源</text>
66
+ <text x="425" y="450" class="node-sub">内容:日报摘要、待办快照、互动记录、可聚合的业务热数据</text>
67
+ <text x="425" y="472" class="small">结构化查询 · 跨 Agent 可读 · ID 与 schema 必须显式绑定</text>
68
+
69
+ <rect x="405" y="531" width="565" height="138" rx="12" fill="#f0fdf4" stroke="#86efac" stroke-width="1.8" filter="url(#shadow)"/>
70
+ <rect x="425" y="550" width="78" height="34" rx="17" fill="#15803d"/><text x="464" y="573" text-anchor="middle" fill="#ffffff" font-size="13" font-weight="700">L3 长期</text>
71
+ <text x="525" y="571" class="node-title">知识与能力资产</text>
72
+ <text x="425" y="608" class="node-sub">介质:钉钉文档树 / 知识库 / Wiki;按来源、范围与版本治理</text>
73
+ <text x="425" y="633" class="node-sub">内容:身份、职责、Skill、SOP、人物模式、错误库、稳定知识</text>
74
+ <text x="425" y="655" class="small">低频写入 · 需证据与准入 · 新 Run 才加载已发布版本</text>
75
+
76
+ <path d="M405 220 L330 220" fill="none" stroke="#059669" stroke-width="1.8" marker-end="url(#green)"/>
77
+ <path d="M330 258 L405 258" fill="none" stroke="#059669" stroke-width="1.6" stroke-dasharray="5 3" marker-end="url(#green)"/>
78
+ <rect x="342" y="194" width="52" height="20" rx="5" fill="#ffffff" opacity=".96"/><text x="368" y="209" text-anchor="middle" class="label">read</text>
79
+ <rect x="342" y="266" width="52" height="20" rx="5" fill="#ffffff" opacity=".96"/><text x="368" y="281" text-anchor="middle" class="label">write</text>
80
+
81
+ <path d="M405 400 L330 400" fill="none" stroke="#059669" stroke-width="1.8" marker-end="url(#green)"/>
82
+ <path d="M330 444 L405 444" fill="none" stroke="#059669" stroke-width="1.6" stroke-dasharray="5 3" marker-end="url(#green)"/>
83
+ <rect x="337" y="374" width="62" height="20" rx="5" fill="#ffffff" opacity=".96"/><text x="368" y="389" text-anchor="middle" class="label">query</text>
84
+ <rect x="342" y="452" width="52" height="20" rx="5" fill="#ffffff" opacity=".96"/><text x="368" y="467" text-anchor="middle" class="label">write</text>
85
+
86
+ <path d="M405 583 L330 583" fill="none" stroke="#059669" stroke-width="1.8" marker-end="url(#green)"/>
87
+ <path d="M330 627 L405 627" fill="none" stroke="#059669" stroke-width="1.6" stroke-dasharray="5 3" marker-end="url(#green)"/>
88
+ <rect x="342" y="557" width="52" height="20" rx="5" fill="#ffffff" opacity=".96"/><text x="368" y="572" text-anchor="middle" class="label">load</text>
89
+ <rect x="335" y="635" width="66" height="20" rx="5" fill="#ffffff" opacity=".96"/><text x="368" y="650" text-anchor="middle" class="label">propose</text>
90
+
91
+ <path d="M687 303 L687 348" fill="none" stroke="#7c3aed" stroke-width="1.7" marker-end="url(#purple)"/>
92
+ <path d="M687 486 L687 531" fill="none" stroke="#7c3aed" stroke-width="1.7" marker-end="url(#purple)"/>
93
+ <rect x="700" y="316" width="78" height="20" rx="5" fill="#ffffff" opacity=".96"/><text x="739" y="331" text-anchor="middle" class="label">结构化</text>
94
+ <rect x="700" y="499" width="78" height="20" rx="5" fill="#ffffff" opacity=".96"/><text x="739" y="514" text-anchor="middle" class="label">验证沉淀</text>
95
+
96
+ <rect x="1045" y="105" width="365" height="320" rx="14" fill="#fef2f2" stroke="#f87171" stroke-width="1.6" stroke-dasharray="7 5"/>
97
+ <text x="1065" y="132" fill="#b91c1c" font-size="12" font-weight="700" letter-spacing=".08em">CONTROL PLANE · 不是记忆</text>
98
+ <text x="1227" y="173" text-anchor="middle" class="node-title">宿主控制状态</text>
99
+
100
+ <rect x="1080" y="200" width="295" height="176" rx="10" fill="#ffffff" stroke="#fca5a5" stroke-width="1.5"/>
101
+ <text x="1105" y="230" class="node-sub">• EventIndex / delivery claim</text>
102
+ <text x="1105" y="258" class="node-sub">• Wait / correlation / timer</text>
103
+ <text x="1105" y="286" class="node-sub">• lock / generation / cancellation</text>
104
+ <text x="1105" y="314" class="node-sub">• idempotency key / action budget</text>
105
+ <text x="1105" y="342" class="node-sub">• Action intent / attempt / receipt</text>
106
+ <text x="1227" y="366" text-anchor="middle" class="small">需要 CAS / 原子写 / 可恢复语义</text>
107
+
108
+ <path d="M1045 270 L1018 270 L1018 708 L320 708 L320 604 L290 604" fill="none" stroke="#dc2626" stroke-width="1.8" marker-end="url(#rose)"/>
109
+ <rect x="925" y="681" width="88" height="20" rx="5" fill="#ffffff" opacity=".96"/><text x="969" y="696" text-anchor="middle" class="label">atomic state</text>
110
+
111
+ <rect x="1045" y="465" width="365" height="260" rx="14" fill="#faf5ff" stroke="#c084fc" stroke-width="1.6"/>
112
+ <text x="1065" y="492" fill="#7e22ce" font-size="12" font-weight="700" letter-spacing=".08em">GIT RELEASE PLANE</text>
113
+ <text x="1227" y="535" text-anchor="middle" class="node-title">定义与 Skill 的版本面</text>
114
+ <text x="1080" y="574" class="node-sub">• Agent Definition / Skill 源码与快照</text>
115
+ <text x="1080" y="603" class="node-sub">• 候选改进、评审、发布、回滚</text>
116
+ <text x="1080" y="632" class="node-sub">• 人可干预的语义 checkpoint 导出</text>
117
+ <rect x="1080" y="656" width="295" height="42" rx="8" fill="#ffffff" stroke="#d8b4fe" stroke-width="1.2"/>
118
+ <text x="1227" y="675" text-anchor="middle" fill="#7e22ce" font-size="12" font-weight="700">Git ≠ runtime lock / Wait / PCB authority</text>
119
+ <text x="1227" y="692" text-anchor="middle" class="small">发布是双向的,运行控制仍归宿主</text>
120
+
121
+ <path d="M1045 585 L1000 585 L1000 600 L970 600" fill="none" stroke="#7c3aed" stroke-width="1.7" stroke-dasharray="5 3" marker-end="url(#purple)"/>
122
+ <rect x="980" y="556" width="63" height="20" rx="5" fill="#ffffff" opacity=".96"/><text x="1011" y="571" text-anchor="middle" class="label">publish</text>
123
+
124
+ <rect x="30" y="765" width="1380" height="78" rx="10" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
125
+ <text x="50" y="792" fill="#111827" font-size="13" font-weight="700">介质选择原则</text>
126
+ <text x="50" y="821" fill="#334155" font-size="14">当前事项 → Session | 可统计业务事实 → 原生表/任务/日历 | 稳定可复用知识 → 文档/Wiki | 并发与副作用 → Control State | 发布与回滚 → Git</text>
127
+
128
+ <line x1="40" y1="873" x2="76" y2="873" stroke="#059669" stroke-width="1.8" marker-end="url(#green)"/><text x="84" y="877" class="small">读取</text>
129
+ <line x1="150" y1="873" x2="186" y2="873" stroke="#059669" stroke-width="1.6" stroke-dasharray="5 3" marker-end="url(#green)"/><text x="194" y="877" class="small">写入</text>
130
+ <line x1="265" y1="873" x2="301" y2="873" stroke="#7c3aed" stroke-width="1.7" marker-end="url(#purple)"/><text x="309" y="877" class="small">压缩 / 发布</text>
131
+ <line x1="440" y1="873" x2="476" y2="873" stroke="#dc2626" stroke-width="1.8" marker-end="url(#rose)"/><text x="484" y="877" class="small">原子控制</text>
132
+ </svg>
@@ -0,0 +1,149 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 920" width="1440" height="920" role="img" aria-labelledby="title desc">
2
+ <title id="title">dingtalk-agent 通用 Agent 行为内核拓扑</title>
3
+ <desc id="desc">外部触发器提供标准化 Invocation;Agent Definition、基础 Skill 与岗位 Skill 定义具体员工;dingtalk-agent 内核补齐感知、判断响应资格、维护 Session Run Wait 并约束 Action;DWS 负责执行钉钉产品能力。</desc>
4
+ <style>
5
+ text { font-family:'Helvetica Neue',Helvetica,Arial,'PingFang SC','Microsoft YaHei',sans-serif; }
6
+ .title { fill:#111827;font-size:28px;font-weight:700; }
7
+ .subtitle { fill:#6b7280;font-size:14px; }
8
+ .lane { fill:#475569;font-size:12px;font-weight:700;letter-spacing:.08em; }
9
+ .node-title { fill:#111827;font-size:16px;font-weight:700; }
10
+ .node-sub { fill:#4b5563;font-size:12px; }
11
+ .small { fill:#64748b;font-size:11px; }
12
+ .label { fill:#475569;font-size:11px;font-weight:600; }
13
+ </style>
14
+ <defs>
15
+ <marker id="blue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"><polygon points="0 0,10 3.5,0 7" fill="#2563eb"/></marker>
16
+ <marker id="orange" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"><polygon points="0 0,10 3.5,0 7" fill="#ea580c"/></marker>
17
+ <marker id="green" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"><polygon points="0 0,10 3.5,0 7" fill="#059669"/></marker>
18
+ <marker id="purple" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"><polygon points="0 0,10 3.5,0 7" fill="#7c3aed"/></marker>
19
+ <marker id="gray" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"><polygon points="0 0,10 3.5,0 7" fill="#64748b"/></marker>
20
+ <filter id="shadow" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="2" stdDeviation="3" flood-color="#0f172a" flood-opacity=".10"/></filter>
21
+ </defs>
22
+
23
+ <rect width="1440" height="920" fill="#ffffff"/>
24
+ <text x="40" y="48" class="title">dingtalk-agent · 从一个 Agent 泛化到所有 Agent</text>
25
+ <text x="40" y="75" class="subtitle">触发端可替换,模型与沙箱可替换,岗位能力可叠加;不变的是定义、上下文、状态、闸门与效果证据。</text>
26
+
27
+ <rect x="30" y="100" width="1380" height="130" rx="12" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1.2" stroke-dasharray="7 5"/>
28
+ <text x="48" y="124" class="lane">EXTERNAL INVOCATION · 触发不属于 dta</text>
29
+
30
+ <rect x="55" y="145" width="245" height="62" rx="9" fill="#fff7ed" stroke="#fdba74" stroke-width="1.6"/>
31
+ <text x="177" y="171" text-anchor="middle" class="node-title">任意触发 Adapter</text>
32
+ <text x="177" y="192" text-anchor="middle" class="node-sub">DM · @ · ambient · heartbeat · API</text>
33
+
34
+ <rect x="385" y="137" width="300" height="78" rx="10" fill="#eff6ff" stroke="#60a5fa" stroke-width="2" filter="url(#shadow)"/>
35
+ <text x="535" y="166" text-anchor="middle" class="node-title">Invocation Context</text>
36
+ <text x="535" y="189" text-anchor="middle" class="node-sub">mode · actor · target · conversation · sessionKey</text>
37
+ <text x="535" y="207" text-anchor="middle" class="small">无可信事件时默认 direct;外发仍 fail closed</text>
38
+
39
+ <rect x="770" y="137" width="590" height="78" rx="10" fill="#faf5ff" stroke="#c084fc" stroke-width="1.6"/>
40
+ <text x="1065" y="164" text-anchor="middle" class="node-title">同一内核的不同员工实例</text>
41
+ <text x="1065" y="190" text-anchor="middle" class="node-sub">FDE 教练 · 招聘助理 · 运维助手 · 项目经理 · 下一位 Agent</text>
42
+
43
+ <path d="M300 176 L385 176" fill="none" stroke="#ea580c" stroke-width="1.8" stroke-dasharray="6 4" marker-end="url(#orange)"/>
44
+ <rect x="314" y="153" width="57" height="20" rx="5" fill="#ffffff" opacity=".96"/><text x="342" y="168" text-anchor="middle" class="label">normalize</text>
45
+
46
+ <rect x="30" y="255" width="1380" height="165" rx="12" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1.2" stroke-dasharray="7 5"/>
47
+ <text x="48" y="280" class="lane">AGENT DEFINITION · 差异在这里叠加</text>
48
+
49
+ <rect x="55" y="305" width="345" height="86" rx="10" fill="#eff6ff" stroke="#93c5fd" stroke-width="1.7" filter="url(#shadow)"/>
50
+ <text x="227" y="334" text-anchor="middle" class="node-title">Agent Definition</text>
51
+ <text x="227" y="357" text-anchor="middle" class="node-sub">身份 · 职责 · 服务对象 · 权限 · 存储绑定</text>
52
+ <text x="227" y="377" text-anchor="middle" class="small">一个可版本化、可审查、可冻结的员工合同</text>
53
+
54
+ <rect x="460" y="305" width="260" height="86" rx="10" fill="#f0fdfa" stroke="#5eead4" stroke-width="1.7"/>
55
+ <text x="590" y="334" text-anchor="middle" class="node-title">Basic Behavior Skill</text>
56
+ <text x="590" y="358" text-anchor="middle" class="node-sub">所有员工共享</text>
57
+ <text x="590" y="378" text-anchor="middle" class="small">响应资格 · 追问 · 静默 · 验证</text>
58
+
59
+ <rect x="780" y="305" width="260" height="86" rx="10" fill="#f0fdf4" stroke="#86efac" stroke-width="1.7"/>
60
+ <text x="910" y="334" text-anchor="middle" class="node-title">Role / Workflow Skills</text>
61
+ <text x="910" y="358" text-anchor="middle" class="node-sub">按岗位叠加</text>
62
+ <text x="910" y="378" text-anchor="middle" class="small">FDE · 招聘 · 周报 · 事故处理</text>
63
+
64
+ <rect x="1100" y="305" width="260" height="86" rx="10" fill="#faf5ff" stroke="#c084fc" stroke-width="1.7"/>
65
+ <text x="1230" y="334" text-anchor="middle" class="node-title">Agent Host / Sandbox</text>
66
+ <text x="1230" y="358" text-anchor="middle" class="node-sub">Claude Code · Codex · 其它 Runtime</text>
67
+ <text x="1230" y="378" text-anchor="middle" class="small">模型与执行体可替换</text>
68
+
69
+ <rect x="30" y="445" width="1160" height="315" rx="14" fill="#f8fafc" stroke="#0f766e" stroke-width="2"/>
70
+ <text x="50" y="473" fill="#0f766e" font-size="13" font-weight="700" letter-spacing=".08em">DINGTALK-AGENT KERNEL · Skill 劝,CLI 拦,本体与状态各归其位</text>
71
+
72
+ <rect x="60" y="500" width="420" height="205" rx="12" fill="#f0fdfa" stroke="#5eead4" stroke-width="1.4" stroke-dasharray="6 4"/>
73
+ <text x="78" y="525" fill="#0f766e" font-size="12" font-weight="700">贴心半闸门 · 让 Agent 看见完整现场</text>
74
+
75
+ <rect x="85" y="550" width="165" height="112" rx="9" fill="#ffffff" stroke="#5eead4" stroke-width="1.6"/>
76
+ <text x="167" y="580" text-anchor="middle" class="node-title">感知预处理</text>
77
+ <text x="167" y="604" text-anchor="middle" class="node-sub">引用 · 群上下文 · 附件</text>
78
+ <text x="167" y="625" text-anchor="middle" class="node-sub">身份解析 · 连发合并</text>
79
+ <text x="167" y="646" text-anchor="middle" class="small">统一 Enriched Event</text>
80
+
81
+ <rect x="290" y="550" width="165" height="112" rx="9" fill="#ffffff" stroke="#5eead4" stroke-width="1.6"/>
82
+ <text x="372" y="580" text-anchor="middle" class="node-title">行为策略</text>
83
+ <text x="372" y="604" text-anchor="middle" class="node-sub">中期回执 · 安静时段</text>
84
+ <text x="372" y="625" text-anchor="middle" class="node-sub">会议免打扰 · 收口快照</text>
85
+ <text x="372" y="646" text-anchor="middle" class="small">给 Skill 可判断的提示</text>
86
+
87
+ <rect x="510" y="500" width="650" height="205" rx="12" fill="#fff7ed" stroke="#fdba74" stroke-width="1.4" stroke-dasharray="6 4"/>
88
+ <text x="528" y="525" fill="#c2410c" font-size="12" font-weight="700">安全半闸门 · 必须成立的约束进入代码</text>
89
+
90
+ <rect x="535" y="550" width="170" height="112" rx="9" fill="#ffffff" stroke="#fdba74" stroke-width="1.6"/>
91
+ <text x="620" y="580" text-anchor="middle" class="node-title">Response Gate</text>
92
+ <text x="620" y="604" text-anchor="middle" class="node-sub">先判断能否响应</text>
93
+ <text x="620" y="625" text-anchor="middle" class="node-sub">@ · DM · ambient · scope</text>
94
+ <text x="620" y="646" text-anchor="middle" class="small">内容生成之前</text>
95
+
96
+ <rect x="745" y="540" width="180" height="132" rx="10" fill="#eff6ff" stroke="#60a5fa" stroke-width="1.8" filter="url(#shadow)"/>
97
+ <text x="835" y="574" text-anchor="middle" class="node-title">Session Runtime</text>
98
+ <text x="835" y="598" text-anchor="middle" class="node-sub">Session · Run · Wait</text>
99
+ <text x="835" y="619" text-anchor="middle" class="node-sub">Skill snapshot · budget</text>
100
+ <text x="835" y="640" text-anchor="middle" class="node-sub">checkpoint · resume</text>
101
+ <text x="835" y="660" text-anchor="middle" class="small">一件事跨多次唤醒</text>
102
+
103
+ <rect x="965" y="550" width="170" height="112" rx="9" fill="#ffffff" stroke="#f87171" stroke-width="1.8"/>
104
+ <text x="1050" y="580" text-anchor="middle" class="node-title">Action Gate</text>
105
+ <text x="1050" y="604" text-anchor="middle" class="node-sub">目标 · 身份 · 权限</text>
106
+ <text x="1050" y="625" text-anchor="middle" class="node-sub">幂等 · 回读 · Receipt</text>
107
+ <text x="1050" y="646" text-anchor="middle" class="small">副作用之前</text>
108
+
109
+ <path d="M535 215 L535 238 L42 238 L42 606 L85 606" fill="none" stroke="#2563eb" stroke-width="2" marker-end="url(#blue)"/>
110
+ <path d="M250 606 L290 606" fill="none" stroke="#059669" stroke-width="1.8" marker-end="url(#green)"/>
111
+ <path d="M455 606 L535 606" fill="none" stroke="#2563eb" stroke-width="2" marker-end="url(#blue)"/>
112
+ <path d="M705 606 L745 606" fill="none" stroke="#2563eb" stroke-width="2" marker-end="url(#blue)"/>
113
+ <path d="M925 606 L965 606" fill="none" stroke="#2563eb" stroke-width="2" marker-end="url(#blue)"/>
114
+
115
+ <path d="M227 391 L227 430 L780 430 L780 540" fill="none" stroke="#7c3aed" stroke-width="1.7" marker-end="url(#purple)"/>
116
+ <path d="M590 391 L590 440 L810 440 L810 540" fill="none" stroke="#7c3aed" stroke-width="1.7" marker-end="url(#purple)"/>
117
+ <path d="M910 391 L910 440 L850 440 L850 540" fill="none" stroke="#7c3aed" stroke-width="1.7" marker-end="url(#purple)"/>
118
+ <path d="M1230 391 L1230 430 L895 430 L895 540" fill="none" stroke="#7c3aed" stroke-width="1.7" marker-end="url(#purple)"/>
119
+
120
+ <rect x="355" y="720" width="510" height="24" rx="6" fill="#ffffff" stroke="#d1d5db" stroke-width="1"/>
121
+ <text x="610" y="737" text-anchor="middle" class="small">三层语义记忆按需读取;Wait / 锁 / 幂等 / Receipt 进入独立控制状态</text>
122
+
123
+ <rect x="1230" y="520" width="160" height="92" rx="10" fill="#f0fdfa" stroke="#2dd4bf" stroke-width="2" filter="url(#shadow)"/>
124
+ <circle cx="1262" cy="550" r="18" fill="#1677ff"/><text x="1262" y="555" text-anchor="middle" fill="#ffffff" font-size="10" font-weight="700">DWS</text>
125
+ <text x="1310" y="551" text-anchor="middle" class="node-title">驱动层</text>
126
+ <text x="1310" y="579" text-anchor="middle" class="node-sub">标准产品能力</text>
127
+ <text x="1310" y="598" text-anchor="middle" class="small">CLI / 未来 SDK</text>
128
+
129
+ <rect x="1230" y="660" width="160" height="92" rx="10" fill="#eff6ff" stroke="#93c5fd" stroke-width="1.7"/>
130
+ <text x="1310" y="689" text-anchor="middle" class="node-title">钉钉产品</text>
131
+ <text x="1310" y="713" text-anchor="middle" class="node-sub">消息 · 文档 · 待办</text>
132
+ <text x="1310" y="734" text-anchor="middle" class="node-sub">日历 · 表格 · 审批</text>
133
+
134
+ <path d="M1135 606 L1185 606 L1185 566 L1230 566" fill="none" stroke="#2563eb" stroke-width="2.2" marker-end="url(#blue)"/>
135
+ <path d="M1310 612 L1310 660" fill="none" stroke="#2563eb" stroke-width="2.2" marker-end="url(#blue)"/>
136
+ <path d="M1230 706 L1188 706 L1188 688 L1050 688 L1050 662" fill="none" stroke="#64748b" stroke-width="1.6" stroke-dasharray="5 4" marker-end="url(#gray)"/>
137
+ <rect x="1082" y="676" width="82" height="20" rx="5" fill="#ffffff" opacity=".96"/><text x="1123" y="691" text-anchor="middle" class="label">平台回读</text>
138
+
139
+ <rect x="30" y="790" width="1380" height="76" rx="10" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
140
+ <text x="50" y="816" fill="#111827" font-size="13" font-weight="700">可叠加公式</text>
141
+ <text x="50" y="844" fill="#334155" font-size="15">Agent Host + dta Kernel + Agent Definition + Basic Behavior + Role Skills + DWS = 一个可工作的钉钉数字员工</text>
142
+ <text x="940" y="844" class="small">触发、模型、沙箱、岗位与存储 Provider 均可替换</text>
143
+
144
+ <line x1="40" y1="892" x2="76" y2="892" stroke="#2563eb" stroke-width="2" marker-end="url(#blue)"/><text x="84" y="896" class="small">主处理流</text>
145
+ <line x1="210" y1="892" x2="246" y2="892" stroke="#ea580c" stroke-width="1.8" stroke-dasharray="6 4" marker-end="url(#orange)"/><text x="254" y="896" class="small">外部触发</text>
146
+ <line x1="370" y1="892" x2="406" y2="892" stroke="#059669" stroke-width="1.8" marker-end="url(#green)"/><text x="414" y="896" class="small">感知补齐</text>
147
+ <line x1="530" y1="892" x2="566" y2="892" stroke="#7c3aed" stroke-width="1.8" marker-end="url(#purple)"/><text x="574" y="896" class="small">定义 / Skill 注入</text>
148
+ <line x1="735" y1="892" x2="771" y2="892" stroke="#64748b" stroke-width="1.6" stroke-dasharray="5 4" marker-end="url(#gray)"/><text x="779" y="896" class="small">回读 / 控制反馈</text>
149
+ </svg>