agent-relay 3.2.2 → 3.2.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 (246) hide show
  1. package/bin/agent-relay-broker-darwin-arm64 +0 -0
  2. package/bin/agent-relay-broker-darwin-x64 +0 -0
  3. package/bin/agent-relay-broker-linux-arm64 +0 -0
  4. package/bin/agent-relay-broker-linux-x64 +0 -0
  5. package/dist/index.cjs +1358 -941
  6. package/dist/src/cli/commands/agent-management.d.ts +2 -2
  7. package/dist/src/cli/commands/agent-management.d.ts.map +1 -1
  8. package/dist/src/cli/commands/agent-management.js +41 -240
  9. package/dist/src/cli/commands/agent-management.js.map +1 -1
  10. package/dist/src/cli/commands/messaging.d.ts +1 -1
  11. package/dist/src/cli/commands/messaging.d.ts.map +1 -1
  12. package/dist/src/cli/commands/messaging.js +14 -5
  13. package/dist/src/cli/commands/messaging.js.map +1 -1
  14. package/dist/src/cli/lib/agent-management-listing.d.ts +4 -1
  15. package/dist/src/cli/lib/agent-management-listing.d.ts.map +1 -1
  16. package/dist/src/cli/lib/agent-management-listing.js +27 -2
  17. package/dist/src/cli/lib/agent-management-listing.js.map +1 -1
  18. package/package.json +11 -10
  19. package/packages/acp-bridge/package.json +2 -2
  20. package/packages/config/package.json +1 -1
  21. package/packages/hooks/package.json +4 -4
  22. package/packages/memory/package.json +2 -2
  23. package/packages/openclaw/package.json +2 -2
  24. package/packages/policy/package.json +2 -2
  25. package/packages/sdk/ADAPTER_REVIEW.md +109 -0
  26. package/packages/sdk/dist/client.d.ts +66 -0
  27. package/packages/sdk/dist/client.d.ts.map +1 -1
  28. package/packages/sdk/dist/client.js +230 -0
  29. package/packages/sdk/dist/client.js.map +1 -1
  30. package/packages/sdk/dist/communicate/a2a-bridge.d.ts +25 -0
  31. package/packages/sdk/dist/communicate/a2a-bridge.d.ts.map +1 -0
  32. package/packages/sdk/dist/communicate/a2a-bridge.js +89 -0
  33. package/packages/sdk/dist/communicate/a2a-bridge.js.map +1 -0
  34. package/packages/sdk/dist/communicate/a2a-server.d.ts +31 -0
  35. package/packages/sdk/dist/communicate/a2a-server.d.ts.map +1 -0
  36. package/packages/sdk/dist/communicate/a2a-server.js +220 -0
  37. package/packages/sdk/dist/communicate/a2a-server.js.map +1 -0
  38. package/packages/sdk/dist/communicate/a2a-transport.d.ts +48 -0
  39. package/packages/sdk/dist/communicate/a2a-transport.d.ts.map +1 -0
  40. package/packages/sdk/dist/communicate/a2a-transport.js +302 -0
  41. package/packages/sdk/dist/communicate/a2a-transport.js.map +1 -0
  42. package/packages/sdk/dist/communicate/a2a-types.d.ts +107 -0
  43. package/packages/sdk/dist/communicate/a2a-types.d.ts.map +1 -0
  44. package/packages/sdk/dist/communicate/a2a-types.js +209 -0
  45. package/packages/sdk/dist/communicate/a2a-types.js.map +1 -0
  46. package/packages/sdk/dist/communicate/adapters/claude-sdk.d.ts +28 -0
  47. package/packages/sdk/dist/communicate/adapters/claude-sdk.d.ts.map +1 -0
  48. package/packages/sdk/dist/communicate/adapters/claude-sdk.js +47 -0
  49. package/packages/sdk/dist/communicate/adapters/claude-sdk.js.map +1 -0
  50. package/packages/sdk/dist/communicate/adapters/crewai.d.ts +42 -0
  51. package/packages/sdk/dist/communicate/adapters/crewai.d.ts.map +1 -0
  52. package/packages/sdk/dist/communicate/adapters/crewai.js +95 -0
  53. package/packages/sdk/dist/communicate/adapters/crewai.js.map +1 -0
  54. package/packages/sdk/dist/communicate/adapters/google-adk.d.ts +53 -0
  55. package/packages/sdk/dist/communicate/adapters/google-adk.d.ts.map +1 -0
  56. package/packages/sdk/dist/communicate/adapters/google-adk.js +77 -0
  57. package/packages/sdk/dist/communicate/adapters/google-adk.js.map +1 -0
  58. package/packages/sdk/dist/communicate/adapters/index.d.ts +7 -0
  59. package/packages/sdk/dist/communicate/adapters/index.d.ts.map +1 -0
  60. package/packages/sdk/dist/communicate/adapters/index.js +7 -0
  61. package/packages/sdk/dist/communicate/adapters/index.js.map +1 -0
  62. package/packages/sdk/dist/communicate/adapters/langgraph.d.ts +40 -0
  63. package/packages/sdk/dist/communicate/adapters/langgraph.d.ts.map +1 -0
  64. package/packages/sdk/dist/communicate/adapters/langgraph.js +77 -0
  65. package/packages/sdk/dist/communicate/adapters/langgraph.js.map +1 -0
  66. package/packages/sdk/dist/communicate/adapters/openai-agents.d.ts +25 -0
  67. package/packages/sdk/dist/communicate/adapters/openai-agents.d.ts.map +1 -0
  68. package/packages/sdk/dist/communicate/adapters/openai-agents.js +70 -0
  69. package/packages/sdk/dist/communicate/adapters/openai-agents.js.map +1 -0
  70. package/packages/sdk/dist/communicate/adapters/pi.d.ts +45 -0
  71. package/packages/sdk/dist/communicate/adapters/pi.d.ts.map +1 -0
  72. package/packages/sdk/dist/communicate/adapters/pi.js +59 -0
  73. package/packages/sdk/dist/communicate/adapters/pi.js.map +1 -0
  74. package/packages/sdk/dist/communicate/core.d.ts +58 -0
  75. package/packages/sdk/dist/communicate/core.d.ts.map +1 -0
  76. package/packages/sdk/dist/communicate/core.js +128 -0
  77. package/packages/sdk/dist/communicate/core.js.map +1 -0
  78. package/packages/sdk/dist/communicate/index.d.ts +4 -0
  79. package/packages/sdk/dist/communicate/index.d.ts.map +1 -0
  80. package/packages/sdk/dist/communicate/index.js +4 -0
  81. package/packages/sdk/dist/communicate/index.js.map +1 -0
  82. package/packages/sdk/dist/communicate/transport.d.ts +36 -0
  83. package/packages/sdk/dist/communicate/transport.d.ts.map +1 -0
  84. package/packages/sdk/dist/communicate/transport.js +371 -0
  85. package/packages/sdk/dist/communicate/transport.js.map +1 -0
  86. package/packages/sdk/dist/communicate/types.d.ts +58 -0
  87. package/packages/sdk/dist/communicate/types.d.ts.map +1 -0
  88. package/packages/sdk/dist/communicate/types.js +66 -0
  89. package/packages/sdk/dist/communicate/types.js.map +1 -0
  90. package/packages/sdk/dist/workflows/builder.d.ts +35 -5
  91. package/packages/sdk/dist/workflows/builder.d.ts.map +1 -1
  92. package/packages/sdk/dist/workflows/builder.js +81 -7
  93. package/packages/sdk/dist/workflows/builder.js.map +1 -1
  94. package/packages/sdk/dist/workflows/cli.js +14 -1
  95. package/packages/sdk/dist/workflows/cli.js.map +1 -1
  96. package/packages/sdk/dist/workflows/runner.d.ts +10 -2
  97. package/packages/sdk/dist/workflows/runner.d.ts.map +1 -1
  98. package/packages/sdk/dist/workflows/runner.js +95 -1
  99. package/packages/sdk/dist/workflows/runner.js.map +1 -1
  100. package/packages/sdk/dist/workflows/types.d.ts +11 -0
  101. package/packages/sdk/dist/workflows/types.d.ts.map +1 -1
  102. package/packages/sdk/examples/communicate/claude_sdk_example.ts +5 -0
  103. package/packages/sdk/examples/communicate/pi_example.ts +8 -0
  104. package/packages/sdk/package.json +48 -2
  105. package/packages/sdk/src/__tests__/builder-deterministic.test.ts +132 -0
  106. package/packages/sdk/src/__tests__/communicate/a2a-bridge.test.ts +211 -0
  107. package/packages/sdk/src/__tests__/communicate/a2a-server.test.ts +359 -0
  108. package/packages/sdk/src/__tests__/communicate/a2a-transport.test.ts +537 -0
  109. package/packages/sdk/src/__tests__/communicate/a2a-types.test.ts +297 -0
  110. package/packages/sdk/src/__tests__/communicate/adapters/claude-sdk.test.ts +163 -0
  111. package/packages/sdk/src/__tests__/communicate/adapters/crewai.test.ts +219 -0
  112. package/packages/sdk/src/__tests__/communicate/adapters/e2e-crewai.test.ts +101 -0
  113. package/packages/sdk/src/__tests__/communicate/adapters/e2e-google-adk.test.ts +166 -0
  114. package/packages/sdk/src/__tests__/communicate/adapters/e2e-langgraph.test.ts +181 -0
  115. package/packages/sdk/src/__tests__/communicate/adapters/e2e-openai-agents.test.ts +137 -0
  116. package/packages/sdk/src/__tests__/communicate/adapters/e2e-pi.test.ts +140 -0
  117. package/packages/sdk/src/__tests__/communicate/adapters/google-adk.test.ts +200 -0
  118. package/packages/sdk/src/__tests__/communicate/adapters/langgraph.test.ts +162 -0
  119. package/packages/sdk/src/__tests__/communicate/adapters/openai-agents.test.ts +166 -0
  120. package/packages/sdk/src/__tests__/communicate/adapters/pi.test.ts +140 -0
  121. package/packages/sdk/src/__tests__/communicate/core.test.ts +574 -0
  122. package/packages/sdk/src/__tests__/communicate/integration/cross-framework.test.ts +353 -0
  123. package/packages/sdk/src/__tests__/communicate/transport.test.ts +613 -0
  124. package/packages/sdk/src/__tests__/start-from.test.ts +346 -0
  125. package/packages/sdk/src/client.ts +301 -0
  126. package/packages/sdk/src/communicate/a2a-bridge.ts +111 -0
  127. package/packages/sdk/src/communicate/a2a-server.ts +277 -0
  128. package/packages/sdk/src/communicate/a2a-transport.ts +395 -0
  129. package/packages/sdk/src/communicate/a2a-types.ts +338 -0
  130. package/packages/sdk/src/communicate/adapters/claude-sdk.ts +85 -0
  131. package/packages/sdk/src/communicate/adapters/crewai.ts +141 -0
  132. package/packages/sdk/src/communicate/adapters/google-adk.ts +139 -0
  133. package/packages/sdk/src/communicate/adapters/index.ts +6 -0
  134. package/packages/sdk/src/communicate/adapters/langgraph.ts +112 -0
  135. package/packages/sdk/src/communicate/adapters/openai-agents.ts +113 -0
  136. package/packages/sdk/src/communicate/adapters/pi.ts +105 -0
  137. package/packages/sdk/src/communicate/core.ts +157 -0
  138. package/packages/sdk/src/communicate/index.ts +3 -0
  139. package/packages/sdk/src/communicate/transport.ts +489 -0
  140. package/packages/sdk/src/communicate/types.ts +106 -0
  141. package/packages/sdk/src/examples/workflows/fix-dashboard-user-registration.yaml +182 -0
  142. package/packages/sdk/src/workflows/builder.ts +97 -9
  143. package/packages/sdk/src/workflows/cli.ts +16 -1
  144. package/packages/sdk/src/workflows/runner.ts +110 -1
  145. package/packages/sdk/src/workflows/types.ts +14 -0
  146. package/packages/sdk/tsconfig.build.json +1 -7
  147. package/packages/sdk/tsconfig.json +1 -7
  148. package/packages/sdk-py/README.md +67 -25
  149. package/packages/sdk-py/examples/communicate/agno_example.py +8 -0
  150. package/packages/sdk-py/examples/communicate/claude_sdk_example.py +6 -0
  151. package/packages/sdk-py/examples/communicate/crewai_example.py +7 -0
  152. package/packages/sdk-py/examples/communicate/google_adk_example.py +7 -0
  153. package/packages/sdk-py/examples/communicate/openai_agents_example.py +8 -0
  154. package/packages/sdk-py/examples/communicate/swarms_example.py +7 -0
  155. package/packages/sdk-py/pyproject.toml +12 -1
  156. package/packages/sdk-py/src/agent_relay/__init__.py +8 -0
  157. package/packages/sdk-py/src/agent_relay/builder.py +65 -26
  158. package/packages/sdk-py/src/agent_relay/communicate/__init__.py +6 -0
  159. package/packages/sdk-py/src/agent_relay/communicate/a2a_bridge.py +138 -0
  160. package/packages/sdk-py/src/agent_relay/communicate/a2a_server.py +242 -0
  161. package/packages/sdk-py/src/agent_relay/communicate/a2a_transport.py +366 -0
  162. package/packages/sdk-py/src/agent_relay/communicate/a2a_types.py +294 -0
  163. package/packages/sdk-py/src/agent_relay/communicate/adapters/__init__.py +10 -0
  164. package/packages/sdk-py/src/agent_relay/communicate/adapters/agno.py +74 -0
  165. package/packages/sdk-py/src/agent_relay/communicate/adapters/claude_sdk.py +78 -0
  166. package/packages/sdk-py/src/agent_relay/communicate/adapters/crewai.py +143 -0
  167. package/packages/sdk-py/src/agent_relay/communicate/adapters/google_adk.py +69 -0
  168. package/packages/sdk-py/src/agent_relay/communicate/adapters/openai_agents.py +86 -0
  169. package/packages/sdk-py/src/agent_relay/communicate/adapters/pi.py +175 -0
  170. package/packages/sdk-py/src/agent_relay/communicate/adapters/swarms.py +44 -0
  171. package/packages/sdk-py/src/agent_relay/communicate/core.py +293 -0
  172. package/packages/sdk-py/src/agent_relay/communicate/transport.py +502 -0
  173. package/packages/sdk-py/src/agent_relay/communicate/types.py +89 -0
  174. package/packages/sdk-py/src/agent_relay/types.py +2 -1
  175. package/packages/sdk-py/tests/communicate/__init__.py +0 -0
  176. package/packages/sdk-py/tests/communicate/adapters/__init__.py +0 -0
  177. package/packages/sdk-py/tests/communicate/adapters/e2e_test_agno.py +154 -0
  178. package/packages/sdk-py/tests/communicate/adapters/e2e_test_claude_sdk.py +428 -0
  179. package/packages/sdk-py/tests/communicate/adapters/e2e_test_crewai.py +234 -0
  180. package/packages/sdk-py/tests/communicate/adapters/e2e_test_google_adk.py +182 -0
  181. package/packages/sdk-py/tests/communicate/adapters/e2e_test_langgraph.py +262 -0
  182. package/packages/sdk-py/tests/communicate/adapters/e2e_test_openai_agents.py +88 -0
  183. package/packages/sdk-py/tests/communicate/adapters/e2e_test_pi.py +156 -0
  184. package/packages/sdk-py/tests/communicate/adapters/e2e_test_swarms.py +239 -0
  185. package/packages/sdk-py/tests/communicate/adapters/test_agno.py +140 -0
  186. package/packages/sdk-py/tests/communicate/adapters/test_claude_sdk.py +147 -0
  187. package/packages/sdk-py/tests/communicate/adapters/test_crewai.py +136 -0
  188. package/packages/sdk-py/tests/communicate/adapters/test_google_adk.py +125 -0
  189. package/packages/sdk-py/tests/communicate/adapters/test_openai_agents.py +99 -0
  190. package/packages/sdk-py/tests/communicate/adapters/test_pi.py +270 -0
  191. package/packages/sdk-py/tests/communicate/adapters/test_swarms.py +113 -0
  192. package/packages/sdk-py/tests/communicate/conftest.py +555 -0
  193. package/packages/sdk-py/tests/communicate/integration/__init__.py +1 -0
  194. package/packages/sdk-py/tests/communicate/integration/test_cross_framework.py +331 -0
  195. package/packages/sdk-py/tests/communicate/integration/test_end_to_end.py +151 -0
  196. package/packages/sdk-py/tests/communicate/test_a2a_bridge.py +363 -0
  197. package/packages/sdk-py/tests/communicate/test_a2a_server.py +346 -0
  198. package/packages/sdk-py/tests/communicate/test_a2a_transport.py +561 -0
  199. package/packages/sdk-py/tests/communicate/test_a2a_types.py +342 -0
  200. package/packages/sdk-py/tests/communicate/test_auto_detect.py +67 -0
  201. package/packages/sdk-py/tests/communicate/test_core.py +331 -0
  202. package/packages/sdk-py/tests/communicate/test_transport.py +373 -0
  203. package/packages/sdk-py/tests/communicate/test_types.py +285 -0
  204. package/packages/sdk-py/tests/test_builder_deterministic.py +118 -0
  205. package/packages/telemetry/package.json +1 -1
  206. package/packages/trajectory/package.json +2 -2
  207. package/packages/user-directory/package.json +2 -2
  208. package/packages/utils/package.json +2 -2
  209. package/packages/sdk/dist/__tests__/completion-pipeline.test.d.ts +0 -14
  210. package/packages/sdk/dist/__tests__/completion-pipeline.test.d.ts.map +0 -1
  211. package/packages/sdk/dist/__tests__/completion-pipeline.test.js +0 -1476
  212. package/packages/sdk/dist/__tests__/completion-pipeline.test.js.map +0 -1
  213. package/packages/sdk/dist/__tests__/contract-fixtures.test.d.ts +0 -2
  214. package/packages/sdk/dist/__tests__/contract-fixtures.test.d.ts.map +0 -1
  215. package/packages/sdk/dist/__tests__/contract-fixtures.test.js +0 -152
  216. package/packages/sdk/dist/__tests__/contract-fixtures.test.js.map +0 -1
  217. package/packages/sdk/dist/__tests__/e2e-owner-review.test.d.ts +0 -16
  218. package/packages/sdk/dist/__tests__/e2e-owner-review.test.d.ts.map +0 -1
  219. package/packages/sdk/dist/__tests__/e2e-owner-review.test.js +0 -640
  220. package/packages/sdk/dist/__tests__/e2e-owner-review.test.js.map +0 -1
  221. package/packages/sdk/dist/__tests__/facade.test.d.ts +0 -2
  222. package/packages/sdk/dist/__tests__/facade.test.d.ts.map +0 -1
  223. package/packages/sdk/dist/__tests__/facade.test.js +0 -305
  224. package/packages/sdk/dist/__tests__/facade.test.js.map +0 -1
  225. package/packages/sdk/dist/__tests__/integration.test.d.ts +0 -2
  226. package/packages/sdk/dist/__tests__/integration.test.d.ts.map +0 -1
  227. package/packages/sdk/dist/__tests__/integration.test.js +0 -205
  228. package/packages/sdk/dist/__tests__/integration.test.js.map +0 -1
  229. package/packages/sdk/dist/__tests__/pty.test.d.ts +0 -2
  230. package/packages/sdk/dist/__tests__/pty.test.d.ts.map +0 -1
  231. package/packages/sdk/dist/__tests__/pty.test.js +0 -20
  232. package/packages/sdk/dist/__tests__/pty.test.js.map +0 -1
  233. package/packages/sdk/dist/__tests__/quickstart.test.d.ts +0 -2
  234. package/packages/sdk/dist/__tests__/quickstart.test.d.ts.map +0 -1
  235. package/packages/sdk/dist/__tests__/quickstart.test.js +0 -176
  236. package/packages/sdk/dist/__tests__/quickstart.test.js.map +0 -1
  237. package/packages/sdk/dist/__tests__/spawn-from-env.test.d.ts +0 -2
  238. package/packages/sdk/dist/__tests__/spawn-from-env.test.d.ts.map +0 -1
  239. package/packages/sdk/dist/__tests__/spawn-from-env.test.js +0 -222
  240. package/packages/sdk/dist/__tests__/spawn-from-env.test.js.map +0 -1
  241. package/packages/sdk/dist/__tests__/unit.test.d.ts +0 -2
  242. package/packages/sdk/dist/__tests__/unit.test.d.ts.map +0 -1
  243. package/packages/sdk/dist/__tests__/unit.test.js +0 -357
  244. package/packages/sdk/dist/__tests__/unit.test.js.map +0 -1
  245. package/packages/sdk-py/agent_relay/__init__.py +0 -21
  246. package/packages/sdk-py/agent_relay/models.py +0 -398
@@ -0,0 +1,182 @@
1
+ version: '1.0'
2
+ name: fix-dashboard-user-registration
3
+ description: >
4
+ Fixes the dashboard agent registration so the user registers as the current
5
+ system user (whoami / os.userInfo().username) instead of the cwd directory name.
6
+
7
+ Currently, both relaycast-provider.ts and proxy-server.ts in relay-dashboard
8
+ derive projectIdentity from path.basename(path.resolve(dataDir, '..')) — which
9
+ gives the working directory name. This workflow changes both to use
10
+ os.userInfo().username so the registered name reflects the actual user.
11
+
12
+ swarm:
13
+ pattern: pipeline
14
+ channel: wf-fix-dashboard-user-reg
15
+ maxConcurrency: 3
16
+ timeoutMs: 1200000 # 20 min
17
+
18
+ agents:
19
+ - name: implementer
20
+ cli: claude
21
+ preset: worker
22
+ role: 'Makes targeted edits to two dashboard-server files to use os.userInfo().username instead of path.basename(cwd).'
23
+ constraints:
24
+ model: sonnet
25
+
26
+ - name: reviewer
27
+ cli: claude
28
+ preset: reviewer
29
+ role: 'Reviews the diff to confirm correctness and no unintended side effects.'
30
+ constraints:
31
+ model: sonnet
32
+
33
+ workflows:
34
+ - name: default
35
+ onError: fail-fast
36
+
37
+ steps:
38
+ # ── Phase 1: Capture current code for context injection ──────────────────
39
+
40
+ - name: read-relaycast-provider
41
+ type: deterministic
42
+ command: >
43
+ sed -n '1,15p' ../relay-dashboard/packages/dashboard-server/src/relaycast-provider.ts &&
44
+ echo "---" &&
45
+ sed -n '80,100p' ../relay-dashboard/packages/dashboard-server/src/relaycast-provider.ts
46
+ captureOutput: true
47
+ failOnError: true
48
+
49
+ - name: read-proxy-server
50
+ type: deterministic
51
+ command: >
52
+ grep -n "^import" ../relay-dashboard/packages/dashboard-server/src/proxy-server.ts | head -20 &&
53
+ echo "---" &&
54
+ sed -n '205,220p' ../relay-dashboard/packages/dashboard-server/src/proxy-server.ts
55
+ captureOutput: true
56
+ failOnError: true
57
+
58
+ # ── Phase 2: Implement the fix ───────────────────────────────────────────
59
+
60
+ - name: implement
61
+ type: agent
62
+ agent: implementer
63
+ dependsOn: [read-relaycast-provider, read-proxy-server]
64
+ task: |
65
+ Fix two files in the relay-dashboard package so the dashboard user registers
66
+ with the system username instead of the cwd directory name.
67
+
68
+ ── File 1: ../relay-dashboard/packages/dashboard-server/src/relaycast-provider.ts ──
69
+
70
+ Current imports and loadRelaycastConfig function:
71
+ {{steps.read-relaycast-provider.output}}
72
+
73
+ Changes required:
74
+ 1. Add `import os from 'node:os';` after the existing `import path from 'path';` line.
75
+ 2. In the `loadRelaycastConfig` function, replace:
76
+ const projectDir = path.basename(path.resolve(dataDir, '..'));
77
+ with:
78
+ const projectIdentity = os.userInfo().username;
79
+ 3. Remove the line `const projectIdentity = projectDir.trim();` (it's now set above).
80
+ 4. The return statement `return { apiKey: envApiKey, baseUrl, projectIdentity };` stays the same.
81
+
82
+ ── File 2: ../relay-dashboard/packages/dashboard-server/src/proxy-server.ts ──
83
+
84
+ Current imports and resolveRelaycastConfig function:
85
+ {{steps.read-proxy-server.output}}
86
+
87
+ Changes required:
88
+ 1. Add `import os from 'node:os';` near the top of the file with the other imports.
89
+ 2. In the `resolveRelaycastConfig` function, replace:
90
+ const projectDir = path.basename(path.resolve(dataDir, '..'));
91
+ with:
92
+ const projectIdentity = os.userInfo().username;
93
+ 3. Update the `applyCachedAgentIdentity` call: change `projectIdentity: projectDir`
94
+ to `projectIdentity: projectIdentity` (variable is already named correctly).
95
+
96
+ IMPORTANT:
97
+ - Write both files to disk using your file-writing tools.
98
+ - Use `import os from 'node:os'` (Node.js built-in with node: prefix).
99
+ - Do not change anything else in either file.
100
+ - Preserve all existing imports, logic, and formatting.
101
+ verification:
102
+ type: exit_code
103
+
104
+ # ── Phase 3: Verify the changes look correct ─────────────────────────────
105
+
106
+ - name: verify-changes
107
+ type: deterministic
108
+ dependsOn: [implement]
109
+ command: |
110
+ echo "=== relaycast-provider.ts: os import ==="
111
+ grep -n "import os\|node:os" ../relay-dashboard/packages/dashboard-server/src/relaycast-provider.ts || echo "MISSING: os import"
112
+
113
+ echo ""
114
+ echo "=== relaycast-provider.ts: loadRelaycastConfig ==="
115
+ sed -n '85,96p' ../relay-dashboard/packages/dashboard-server/src/relaycast-provider.ts
116
+
117
+ echo ""
118
+ echo "=== proxy-server.ts: os import ==="
119
+ grep -n "import os\|node:os" ../relay-dashboard/packages/dashboard-server/src/proxy-server.ts || echo "MISSING: os import"
120
+
121
+ echo ""
122
+ echo "=== proxy-server.ts: resolveRelaycastConfig ==="
123
+ grep -n -A8 "const resolveRelaycastConfig" ../relay-dashboard/packages/dashboard-server/src/proxy-server.ts | head -15
124
+
125
+ echo ""
126
+ echo "=== Confirm no remaining path.basename(.*dataDir) calls ==="
127
+ grep -n "path.basename.*dataDir\|basename.*resolve.*dataDir" \
128
+ ../relay-dashboard/packages/dashboard-server/src/relaycast-provider.ts \
129
+ ../relay-dashboard/packages/dashboard-server/src/proxy-server.ts && echo "WARN: stale cwd reference found" || echo "OK: no stale cwd references"
130
+ captureOutput: true
131
+ failOnError: false
132
+
133
+ # ── Phase 4: Capture diff for review ─────────────────────────────────────
134
+
135
+ - name: capture-diff
136
+ type: deterministic
137
+ dependsOn: [verify-changes]
138
+ command: >
139
+ cd ../relay-dashboard &&
140
+ git diff packages/dashboard-server/src/relaycast-provider.ts
141
+ packages/dashboard-server/src/proxy-server.ts
142
+ captureOutput: true
143
+ failOnError: false
144
+
145
+ # ── Phase 5: Code review ──────────────────────────────────────────────────
146
+
147
+ - name: review
148
+ type: agent
149
+ agent: reviewer
150
+ dependsOn: [capture-diff, verify-changes]
151
+ task: |
152
+ Review this change to the relay-dashboard dashboard-server package.
153
+
154
+ The goal: dashboard user now registers with os.userInfo().username (the system user
155
+ running the process) instead of path.basename(cwd) (the working directory name).
156
+
157
+ Verification output:
158
+ {{steps.verify-changes.output}}
159
+
160
+ Diff:
161
+ {{steps.capture-diff.output}}
162
+
163
+ Review checklist:
164
+ 1. Both files now import `os` from `'node:os'` — correct prefix?
165
+ 2. `os.userInfo().username` is used in both `loadRelaycastConfig` and
166
+ `resolveRelaycastConfig` — no leftover `path.basename` / `projectDir` references?
167
+ 3. The `projectIdentity` variable name is preserved in both call sites?
168
+ 4. No unintended whitespace, import order, or formatting changes?
169
+ 5. The `path` import in relaycast-provider.ts is still present if used elsewhere in the file?
170
+
171
+ errorHandling:
172
+ strategy: fail-fast
173
+ maxRetries: 1
174
+ retryDelayMs: 5000
175
+
176
+ state:
177
+ backend: memory
178
+ ttlMs: 3600000 # 1 hour
179
+
180
+ trajectories:
181
+ enabled: true
182
+ autoDecisions: true
@@ -5,13 +5,18 @@ import type {
5
5
  AgentCli,
6
6
  AgentDefinition,
7
7
  AgentPreset,
8
+ Barrier,
9
+ CoordinationConfig,
8
10
  DryRunReport,
9
11
  ErrorHandlingConfig,
10
12
  IdleNudgeConfig,
11
13
  RelayYamlConfig,
14
+ StateConfig,
12
15
  SwarmPattern,
16
+ TrajectoryConfig,
13
17
  VerificationCheck,
14
18
  WorkflowDefinition,
19
+ WorkflowExecuteOptions,
15
20
  WorkflowRunRow,
16
21
  WorkflowStep,
17
22
  } from './types.js';
@@ -52,15 +57,27 @@ export interface AgentStepOptions {
52
57
  export interface DeterministicStepOptions {
53
58
  type: 'deterministic';
54
59
  command: string;
55
- dependsOn?: string[];
56
- /** Fail if command exit code is non-zero. Default: true. */
57
- failOnError?: boolean;
58
60
  /** Capture stdout as step output for downstream steps. Default: true. */
59
61
  captureOutput?: boolean;
62
+ /** Fail if command exit code is non-zero. Default: true. */
63
+ failOnError?: boolean;
64
+ dependsOn?: string[];
65
+ verification?: VerificationCheck;
60
66
  timeoutMs?: number;
61
67
  }
62
68
 
63
- export type StepOptions = AgentStepOptions | DeterministicStepOptions;
69
+ /** Options for worktree steps (create/checkout git worktrees). */
70
+ export interface WorktreeStepOptions {
71
+ type: 'worktree';
72
+ branch: string;
73
+ baseBranch?: string;
74
+ path?: string;
75
+ createBranch?: boolean;
76
+ dependsOn?: string[];
77
+ timeoutMs?: number;
78
+ }
79
+
80
+ export type StepOptions = AgentStepOptions | DeterministicStepOptions | WorktreeStepOptions;
64
81
 
65
82
  export interface ErrorOptions {
66
83
  maxRetries?: number;
@@ -83,6 +100,10 @@ export interface WorkflowRunOptions {
83
100
  dryRun?: boolean;
84
101
  /** External step executor (e.g. Daytona sandbox backend). */
85
102
  executor?: StepExecutor;
103
+ /** Start from a specific step, skipping all predecessors. */
104
+ startFrom?: string;
105
+ /** Previous run ID whose cached outputs are used with startFrom. */
106
+ previousRunId?: string;
86
107
  }
87
108
 
88
109
  // ── WorkflowBuilder ─────────────────────────────────────────────────────────
@@ -113,6 +134,11 @@ export class WorkflowBuilder {
113
134
  private _agents: AgentDefinition[] = [];
114
135
  private _steps: WorkflowStep[] = [];
115
136
  private _errorHandling?: ErrorHandlingConfig;
137
+ private _coordination?: CoordinationConfig;
138
+ private _state?: StateConfig;
139
+ private _trajectories?: TrajectoryConfig | false;
140
+ private _startFrom?: string;
141
+ private _previousRunId?: string;
116
142
 
117
143
  constructor(name: string) {
118
144
  this._name = name;
@@ -154,6 +180,36 @@ export class WorkflowBuilder {
154
180
  return this;
155
181
  }
156
182
 
183
+ /** Set workflow coordination settings (barriers, voting threshold, consensus strategy). */
184
+ coordination(config: CoordinationConfig): this {
185
+ this._coordination = config;
186
+ return this;
187
+ }
188
+
189
+ /** Configure shared workflow state backend settings. */
190
+ state(config: StateConfig): this {
191
+ this._state = config;
192
+ return this;
193
+ }
194
+
195
+ /** Configure trajectory recording, or pass `false` to disable it. */
196
+ trajectories(config: TrajectoryConfig | false): this {
197
+ this._trajectories = config;
198
+ return this;
199
+ }
200
+
201
+ /** Start execution from a specific step, skipping all predecessor steps. */
202
+ startFrom(stepName: string): this {
203
+ this._startFrom = stepName;
204
+ return this;
205
+ }
206
+
207
+ /** Set the previous run ID whose cached step outputs should be used with startFrom. */
208
+ previousRunId(id: string): this {
209
+ this._previousRunId = id;
210
+ return this;
211
+ }
212
+
157
213
  /** Add an agent definition. */
158
214
  agent(name: string, options: AgentOptions): this {
159
215
  const def: AgentDefinition = {
@@ -192,21 +248,44 @@ export class WorkflowBuilder {
192
248
  const step: WorkflowStep = { name };
193
249
 
194
250
  if ('type' in options && options.type === 'deterministic') {
251
+ if (!options.command) {
252
+ throw new Error('deterministic steps must have a command');
253
+ }
254
+ if ('agent' in options || 'task' in options) {
255
+ throw new Error('deterministic steps must not have agent or task');
256
+ }
195
257
  step.type = 'deterministic';
196
258
  step.command = options.command;
197
- if (options.failOnError !== undefined) step.failOnError = options.failOnError;
198
259
  if (options.captureOutput !== undefined) step.captureOutput = options.captureOutput;
260
+ if (options.failOnError !== undefined) step.failOnError = options.failOnError;
261
+ if (options.dependsOn !== undefined) step.dependsOn = options.dependsOn;
262
+ if (options.verification !== undefined) step.verification = options.verification;
263
+ if (options.timeoutMs !== undefined) step.timeoutMs = options.timeoutMs;
264
+ } else if ('type' in options && options.type === 'worktree') {
265
+ if ('agent' in options || 'task' in options) {
266
+ throw new Error('worktree steps must not have agent or task');
267
+ }
268
+ step.type = 'worktree';
269
+ step.branch = options.branch;
270
+ if (options.baseBranch !== undefined) step.baseBranch = options.baseBranch;
271
+ if (options.path !== undefined) step.path = options.path;
272
+ if (options.createBranch !== undefined) step.createBranch = options.createBranch;
273
+ if (options.dependsOn !== undefined) step.dependsOn = options.dependsOn;
274
+ if (options.timeoutMs !== undefined) step.timeoutMs = options.timeoutMs;
199
275
  } else {
276
+ // Agent step
200
277
  const agentOpts = options as AgentStepOptions;
278
+ if (!agentOpts.agent || !agentOpts.task) {
279
+ throw new Error('Agent steps must have both agent and task');
280
+ }
201
281
  step.agent = agentOpts.agent;
202
282
  step.task = agentOpts.task;
283
+ if (agentOpts.dependsOn !== undefined) step.dependsOn = agentOpts.dependsOn;
203
284
  if (agentOpts.verification !== undefined) step.verification = agentOpts.verification;
285
+ if (agentOpts.timeoutMs !== undefined) step.timeoutMs = agentOpts.timeoutMs;
204
286
  if (agentOpts.retries !== undefined) step.retries = agentOpts.retries;
205
287
  }
206
288
 
207
- if (options.dependsOn !== undefined) step.dependsOn = options.dependsOn;
208
- if (options.timeoutMs !== undefined) step.timeoutMs = options.timeoutMs;
209
-
210
289
  this._steps.push(step);
211
290
  return this;
212
291
  }
@@ -251,6 +330,9 @@ export class WorkflowBuilder {
251
330
  if (this._channel !== undefined) config.swarm.channel = this._channel;
252
331
  if (this._idleNudge !== undefined) config.swarm.idleNudge = this._idleNudge;
253
332
  if (this._errorHandling !== undefined) config.errorHandling = this._errorHandling;
333
+ if (this._coordination !== undefined) config.coordination = this._coordination;
334
+ if (this._state !== undefined) config.state = this._state;
335
+ if (this._trajectories !== undefined) config.trajectories = this._trajectories;
254
336
 
255
337
  return config;
256
338
  }
@@ -285,7 +367,13 @@ export class WorkflowBuilder {
285
367
  runner.on(options.onEvent);
286
368
  }
287
369
 
288
- return runner.execute(config, options.workflow, options.vars);
370
+ const startFrom = this._startFrom ?? options.startFrom;
371
+ const previousRunId = this._previousRunId ?? options.previousRunId;
372
+ const executeOptions: WorkflowExecuteOptions | undefined = startFrom
373
+ ? { startFrom, previousRunId }
374
+ : undefined;
375
+
376
+ return runner.execute(config, options.workflow, options.vars, executeOptions);
289
377
  }
290
378
  }
291
379
 
@@ -28,6 +28,8 @@ Arguments:
28
28
  Options:
29
29
  --workflow <name> Run a specific workflow by name (default: first)
30
30
  --resume <run-id> Resume a failed or interrupted run by its run ID
31
+ --start-from <step> Start from a specific step, skipping predecessors
32
+ --previous-run-id <id> Use cached outputs from a specific prior run (with --start-from)
31
33
  --validate Validate workflow YAML for common issues without running
32
34
  --help Show this help message
33
35
 
@@ -136,6 +138,18 @@ async function main(): Promise<void> {
136
138
  workflowName = args[workflowIdx + 1];
137
139
  }
138
140
 
141
+ let startFromStep: string | undefined;
142
+ const startFromIdx = args.indexOf('--start-from');
143
+ if (startFromIdx !== -1 && args[startFromIdx + 1]) {
144
+ startFromStep = args[startFromIdx + 1];
145
+ }
146
+
147
+ let previousRunId: string | undefined;
148
+ const prevRunIdx = args.indexOf('--previous-run-id');
149
+ if (prevRunIdx !== -1 && args[prevRunIdx + 1]) {
150
+ previousRunId = args[prevRunIdx + 1];
151
+ }
152
+
139
153
  const isValidate = args.includes('--validate');
140
154
 
141
155
  console.log(`Running workflow from ${yamlPath}...`);
@@ -157,7 +171,8 @@ async function main(): Promise<void> {
157
171
  }
158
172
 
159
173
  runner.on((event) => console.log(formatEvent(event)));
160
- const result = await runner.execute(config, workflowName);
174
+ const executeOptions = startFromStep ? { startFrom: startFromStep, previousRunId } : undefined;
175
+ const result = await runner.execute(config, workflowName, undefined, executeOptions);
161
176
 
162
177
  if (result.status === 'completed') {
163
178
  console.log(`\nWorkflow completed successfully.`);
@@ -59,6 +59,7 @@ import type {
59
59
  WorkflowRunRow,
60
60
  WorkflowRunStatus,
61
61
  WorkflowStep,
62
+ WorkflowExecuteOptions,
62
63
  WorkflowStepCompletionReason,
63
64
  WorkflowStepRow,
64
65
  WorkflowStepStatus,
@@ -1778,7 +1779,8 @@ export class WorkflowRunner {
1778
1779
  async execute(
1779
1780
  config: RelayYamlConfig,
1780
1781
  workflowName?: string,
1781
- vars?: VariableContext
1782
+ vars?: VariableContext,
1783
+ executeOptions?: WorkflowExecuteOptions
1782
1784
  ): Promise<WorkflowRunRow> {
1783
1785
  // Set up abort controller early so callers can abort() even during setup
1784
1786
  this.abortController = new AbortController();
@@ -1861,6 +1863,49 @@ export class WorkflowRunner {
1861
1863
  stepStates.set(step.name, { row: stepRow });
1862
1864
  }
1863
1865
 
1866
+ // Handle startFrom: skip all transitive dependencies of the target step
1867
+ if (executeOptions?.startFrom) {
1868
+ const startFromName = executeOptions.startFrom;
1869
+ const stepNames = new Set(resolvedWorkflow.steps.map((s) => s.name));
1870
+ if (!stepNames.has(startFromName)) {
1871
+ throw new Error(
1872
+ `startFrom step "${startFromName}" not found in workflow. Available steps: ${[...stepNames].join(', ')}`
1873
+ );
1874
+ }
1875
+
1876
+ const transitiveDeps = this.collectTransitiveDeps(startFromName, resolvedWorkflow.steps);
1877
+ const skippedCount = transitiveDeps.size;
1878
+
1879
+ // Determine which run ID to load cached outputs from
1880
+ const cacheRunId = executeOptions.previousRunId
1881
+ ?? this.findMostRecentRunWithSteps(transitiveDeps);
1882
+
1883
+ for (const depName of transitiveDeps) {
1884
+ const state = stepStates.get(depName);
1885
+ if (!state) continue;
1886
+
1887
+ // Load cached output from a previous run if available
1888
+ const cachedOutput = cacheRunId ? this.loadStepOutput(cacheRunId, depName) : undefined;
1889
+ if (!cachedOutput) {
1890
+ this.log(`[startFrom] No cached output for skipped step "${depName}" — using empty string`);
1891
+ }
1892
+
1893
+ state.row.status = 'completed';
1894
+ state.row.output = cachedOutput ?? '';
1895
+ state.row.completedAt = now;
1896
+ await this.db.updateStep(state.row.id, {
1897
+ status: 'completed',
1898
+ output: state.row.output,
1899
+ completedAt: now,
1900
+ updatedAt: now,
1901
+ });
1902
+ }
1903
+
1904
+ if (skippedCount > 0) {
1905
+ this.log(`[startFrom] Skipping ${skippedCount} steps, starting from "${startFromName}"`);
1906
+ }
1907
+ }
1908
+
1864
1909
  return this.runWorkflowCore({
1865
1910
  run,
1866
1911
  workflow: resolvedWorkflow,
@@ -5719,6 +5764,35 @@ export class WorkflowRunner {
5719
5764
  }
5720
5765
  }
5721
5766
 
5767
+ // ── startFrom dependency resolution ─────────────────────────────────
5768
+
5769
+ /**
5770
+ * Walk the dependsOn graph backwards from a target step to collect ALL
5771
+ * transitive dependencies (i.e. every step that must complete before
5772
+ * the target step can run). The target step itself is NOT included.
5773
+ */
5774
+ private collectTransitiveDeps(targetStep: string, steps: WorkflowStep[]): Set<string> {
5775
+ const stepMap = new Map<string, WorkflowStep>();
5776
+ for (const s of steps) stepMap.set(s.name, s);
5777
+
5778
+ const deps = new Set<string>();
5779
+ const queue = [...(stepMap.get(targetStep)?.dependsOn ?? [])];
5780
+
5781
+ while (queue.length > 0) {
5782
+ const current = queue.shift()!;
5783
+ if (deps.has(current)) continue;
5784
+ deps.add(current);
5785
+ const step = stepMap.get(current);
5786
+ if (step?.dependsOn) {
5787
+ for (const dep of step.dependsOn) {
5788
+ if (!deps.has(dep)) queue.push(dep);
5789
+ }
5790
+ }
5791
+ }
5792
+
5793
+ return deps;
5794
+ }
5795
+
5722
5796
  // ── Control flow helpers ──────────────────────────────────────────────
5723
5797
 
5724
5798
  private checkAborted(): void {
@@ -6203,6 +6277,41 @@ export class WorkflowRunner {
6203
6277
  this.postToChannel(`**[${stepName}] Output:**\n\`\`\`\n${preview}\n\`\`\``, { stepName });
6204
6278
  }
6205
6279
 
6280
+ /** Scan .agent-relay/step-outputs/ for the most recent run directory containing the needed steps. */
6281
+ private findMostRecentRunWithSteps(stepNames: Set<string>): string | undefined {
6282
+ try {
6283
+ const baseDir = path.join(this.cwd, '.agent-relay', 'step-outputs');
6284
+ if (!existsSync(baseDir)) return undefined;
6285
+
6286
+ const entries = readdirSync(baseDir);
6287
+ let best: { name: string; mtime: number } | undefined;
6288
+
6289
+ for (const entry of entries) {
6290
+ const dirPath = path.join(baseDir, entry);
6291
+ try {
6292
+ const stat = statSync(dirPath);
6293
+ if (!stat.isDirectory()) continue;
6294
+
6295
+ // Check if this directory has at least one of the needed step files
6296
+ const hasAny = [...stepNames].some(name =>
6297
+ existsSync(path.join(dirPath, `${name}.md`))
6298
+ );
6299
+ if (!hasAny) continue;
6300
+
6301
+ if (!best || stat.mtimeMs > best.mtime) {
6302
+ best = { name: entry, mtime: stat.mtimeMs };
6303
+ }
6304
+ } catch {
6305
+ continue;
6306
+ }
6307
+ }
6308
+
6309
+ return best?.name;
6310
+ } catch {
6311
+ return undefined;
6312
+ }
6313
+ }
6314
+
6206
6315
  /** Load persisted step output from disk. */
6207
6316
  private loadStepOutput(runId: string, stepName: string): string | undefined {
6208
6317
  try {
@@ -502,6 +502,20 @@ export interface DryRunReport {
502
502
  estimatedTotalAgentSteps?: number;
503
503
  }
504
504
 
505
+ // ── Workflow execution options ───────────────────────────────────────────────
506
+
507
+ /** Options that control how a workflow run executes. */
508
+ export interface WorkflowExecuteOptions {
509
+ /** Start execution from a specific step, skipping all predecessor steps.
510
+ * Predecessor outputs are loaded from cached step-outputs on disk when available. */
511
+ startFrom?: string;
512
+ /** Run ID of a previous execution whose cached step outputs should be used
513
+ * when skipping predecessor steps via `startFrom`. If omitted, the runner
514
+ * scans `.agent-relay/step-outputs/` for the most recent directory that
515
+ * contains the needed step files. */
516
+ previousRunId?: string;
517
+ }
518
+
505
519
  // ── Database row types ──────────────────────────────────────────────────────
506
520
 
507
521
  export type WorkflowRunStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
@@ -14,12 +14,6 @@
14
14
  },
15
15
  "include": ["src/**/*.ts"],
16
16
  "exclude": [
17
- "src/__tests__/workflow-runner.test.ts",
18
- "src/__tests__/workflow-trajectory.test.ts",
19
- "src/__tests__/swarm-coordinator.test.ts",
20
- "src/__tests__/error-scenarios.test.ts",
21
- "src/__tests__/idle-nudge.test.ts",
22
- "src/__tests__/orchestration-upgrades.test.ts",
23
- "src/__tests__/yaml-validation.test.ts"
17
+ "src/__tests__/**"
24
18
  ]
25
19
  }
@@ -10,12 +10,6 @@
10
10
  },
11
11
  "include": ["src/**/*.ts"],
12
12
  "exclude": [
13
- "src/__tests__/workflow-runner.test.ts",
14
- "src/__tests__/workflow-trajectory.test.ts",
15
- "src/__tests__/swarm-coordinator.test.ts",
16
- "src/__tests__/error-scenarios.test.ts",
17
- "src/__tests__/idle-nudge.test.ts",
18
- "src/__tests__/orchestration-upgrades.test.ts",
19
- "src/__tests__/yaml-validation.test.ts"
13
+ "src/__tests__/**"
20
14
  ]
21
15
  }