better-dsh 0.0.0 → 0.2.2-a

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 (142) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +294 -4
  3. package/control-prompt.md +37 -0
  4. package/cordis.patch.yml +53 -0
  5. package/docs/00_adr/0001-bridge-tool-layer-not-service-layer.md +14 -0
  6. package/docs/00_adr/0002-masking-is-presentation-only.md +15 -0
  7. package/docs/10_plans/A2A-messaging-channel-test-archive.md +256 -0
  8. package/docs/10_plans/code-mode-vs-rlm-ipython-comparison.md +137 -0
  9. package/docs/10_plans/dashr-blueprint-review.md +201 -0
  10. package/docs/10_plans/dashr-blueprint.md +561 -0
  11. package/docs/10_plans/dashr-compaction-window-and-archive.md +307 -0
  12. package/docs/10_plans/dashr-profile-layer-feasibility.md +367 -0
  13. package/docs/10_plans/dashr-sandbox-escalation-semantics-gap.md +171 -0
  14. package/docs/10_plans/dashr-security-sandbox-analysis.md +187 -0
  15. package/docs/10_plans/dashr-surface-invariant-and-omp-imports.md +97 -0
  16. package/docs/10_plans/ipython-kernel-interactive-interface-test-report.md +152 -0
  17. package/docs/10_plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft.md +146 -0
  18. package/docs/10_plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v3.md +50 -0
  19. package/docs/10_plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v4.md +79 -0
  20. package/docs/10_plans/kernel-refactoring/Dash-vs-PrimeAgent-systemprompt-toolcatalog-comparison.md +138 -0
  21. package/docs/10_plans/kernel-refactoring/RLM-system-prompt-injection-gap-report.md +161 -0
  22. package/docs/10_plans/kernel-refactoring/V0.1.5-development-plan.md +109 -0
  23. package/docs/10_plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_dsh.md +50 -0
  24. package/docs/10_plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_prime.md +113 -0
  25. package/docs/10_plans/recallable-compaction.md +147 -0
  26. package/docs/10_plans/spike-tag-repro.mjs +102 -0
  27. package/docs/10_plans/upstream-analysis.md +128 -0
  28. package/docs/50_test-reports/REPL-/345/267/245/345/205/267/350/260/203/347/224/250-/346/210/252/346/226/255/350/257/212/346/226/255.md +110 -0
  29. package/docs/50_test-reports/kernel-provisioning.md +44 -0
  30. package/docs/50_test-reports/repl-kernel-provisioning-test-report.md +87 -0
  31. package/docs/50_test-reports/upstream-dsh-0.1.2-alpha.5-local-test-report.md +81 -0
  32. package/docs/50_test-reports/upstream-dsh-0.1.2-alpha.5-report.md +93 -0
  33. package/docs/50_test-reports/v0.1.8-improved-/345/256/236/346/265/213/346/212/245/345/221/212.md +142 -0
  34. package/docs/50_test-reports/v0.1.8-/345/256/236/346/265/213/346/212/245/345/221/212.md +193 -0
  35. package/docs/50_test-reports/v0.1.8b-/345/256/236/346/265/213/346/212/245/345/221/212.md +96 -0
  36. package/docs/50_test-reports/v0.1.8c-/345/256/236/346/265/213/346/212/245/345/221/212.md +127 -0
  37. package/docs/50_test-reports/v0.1.8d-/345/256/236/346/265/213/346/212/245/345/221/212.md +150 -0
  38. package/docs/50_test-reports/v0.1.8d_artifacts/README.md +138 -0
  39. package/docs/50_test-reports/v0.1.8d_artifacts/code-mode-repl-only.observation.md +74 -0
  40. package/docs/50_test-reports/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.jsonl +3890 -0
  41. package/docs/50_test-reports/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.w-sample-0435.jsonl +544 -0
  42. package/docs/50_test-reports/v0.1.8d_artifacts/functions.json +592 -0
  43. package/docs/50_test-reports/v0.1.8d_artifacts/skills-catalog.snapshot.md +30 -0
  44. package/docs/50_test-reports/v0.1.8d_artifacts/tools-sdk.output-schemas.json +1236 -0
  45. package/docs/50_test-reports/v0.1.8d_artifacts/tools-sdk.python.txt +592 -0
  46. package/docs/50_test-reports/v0.1.8d_artifacts/tools-sdk.typescript.txt +516 -0
  47. package/docs/50_test-reports/v0.1.8d_artifacts/wire-vs-transcription.diff.md +54 -0
  48. package/docs/50_test-reports/v0.1.8e-/345/256/236/346/265/213/346/212/245/345/221/212.md +224 -0
  49. package/docs/50_test-reports/v0.1.9a-/345/256/236/346/265/213/346/212/245/345/221/212.md +168 -0
  50. package/docs/50_test-reports/v0.2.0b-/345/256/236/346/265/213/346/212/245/345/221/212.md +123 -0
  51. package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/Cargo.lock +7 -0
  52. package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/Cargo.toml +6 -0
  53. package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/src/bin/messy.rs +8 -0
  54. package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/src/main.rs +4 -0
  55. package/docs/50_test-reports/v0.2.0b_artifacts/hashline-probe.md +5 -0
  56. package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/Cargo.lock +7 -0
  57. package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/Cargo.toml +7 -0
  58. package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/build.rs +4 -0
  59. package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/src/main.rs +13 -0
  60. package/docs/50_test-reports/v0.2.1-/345/256/236/346/265/213/346/212/245/345/221/212.md +110 -0
  61. package/docs/50_test-reports/v0.2.1b-/345/256/236/346/265/213/346/212/245/345/221/212.md +86 -0
  62. package/docs/50_test-reports/v0.2.1c-/345/256/236/346/265/213/346/212/245/345/221/212.md +66 -0
  63. package/docs/50_test-reports/v0.2.1d-/345/256/236/346/265/213/346/212/245/345/221/212.md +67 -0
  64. package/docs/50_test-reports/v0.2.1e-P1-/345/256/236/346/265/213/346/212/245/345/221/212.md +136 -0
  65. package/docs/50_test-reports/v0.2.1ef-dev-audit-report.md +73 -0
  66. package/docs/50_test-reports/v0.2.1f-plugin-shipped-ui-patches/345/256/236/346/265/213/346/212/245/345/221/212.md +102 -0
  67. package/docs/60_exploration-and-research/cordis-research.md +350 -0
  68. package/docs/60_exploration-and-research/dsh-web-profile-package-map.md +186 -0
  69. package/docs/60_exploration-and-research/dsh-web-ui-slot-system-research.md +310 -0
  70. package/docs/60_exploration-and-research/dsh-webui-strip-boundary-research.md +300 -0
  71. package/docs/60_exploration-and-research/ios-chat-app-bridge-research.md +324 -0
  72. package/docs/60_exploration-and-research/web-frontend-composability-research.md +191 -0
  73. package/docs/REPL-/345/267/245/345/205/267/350/260/203/347/224/250-/346/210/252/346/226/255/350/257/212/346/226/255.md +110 -0
  74. package/docs/adr/0001-bridge-tool-layer-not-service-layer.md +14 -0
  75. package/docs/adr/0002-masking-is-presentation-only.md +15 -0
  76. package/docs/distro-blueprint.md +81 -0
  77. package/docs/dsh-webUI-with-rlm-mode.png +0 -0
  78. package/docs/plans/A2A-messaging-channel-test-archive.md +256 -0
  79. package/docs/plans/code-mode-vs-rlm-ipython-comparison.md +137 -0
  80. package/docs/plans/dashr-blueprint-review.md +201 -0
  81. package/docs/plans/dashr-blueprint.md +561 -0
  82. package/docs/plans/dashr-compaction-window-and-archive.md +307 -0
  83. package/docs/plans/dashr-profile-layer-feasibility.md +367 -0
  84. package/docs/plans/dashr-sandbox-escalation-semantics-gap.md +171 -0
  85. package/docs/plans/dashr-security-sandbox-analysis.md +187 -0
  86. package/docs/plans/dashr-surface-invariant-and-omp-imports.md +97 -0
  87. package/docs/plans/ipython-kernel-interactive-interface-test-report.md +152 -0
  88. package/docs/plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft.md +146 -0
  89. package/docs/plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v3.md +50 -0
  90. package/docs/plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v4.md +79 -0
  91. package/docs/plans/kernel-refactoring/Dash-vs-PrimeAgent-systemprompt-toolcatalog-comparison.md +138 -0
  92. package/docs/plans/kernel-refactoring/RLM-system-prompt-injection-gap-report.md +161 -0
  93. package/docs/plans/kernel-refactoring/V0.1.5-development-plan.md +109 -0
  94. package/docs/plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_dsh.md +50 -0
  95. package/docs/plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_prime.md +113 -0
  96. package/docs/plans/recallable-compaction.md +147 -0
  97. package/docs/plans/spike-tag-repro.mjs +102 -0
  98. package/docs/plans/upstream-analysis.md +128 -0
  99. package/docs/repositioning-and-rebranding.md +102 -0
  100. package/docs/v0.1.8-improved-/345/256/236/346/265/213/346/212/245/345/221/212.md +142 -0
  101. package/docs/v0.1.8-/345/256/236/346/265/213/346/212/245/345/221/212.md +193 -0
  102. package/docs/v0.1.8b-/345/256/236/346/265/213/346/212/245/345/221/212.md +96 -0
  103. package/docs/v0.1.8c-/345/256/236/346/265/213/346/212/245/345/221/212.md +127 -0
  104. package/docs/v0.1.8d-/345/256/236/346/265/213/346/212/245/345/221/212.md +150 -0
  105. package/docs/v0.1.8d_artifacts/README.md +138 -0
  106. package/docs/v0.1.8d_artifacts/code-mode-repl-only.observation.md +74 -0
  107. package/docs/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.jsonl +3890 -0
  108. package/docs/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.w-sample-0435.jsonl +544 -0
  109. package/docs/v0.1.8d_artifacts/functions.json +592 -0
  110. package/docs/v0.1.8d_artifacts/skills-catalog.snapshot.md +30 -0
  111. package/docs/v0.1.8d_artifacts/tools-sdk.output-schemas.json +1236 -0
  112. package/docs/v0.1.8d_artifacts/tools-sdk.python.txt +592 -0
  113. package/docs/v0.1.8d_artifacts/tools-sdk.typescript.txt +516 -0
  114. package/docs/v0.1.8d_artifacts/wire-vs-transcription.diff.md +54 -0
  115. package/docs/v0.1.8e-/345/256/236/346/265/213/346/212/245/345/221/212.md +224 -0
  116. package/docs/v0.1.9a-/345/256/236/346/265/213/346/212/245/345/221/212.md +168 -0
  117. package/docs/v0.2.0b-/345/256/236/346/265/213/346/212/245/345/221/212.md +123 -0
  118. package/docs/v0.2.0b_artifacts/f2probe/Cargo.lock +7 -0
  119. package/docs/v0.2.0b_artifacts/f2probe/Cargo.toml +6 -0
  120. package/docs/v0.2.0b_artifacts/f2probe/src/bin/messy.rs +8 -0
  121. package/docs/v0.2.0b_artifacts/f2probe/src/main.rs +4 -0
  122. package/docs/v0.2.0b_artifacts/hashline-probe.md +5 -0
  123. package/docs/v0.2.0b_artifacts/slowprobe/Cargo.lock +7 -0
  124. package/docs/v0.2.0b_artifacts/slowprobe/Cargo.toml +7 -0
  125. package/docs/v0.2.0b_artifacts/slowprobe/build.rs +4 -0
  126. package/docs/v0.2.0b_artifacts/slowprobe/src/main.rs +13 -0
  127. package/docs/v0.2.1-/345/256/236/346/265/213/346/212/245/345/221/212.md +110 -0
  128. package/docs/v0.2.1b-/345/256/236/346/265/213/346/212/245/345/221/212.md +86 -0
  129. package/docs/v0.2.1c-/345/256/236/346/265/213/346/212/245/345/221/212.md +66 -0
  130. package/lib/client/index.js +473 -0
  131. package/lib/index.d.ts +736 -0
  132. package/lib/index.js +11518 -0
  133. package/lib/kernel-env-hxaihi9C.js +195 -0
  134. package/lib/kernel-env.d.ts +80 -0
  135. package/lib/kernel-env.js +3 -0
  136. package/lib/py-sdk-BCaOGYz7.d.ts +125 -0
  137. package/lib/py-sdk-CbgYiX8O.js +691 -0
  138. package/lib/py-sdk.d.ts +2 -0
  139. package/lib/py-sdk.js +3 -0
  140. package/package.json +325 -4
  141. package/scripts/kernel-provision.mjs +35 -0
  142. package/index.js +0 -3
@@ -0,0 +1,256 @@
1
+ # Dash 运行时 A2A Messaging Channel 实测存档
2
+
3
+ > 实测日期(UTC):2026-08-17T17:57:57Z
4
+ > 实测主体:Dash Agent 运行时自身(root session,`deepseek-v4-pro`)
5
+ > 工作区:`/home/u1/workspaces/dashr`
6
+ > 方式:全程通过 `run_cell` 调用 `tools.*` 实际执行,所有结论均来自真实工具返回,非文档推断。
7
+
8
+ ---
9
+
10
+ ## 1. 测试目标与范围
11
+
12
+ 验证 Dash 运行时的 **A2A(Agent-to-Agent)messaging channel** 是否实现及其边界。
13
+
14
+ Dash 运行时按 **session 树** 划分 agent,因此 A2A 关系可归为三类:
15
+
16
+ 1. **Parent ↔ Child**(双向)
17
+ 2. **Siblings**(同父、同层)
18
+ 3. ~~Out of family tree~~(跨 family tree)
19
+
20
+ 第 3 类**天然不在范围**:运行时没有全局 session 总线,消息路由完全基于 session 树的 `parentSession` 指针。本存档只实测第 1、2 类,并以一个 grandchild 场景做旁证。
21
+
22
+ ---
23
+
24
+ ## 2. 实测拓扑(真实 session 树)
25
+
26
+ 从 root 视角 `list_agents(scope=descendants)` 及各 session 头部记录还原:
27
+
28
+ ```text
29
+ ROOT(me) session-d11e193f-a813-4200-96b1-0465ae8e8063 depth=0 parentSession=null preset=standard
30
+ ├── A f743dca9-3953-4382-ac45-487a27df9db1 depth=1 parentSession=ROOT preset=rlm-mode
31
+ │ └── G 057bd298-d186-4eb4-bb5c-4a6ee2c158cd depth=2 parentSession=A preset=rlm-mode
32
+ └── B 06ac8b2c-fb2e-458f-80d6-a0d28e50f193 depth=1 parentSession=ROOT preset=rlm-mode
33
+ ```
34
+
35
+ 各 session 头部记录(`session.jsonl.zstd` 首行,`type=session`)实测摘录:
36
+
37
+ | agent | id | parentSession | origin | delegationDepth | agentPreset |
38
+ |---|---|---|---|---|---|
39
+ | root | `session-d11e193f-a813-4200-96b1-0465ae8e8063` | `null` | `null` | 0 | `standard` |
40
+ | A | `f743dca9-3953-4382-ac45-487a27df9db1` | `session-d11e193f-...` | `subagent` | 1 | `rlm-mode` |
41
+ | B | `06ac8b2c-fb2e-458f-80d6-a0d28e50f193` | `session-d11e193f-...` | `subagent` | 1 | `rlm-mode` |
42
+ | G | `057bd298-d186-4eb4-bb5c-4a6ee2c158cd` | `f743dca9-3953-...` | `subagent` | 2 | `rlm-mode` |
43
+
44
+ ---
45
+
46
+ ## 3. 关键机制发现
47
+
48
+ ### 3.1 身份:subagent id == 子 session id == `DSH_SESSION_ID`
49
+
50
+ `subagent(..., run_in_background=true)` 返回的 `subagentId` 就是子 session 的 id,也等于子 agent 进程内的 `DSH_SESSION_ID`。
51
+
52
+ - spawn A 返回:`{"kind":"continuable","subagentId":"f743dca9-3953-4382-ac45-487a27df9db1"}`
53
+ - A 自报:`DSH_SESSION_ID=f743dca9-3953-4382-ac45-487a27df9db1`(一致)
54
+
55
+ ### 3.2 父身份:不暴露在 env / list_agents,只写在子 session 日志头部
56
+
57
+ 子 agent **无法**通过环境变量(无 `DSH_PARENT_*`)或 `list_agents`(只显示自己的 children/descendants)得知父身份。
58
+
59
+ 但父身份写在子 agent **自己的** `session.jsonl` 头部 `parentSession` 字段里。B 实测是读自己 session 日志首条记录发现的:
60
+
61
+ ```json
62
+ {"type":"session","id":"06ac8b2c-...","parentSession":"session-d11e193f-a813-4200-96b1-0465ae8e8063","origin":"subagent","delegationDepth":1,"agentPreset":"rlm-mode"}
63
+ ```
64
+
65
+ ### 3.3 路由规则(核心)
66
+
67
+ `send_message(caller, target)` 仅当 **`target.parentSession == caller.sessionId`** 时放行,即 **只能给自己的“直接子”发消息**。
68
+
69
+ 越界时统一抛 `ToolCallError`:
70
+ > `subagent "<id>" belongs to another parent session`
71
+
72
+ ---
73
+
74
+ ## 4. 测试矩阵与结果
75
+
76
+ ### 4.1 Parent ↔ Child ✅(可用,但**不对称**)
77
+
78
+ | 方向 | 通道 | 结果 | 证据 |
79
+ |---|---|---|---|
80
+ | Parent→Child | `send_message`(显式下行) | ✅ 可用,可递归 | 见下 |
81
+ | Child→Parent | completion notice(完成回传) | ✅ 可用 | A/B/G 每次 final message 都回到 root |
82
+ | Child→Parent | `send_message`(显式上行 push) | ❌ 不可用 | `belongs to another parent session` |
83
+
84
+ **下行实测(都回传了 token):**
85
+ - root→A:`DOWN_PING_8841` → A 回 `DOWN_OK` ✅
86
+ - root→B:`RELAY_OK` → B 回 `RELAY_OK` ✅
87
+ - A→G:`G_ECHO_PING` → G 回 `G_ECHO_OK` ✅(证明子 agent 可递归当父节点)
88
+
89
+ **上行实测:**
90
+ - A 调 `send_message(subagent_id="session-d11e193f-...", ...)` → 抛错 `subagent "session-d11e193f-..." belongs to another parent session` ❌
91
+
92
+ > 结论:下行是显式消息通道;上行只有“交结果”的完成回传,**不是对等双向**。
93
+
94
+ ### 4.2 Siblings ❌(无直接通道)
95
+
96
+ - **A→B 直接发消息**:抛错 `subagent "06ac8b2c-fb2e-458f-80d6-a0d28e50f193" belongs to another parent session` ❌
97
+ - **不可见**:A 视角 `list_agents(scope=children)` 与 `scope=descendants` 均返回 `[]`,看不到 sibling B;sibling 关系只有共同父节点(root)能通过 `list_agents` 看到。
98
+ - **唯一通路**:经共同 parent 中转(A 交回 root → root 转发给 B)。实测 root→B 中转腿可行。
99
+
100
+ ### 4.3 Grandchild(旁证:规则不特判、只认“直接子”)
101
+
102
+ - root→G(depth 2)直接发消息:抛错 `subagent "057bd298-..." belongs to another parent session` ❌
103
+ - 说明 sibling / 向上 / 跨层 全被同一条规则挡下,**不是针对 sibling 的特判**。
104
+
105
+ ---
106
+
107
+ ## 5. 原始证据汇总
108
+
109
+ **关键消息 ID(`send_message` 返回):**
110
+ - root→A(DOWN 测试):`400063ce-b604-48db-b853-5bc2811df8e2`
111
+ - root→B(RELAY 测试):`946106a9-59e3-4527-8eba-211999289db4`
112
+ - A→G(follow-up):`590760b1-443d-4124-a0f9-8bbfc26f0eef`
113
+ - A 交叉测试指令:`ace2038e-ca4a-499b-8754-77b1d5c4cacb`
114
+
115
+ **统一拒绝错误(3 处实测一致):**
116
+ ```
117
+ ToolCallError(send_message): subagent "<id>" belongs to another parent session
118
+ ```
119
+ 分别出现在:A→B(sibling)、A→root(上行)、root→G(跨层)。
120
+
121
+ ---
122
+
123
+ ## 6. 结论
124
+
125
+ 1. **A2A messaging channel 已实现,但形态是“树上的定向消息 + 完成回传”,不是全局对等消息总线。**
126
+ 2. 边界严格由 `parentSession` 指针决定:`send_message` 只到**自己的直接子**。
127
+ 3. **Parent↔Child**:下行可用且可递归;上行仅有完成回传,无显式 push。
128
+ 4. **Siblings**:无直接通道、不可见,只能经共同父节点中转。
129
+ 5. **Out of family tree / 跨层**:被同一条路由规则拒绝,符合“无全局总线”的预判。
130
+
131
+ ---
132
+
133
+ ## 7. 遗留
134
+
135
+ 测试产生的子 agent A、B、G 当前均处于 `ready`(空闲可续),不会再执行任务,除非继续 `send_message`。
136
+ - A = `f743dca9-3953-4382-ac45-487a27df9db1`
137
+ - B = `06ac8b2c-fb2e-458f-80d6-a0d28e50f193`
138
+ - G = `057bd298-d186-4eb4-bb5c-4a6ee2c158cd`
139
+
140
+ ---
141
+
142
+ # 附录(2026-08-17 追加):Prime Agent 参照调查 — Finisher 事件实录与通道对比
143
+
144
+ > 追加背景:用户对本文 §4.2 的"sibling 之间不能直接通讯"提出疑问——Dash 的机制参考自 Prime Agent(当前 conversation 的运行时),而 Prime Agent 在真实工作中发生过一次 sibling 间"感知"事件(Doer 被用户 Escape 中断后 continue,主 Agent 误判其死亡并派了 Finisher,Finisher 却自己发现了 Doer 还在工作)。本附录从 Prime Agent 的会话日志与源码取证,回答四个问题,并给出两个实现的通道对比表。
145
+ >
146
+ > 术语口径:本附录按"设施(facility)= 运行时/界面直接提供给模型、cell 内可直接调用的能力"计;"读源码找端点 curl"类旁证不算工具。
147
+ > 取证来源:主会话日志 `/home/u1/.prime/agent/sessions/01a00967-75d6-755c-827c-562a446786a1.jsonl`(entry 2352/2357/2358 等)、Finisher 自身 session transcript(`sub-ff62e2e1/*.jsonl`)、Prime Agent 源码 `dist/core/agent-messages.js` + `dist/modes/daemon/daemon-mode.js`。
148
+
149
+ ## 8. Finisher 事件实录(Q1–Q4)
150
+
151
+ ### 8.1 Q1:Finisher 是怎么知道 Doer 还活着的?
152
+
153
+ **不是消息,是观察通道(`agent_observe`)。** Finisher 自身 transcript 的调用统计:
154
+
155
+ ```
156
+ agent_observe.get_agent ×5 (读 sibling 的实时 status)
157
+ agent_observe.recent_messages ×7 (读 sibling 的 transcript 尾部)
158
+ ```
159
+
160
+ 它读到的事实:`m4b-doer-glm52 status=running、isStreaming=true`,transcript 末尾是"刚修完 tsc 类型错误、刚跑完孤儿检查"。辅助旁证是文件系统(mtime 4 秒前刚变、debug 文件被删、新文件出现)——但**主通道是直接读 sibling 的 transcript**。在 Prime Agent 里这不是猜测,是读取。
161
+
162
+ **术语澄清(用户追问,2026-08-17)**:`agent_observe` 不是"读源码 + 找端点 + curl"式的 API 调用。它和 `agent_message`、`websearch`、`edit` 一样,是运行时**预注入 kernel 命名空间的 Python 模块**——模型在 run_cell 里直接 `await agent_observe.get_agent('m4b-doer-glm52')`,与调用任何其他工具无异;daemon 通信、身份、权限对模型完全透明。按用户的设施定义("界面和运行时直接提供给模型、可直接 interact 的东西"),这是**设施(facility)**,不是外部 API。本文 §9 表格中的"观察 API"字样应按"观察设施"理解——措辞已在下文统一修正。
163
+
164
+ ### 8.2 Q2:Prime Agent 的 channel 能看到 sibling 吗?
165
+
166
+ **能,且是设计内的一等公民。** 源码(`dist/core/agent-messages.js`):
167
+
168
+ ```js
169
+ agentFamilyRelationship(current, target) {
170
+ if (isAgentFamilyParent(target, current)) return "parent";
171
+ if (isAgentFamilyParent(current, target)) return "child";
172
+ if (current.depth === target.depth && sameAgentFamilyParent(current, target, ...))
173
+ return "sibling"; // 同 depth + 同 parentSessionId/Path = sibling
174
+ return undefined; // 核家庭之外 → 拒绝
175
+ }
176
+ ```
177
+
178
+ `buildAgentFamilyRoster()` 把 **parent + siblings + children(含各自 status)** 全部列给当前 agent——sibling 的存在、名字、状态对每个 agent 可见。daemon 侧(`daemon-mode.js`)的 target 解析对消息与观察统一走同一守卫:`assertAgentFamilyReach`(parent/siblings/children 之外一律拒绝,错误文案 `"Agent reach is limited to parent, siblings, and children"`)。
179
+
180
+ ### 8.3 Q3:sibling 之间究竟能不能通讯?
181
+
182
+ - **Prime Agent:能。** `agent_message.send(..., receiver_role='sibling')` 合法,`send("all")` 家庭广播也覆盖 sibling。
183
+ - **但那次冲突的 resolve 走的是父,不是 sibling 直连。** 实录消息流(主会话 entry 2352/2357/2358):
184
+ 1. Finisher → 父:报告"Doer 未死" + 自己的计划,并明说"需要你先停掉/删除 m4b-doer-glm52,避免对写。**请指示**";
185
+ 2. 父 → Finisher:`receiver_role='child'` 角色变更指令"**它在写,你只看**",`deliveryStatus: queued`(steering 投递——busy 中的目标在运行中也能收到);
186
+ 3. Finisher 此后持续 `agent_observe` 盯 Doer,Doer idle 后做只读验收;Doer 全程未被直接打扰。
187
+ - 原因:Finisher 正确判断了**生命周期归属**——停/删 Doer 是父的权限(`delete_subagent` 是 parent-owned),冲突裁决权在父。**能力存在,编排走父**。这是权限模型(谁有权裁决)与能力模型(谁可以直达)的区别。
188
+
189
+ ### 8.4 Q4:冲突 resolve 时消息是怎么传的?
190
+
191
+ 三步,全部经父中转(见 8.3);Finisher 与 Doer 之间没有直接消息,只有 Finisher → Doer 的**单向只读观察**(status + transcript 预览)。这与 Dash 实测的"唯一通路:经共同 parent 中转"表面相同,但 Dash 的中转是**因为没有其他通道**,Prime Agent 的中转是**编排选择**(存在 sibling 直连与观察通道)。
192
+
193
+ ## 9. Prime Agent vs Dash:A2A Messaging Channel 对比表
194
+
195
+ | 维度 | Prime Agent | Dash(本文 §3–§5 实测 + 上游 continuation.ts) |
196
+ |---|---|---|
197
+ | 拓扑模型 | **核家庭(nuclear family)**:parent + siblings + direct children 双向;根互为 sibling | **严格树**:只认 `parentSession` 指针 |
198
+ | 可达性判定 | `agentFamilyRelationship`(同 parent 边即 sibling) | `target.parentSession == caller.sessionId`(**只能是直接子**) |
199
+ | Sibling 可见性 | ✅ 家庭名单显式列出 siblings + status | ❌ 不可见(`list_agents` 只有自己的 descendants) |
200
+ | Sibling 消息 | ✅ `receiver_role='sibling'` | ❌ `subagent "<id>" belongs to another parent session` |
201
+ | Sibling 观察(设施) | ✅ 预注入 kernel 模块 `agent_observe`:cell 内直接调用 `get_agent` / `recent_messages` / `list_agents`——status + 有界 transcript 预览,只读 | ❌ 无观察设施:cell 内没有任何可调用的观察函数;只能靠非设施旁证(读文件 mtime、自己翻 session 日志文件——按用户定义"不算工具") |
202
+ | 上行 | ✅ 显式消息(双向对等) | ❌ 显式 push 被拒,只有完成回传 |
203
+ | 下行 | ✅ 可递归 | ✅ 可递归(实测 A→G) |
204
+ | 群发 | ✅ `send("all")` 家庭广播(逐条 receipt) | ❌ |
205
+ | 投递语义 | steering delivery:busy 目标运行中可收(`deliveryStatus: queued`);idle 目标直接进上下文 | 完成回传 + 显式下行(busy 中的投递语义未实测) |
206
+ | 身份 | daemon 推导 sender,不可伪造;无 `from` 参数 | 父身份不暴露在 env / list_agents,只在子 session 日志头部 |
207
+ | 生命周期 | 父拥有 `delete_subagent`;child 仅在父会话存续期可用 | 父拥有(continuation 同源规则) |
208
+ | 观察/消息分权 | 观察只读(无 mutate 命令),与消息分离 | 无观察层 |
209
+
210
+ **一句话总结**:Dash 实现的是"树上的一条下行边 + 完成回传"的最小树消息;Prime Agent 把可达域从"父子边"扩展成**核家庭**——多出的是 sibling 可达(消息)、sibling 观察(status/transcript 只读)、家庭名单可见性、显式上行与群发。8.1 的 Finisher 事件恰好命中了 Dash 缺失的那一块:在 Dash 运行时上重演同一场景,Finisher 会完全失明——看不到 Doer 的 status、读不到 transcript,冲突的发现大概率迟到到"两个 agent 开始对写同一批文件"之后。
211
+
212
+ ## 10. 对 Dash 的启示(遗留待办候选)
213
+
214
+ 1. **补 sibling 观察(设施口径)**:只读的 status + 最近消息预览(有界),是上面场景的充分条件——即使不开放 sibling 直接消息,观察通道也能让冲突在写入前被发现。实现形态应与 Prime Agent 同级:**预注入 kernel 的 Python 模块**(Dash 侧即 tools.* binding 或 `_dashr_*` 注入 helper),模型 cell 内直接调用;而不是"自己去读 session 日志文件"——后者按用户定义不算工具,只能算碰巧存在的旁证。
215
+ 2. **补家庭名单可见性**:`list_agents` 至少向每个 agent 暴露同父 sibling 的存在与状态(当前只显示 descendants,父身份还要读自己日志)。
216
+ 3. **sibling 消息是否开放**是设计取舍:Prime Agent 有直连但编排惯例走父(生命周期在父)。Dash 若只补观察,可保持"消息走父、观察可横"的分权。
217
+ 4. **上行显式 push**:Prime Agent 双向对等;Dash 只有完成回传,子 agent 无法主动给父发"我需要裁决"类消息(Finisher 事件里那条"请指示"在 Dash 上发不出去)。
218
+
219
+ ---
220
+
221
+ ## 11. Delegation 三层模型:通道与"返回结果"的关系(2026-08-17 追加)
222
+
223
+ > 用户追问:"PA 的 A2A Messaging Channel 是不是独立于 delegation 返回 result 的东西?"——答案:方向对了一半,有一个关键修正:**结果本身恰恰就是骑在这个通道上传的**。
224
+
225
+ ### 11.1 Prime Agent 的三层结构
226
+
227
+ ```
228
+ ① 委派准入(spawn/admission)
229
+ rlm('task', name=...) → 立即返回 handle(rlm_child_id / session_dir / model)
230
+ ← 独立于通道,纯簿记。rlm() 永远不返回子 agent 的答案
231
+
232
+ ② 结果传输
233
+ 子 agent 的最终答复 = await agent_message.send(message, receiver_role='parent')
234
+ ← 结果就是一条父向消息,骑在 messaging channel 上("写文件给父读"是旁路)
235
+
236
+ ③ 存活/完成状态面
237
+ status(idle/running)、repliedSinceTask、"completed without sending a reply" 通知、
238
+ agent_observe 的 status + transcript 预览
239
+ ← 独立于通道,是监测机制,不是结果传输
240
+ ```
241
+
242
+ - 说"通道独立于 delegation 的返回"**对一半**:`rlm()` 的准入返回与通道无关(只给 handle、立刻返回、绝不等结果)。
243
+ - 但 delegation 的 **result 没有独立管道**:子 agent 的最终答案就是一条父向消息。Finisher 事件里那条 "[from child:m4b-finisher-glm52] …请指示" 与它的正式交付报告形态完全相同——**结果交付只是通道的一种用途,不是另一套机制**。
244
+
245
+ ### 11.2 两实现的对照(DSH 实测 §4.1 的"不对称"之根源)
246
+
247
+ | | 结果传输 | 显式消息 |
248
+ |---|---|---|
249
+ | **Dash** | 完成回传:内置 delegation 机制,final message 自动回根 | `send_message` 显式下行——**两套东西** |
250
+ | **Prime Agent** | 子 agent 显式 `agent_message.send(receiver_role='parent')`——**结果也是一条消息** | 同一通道,双向 + sibling + 群发——**一套东西** |
251
+
252
+ Dash 把"交结果"做成了 delegation 的内置特权路径(上行 push 被拒无妨,结果有专线);Prime Agent 把"交结果"统一成了消息(上行 push 天然存在,因为结果本身就是上行消息的一种)。
253
+
254
+ ### 11.3 一个由此产生的行为差异
255
+
256
+ Finisher 事件里,父 agent 被 "completed without sending a reply" 误导——因为 Prime Agent 里**"完成"与"回传结果"是解耦的**:③ 层的完成状态通知先到(子 agent 因 interrupt 被误报 completed),② 层的结果消息还没发。Dash 里这两件事绑在一起(完成回传 = 结果到达),反而没有这个坑。**两解耦各有代价**:解耦 = 结果通道可复用(sibling 消息、steering、角色变更都走同一设施),但完成≠有结果;绑定 = 语义简单,但通道只剩"显式下行"这一条窄边。
@@ -0,0 +1,137 @@
1
+ # 上游 DSH Code Mode 与 Dash RLM(ipython)对比调研
2
+
3
+ > 调研日期(UTC):2026-08-19
4
+ > 上游源码:`upstream/deepseek-harness`(已从 rc.5 更新到 `dsh-v0.1.0-rc.7`,commit `99f6f02fec`)
5
+ > 对比对象:DSH 原生 Code Mode(`run_code`)vs Dash RLM 插件(`ipython`)
6
+ > 方式:读上游源码 + 设计 Agent Note + 本会话实测 dashr 运行时,全部结论均有文件/行号/引文支撑。
7
+
8
+ ---
9
+
10
+ ## 1. 结论速览(TL;DR)
11
+
12
+ | 问题 | 结论 |
13
+ |---|---|
14
+ | ① DSH Code Mode 是否也是「单一顶层工具 + 代码块」? | ✅ 是。`run_code` 就是唯一顶层工具,形状与 `ipython` 完全同构 |
15
+ | ② 沙箱逃逸是否等价? | ✅ 是。上游自己也写明「containment, not a security boundary」,信任姿态 = bash;任何图灵完备模式都会逃逸,只是快慢/直接间接之别 |
16
+ | ③ 最关键差异 | 🔴 **DSH 明确「拒绝」了持久化 kernel(REPL 式),而 Dash RLM 恰恰是持久化 IPython kernel**。这是二者最根本的分歧,根因是「可重建性」(reconstructability) |
17
+
18
+ ---
19
+
20
+ ## 2. 上游版本与源码定位
21
+
22
+ - 远程:`https://github.com/deepseek-ai/deepseek-harness.git`
23
+ - 更新:本地 rc.5 → `dsh-v0.1.0-rc.7`(tag 即 `origin/master`,`git merge --ff-only` 完成)
24
+ - 核心文件:
25
+ - `packages/core/tools/src/code-mode.ts` —— `run_code` 工具定义 + dispatch bridge
26
+ - `packages/core/tools/src/py-types.ts` / `ts-types.ts` —— SDK 生成(Python/TS 两套)
27
+ - `packages/code-runtime/code-runtime/` —— 执行能力 seam(`ctx.codeRuntime`)
28
+ - `packages/code-runtime/code-runtime-worker-thread/` —— 唯一 shipped 后端
29
+ - `.agents/notes/implemented/feature/2026-06-15-code-mode.md` —— 权威设计文档
30
+ - `.agents/notes/implemented/feature/2026-07-31-code-mode-language-dispatch.md` —— Python 呈现层
31
+
32
+ ---
33
+
34
+ ## 3. 表面形状对比:是不是「单一顶层工具」
35
+
36
+ **是。** 两者都把「工具调用界面」归一化成一个顶层工具:
37
+
38
+ | | DSH Code Mode | Dash RLM |
39
+ |---|---|---|
40
+ | 顶层工具名 | `run_code`(`RUN_CODE_NAME`) | `ipython` |
41
+ | 必填参数 | `code` + `description` 两个 | `cell` + `description` 两个 |
42
+ | 代码块语义 | 「async 函数的 body」,顶层 `await`/`return` 可用 | 一个 IPython cell,顶层 `await`/`return` 可用 |
43
+ | 输出契约 | 只 `print`/`return` 的才进模型上下文 | 只 `print`/`return` 的才回来 |
44
+ | 模式开关 | `tools: { mode: 'native'|'code'|'both' }` | `agent-preset: rlm-mode` |
45
+
46
+ 在 `mode: 'code'` 下,wire 上只挂 `run_code` 一个工具 + 一段生成的 SDK `.d.ts`。这与 dashr 的「只有 `ipython` 可直连」是同一形态。
47
+
48
+ ---
49
+
50
+ ## 4. 执行基底对比(最根本差异)
51
+
52
+ | 维度 | DSH Code Mode | Dash RLM |
53
+ |---|---|---|
54
+ | 执行载体 | 每次 run 起一个**全新** `worker_threads.Worker` | **持久化** IPython/Jupyter kernel 进程 |
55
+ | 状态 | **无状态**(每次 fresh,进程世界随 worker 销毁) | **有状态**(变量/import 跨 cell 存活,实测确认) |
56
+ | 语言 | TypeScript(唯一 shipped 后端) | Python(真实 IPython) |
57
+ | 隔离 | worker 线程:空 env、heap 上限、可硬终止 | 真实 kernel 进程(无 worker 级 containment) |
58
+
59
+ DSH 把 TS 程序 host-side 做 `stripTypeScriptTypes`(去类型),再包成 `AsyncFunction` 在 worker 里执行;绑定经 message port 桥接。**每次都是纯函数调用,无跨 run 状态。**
60
+
61
+ Dash RLM 则是在一个长期存活的内核里逐 cell `exec`,变量天然累积——这就是我在本会话里直接验证过的「上一轮变量下一轮还在」。
62
+
63
+ ---
64
+
65
+ ## 5. 语言对比
66
+
67
+ | | DSH | Dash RLM |
68
+ |---|---|---|
69
+ | 实际可运行语言 | **TypeScript**(`language = 'typescript'`,`isolation = 'worker-thread'`) | **Python**(IPython) |
70
+ | Python 支持 | **仅呈现层**:`py-types.ts` + `renderToolsSdkPy` + `PYTHON_FLAVOR` 都在,但**没有 published Python 后端**——设计文档原话:「The Python branch of both tables is unreachable in the shipped tree」 | 原生 Python,真跑 |
71
+
72
+ 即:DSH 把 Python 的「schema/SDK/描述」都准备好了,但还没有能执行 Python 的后端;dashr 则是反过来的——直接实现了 Python 执行(IPython),走的是 DSH 预留的「future Python backend」那条路。
73
+
74
+ ---
75
+
76
+ ## 6. 工具绑定形式对比
77
+
78
+ | | DSH | Dash RLM |
79
+ |---|---|---|
80
+ | 调用形式 | `await tools.name(args)`(命名空间对象 `tools`) | `await name(args)`(扁平顶层函数) |
81
+ | 错误类 | `ToolCallError`,带 `toolName` | `ToolCallError`,带 `toolName` |
82
+ | 参数契约 | 单个 args 对象,必须 lossless JSON | 单个位置 args 对象,拒绝 kwargs |
83
+ | 命名防护 | null-prototype + `defineProperty` 防 `__proto__`/`constructor` 撞名 | 扁平 `user_ns[global_name]` 绑定 |
84
+
85
+ `ToolCallError` + `toolName` 这个契约是 dashr 从上游「搬」过来的(上游 `code-mode.ts` 里 `errorClass: { name: 'ToolCallError', memberNameProperty: 'toolName' }` 与 dashr bootstrap 完全一致)。差异在命名空间:DSH 用 `tools.` 前缀统一收敛,dashr 用扁平全局名(这是我在实测里注意到的「工具目录像原生函数」摩擦的根源之一)。
86
+
87
+ ---
88
+
89
+ ## 7. 并发模型对比
90
+
91
+ - **DSH**:每个 run 一个调度队列,严格按提交顺序启动,逐调用走 `registry.executionMode`(`isConcurrencySafe`)分类 parallel/exclusive;连续的 parallel 调用最多重叠 `maxParallelSubCalls`(默认 10,1 即串行);exclusive 调用排空池后单独跑。承诺「只读调用可用 `Promise.all`/`asyncio.gather` 重叠,写调用按提交顺序单独跑」。
92
+ - **Dash RLM**:cell 内用 `asyncio.gather` 扇出,同样有重叠上限;底层同样走「并发安全分类 + 顺序提交」的契约。
93
+
94
+ 二者并发语义高度同构——dashr 的「submission-order + overlap cap」直接继承自上游这套设计。
95
+
96
+ ---
97
+
98
+ ## 8. 隔离与沙箱逃逸(安全性)
99
+
100
+ **上游自己就把话说透了。** `code-runtime-worker-thread` README 第一段:
101
+
102
+ > **Containment, not a security boundary**: trust posture is bash-equivalent by design ... model code can reach Node APIs and has authority comparable to the bash tool.
103
+
104
+ 设计文档 §Trust posture(第 84 行):
105
+
106
+ > The worker runtime provides containment, not a security boundary ... `worker.terminate()` stops the thread but not OS processes it spawned. Code Mode uses the same `tools/pre-execute` policy gate as bash ...
107
+
108
+ **结论**:DSH Code Mode 的 worker 只是「资源隔离」(isolate、空 env、heap 上限、硬终止),**不是安全边界**;信任姿态等价于 bash(bash 本就能执行任意 shell 命令)。所以:
109
+
110
+ - **Code Mode 逃逸**:模型代码能直接 reach Node API,等价于 bash。
111
+ - **RLM/ipython 逃逸**:kernel 进程原生 `open()` 可写任意路径(本会话已实测复现)。
112
+ - **普通 native 模式逃逸**:bash + write 组合先写脚本再执行,同样图灵完备。
113
+
114
+ 三者本质等价——都是「图灵完备的代码执行能力」,差别只在**实现步骤的快慢/直接间接**,不在是否可能。这与你(用户)的判断完全一致。
115
+
116
+ ---
117
+
118
+ ## 9. 关键分歧:DSH 明确拒绝了「持久化 kernel」
119
+
120
+ 设计文档「Alternatives considered」第 119 行,一字不差:
121
+
122
+ > **A REPL-style persistent kernel** (state survives across `run_code` calls). **Rejected for the MVP**: cross-call state would be invisible to the session log, breaking the **reconstructability guarantee that every request is a pure function of the log**; fresh-per-run keeps it. A kernel-style backend remains expressible behind the seam later, with its own logging story.
123
+
124
+ **这正是 dashr 现在的做法。** 上游为了「每个请求是日志的纯函数、会话可完整重建」这个保证,主动放弃了持久化 kernel;dashr 反其道而行,选了持久化 IPython kernel,因此:
125
+
126
+ - **得到**:对偏好编程/强化编程训练的模型更直接、状态可累积(不需要每次重新声明变量/import)、真正的交互式内核体验。
127
+ - **失去**:跨 cell 状态对 session log 不可见 → 破坏了「纯函数 of log」的可重建性;任何一次会话回放都无法仅凭日志重建出与当时一致的 kernel 内存态。
128
+
129
+ 这不是对错问题,而是 **capability(能力)与 reproducibility/security(可重建性/安全)的取舍**——dashr 站在了「能力/直接性」这一侧,上游站在了「可重建/可审计」这一侧。
130
+
131
+ ---
132
+
133
+ ## 10. 对 dashr 的启示(可选下一步)
134
+
135
+ 1. **接口命名**:上游用 `tools.name()` 命名空间,dashr 用扁平 `name()`。命名空间能显著缓解「工具目录像原生函数、被模型直接调用」的心智摩擦(本会话实测两次直接调 `grep`/`read` 被拒)。
136
+ 2. **无状态 vs 有状态**:dashr 的持久化 kernel 需要补「状态可见化」——至少把关键状态(如写入过的变量、已安装的包)显式记录进 log,否则回放/审计会失真。上游的 fresh-per-run 是零成本的这一面。
137
+ 3. **沙箱叙事**:上游已经把「containment ≠ security boundary」写进 README 和设计文档;dashr 的文档可以对齐这个表述,把「kernel 原生 I/O 可写工作区外」从「隐患」重新定性为「bash 等价信任姿态」。
@@ -0,0 +1,201 @@
1
+ # DASHR 蓝图评审 v1.0 — 对 dashr-blueprint.md v0.3
2
+
3
+ > 日期:2026-08-16 · 评审对象:`dashr-blueprint.md` v0.3(2026-08-16)
4
+ > 方法:不评观点、评证据——蓝图引用的每处"源码证据"到两个 clone
5
+ > (`deepseek-harness @47f9438` / `prime-agent @97b994c`)逐条核实,
6
+ > 再核对推理是否用满了证据。讨论底稿为 2026-08-16 会话,本文为其档存。
7
+ > 一句话结论:**方向判断与证据链质量高,抽查引用全部属实;另发现 4 处
8
+ > 上游利好、1 处被低估的明文契约冲突、4 个蓝图未触到的决策点。**
9
+
10
+ ## 0. 验证记录(蓝图引用核实)
11
+
12
+ | 蓝图引用 | 出处(clone 内实读) | 结果 |
13
+ |---|---|---|
14
+ | `CodeRunRequest.program` = async function body,一次性 run | `packages/code-runtime/code-runtime/src/types.ts` | ✅ |
15
+ | `RunCodeFlavor` 按 language 注册、`PYTHON_FLAVOR` 已存在 | `packages/core/tools/src/code-mode.ts`(`RUN_CODE_FLAVORS` + `resolveFlavor`) | ✅ |
16
+ | worker provider = 标准 Cordis 插件(Context + schemastery z) | `code-runtime-worker-thread/src/index.ts` | ✅ |
17
+ | provider 已 import `snapshotJsonValue` from `@deepseek-ai/dsh-session` | 同上 L18 | ✅ |
18
+ | preset 会话锁 `agent-preset-locked` | `packages/host/apiproxy/src/*`;agent-presets README | ✅ |
19
+ | PA `KernelManager` 构造参数(sessionId/hostHandlers/pythonSkills/snapshot) | `prime-agent/.../core/kernel/index.ts` L160-164, L625 | ✅ |
20
+ | state-snapshot.ts 297 行;1500ms debounce;cleanup → `shutdown({snapshot:true})` | 同上(wc=297;L151;L551-565) | ✅ |
21
+
22
+ ---
23
+
24
+ ## 1. 核心异议:run 隔离是**明文契约**,不是"隐含假设"(风险表第 1 条需改写)
25
+
26
+ `CodeRuntime` 抽象类 doc(`code-runtime/src/index.ts`)对实现者的明文要求:
27
+
28
+ > "Implementations bridge structured-cloneable bindings, materialize each
29
+ > declared namespace rejection class, **treat programs as hostile peers,
30
+ > isolate runs from one another**, and terminate and await in-flight runs
31
+ > during disposal."
32
+
33
+ 蓝图 §5 风险表第 1 条把它写成"契约**隐含**一次性 run"——低估了严重性。
34
+ run 间隔离是 Service Definition 的书面 invariant,DASHR 的立身之本
35
+ (跨 run 持久 namespace)**直接与之抵触**。后果:
36
+
37
+ - "provider 可替换、Consumer 零改动"在**机械层面**成立(接口签名满足),
38
+ 在**语义层面**是违反书面契约的第三方实现——恰恰是最容易在上游升级时
39
+ 静默坏掉的那类(上游按契约优化 Consumer/清理逻辑时不会通知违约者)。
40
+
41
+ **处置选项**:
42
+
43
+ | 路线 | 说明 | 评估 |
44
+ |---|---|---|
45
+ | A(推荐) | 上游提 issue/PR:给 Service Definition 加 `stateful` / `sessionAffinity` capability descriptor | 时机好——kernel 文件首行官方 TODO("RLM-1 weights 落地后重估 persistent kernel vs stateless python -c")说明上游本就在想此方向,DASHR 是现成数据点。M1 即启动对话 |
46
+ | B | 插件私有分叉契约、文档化 divergence | 可行但脆弱,升级靠人肉 re-verify |
47
+ | C | 换 service 名(如 `ctx.kernelRuntime`)自立门户 | 失去 Consumer 零改动红利,不推荐 |
48
+
49
+ 蓝图动作:§5 风险表第 1 条"缓解"从"M1 实测"升格为"M1 实测 **+ 上游
50
+ stateful descriptor 对话启动**"。
51
+
52
+ ## 2. 利好:上游比蓝图以为的更友好(4 项,可入蓝图加强论证)
53
+
54
+ ### 2.1 Python 是预留 portability target,不是蹭道
55
+
56
+ `PORTABLE_RESERVED_WORDS` 注释(`code-runtime/src/index.ts`):
57
+
58
+ > "Python is a portability target here **even though only the TypeScript
59
+ > worker has a published backend**."
60
+
61
+ ### 2.2 Python backend 的 bootstrap wrapper 上游已设计过
62
+
63
+ `RESERVED_BINDING_GLOBALS` 含 `__dsh_main__` / `__builtins__` / `__name__`,
64
+ 注释明说 reserved for "the Python backend's bootstrap wrapper and seeded
65
+ module globals"。即 **async-function-body 契约到 Python 的 wrapper 适配
66
+ 上游已有设计稿**——§1.1 "cell 语义兼容函数体契约"论证可直接引这条,
67
+ 比现有论证更硬。
68
+
69
+ ### 2.3 `mode: 'code'` / `'both'` 是内置机制,§7.2 "唯一界面"免费获得
70
+
71
+ `py-types.ts` 头部:
72
+
73
+ > "Under `mode: 'code'` the native tool schemas are omitted from the
74
+ > request, so this generated SDK is the model's ONLY source... under
75
+ > `mode: 'both'` the native schemas ship alongside it."
76
+
77
+ §7.2 设想的"以 IPython kernel 为唯一工具界面的第五 preset"无需自研
78
+ schema 抑制机制——组 `mode: 'code'` 的 preset 即可。这同时消解了
79
+ "原生工具 + run_code 双界面导致模型重复调用"的潜在隐患。
80
+
81
+ ### 2.4 工具桥比蓝图估的便宜,风险表可降级
82
+
83
+ `code-mode.ts` 头部:
84
+
85
+ > "Programs call the registry's agent-visible tools through **nested
86
+ > executions scheduled under the native concurrency contract**; each
87
+ > sub-dispatch is **logged for reconstruction**, while only the outer
88
+ > curated result enters model history."
89
+
90
+ 嵌套执行调度 + 审计 logging 全在 **Consumer 侧**(不用 provider 重做)。
91
+ provider 只需把 `CodeBindingNamespace[]` 物化为 Python async 函数
92
+ (JSON in/out,与 PA `host_request` 同形)。§5 风险表"工具桥并行语义"
93
+ 可从 中 降为 低-中。
94
+
95
+ ## 3. 决策点:完成值语义(PA repr 习惯 vs dsh fail-the-run 契约)
96
+
97
+ `types.ts`(`CodeRunResult.value` doc):
98
+
99
+ > "Invalid or over-limit completions **fail the run instead of
100
+ > substituting a rendered string**."
101
+
102
+ - PA 范式:cell 最后表达式的 repr 自动展示(`df` 直接可见)
103
+ - dsh 契约:`return df` → `invalid-output` **run 失败**
104
+ - `PYTHON_FLAVOR` schema 文案已在训练模型 "only that comes back, so
105
+ curate it",但 PA 迁移来的习惯会踩坑
106
+
107
+ **建议**:严格守约(与上游一致),在 py-types SDK instructions 层补一条
108
+ PA→dsh 迁移提示("repr 不会自动展示;显式 print/repr 或 return 可 JSON
109
+ 化的小结")。**不建议** wrapper 兜底 repr——违反契约字面义,回到 §1
110
+ 违约实现的老路。
111
+
112
+ ## 4. 决策点:`'worker-exit'` 与 abort 在持久 kernel 上被放大
113
+
114
+ - worker-thread 死了丢**一次 run**;kernel 死了丢**整个会话的变量**,
115
+ 且模型还以为 `df` 存在(上下文无感知)
116
+ - 好在 PA `KernelManager` L163 已有 "Persist/revive the user namespace
117
+ across kernel **restarts** and session resume"
118
+ - DASHR 应把以下写成明确行为:**kernel death → 从 snapshot 自动 revive
119
+ → error message 告知模型"namespace 已从 turn-N 快照恢复,最近 K 轮
120
+ 变量操作需重放"**
121
+ - abort:dsh 契约要 "hard, even mid-loop";IPython interrupt 是控制通道
122
+ **软**中断(C 扩展内不可中断;PA L46 有 busy-kernel 提示文案)。
123
+ 需要 interrupt → grace → restart(revive) 升级策略,建议进 §8 设计
124
+
125
+ ## 5. 蓝图未触:子代理继承 preset 的连带效应
126
+
127
+ agent-presets README:
128
+
129
+ > "A subagent's child joins its parent's standing composition through
130
+ > `composeFrom()`, never through `mount()`."
131
+
132
+ 即 dsh subagent **继承父 composition**——rlm() 派生的每个子代理都会挂
133
+ DASHR provider。若 kernel 非 lazy,一次并行 rlm() ×N = N 个 IPython
134
+ kernel 子进程。
135
+
136
+ - **要求**:kernel 必须 **lazy-start**(首个 run_code 才拉起;PA
137
+ `IpythonKernelProvisioner.ensure()` 已是此形态)——建议写进 §9 与 M3
138
+ - **反面是机会**:子代理跑的是新 kernel,变量不共享——这反而抬高了
139
+ phase 2 fork-server(复用父 kernel 状态)的接入价值
140
+
141
+ ## 6. §8 快照一致性可以再进一步
142
+
143
+ - 1500ms debounce + 崩溃 ⇒ snapshot 必然落后 transcript 若干 turn;
144
+ dsh 若支持历史编辑/中途回滚,dill 是**不透明 blob**、无法随 transcript
145
+ 回滚
146
+ - 建议蓝图明确一句:**变量态与 transcript 非事务一致;resume 以
147
+ snapshot + manifest(python 版本/venv/skills 清单)校验为准,不匹配则
148
+ 降级为空 namespace 并告知模型**
149
+ - 大对象(GB 级 DataFrame)× 1500ms debounce = IO 风暴:现有"serialize
150
+ 黑名单"建议升格为 **size-cap + turn-end snapshot 混合策略**,列为
151
+ M3 设计点
152
+
153
+ ## 7. 勘误两处
154
+
155
+ 1. §7.2 "四个运行模式(standard/minimal/code/creator)":本次抽查仅在
156
+ `packages/preset/agent-presets/tests/fixtures/` 核实了
157
+ standard/minimal;code/creator 两个名字未在 clone 的 `packages/preset`
158
+ 内定位(可能在 apps/cli 或发布版文档)。不影响结论,引用出处建议修准。
159
+ 2. §7.2 "包名规约 `@deepseek-ai/dsh-<name>` 系":那是**官方包**的 npm
160
+ scope,第三方不能发布。DASHR 应用自有 scope(如
161
+ `@<user>/dashr-code-runtime-ipython`);`dsh plugin add <pkg>` 对任意
162
+ npm 包成立,不受影响。
163
+
164
+ ## 8. 里程碑验收补充
165
+
166
+ - **M1 加四项**:
167
+ 1. 并行 run_code ×2 的行为(`enqueueExecute` 串行化 + 结果归属正确)
168
+ 2. abort 中断后 namespace 一致性
169
+ 3. session end 时 disposer → `shutdown({snapshot:true})` 落盘验证
170
+ 4. 上游 stateful descriptor 的 issue/PR 发出(对应 §1 路线 A)
171
+ - **M3 加两项**:
172
+ 1. lazy-start 要求落地
173
+ 2. 子代理 kernel 计数断言(rlm() ×3 后宿主 kernel 数 ≤1)
174
+
175
+ ## 9. 待决清单(需用户拍板)
176
+
177
+ | # | 决策 | 选项与倾向 |
178
+ |---|---|---|
179
+ | 1 | 契约冲突处置路线(§1) | A 上游 descriptor PR(推荐)/ B 私有分叉 / C 换 service 名 |
180
+ | 2 | 完成值语义(§3) | 严格守约 + SDK 迁移提示(推荐)/ wrapper 兜底 repr |
181
+ | 3 | lazy-start 是否作为 M3 硬性要求(§5) | 建议是 |
182
+ | 4 | 包名 scope(§7.2) | 自有 scope(建议),具体名待定 |
183
+ | 5 | §7.2 四模式表述出处修准(§7) | 待定位 code/creator 实际出处后改写 |
184
+
185
+ ---
186
+
187
+ ## 附:与蓝图章节的对应
188
+
189
+ | 本文章 | 对应蓝图章节 | 性质 |
190
+ |---|---|---|
191
+ | §1 | §5 风险表第 1 条 | 改写(严重性升格) |
192
+ | §2 | §1.1 / §7.2 | 加强论证 |
193
+ | §3 | (新) | 决策点 |
194
+ | §4 | §5 / §8 | 补充设计 |
195
+ | §5 | §9 / §6 M3 | 补充要求 |
196
+ | §6 | §8 | 收紧定义 |
197
+ | §7 | §7.2 | 勘误 |
198
+ | §8 | §6 | 验收补充 |
199
+
200
+ 下一步二选一:本文保持独立评审档、蓝图另行吸收出 v0.3.1;或直接把
201
+ 待决清单拍板后合并。默认前者(评审与蓝图分层,便于追溯)。