@swarmclawai/swarmclaw 0.7.2 → 0.7.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 (274) hide show
  1. package/README.md +116 -50
  2. package/bin/package-manager.js +157 -0
  3. package/bin/package-manager.test.js +90 -0
  4. package/bin/server-cmd.js +38 -7
  5. package/bin/swarmclaw.js +54 -4
  6. package/bin/update-cmd.js +48 -10
  7. package/bin/update-cmd.test.js +55 -0
  8. package/package.json +8 -3
  9. package/scripts/postinstall.mjs +26 -0
  10. package/src/app/api/agents/[id]/route.ts +43 -0
  11. package/src/app/api/agents/[id]/thread/route.ts +39 -8
  12. package/src/app/api/agents/route.ts +35 -2
  13. package/src/app/api/auth/route.ts +77 -8
  14. package/src/app/api/chatrooms/[id]/chat/route.ts +22 -6
  15. package/src/app/api/chatrooms/[id]/pins/route.ts +2 -1
  16. package/src/app/api/chatrooms/[id]/reactions/route.ts +2 -1
  17. package/src/app/api/chatrooms/[id]/route.ts +6 -0
  18. package/src/app/api/chats/[id]/browser/route.ts +5 -1
  19. package/src/app/api/chats/[id]/chat/route.ts +7 -3
  20. package/src/app/api/chats/[id]/messages/route.ts +19 -13
  21. package/src/app/api/chats/[id]/route.ts +30 -0
  22. package/src/app/api/chats/[id]/stop/route.ts +6 -1
  23. package/src/app/api/chats/heartbeat/route.ts +2 -1
  24. package/src/app/api/chats/route.ts +23 -1
  25. package/src/app/api/connectors/[id]/doctor/route.ts +26 -0
  26. package/src/app/api/connectors/doctor/route.ts +13 -0
  27. package/src/app/api/external-agents/[id]/heartbeat/route.ts +33 -0
  28. package/src/app/api/external-agents/[id]/route.ts +31 -0
  29. package/src/app/api/external-agents/register/route.ts +3 -0
  30. package/src/app/api/external-agents/route.ts +66 -0
  31. package/src/app/api/files/open/route.ts +16 -14
  32. package/src/app/api/gateways/[id]/health/route.ts +28 -0
  33. package/src/app/api/gateways/[id]/route.ts +79 -0
  34. package/src/app/api/gateways/route.ts +57 -0
  35. package/src/app/api/memory/maintenance/route.ts +11 -1
  36. package/src/app/api/openclaw/agent-files/route.ts +27 -4
  37. package/src/app/api/openclaw/gateway/route.ts +10 -7
  38. package/src/app/api/openclaw/skills/route.ts +12 -4
  39. package/src/app/api/plugins/dependencies/route.ts +24 -0
  40. package/src/app/api/plugins/install/route.ts +15 -92
  41. package/src/app/api/plugins/route.ts +3 -26
  42. package/src/app/api/plugins/settings/route.ts +17 -12
  43. package/src/app/api/plugins/ui/route.ts +1 -0
  44. package/src/app/api/providers/[id]/discover-models/route.ts +27 -0
  45. package/src/app/api/schedules/[id]/route.ts +38 -9
  46. package/src/app/api/schedules/route.ts +51 -28
  47. package/src/app/api/settings/route.ts +55 -17
  48. package/src/app/api/setup/doctor/route.ts +6 -4
  49. package/src/app/api/tasks/[id]/route.ts +16 -6
  50. package/src/app/api/tasks/bulk/route.ts +3 -3
  51. package/src/app/api/tasks/route.ts +9 -4
  52. package/src/app/api/webhooks/[id]/route.ts +8 -1
  53. package/src/app/page.tsx +135 -17
  54. package/src/cli/binary.test.js +142 -0
  55. package/src/cli/index.js +38 -11
  56. package/src/cli/index.test.js +195 -0
  57. package/src/cli/index.ts +21 -12
  58. package/src/cli/server-cmd.test.js +59 -0
  59. package/src/cli/spec.js +20 -2
  60. package/src/components/agents/agent-card.tsx +15 -12
  61. package/src/components/agents/agent-chat-list.tsx +101 -1
  62. package/src/components/agents/agent-list.tsx +46 -9
  63. package/src/components/agents/agent-sheet.tsx +456 -23
  64. package/src/components/agents/inspector-panel.tsx +110 -49
  65. package/src/components/agents/sandbox-env-panel.tsx +4 -1
  66. package/src/components/auth/access-key-gate.tsx +36 -97
  67. package/src/components/auth/setup-wizard.tsx +970 -275
  68. package/src/components/chat/chat-area.tsx +70 -27
  69. package/src/components/chat/chat-card.tsx +6 -21
  70. package/src/components/chat/chat-header.tsx +263 -366
  71. package/src/components/chat/chat-list.tsx +62 -26
  72. package/src/components/chat/checkpoint-timeline.tsx +1 -1
  73. package/src/components/chat/message-list.tsx +145 -19
  74. package/src/components/chatrooms/chatroom-input.tsx +96 -33
  75. package/src/components/chatrooms/chatroom-list.tsx +141 -72
  76. package/src/components/chatrooms/chatroom-message.tsx +7 -6
  77. package/src/components/chatrooms/chatroom-sheet.tsx +13 -1
  78. package/src/components/chatrooms/chatroom-tool-request-banner.tsx +5 -2
  79. package/src/components/chatrooms/chatroom-view.tsx +422 -209
  80. package/src/components/chatrooms/reaction-picker.tsx +38 -33
  81. package/src/components/connectors/connector-list.tsx +265 -127
  82. package/src/components/connectors/connector-sheet.tsx +217 -0
  83. package/src/components/gateways/gateway-sheet.tsx +567 -0
  84. package/src/components/home/home-view.tsx +128 -4
  85. package/src/components/input/chat-input.tsx +135 -86
  86. package/src/components/layout/app-layout.tsx +385 -194
  87. package/src/components/layout/mobile-header.tsx +26 -8
  88. package/src/components/memory/memory-browser.tsx +71 -6
  89. package/src/components/memory/memory-card.tsx +18 -0
  90. package/src/components/memory/memory-detail.tsx +58 -31
  91. package/src/components/memory/memory-sheet.tsx +32 -4
  92. package/src/components/plugins/plugin-list.tsx +15 -3
  93. package/src/components/plugins/plugin-sheet.tsx +118 -9
  94. package/src/components/projects/project-detail.tsx +189 -1
  95. package/src/components/providers/provider-list.tsx +158 -2
  96. package/src/components/providers/provider-sheet.tsx +81 -70
  97. package/src/components/shared/agent-picker-list.tsx +2 -2
  98. package/src/components/shared/bottom-sheet.tsx +31 -15
  99. package/src/components/shared/command-palette.tsx +111 -24
  100. package/src/components/shared/confirm-dialog.tsx +45 -30
  101. package/src/components/shared/model-combobox.tsx +90 -8
  102. package/src/components/shared/settings/plugin-manager.tsx +20 -4
  103. package/src/components/shared/settings/section-capability-policy.tsx +105 -0
  104. package/src/components/shared/settings/section-heartbeat.tsx +88 -6
  105. package/src/components/shared/settings/section-orchestrator.tsx +6 -3
  106. package/src/components/shared/settings/section-runtime-loop.tsx +5 -5
  107. package/src/components/shared/settings/section-secrets.tsx +6 -6
  108. package/src/components/shared/settings/section-user-preferences.tsx +1 -1
  109. package/src/components/shared/settings/section-voice.tsx +5 -1
  110. package/src/components/shared/settings/section-web-search.tsx +10 -2
  111. package/src/components/shared/settings/settings-page.tsx +248 -47
  112. package/src/components/tasks/approvals-panel.tsx +211 -18
  113. package/src/components/tasks/task-board.tsx +242 -46
  114. package/src/components/ui/dialog.tsx +2 -2
  115. package/src/components/usage/metrics-dashboard.tsx +74 -1
  116. package/src/components/wallets/wallet-approval-dialog.tsx +59 -54
  117. package/src/components/wallets/wallet-panel.tsx +17 -5
  118. package/src/components/webhooks/webhook-sheet.tsx +7 -7
  119. package/src/lib/auth.ts +17 -0
  120. package/src/lib/chat-streaming-state.test.ts +108 -0
  121. package/src/lib/chat-streaming-state.ts +108 -0
  122. package/src/lib/heartbeat-defaults.ts +48 -0
  123. package/src/lib/memory-presentation.ts +59 -0
  124. package/src/lib/openclaw-agent-id.test.ts +14 -0
  125. package/src/lib/openclaw-agent-id.ts +31 -0
  126. package/src/lib/provider-model-discovery-client.ts +29 -0
  127. package/src/lib/providers/index.ts +12 -5
  128. package/src/lib/runtime-loop.ts +105 -3
  129. package/src/lib/safe-storage.ts +6 -1
  130. package/src/lib/server/agent-assignment.test.ts +112 -0
  131. package/src/lib/server/agent-assignment.ts +169 -0
  132. package/src/lib/server/agent-runtime-config.test.ts +141 -0
  133. package/src/lib/server/agent-runtime-config.ts +277 -0
  134. package/src/lib/server/approval-connector-notify.test.ts +253 -0
  135. package/src/lib/server/approvals-auto-approve.test.ts +264 -0
  136. package/src/lib/server/approvals.ts +483 -75
  137. package/src/lib/server/autonomy-runtime.test.ts +341 -0
  138. package/src/lib/server/browser-state.test.ts +118 -0
  139. package/src/lib/server/browser-state.ts +123 -0
  140. package/src/lib/server/build-llm.test.ts +44 -0
  141. package/src/lib/server/build-llm.ts +11 -4
  142. package/src/lib/server/builtin-plugins.ts +34 -0
  143. package/src/lib/server/chat-execution-heartbeat.test.ts +40 -0
  144. package/src/lib/server/chat-execution-tool-events.test.ts +219 -0
  145. package/src/lib/server/chat-execution.ts +402 -125
  146. package/src/lib/server/chatroom-health.test.ts +26 -0
  147. package/src/lib/server/chatroom-health.ts +2 -3
  148. package/src/lib/server/chatroom-helpers.test.ts +74 -2
  149. package/src/lib/server/chatroom-helpers.ts +144 -11
  150. package/src/lib/server/chatroom-session-persistence.test.ts +87 -0
  151. package/src/lib/server/connectors/discord.ts +175 -11
  152. package/src/lib/server/connectors/doctor.test.ts +80 -0
  153. package/src/lib/server/connectors/doctor.ts +116 -0
  154. package/src/lib/server/connectors/manager.ts +994 -130
  155. package/src/lib/server/connectors/policy.test.ts +222 -0
  156. package/src/lib/server/connectors/policy.ts +452 -0
  157. package/src/lib/server/connectors/slack.ts +189 -10
  158. package/src/lib/server/connectors/telegram.ts +65 -15
  159. package/src/lib/server/connectors/thread-context.test.ts +44 -0
  160. package/src/lib/server/connectors/thread-context.ts +72 -0
  161. package/src/lib/server/connectors/types.ts +41 -11
  162. package/src/lib/server/daemon-state.ts +62 -3
  163. package/src/lib/server/data-dir.ts +13 -0
  164. package/src/lib/server/delegation-jobs.test.ts +140 -0
  165. package/src/lib/server/delegation-jobs.ts +248 -0
  166. package/src/lib/server/document-utils.test.ts +47 -0
  167. package/src/lib/server/document-utils.ts +397 -0
  168. package/src/lib/server/eval/agent-regression.test.ts +47 -0
  169. package/src/lib/server/eval/agent-regression.ts +1742 -0
  170. package/src/lib/server/eval/runner.ts +11 -1
  171. package/src/lib/server/eval/store.ts +2 -1
  172. package/src/lib/server/heartbeat-service.ts +23 -43
  173. package/src/lib/server/heartbeat-source.test.ts +22 -0
  174. package/src/lib/server/heartbeat-source.ts +7 -0
  175. package/src/lib/server/identity-continuity.test.ts +77 -0
  176. package/src/lib/server/identity-continuity.ts +127 -0
  177. package/src/lib/server/mailbox-utils.ts +347 -0
  178. package/src/lib/server/main-agent-loop.ts +31 -964
  179. package/src/lib/server/memory-db.ts +4 -6
  180. package/src/lib/server/memory-tiers.ts +40 -0
  181. package/src/lib/server/openclaw-agent-resolver.test.ts +70 -0
  182. package/src/lib/server/openclaw-agent-resolver.ts +128 -0
  183. package/src/lib/server/openclaw-exec-config.ts +6 -5
  184. package/src/lib/server/openclaw-gateway.ts +123 -36
  185. package/src/lib/server/openclaw-skills-normalize.test.ts +56 -0
  186. package/src/lib/server/openclaw-skills-normalize.ts +136 -0
  187. package/src/lib/server/openclaw-sync.ts +3 -2
  188. package/src/lib/server/orchestrator-lg.ts +18 -8
  189. package/src/lib/server/orchestrator.ts +5 -4
  190. package/src/lib/server/playwright-proxy.mjs +27 -3
  191. package/src/lib/server/plugins.test.ts +215 -0
  192. package/src/lib/server/plugins.ts +832 -69
  193. package/src/lib/server/provider-health.ts +33 -3
  194. package/src/lib/server/provider-model-discovery.ts +481 -0
  195. package/src/lib/server/queue.ts +4 -21
  196. package/src/lib/server/runtime-settings.test.ts +119 -0
  197. package/src/lib/server/runtime-settings.ts +12 -92
  198. package/src/lib/server/schedule-normalization.ts +187 -0
  199. package/src/lib/server/scheduler.ts +2 -0
  200. package/src/lib/server/session-archive-memory.test.ts +85 -0
  201. package/src/lib/server/session-archive-memory.ts +230 -0
  202. package/src/lib/server/session-mailbox.ts +8 -18
  203. package/src/lib/server/session-reset-policy.test.ts +99 -0
  204. package/src/lib/server/session-reset-policy.ts +311 -0
  205. package/src/lib/server/session-run-manager.ts +33 -80
  206. package/src/lib/server/session-tools/autonomy-tools.test.ts +128 -0
  207. package/src/lib/server/session-tools/calendar.ts +2 -12
  208. package/src/lib/server/session-tools/connector.ts +109 -8
  209. package/src/lib/server/session-tools/context.ts +14 -2
  210. package/src/lib/server/session-tools/crawl.ts +447 -0
  211. package/src/lib/server/session-tools/crud.ts +96 -34
  212. package/src/lib/server/session-tools/delegate-fallback.test.ts +219 -0
  213. package/src/lib/server/session-tools/delegate.ts +406 -20
  214. package/src/lib/server/session-tools/discovery-approvals.test.ts +170 -0
  215. package/src/lib/server/session-tools/discovery.ts +40 -12
  216. package/src/lib/server/session-tools/document.ts +283 -0
  217. package/src/lib/server/session-tools/email.ts +1 -3
  218. package/src/lib/server/session-tools/extract.ts +137 -0
  219. package/src/lib/server/session-tools/file-normalize.test.ts +98 -0
  220. package/src/lib/server/session-tools/file-send.test.ts +84 -1
  221. package/src/lib/server/session-tools/file.ts +243 -24
  222. package/src/lib/server/session-tools/http.ts +9 -3
  223. package/src/lib/server/session-tools/human-loop.ts +227 -0
  224. package/src/lib/server/session-tools/image-gen.ts +1 -3
  225. package/src/lib/server/session-tools/index.ts +87 -2
  226. package/src/lib/server/session-tools/mailbox.ts +276 -0
  227. package/src/lib/server/session-tools/manage-schedules.test.ts +137 -0
  228. package/src/lib/server/session-tools/memory.ts +35 -3
  229. package/src/lib/server/session-tools/monitor.ts +162 -12
  230. package/src/lib/server/session-tools/normalize-tool-args.ts +17 -14
  231. package/src/lib/server/session-tools/openclaw-nodes.test.ts +111 -0
  232. package/src/lib/server/session-tools/openclaw-nodes.ts +86 -20
  233. package/src/lib/server/session-tools/platform-normalize.test.ts +142 -0
  234. package/src/lib/server/session-tools/platform.ts +142 -4
  235. package/src/lib/server/session-tools/plugin-creator.ts +95 -25
  236. package/src/lib/server/session-tools/primitive-tools.test.ts +257 -0
  237. package/src/lib/server/session-tools/replicate.ts +1 -3
  238. package/src/lib/server/session-tools/sandbox.ts +51 -92
  239. package/src/lib/server/session-tools/schedule.ts +20 -10
  240. package/src/lib/server/session-tools/session-info.ts +58 -4
  241. package/src/lib/server/session-tools/session-tools-wiring.test.ts +54 -17
  242. package/src/lib/server/session-tools/shell.ts +2 -2
  243. package/src/lib/server/session-tools/subagent.ts +195 -27
  244. package/src/lib/server/session-tools/table.ts +587 -0
  245. package/src/lib/server/session-tools/wallet.ts +13 -10
  246. package/src/lib/server/session-tools/web-browser-config.test.ts +39 -0
  247. package/src/lib/server/session-tools/web.ts +947 -108
  248. package/src/lib/server/storage.ts +255 -10
  249. package/src/lib/server/stream-agent-chat.test.ts +61 -0
  250. package/src/lib/server/stream-agent-chat.ts +185 -25
  251. package/src/lib/server/structured-extract.test.ts +72 -0
  252. package/src/lib/server/structured-extract.ts +373 -0
  253. package/src/lib/server/task-mention.test.ts +16 -2
  254. package/src/lib/server/task-mention.ts +61 -11
  255. package/src/lib/server/tool-aliases.ts +80 -12
  256. package/src/lib/server/tool-capability-policy.ts +7 -1
  257. package/src/lib/server/tool-retry.ts +2 -0
  258. package/src/lib/server/watch-jobs.test.ts +173 -0
  259. package/src/lib/server/watch-jobs.ts +532 -0
  260. package/src/lib/server/ws-hub.ts +5 -3
  261. package/src/lib/setup-defaults.ts +352 -11
  262. package/src/lib/tool-definitions.ts +3 -4
  263. package/src/lib/validation/schemas.test.ts +26 -0
  264. package/src/lib/validation/schemas.ts +62 -1
  265. package/src/lib/ws-client.ts +14 -12
  266. package/src/proxy.ts +5 -5
  267. package/src/stores/use-app-store.ts +43 -7
  268. package/src/stores/use-chat-store.ts +31 -2
  269. package/src/stores/use-chatroom-store.ts +153 -26
  270. package/src/types/index.ts +470 -44
  271. package/src/app/api/chats/[id]/main-loop/route.ts +0 -94
  272. package/src/components/chat/new-chat-sheet.tsx +0 -253
  273. package/src/lib/server/main-session.ts +0 -17
  274. package/src/lib/server/session-run-manager.test.ts +0 -26
@@ -3,13 +3,25 @@ import { tool, type StructuredToolInterface } from '@langchain/core/tools'
3
3
  import { genId } from '@/lib/id'
4
4
  import { DEFAULT_DELEGATION_MAX_DEPTH } from '@/lib/runtime-loop'
5
5
  import { loadAgents, loadSessions, saveSessions } from '../storage'
6
- import { executeSessionChatTurn } from '../chat-execution'
7
- import { log } from '../logger'
6
+ import { enqueueSessionRun } from '../session-run-manager'
8
7
  import { loadRuntimeSettings } from '../runtime-settings'
9
8
  import type { ToolBuildContext } from './context'
10
9
  import type { Plugin, PluginHooks } from '@/types'
11
10
  import { getPluginManager } from '../plugins'
12
11
  import { normalizeToolInputArgs } from './normalize-tool-args'
12
+ import { applyResolvedRoute, resolvePrimaryAgentRoute } from '../agent-runtime-config'
13
+ import {
14
+ appendDelegationCheckpoint,
15
+ cancelDelegationJob,
16
+ completeDelegationJob,
17
+ createDelegationJob,
18
+ failDelegationJob,
19
+ getDelegationJob,
20
+ listDelegationJobs,
21
+ recoverStaleDelegationJobs,
22
+ registerDelegationRuntime,
23
+ startDelegationJob,
24
+ } from '../delegation-jobs'
13
25
 
14
26
  function getSessionDepth(sessionId: string | undefined, maxDepth: number): number {
15
27
  if (!sessionId) return 0
@@ -25,40 +37,187 @@ function getSessionDepth(sessionId: string | undefined, maxDepth: number): numbe
25
37
  return depth
26
38
  }
27
39
 
40
+ function sleep(ms: number) {
41
+ return new Promise((resolve) => setTimeout(resolve, ms))
42
+ }
43
+
44
+ export function resolveSubagentBrowserProfileId(
45
+ parentSession: Record<string, unknown> | null | undefined,
46
+ childSessionId: string,
47
+ shareBrowserProfile: boolean,
48
+ ): string {
49
+ if (!shareBrowserProfile) return childSessionId
50
+ const inherited = typeof parentSession?.browserProfileId === 'string' && parentSession.browserProfileId.trim()
51
+ ? parentSession.browserProfileId.trim()
52
+ : typeof parentSession?.id === 'string' && parentSession.id.trim()
53
+ ? parentSession.id.trim()
54
+ : ''
55
+ return inherited || childSessionId
56
+ }
57
+
58
+ async function startSubagentJob(jobId: string, args: {
59
+ agentId: string
60
+ message: string
61
+ cwd?: string
62
+ shareBrowserProfile?: boolean
63
+ }, context: { sessionId?: string; cwd: string }) {
64
+ const runtime = loadRuntimeSettings()
65
+ const maxDepth = runtime.delegationMaxDepth || DEFAULT_DELEGATION_MAX_DEPTH
66
+ const agents = loadAgents()
67
+ const agent = agents[args.agentId]
68
+ if (!agent) throw new Error(`Agent "${args.agentId}" not found.`)
69
+
70
+ const depth = getSessionDepth(context.sessionId, maxDepth)
71
+ if (depth >= maxDepth) throw new Error('Max subagent depth reached.')
72
+
73
+ const sid = genId()
74
+ const now = Date.now()
75
+ const sessions = loadSessions()
76
+ const parent = context.sessionId ? sessions[context.sessionId] : null
77
+ const browserProfileId = resolveSubagentBrowserProfileId(parent, sid, args.shareBrowserProfile === true)
78
+ const nextSession = {
79
+ id: sid,
80
+ name: `subagent-${agent.name}`,
81
+ cwd: args.cwd || context.cwd,
82
+ user: 'agent',
83
+ provider: agent.provider,
84
+ model: agent.model,
85
+ credentialId: agent.credentialId || null,
86
+ messages: [],
87
+ createdAt: now,
88
+ lastActiveAt: now,
89
+ sessionType: 'orchestrated',
90
+ agentId: agent.id,
91
+ parentSessionId: context.sessionId || null,
92
+ plugins: agent.plugins || agent.tools || [],
93
+ browserProfileId,
94
+ }
95
+ sessions[sid] = applyResolvedRoute(nextSession, resolvePrimaryAgentRoute(agent))
96
+ saveSessions(sessions)
97
+
98
+ startDelegationJob(jobId, {
99
+ childSessionId: sid,
100
+ agentId: agent.id,
101
+ agentName: agent.name,
102
+ cwd: args.cwd || context.cwd,
103
+ })
104
+ appendDelegationCheckpoint(jobId, `Created child session ${sid}`, 'running')
105
+
106
+ const run = enqueueSessionRun({
107
+ sessionId: sid,
108
+ message: args.message,
109
+ internal: true,
110
+ source: 'subagent',
111
+ mode: 'followup',
112
+ })
113
+
114
+ registerDelegationRuntime(jobId, {
115
+ cancel: () => run.abort(),
116
+ })
117
+
118
+ run.promise
119
+ .then((result) => {
120
+ const latest = getDelegationJob(jobId)
121
+ if (latest?.status === 'cancelled') return
122
+ appendDelegationCheckpoint(jobId, 'Child session completed', 'completed')
123
+ completeDelegationJob(jobId, result.text.slice(0, 8000), { childSessionId: sid })
124
+ })
125
+ .catch((err: unknown) => {
126
+ const message = err instanceof Error ? err.message : String(err)
127
+ const latest = getDelegationJob(jobId)
128
+ if (latest?.status === 'cancelled') return
129
+ appendDelegationCheckpoint(jobId, `Child session failed: ${message}`, 'failed')
130
+ failDelegationJob(jobId, message, { childSessionId: sid })
131
+ })
132
+
133
+ return { run, sid, agent }
134
+ }
135
+
136
+ async function waitForSubagentJob(jobId: string, timeoutSec = 30): Promise<string> {
137
+ const timeoutAt = Date.now() + Math.max(1, timeoutSec) * 1000
138
+ while (Date.now() < timeoutAt) {
139
+ const job = getDelegationJob(jobId)
140
+ if (!job) return `Error: delegation job "${jobId}" not found.`
141
+ if (job.status === 'completed' || job.status === 'failed' || job.status === 'cancelled') {
142
+ return JSON.stringify(job)
143
+ }
144
+ await sleep(1000)
145
+ }
146
+ const latest = getDelegationJob(jobId)
147
+ return latest ? JSON.stringify(latest) : `Error: delegation job "${jobId}" not found.`
148
+ }
149
+
28
150
  /**
29
151
  * Core Subagent Execution Logic
30
152
  */
31
153
  async function executeSubagentAction(args: any, context: { sessionId?: string; cwd: string }) {
32
154
  const normalized = normalizeToolInputArgs((args ?? {}) as Record<string, unknown>)
155
+ const action = String(normalized.action || '').trim().toLowerCase()
33
156
  const agentId = (normalized.agentId ?? normalized.agent_id) as string | undefined
34
157
  const message = normalized.message as string | undefined
35
158
  const cwd = normalized.cwd as string | undefined
159
+ const shareBrowserProfile = normalized.shareBrowserProfile === true || normalized.share_browser_profile === true
160
+ const jobId = typeof normalized.jobId === 'string' ? normalized.jobId.trim() : ''
161
+ const waitForCompletion = normalized.waitForCompletion !== false && normalized.background !== true
162
+
163
+ recoverStaleDelegationJobs()
164
+
36
165
  try {
37
- const runtime = loadRuntimeSettings()
38
- const maxDepth = runtime.delegationMaxDepth || DEFAULT_DELEGATION_MAX_DEPTH
39
- const agents = loadAgents()
166
+ if (action === 'status') {
167
+ if (!jobId) return 'Error: jobId is required.'
168
+ const job = getDelegationJob(jobId)
169
+ return job ? JSON.stringify(job) : `Error: delegation job "${jobId}" not found.`
170
+ }
171
+ if (action === 'list') {
172
+ return JSON.stringify(listDelegationJobs({ parentSessionId: context.sessionId || null }))
173
+ }
174
+ if (action === 'cancel') {
175
+ if (!jobId) return 'Error: jobId is required.'
176
+ const job = cancelDelegationJob(jobId)
177
+ return job ? JSON.stringify(job) : `Error: delegation job "${jobId}" not found.`
178
+ }
179
+ if (action === 'wait') {
180
+ if (!jobId) return 'Error: jobId is required.'
181
+ const timeoutSec = typeof normalized.timeoutSec === 'number' ? normalized.timeoutSec : 30
182
+ return waitForSubagentJob(jobId, timeoutSec)
183
+ }
184
+
40
185
  if (!agentId) return 'Error: agentId is required.'
41
186
  if (!message) return 'Error: message is required.'
42
- const agent = agents[agentId]
43
- if (!agent) return `Error: Agent "${agentId}" not found.`
44
-
45
- const depth = getSessionDepth(context.sessionId, maxDepth)
46
- if (depth >= maxDepth) return `Error: Max subagent depth reached.`
47
-
48
- const sid = genId()
49
- const now = Date.now()
50
- const sessions = loadSessions()
51
- sessions[sid] = {
52
- id: sid, name: `subagent-${agent.name}`, cwd: cwd || context.cwd, user: 'agent',
53
- provider: agent.provider, model: agent.model, credentialId: agent.credentialId || null,
54
- messages: [], createdAt: now, lastActiveAt: now, sessionType: 'orchestrated',
55
- agentId: agent.id, parentSessionId: context.sessionId || null, plugins: agent.plugins || agent.tools || [],
187
+
188
+ const job = createDelegationJob({
189
+ kind: 'subagent',
190
+ parentSessionId: context.sessionId || null,
191
+ agentId,
192
+ task: message,
193
+ cwd: cwd || context.cwd,
194
+ })
195
+ appendDelegationCheckpoint(job.id, `Starting subagent ${agentId}`, 'queued')
196
+ const started = await startSubagentJob(job.id, { agentId, message, cwd, shareBrowserProfile }, context)
197
+
198
+ if (!waitForCompletion) {
199
+ return JSON.stringify({
200
+ jobId: job.id,
201
+ status: 'running',
202
+ agentId,
203
+ agentName: started.agent.name,
204
+ sessionId: started.sid,
205
+ })
56
206
  }
57
- saveSessions(sessions)
58
207
 
59
- const result = await executeSessionChatTurn({ sessionId: sid, message, internal: true, source: 'subagent' })
60
- return JSON.stringify({ agentId, agentName: agent.name, sessionId: sid, response: result.text.slice(0, 8000) })
61
- } catch (err: any) { return `Error: ${err.message}` }
208
+ const result = await started.run.promise
209
+ const completed = getDelegationJob(job.id)
210
+ return JSON.stringify({
211
+ jobId: job.id,
212
+ status: completed?.status || 'completed',
213
+ agentId,
214
+ agentName: started.agent.name,
215
+ sessionId: started.sid,
216
+ response: result.text.slice(0, 8000),
217
+ })
218
+ } catch (err: any) {
219
+ return `Error: ${err.message}`
220
+ }
62
221
  }
63
222
 
64
223
  /**
@@ -66,20 +225,29 @@ async function executeSubagentAction(args: any, context: { sessionId?: string; c
66
225
  */
67
226
  const SubagentPlugin: Plugin = {
68
227
  name: 'Core Subagents',
69
- description: 'Delegate tasks to other specialized agents.',
228
+ description: 'Delegate tasks to other specialized agents with resumable job handles.',
70
229
  hooks: {} as PluginHooks,
71
230
  tools: [
72
231
  {
73
232
  name: 'spawn_subagent',
74
- description: 'Delegate a task to another agent.',
233
+ description: 'Delegate a task to another agent. Supports background jobs with action=status|list|wait|cancel and waitForCompletion=false.',
75
234
  parameters: {
76
235
  type: 'object',
77
236
  properties: {
237
+ action: { type: 'string', enum: ['start', 'status', 'list', 'wait', 'cancel'] },
78
238
  agentId: { type: 'string' },
79
239
  message: { type: 'string' },
80
- cwd: { type: 'string' }
240
+ cwd: { type: 'string' },
241
+ shareBrowserProfile: {
242
+ type: 'boolean',
243
+ description: 'When true, inherit the parent session browser profile. Defaults to false so subagents get isolated browser state.',
244
+ },
245
+ jobId: { type: 'string' },
246
+ waitForCompletion: { type: 'boolean' },
247
+ background: { type: 'boolean' },
248
+ timeoutSec: { type: 'number' },
81
249
  },
82
- required: ['agentId', 'message']
250
+ required: []
83
251
  },
84
252
  execute: async (args, context) => executeSubagentAction(args, { sessionId: context.session.id, cwd: context.session.cwd || process.cwd() })
85
253
  }