@desplega.ai/agent-swarm 2.4.2 → 2.4.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 (183) hide show
  1. package/dist/{acp-adapter-dv7hmx4r.js → acp-adapter-thq04adh.js} +4 -5
  2. package/dist/{actions-51nc1gny.js → actions-j6ywh6x5.js} +18 -18
  3. package/dist/{amp-adapter-abp5tdx8.js → amp-adapter-k8b5xmj8.js} +3 -3
  4. package/dist/{app-9h14qvr6.js → app-rb7vc02s.js} +3 -3
  5. package/dist/{assistant-wv1gz3mt.js → assistant-ftta1zjf.js} +20 -20
  6. package/dist/{boot-reembed-6yn53ms9.js → boot-reembed-srp6v6af.js} +1 -1
  7. package/dist/{boot-reembed-7fcka4z5.js → boot-reembed-xns7h5h9.js} +1 -1
  8. package/dist/{boot-scrub-sweep-pm1580ax.js → boot-scrub-sweep-3qqrh2mz.js} +3 -3
  9. package/dist/{boot-seeds-g5hfc1x8.js → boot-seeds-9ks8hce7.js} +4 -4
  10. package/dist/{claude-adapter-gf3kxhf0.js → claude-adapter-k5ksyres.js} +4 -4
  11. package/dist/{claude-managed-setup-h00hsgtz.js → claude-managed-setup-n5a5eqks.js} +1 -1
  12. package/dist/{claude-sdk-session-s2k1qd8y.js → claude-sdk-session-2j3j4kwn.js} +9822 -9749
  13. package/dist/{cli-pkht5hap.js → cli-1d70crsy.js} +2 -2
  14. package/dist/{cli-r99kc9yq.js → cli-1ephgwnq.js} +3 -3
  15. package/dist/{cli-7225gwj7.js → cli-1m17dc9d.js} +1 -1
  16. package/dist/{cli-bcj753sq.js → cli-2v045xyf.js} +3 -3
  17. package/dist/{cli-h38rjv87.js → cli-2y91wnbh.js} +12 -7
  18. package/dist/{cli-sv5gb0yb.js → cli-2zqpkvtt.js} +1 -1
  19. package/dist/{cli-xbzvet96.js → cli-36ckw0wx.js} +5 -4
  20. package/dist/{cli-8sxqsbbq.js → cli-37yb7307.js} +1 -1
  21. package/dist/{cli-hyfw2j1e.js → cli-3cgngyd8.js} +11 -11
  22. package/dist/{cli-a4gvwttf.js → cli-44159k28.js} +2 -2
  23. package/dist/{cli-7awf1fp8.js → cli-4dg55wsk.js} +3 -3
  24. package/dist/{cli-mhywgrrz.js → cli-4sydckyj.js} +1 -1
  25. package/dist/{cli-y2x52gs2.js → cli-51y09c6p.js} +20 -17
  26. package/dist/{cli-ahtpy9kf.js → cli-55qmbp6z.js} +10 -5
  27. package/dist/{cli-pw7v69vp.js → cli-625tb7aq.js} +1 -1
  28. package/dist/{cli-x5mq1fyq.js → cli-74c1wpm0.js} +3 -3
  29. package/dist/{cli-b1dfr1m4.js → cli-7a6p4e65.js} +1 -1
  30. package/dist/{cli-hqhzg1qq.js → cli-82d3nkc3.js} +1 -1
  31. package/dist/{cli-nmqdc2t3.js → cli-9fhkkpj5.js} +78 -12
  32. package/dist/{cli-h93c9vb3.js → cli-amyhm3gj.js} +1 -1
  33. package/dist/{cli-0qvtffe9.js → cli-b8k7epj1.js} +6 -6
  34. package/dist/{cli-1pa3rz69.js → cli-ba8ne1es.js} +6 -1
  35. package/dist/{cli-g0hgtz4p.js → cli-bnz0r3kc.js} +3 -3
  36. package/dist/{cli-0hyhdkdk.js → cli-cebvbc9t.js} +4 -1
  37. package/dist/{cli-efaqv1c7.js → cli-cynvc9fj.js} +35 -7
  38. package/dist/{cli-8zwe9mpk.js → cli-dqb4n629.js} +10 -10
  39. package/dist/{cli-7a91w22y.js → cli-e8xyjvfc.js} +1 -1
  40. package/dist/{cli-s6vr7r2d.js → cli-esxerzg7.js} +1 -1
  41. package/dist/{cli-w9g4sz81.js → cli-gf2850q7.js} +1 -1
  42. package/dist/{cli-10hhg0km.js → cli-gqvh8d8a.js} +7 -7
  43. package/dist/{cli-t30yj95q.js → cli-hj3debgw.js} +1 -1
  44. package/dist/{cli-fpmsqq59.js → cli-nc35pxb7.js} +3 -3
  45. package/dist/{cli-d3qqdy4c.js → cli-p20r8w42.js} +16 -14
  46. package/dist/{cli-shvfedvm.js → cli-pccfmtb5.js} +5 -5
  47. package/dist/{cli-02qm7src.js → cli-q6r7t299.js} +1037 -299
  48. package/dist/{cli-2wag8973.js → cli-qeaq3j6t.js} +1 -1
  49. package/dist/{cli-nn47d7e8.js → cli-qkhc5aqy.js} +15 -15
  50. package/dist/{cli-faypxz7q.js → cli-t7cyef5g.js} +4 -4
  51. package/dist/{cli-z4wd2ftv.js → cli-te6b5wvg.js} +149 -184
  52. package/dist/{cli-5rk36sjf.js → cli-v3yr2gbg.js} +119 -44
  53. package/dist/{cli-239yjk27.js → cli-vdm20wej.js} +5 -5
  54. package/dist/{cli-zfg9enh9.js → cli-vfha21c9.js} +6 -1
  55. package/dist/{cli-rdyw3mct.js → cli-vq97g1jq.js} +6 -5
  56. package/dist/{cli-n85dqg6d.js → cli-w6nadkh4.js} +4 -4
  57. package/dist/{cli-99jez72r.js → cli-w9etnnxk.js} +6 -1
  58. package/dist/{cli-saw9a6f6.js → cli-xc27fwzg.js} +2 -2
  59. package/dist/{cli-ftyypbg5.js → cli-xj0re5tm.js} +1 -1
  60. package/dist/{cli-fyzjmseb.js → cli-zrk6jxv8.js} +1 -1
  61. package/dist/{cli-y8n5k515.js → cli-zrwpctp4.js} +28 -28
  62. package/dist/cli.js +44 -19
  63. package/dist/{codex-adapter-ttygw382.js → codex-adapter-968xwfy7.js} +2 -2
  64. package/dist/{codex-hook-x7nejyrr.js → codex-hook-e2he7aca.js} +2 -2
  65. package/dist/{codex-session-runner-60b58vv3.js → codex-session-runner-ht4z99fa.js} +2 -2
  66. package/dist/{commands-edmdwa4x.js → commands-pcymaeg9.js} +3 -3
  67. package/dist/{controller-m263fg43.js → controller-fpjyk46r.js} +3 -3
  68. package/dist/{controllers-connect-5fym8sw1.js → controllers-connect-mwzx1fh6.js} +19 -19
  69. package/dist/{cursor-adapter-cz6nm6mj.js → cursor-adapter-cp4s2e2f.js} +2 -2
  70. package/dist/{db-2y0mgstc.js → db-sgd12bt9.js} +3 -3
  71. package/dist/{db-nn0hcmx5.js → db-xsjg9jqq.js} +2 -2
  72. package/dist/{dispatcher-0a9wwjcx.js → dispatcher-x0jfw2c9.js} +17 -17
  73. package/dist/{dsh-adapter-3n3net33.js → dsh-adapter-jrq7ma7h.js} +2 -2
  74. package/dist/{e2b-thdcxtjd.js → e2b-16d6ch39.js} +1 -1
  75. package/dist/{e2b-7am6tmq6.js → e2b-zn0b4w5w.js} +1 -1
  76. package/dist/{external-channel-zhvt95n3.js → external-channel-8njj4h3b.js} +2 -2
  77. package/dist/{grok-adapter-qnr1hp2y.js → grok-adapter-kkr97v2f.js} +5 -6
  78. package/dist/handlers-0pvee9nw.js +39 -0
  79. package/dist/{heartbeat-gz97r7ac.js → heartbeat-wd03zhn0.js} +20 -20
  80. package/dist/{hook-1mmdgjqs.js → hook-f0vghj42.js} +10 -5
  81. package/dist/{hook-x8rthca4.js → hook-xzj2ts2p.js} +2 -2
  82. package/dist/{http-r8f85xr9.js → http-4hwxv62p.js} +261 -123
  83. package/dist/{index-va3y63es.js → index-6srwvd5b.js} +1 -2
  84. package/dist/{index-y7rbcrc1.js → index-97q4xn03.js} +20 -11
  85. package/dist/{index-s98037v0.js → index-cbxkmfc5.js} +1 -2
  86. package/dist/{index-vzvfqzfj.js → index-gdh8jrdm.js} +17 -17
  87. package/dist/{index-aex0eba9.js → index-hg0x2cdv.js} +17 -17
  88. package/dist/index-thm0y6a8.js +41 -0
  89. package/dist/{index-smxyk04s.js → index-ww2vznkp.js} +1 -1
  90. package/dist/{keepalive-64c0f34c.js → keepalive-hrh7xnr9.js} +3 -3
  91. package/dist/{lead-b1da0f97.js → lead-ee8vazz2.js} +30 -31
  92. package/dist/{maintenance-mnxpar12.js → maintenance-e8wnwnqx.js} +1 -1
  93. package/dist/{oauth-refresh-sweep-36hs2v4h.js → oauth-refresh-sweep-zm0yj4sj.js} +2 -2
  94. package/dist/{onboard-xes8de61.js → onboard-dtwcq603.js} +3 -3
  95. package/dist/{opencode-adapter-3s7ax02e.js → opencode-adapter-x4tqzhkh.js} +3 -3
  96. package/dist/{otel-impl-fzc57kcq.js → otel-impl-w3fbhpn0.js} +1 -1
  97. package/dist/{pi-mono-adapter-ytp7gz8b.js → pi-mono-adapter-mcfkn9vf.js} +3 -3
  98. package/dist/{pricing-refresh-1nek2w7b.js → pricing-refresh-j38dehfs.js} +3 -3
  99. package/dist/{rbac-roles-ttyfaep2.js → rbac-roles-ae8yttq4.js} +3 -3
  100. package/dist/{rbac-roles-sqefb5hw.js → rbac-roles-ejxx9b35.js} +2 -2
  101. package/dist/{render-v2-vb527jwn.js → render-v2-n16n0phe.js} +3 -3
  102. package/dist/{resume-jcdzg1bn.js → resume-z0fgjc38.js} +5 -5
  103. package/dist/{session-access-zsp4wsp0.js → session-access-cv3mq6mc.js} +6 -4
  104. package/dist/{setup-1nb2zqd3.js → setup-mafhj3yt.js} +1 -1
  105. package/dist/{work-objects-61w08fwr.js → work-objects-8b86mgjp.js} +21 -21
  106. package/dist/{worker-c1e68hpa.js → worker-16s75hm5.js} +30 -31
  107. package/dist/worker-token-xf11yyds.js +136 -0
  108. package/openapi.json +295 -12
  109. package/package.json +5 -5
  110. package/src/apps/action-runner.ts +4 -0
  111. package/src/apps/catalog.generated.json +3 -0
  112. package/src/apps/page-validator.ts +8 -2
  113. package/src/be/db.ts +7 -4
  114. package/src/be/migrations/231_slack_tasks_last_updated_index.sql +5 -0
  115. package/src/be/migrations/232_agent_session_tokens.sql +41 -0
  116. package/src/be/seed-scripts/catalog/heartbeat-jev-gate.ts +10 -1
  117. package/src/be/swarm-config-guard.ts +16 -0
  118. package/src/be/users.ts +169 -12
  119. package/src/cli.tsx +24 -0
  120. package/src/commands/worker-token.ts +164 -0
  121. package/src/github/handlers.ts +6 -5
  122. package/src/hooks/hook.ts +2 -1
  123. package/src/http/apps.ts +43 -5
  124. package/src/http/codex-oauth-keep-warm.ts +27 -9
  125. package/src/http/config.ts +5 -3
  126. package/src/http/core.ts +2 -0
  127. package/src/http/session-access.ts +51 -2
  128. package/src/http/sessions.ts +249 -10
  129. package/src/http/tasks.ts +4 -32
  130. package/src/providers/acp-adapter.ts +33 -13
  131. package/src/providers/acp-swarm-events.ts +1 -1
  132. package/src/providers/amp-adapter.ts +1 -1
  133. package/src/providers/codex-adapter.ts +4 -4
  134. package/src/providers/codex-oauth/storage.ts +1 -1
  135. package/src/providers/opencode-adapter.ts +2 -2
  136. package/src/providers/pi-mono-extension.ts +2 -1
  137. package/src/rbac/legacy-policy.ts +3 -1
  138. package/src/rbac/permissions.ts +4 -0
  139. package/src/tests/acp-adapter.test.ts +10 -23
  140. package/src/tests/acp-fake-agent.ts +36 -0
  141. package/src/tests/acp-swarm-events.test.ts +1 -1
  142. package/src/tests/agent-session-tokens.test.ts +452 -0
  143. package/src/tests/apps-action-parent-task.test.ts +295 -0
  144. package/src/tests/claude-stop-hook.test.ts +47 -0
  145. package/src/tests/codex-adapter.test.ts +42 -0
  146. package/src/tests/codex-oauth-keep-warm.test.ts +85 -1
  147. package/src/tests/config-session-auth.test.ts +14 -0
  148. package/src/tests/docs-index-footprint.test.js +2 -2
  149. package/src/tests/env-flag.test.ts +15 -1
  150. package/src/tests/github-handlers-cancel-config.test.ts +29 -8
  151. package/src/tests/github-handlers-inline-comments.test.ts +9 -2
  152. package/src/tests/grok-adapter.test.ts +3 -3
  153. package/src/tests/heartbeat-jev-gate.test.ts +23 -0
  154. package/src/tests/migration-232-agent-session-tokens.test.ts +67 -0
  155. package/src/tests/rbac-engine.test.ts +1 -0
  156. package/src/tests/runtime-child-token-cleanup.test.ts +3 -3
  157. package/src/tests/script-connections.test.ts +4 -0
  158. package/src/tests/session-route-posture.test.ts +2 -0
  159. package/src/tests/skill-script-refs.test.ts +63 -0
  160. package/src/tests/slack-render-v2-query-plans.test.ts +147 -0
  161. package/src/tests/worker-token-cli.test.ts +76 -0
  162. package/src/tests/workflow-executors.test.ts +4 -2
  163. package/src/tests/workflow-system-one-extraction.test.ts +805 -0
  164. package/src/types.ts +2 -1
  165. package/src/utils/env-flag.ts +9 -0
  166. package/src/utils/request-auth-context.ts +2 -1
  167. package/src/workflows/definition.ts +7 -1
  168. package/src/workflows/engine.ts +18 -12
  169. package/src/workflows/executors/index.ts +1 -0
  170. package/src/workflows/executors/registry.ts +2 -0
  171. package/src/workflows/executors/system-one-decision.ts +56 -255
  172. package/src/workflows/executors/system-one-extract-wire.ts +57 -0
  173. package/src/workflows/executors/system-one-extraction.ts +830 -0
  174. package/src/workflows/executors/system-one-providers.ts +277 -110
  175. package/src/workflows/executors/system-one-transport.ts +264 -0
  176. package/templates/official/lead/HEARTBEAT.md +1 -1
  177. package/templates/skills/apps/SKILL.md +4 -1
  178. package/templates/skills/apps/content.md +4 -1
  179. package/templates/skills/code-quality/content.md +9 -14
  180. package/templates/skills/heartbeat-runbook/content.md +3 -3
  181. package/dist/cli-v1sjhn52.js +0 -7
  182. package/dist/handlers-dkcarkd0.js +0 -39
  183. package/dist/index-5jecgp3n.js +0 -41
@@ -5,8 +5,9 @@ import {
5
5
  validateRuntimeTokenTtlHours,
6
6
  init_swarm_config_guard,
7
7
  init_db3
8
- } from "./cli-d3qqdy4c.js";
8
+ } from "./cli-p20r8w42.js";
9
9
  import {
10
+ registerVolatileSecret,
10
11
  unregisterVolatileSecret,
11
12
  init_secret_scrubber
12
13
  } from "./cli-xf234ws8.js";
@@ -264,11 +265,12 @@ async function resolveUserByToken(plaintext) {
264
265
  async function mintSessionToken(agentId, taskId, ttlMs, parent) {
265
266
  if (parent) {
266
267
  return await getDbClient2().transaction(async (client) => {
267
- const row = await client.get(`SELECT expiresAt FROM session_tokens WHERE id = ? AND agentId = ? AND runtimeId = ?
268
- AND revokedAt IS NULL AND expiresAt > ?`, [parent.tokenId, agentId, parent.runtimeId, new Date().toISOString()]);
268
+ const row = await client.get(parent.runtimeId ? `SELECT expiresAt FROM session_tokens WHERE id = ? AND agentId = ? AND runtimeId = ?
269
+ AND revokedAt IS NULL AND expiresAt > ?` : `SELECT expiresAt FROM session_tokens WHERE id = ? AND agentId = ? AND ${AGENT_TOKEN_BINDING}
270
+ AND revokedAt IS NULL AND expiresAt > ?`, parent.runtimeId ? [parent.tokenId, agentId, parent.runtimeId, new Date().toISOString()] : [parent.tokenId, agentId, new Date().toISOString()]);
269
271
  if (!row)
270
272
  throw new InvalidRuntimeTokenError;
271
- return await insertSessionToken(agentId, taskId, null, ttlMs, parent.runtimeId, row.expiresAt);
273
+ return await insertSessionToken(agentId, taskId, null, ttlMs, parent.runtimeId, row.expiresAt, null, parent.runtimeId ? null : parent.tokenId);
272
274
  });
273
275
  }
274
276
  return await insertSessionToken(agentId, taskId, null, ttlMs);
@@ -280,7 +282,7 @@ function runtimeTokenTtlMs() {
280
282
  async function mintRuntimeToken(agentId, runtimeId, ttlMs = runtimeTokenTtlMs()) {
281
283
  return await insertSessionToken(agentId, null, runtimeId, ttlMs);
282
284
  }
283
- async function insertSessionToken(agentId, taskId, runtimeId, ttlMs, parentRuntimeId = null, expiresAtCeiling, controllerId = null) {
285
+ async function insertSessionToken(agentId, taskId, runtimeId, ttlMs, parentRuntimeId = null, expiresAtCeiling, controllerId = null, parentTokenId = null) {
284
286
  const plaintext = `${SESSION_TOKEN_PREFIX}${base62(randomBytes(24))}`;
285
287
  const tokenId = randomUUID().replace(/-/g, "");
286
288
  const hash = sha256Hex(plaintext);
@@ -288,8 +290,8 @@ async function insertSessionToken(agentId, taskId, runtimeId, ttlMs, parentRunti
288
290
  const now = new Date;
289
291
  const expiresAt = new Date(Math.min(now.getTime() + ttlMs, expiresAtCeiling ? Date.parse(expiresAtCeiling) : Infinity)).toISOString();
290
292
  await getDbClient2().run(`INSERT INTO session_tokens
291
- (id, tokenHash, tokenPreview, agentId, taskId, runtimeId, parentRuntimeId, expiresAt, createdAt, controllerId)
292
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
293
+ (id, tokenHash, tokenPreview, agentId, taskId, runtimeId, parentRuntimeId, expiresAt, createdAt, controllerId, parentTokenId)
294
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
293
295
  tokenId,
294
296
  hash,
295
297
  preview,
@@ -299,7 +301,8 @@ async function insertSessionToken(agentId, taskId, runtimeId, ttlMs, parentRunti
299
301
  parentRuntimeId,
300
302
  expiresAt,
301
303
  now.toISOString(),
302
- controllerId
304
+ controllerId,
305
+ parentTokenId
303
306
  ]);
304
307
  return { tokenId, plaintext };
305
308
  }
@@ -309,11 +312,24 @@ async function revokeSessionToken(tokenId) {
309
312
  if (row?.runtimeId) {
310
313
  await revokeRuntimeTokensForRuntime(row.runtimeId);
311
314
  } else {
312
- await client.run("UPDATE session_tokens SET revokedAt = ? WHERE id = ? AND revokedAt IS NULL", [new Date().toISOString(), tokenId]);
313
- getDbClient2().afterCommit(() => closeSessionTokenConnections([tokenId]));
315
+ await revokeTokensWithChildren(client, [tokenId]);
314
316
  }
315
317
  });
316
318
  }
319
+ async function revokeTokensWithChildren(client, tokenIds) {
320
+ if (tokenIds.length === 0)
321
+ return;
322
+ const placeholders = tokenIds.map(() => "?").join(", ");
323
+ const children = await client.query(`SELECT id FROM session_tokens WHERE parentTokenId IN (${placeholders})`, tokenIds);
324
+ const ids = [...tokenIds, ...children.map((row) => row.id)];
325
+ await client.run(`UPDATE session_tokens SET revokedAt = ?
326
+ WHERE id IN (${ids.map(() => "?").join(", ")}) AND revokedAt IS NULL`, [new Date().toISOString(), ...ids]);
327
+ getDbClient2().afterCommit(() => {
328
+ for (const id of tokenIds)
329
+ unregisterVolatileSecret(`agent-token:${id}`);
330
+ closeSessionTokenConnections(ids);
331
+ });
332
+ }
317
333
  async function revokeRuntimeTokensForRuntime(runtimeId) {
318
334
  await getDbClient2().transaction(async (client) => {
319
335
  const rows = await client.query("SELECT id FROM session_tokens WHERE runtimeId = ? OR parentRuntimeId = ?", [runtimeId, runtimeId]);
@@ -325,6 +341,50 @@ async function revokeRuntimeTokensForRuntime(runtimeId) {
325
341
  });
326
342
  });
327
343
  }
344
+ function storedExpiry(ttlMs) {
345
+ return ttlMs === null ? AGENT_TOKEN_NO_EXPIRY : new Date(Date.now() + ttlMs).toISOString();
346
+ }
347
+ function publicExpiry(expiresAt) {
348
+ return expiresAt === AGENT_TOKEN_NO_EXPIRY ? null : expiresAt;
349
+ }
350
+ async function activeAgentTokenIds(client, agentId) {
351
+ const rows = await client.query(`SELECT id FROM session_tokens WHERE agentId = ? AND ${AGENT_TOKEN_BINDING}
352
+ AND revokedAt IS NULL AND expiresAt > ?`, [agentId, new Date().toISOString()]);
353
+ return rows.map((row) => row.id);
354
+ }
355
+ async function insertAgentToken(agentId, ttlMs) {
356
+ const expiresAt = storedExpiry(ttlMs);
357
+ const token = await insertSessionToken(agentId, null, null, Number.MAX_SAFE_INTEGER, null, expiresAt);
358
+ getDbClient2().afterCommit(() => registerVolatileSecret(token.plaintext, `agent-token:${token.tokenId}`));
359
+ return { ...token, expiresAt: publicExpiry(expiresAt) };
360
+ }
361
+ async function mintAgentToken(agentId, ttlMs = AGENT_TOKEN_DEFAULT_TTL_MS) {
362
+ return await getDbClient2().transaction(async (client) => {
363
+ if ((await activeAgentTokenIds(client, agentId)).length > 0) {
364
+ throw new AgentTokenExistsError;
365
+ }
366
+ return await insertAgentToken(agentId, ttlMs);
367
+ });
368
+ }
369
+ async function rotateAgentToken(agentId, graceMs, ttlMs = AGENT_TOKEN_DEFAULT_TTL_MS) {
370
+ return await getDbClient2().transaction(async (client) => {
371
+ const previous = await activeAgentTokenIds(client, agentId);
372
+ if (previous.length === 0)
373
+ return null;
374
+ const previousExpiresAt = new Date(Date.now() + graceMs).toISOString();
375
+ const placeholders = previous.map(() => "?").join(", ");
376
+ await client.run(`UPDATE session_tokens SET expiresAt = ?
377
+ WHERE (id IN (${placeholders}) OR parentTokenId IN (${placeholders})) AND expiresAt > ?`, [previousExpiresAt, ...previous, ...previous, previousExpiresAt]);
378
+ return { ...await insertAgentToken(agentId, ttlMs), previousExpiresAt };
379
+ });
380
+ }
381
+ async function revokeAgentTokens(agentId) {
382
+ return await getDbClient2().transaction(async (client) => {
383
+ const ids = await activeAgentTokenIds(client, agentId);
384
+ await revokeTokensWithChildren(client, ids);
385
+ return ids.length;
386
+ });
387
+ }
328
388
  async function resolveSessionToken(plaintext, options = {}) {
329
389
  if (!plaintext.startsWith(SESSION_TOKEN_PREFIX))
330
390
  return null;
@@ -356,6 +416,7 @@ async function resolveSessionToken(plaintext, options = {}) {
356
416
  return {
357
417
  kind: "agent",
358
418
  tokenId: row.id,
419
+ tokenKind: row.taskId !== null ? "task" : row.runtimeId !== null ? "runtime" : "agent",
359
420
  agentId: row.agentId,
360
421
  taskId: row.taskId,
361
422
  runtimeId: row.runtimeId,
@@ -365,7 +426,7 @@ async function resolveSessionToken(plaintext, options = {}) {
365
426
  function fingerprintApiKey(rawKey) {
366
427
  return `op:${sha256Hex(rawKey).slice(0, 16)}`;
367
428
  }
368
- var TOKEN_PREFIX = "aswt_", SESSION_TOKEN_PREFIX = "aseph_", InvalidRuntimeTokenError;
429
+ var TOKEN_PREFIX = "aswt_", SESSION_TOKEN_PREFIX = "aseph_", InvalidRuntimeTokenError, AGENT_TOKEN_BINDING = "taskId IS NULL AND runtimeId IS NULL AND controllerId IS NULL AND parentRuntimeId IS NULL", AGENT_TOKEN_NO_EXPIRY = "9999-12-31T23:59:59.999Z", AGENT_TOKEN_DEFAULT_TTL_MS = null, AgentTokenExistsError;
369
430
  var init_users = __esm(() => {
370
431
  init_telemetry_identity();
371
432
  init_secret_scrubber();
@@ -377,6 +438,11 @@ var init_users = __esm(() => {
377
438
  super("Runtime token is no longer valid");
378
439
  }
379
440
  };
441
+ AgentTokenExistsError = class AgentTokenExistsError extends Error {
442
+ constructor() {
443
+ super("Agent already has an active token; rotate or revoke it");
444
+ }
445
+ };
380
446
  });
381
447
 
382
- export { registerSessionTokenConnection, closeSessionTokenConnections, init_session_token_connections, findUserById, findUserByExternalId, findUserByEmail, findUsersByName, getUserIdentities, listUserEvents, listUserTokens, recordIdentityEvent, findOrCreateUserByEmail, linkIdentity, unlinkIdentity, mintToken, revokeToken, resolveUserByToken, InvalidRuntimeTokenError, mintSessionToken, mintRuntimeToken, insertSessionToken, revokeSessionToken, revokeRuntimeTokensForRuntime, resolveSessionToken, fingerprintApiKey, init_users };
448
+ export { registerSessionTokenConnection, closeSessionTokenConnections, init_session_token_connections, findUserById, findUserByExternalId, findUserByEmail, findUsersByName, getUserIdentities, listUserEvents, listUserTokens, recordIdentityEvent, findOrCreateUserByEmail, linkIdentity, unlinkIdentity, mintToken, revokeToken, resolveUserByToken, InvalidRuntimeTokenError, mintSessionToken, mintRuntimeToken, insertSessionToken, revokeSessionToken, revokeRuntimeTokensForRuntime, AgentTokenExistsError, mintAgentToken, rotateAgentToken, revokeAgentTokens, resolveSessionToken, fingerprintApiKey, init_users };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getDb2,
3
3
  init_db3
4
- } from "./cli-d3qqdy4c.js";
4
+ } from "./cli-p20r8w42.js";
5
5
  import {
6
6
  openAICompatibleProviderIds,
7
7
  withRegistryCatalogSections,
@@ -10,7 +10,7 @@ import {
10
10
  init_steering,
11
11
  createLogEntry2,
12
12
  init_db3
13
- } from "./cli-d3qqdy4c.js";
13
+ } from "./cli-p20r8w42.js";
14
14
  import {
15
15
  ackSlackMessage,
16
16
  buildBufferFlushBlocks,
@@ -20,7 +20,7 @@ import {
20
20
  ensureSlackThreadTree2,
21
21
  registerTreeMessage,
22
22
  getSlackApp2
23
- } from "./cli-nn47d7e8.js";
23
+ } from "./cli-qkhc5aqy.js";
24
24
  import {
25
25
  createAdditiveBuffer,
26
26
  TaskCreationBlockedError,
@@ -30,19 +30,19 @@ import {
30
30
  createSlackTaskWithFiles,
31
31
  notifySlackFileFailures,
32
32
  extractSlackMessageText
33
- } from "./cli-5rk36sjf.js";
33
+ } from "./cli-v3yr2gbg.js";
34
34
  import {
35
35
  resolveSlackUserId,
36
36
  rewriteSlackMentions
37
- } from "./cli-bcj753sq.js";
37
+ } from "./cli-2v045xyf.js";
38
38
  import {
39
39
  findUserByExternalId,
40
40
  init_users
41
- } from "./cli-nmqdc2t3.js";
41
+ } from "./cli-9fhkkpj5.js";
42
42
  import {
43
43
  isSteeringEnabled2,
44
44
  init_steering_enabled
45
- } from "./cli-mhywgrrz.js";
45
+ } from "./cli-4sydckyj.js";
46
46
  import {
47
47
  scrubSecrets,
48
48
  init_secret_scrubber
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  isEnvFlagEnabled,
9
9
  init_env_flag
10
- } from "./cli-0hyhdkdk.js";
10
+ } from "./cli-cebvbc9t.js";
11
11
  import {
12
12
  __esm
13
13
  } from "./cli-242037k3.js";
@@ -320,6 +320,7 @@ var init_legacy_policy = __esm(() => {
320
320
  "runtime_pool.write": operatorOrUser,
321
321
  "runtime_pool.bind": leadOrOperatorOrUser,
322
322
  "runtime_controller.write": operatorOrUser,
323
+ "agent.token.manage": operatorOrUser,
323
324
  "extension.write": extensionWrite,
324
325
  "extension.activate": extensionActivation,
325
326
  "extension.install.inline": leadOrOperatorOrUser
@@ -369,6 +370,10 @@ var init_permissions = __esm(() => {
369
370
  description: "View or diff another agent's context history.",
370
371
  namespace: "agent"
371
372
  },
373
+ "agent.token.manage": {
374
+ description: "Mint, rotate, or revoke an agent-bound worker token.",
375
+ namespace: "agent"
376
+ },
372
377
  "task.cancel.any": {
373
378
  description: "Cancel any task (beyond tasks the caller created).",
374
379
  namespace: "task"
@@ -4,7 +4,7 @@ import {
4
4
  } from "./cli-a5ebc95n.js";
5
5
  import {
6
6
  swarmRuntimeInstanceId
7
- } from "./cli-7a91w22y.js";
7
+ } from "./cli-e8xyjvfc.js";
8
8
  import {
9
9
  resolveSlashSkillPrompt
10
10
  } from "./cli-jc1g9ndz.js";
@@ -14,7 +14,7 @@ import {
14
14
  import {
15
15
  DEFAULT_MODEL_TIER_MAP,
16
16
  init_types
17
- } from "./cli-fpmsqq59.js";
17
+ } from "./cli-nc35pxb7.js";
18
18
  import {
19
19
  resolveTemplateFromCode,
20
20
  resolveTemplateAsync,
@@ -24,7 +24,7 @@ import {
24
24
  import {
25
25
  parseEnvFlag,
26
26
  init_env_flag
27
- } from "./cli-0hyhdkdk.js";
27
+ } from "./cli-cebvbc9t.js";
28
28
  import {
29
29
  scrubSecrets,
30
30
  registerVolatileSecret,
@@ -18,10 +18,13 @@ function parseEnvFlag(raw, defaultValue) {
18
18
  function isEnvFlagEnabled(key, defaultValue, env = process.env) {
19
19
  return parseEnvFlag(env[key], defaultValue);
20
20
  }
21
+ function isSessionSummarySkipped(env = process.env) {
22
+ return isEnvFlagEnabled("SKIP_SESSION_SUMMARY", false, env);
23
+ }
21
24
  var TRUTHY, FALSY;
22
25
  var init_env_flag = __esm(() => {
23
26
  TRUTHY = new Set(["true", "1"]);
24
27
  FALSY = new Set(["false", "0"]);
25
28
  });
26
29
 
27
- export { parseEnvFlag, isEnvFlagEnabled, init_env_flag };
30
+ export { parseEnvFlag, isEnvFlagEnabled, isSessionSummarySkipped, init_env_flag };
@@ -9,20 +9,21 @@ import {
9
9
  init_active_sessions,
10
10
  getSteeringMessageById2,
11
11
  init_db3
12
- } from "./cli-d3qqdy4c.js";
12
+ } from "./cli-p20r8w42.js";
13
13
  import {
14
14
  getUserGrant2,
15
15
  init_rbac_roles
16
- } from "./cli-7awf1fp8.js";
16
+ } from "./cli-4dg55wsk.js";
17
17
  import {
18
18
  findUserById,
19
19
  findUserByExternalId,
20
20
  init_users
21
- } from "./cli-nmqdc2t3.js";
21
+ } from "./cli-9fhkkpj5.js";
22
22
  import {
23
23
  isRbacEnabled,
24
+ can,
24
25
  init_rbac
25
- } from "./cli-1pa3rz69.js";
26
+ } from "./cli-ba8ne1es.js";
26
27
  import {
27
28
  init_zod
28
29
  } from "./cli-4chz1hye.js";
@@ -38,7 +39,7 @@ import {
38
39
  import {
39
40
  isEnvFlagEnabled,
40
41
  init_env_flag
41
- } from "./cli-0hyhdkdk.js";
42
+ } from "./cli-cebvbc9t.js";
42
43
  import {
43
44
  scrubSecrets,
44
45
  init_secret_scrubber
@@ -502,7 +503,7 @@ function route(def) {
502
503
  try {
503
504
  const rawBody = def.body ? await parseBody(req, def.maxBodyBytes) : undefined;
504
505
  if (def.session && "bodyTaskIds" in def.session) {
505
- const { bodySessionDenial } = await import("./session-access-zsp4wsp0.js");
506
+ const { bodySessionDenial } = await import("./session-access-cv3mq6mc.js");
506
507
  const denial = await bodySessionDenial(req, def.session.bodyTaskIds(rawBody));
507
508
  if (denial) {
508
509
  jsonError(res, denial, 403);
@@ -770,6 +771,33 @@ function readableByFor2(actor) {
770
771
  return actor.kind === "user" ? { userId: actor.userId } : undefined;
771
772
  }
772
773
  var SESSION_WRITE_DENIED2 = "You can't write in this session. Ask the owner to share it with edit access.";
774
+ async function hasSessionWrite(req, myAgentId, taskId) {
775
+ const access = await sessionAccessFor2(await resolveSessionActor2(req, myAgentId), taskId);
776
+ return hasSessionAccess(access, "write");
777
+ }
778
+ async function denyParentAttach2(req, res, myAgentId, parentTask, principal) {
779
+ const attach = can({
780
+ principal,
781
+ verb: "task.parent.attach",
782
+ resource: {
783
+ kind: "task",
784
+ taskId: parentTask.id,
785
+ requestedByUserId: parentTask.requestedByUserId,
786
+ creatorAgentId: parentTask.creatorAgentId,
787
+ agentId: parentTask.agentId
788
+ },
789
+ source: "http"
790
+ });
791
+ if (!attach.allow) {
792
+ jsonError(res, `You don't have context for parent task ${parentTask.id}.`, 403);
793
+ return true;
794
+ }
795
+ if (!await hasSessionWrite(req, myAgentId, parentTask.id)) {
796
+ jsonError(res, SESSION_WRITE_DENIED2, 403);
797
+ return true;
798
+ }
799
+ return false;
800
+ }
773
801
  async function denialFor(actor, taskId, needed) {
774
802
  if (actor.kind === "bypass")
775
803
  return null;
@@ -845,4 +873,4 @@ async function userAgentIdentityDenial2(req, def, pathSegments) {
845
873
  return USER_AGENT_HEADER_DENIED;
846
874
  }
847
875
 
848
- export { duplicateGuardedQueryKey, warnIfCorsAllowsAnyOrigin, isOriginAllowedForCredentials, allowedCredentialRedirect, setCorsHeaders, parseQueryParams, getPathSegments, wireHttpSpanLifecycle, safeRequestUrlForLog, agentWithCapacity, parseBody, BODY_TOO_LARGE, enforceContentLengthCap, json, jsonError, writeUnhandledError, triggerSchemaErrorResponse, deriveApiBaseUrl, httpServerSemconvAttributes, hasSessionAccess, getSessionRoot, sessionAccessForRoot, listActiveSessionShares, toSessionSharesState, setSessionShares, resolveTaskAuditUserId, resolveHttpAuditUserId, dashboardUserIdHeader, resolveHttpFavoriteOwner, resolveSessionActor2, sessionAccessFor2, SESSION_READ_DENIED2, canReadSession2, readableByFor2, SESSION_WRITE_DENIED2, pathSessionDenial2, bodySessionDenial2, userAgentIdentityDenial2, runtimeInstanceHeader, bodyTask, bodyListTask, routeRegistry, isPublicRoute, findRoute, describeRequestRoute, route };
876
+ export { duplicateGuardedQueryKey, warnIfCorsAllowsAnyOrigin, isOriginAllowedForCredentials, allowedCredentialRedirect, setCorsHeaders, parseQueryParams, getPathSegments, wireHttpSpanLifecycle, safeRequestUrlForLog, agentWithCapacity, parseBody, BODY_TOO_LARGE, enforceContentLengthCap, json, jsonError, writeUnhandledError, triggerSchemaErrorResponse, deriveApiBaseUrl, httpServerSemconvAttributes, hasSessionAccess, getSessionRoot, sessionAccessForRoot, listActiveSessionShares, toSessionSharesState, setSessionShares, resolveTaskAuditUserId, resolveHttpAuditUserId, dashboardUserIdHeader, resolveHttpFavoriteOwner, resolveSessionActor2, sessionAccessFor2, SESSION_READ_DENIED2, canReadSession2, readableByFor2, SESSION_WRITE_DENIED2, denyParentAttach2, pathSessionDenial2, bodySessionDenial2, userAgentIdentityDenial2, runtimeInstanceHeader, bodyTask, bodyListTask, routeRegistry, isPublicRoute, findRoute, describeRequestRoute, route };
@@ -4,7 +4,7 @@ import {
4
4
  CONTROLLER_COMMAND_TIMEOUT_MS,
5
5
  RuntimeHandleSchema,
6
6
  ControllerStatusResultSchema
7
- } from "./cli-hqhzg1qq.js";
7
+ } from "./cli-82d3nkc3.js";
8
8
  import {
9
9
  getDbClient2,
10
10
  isRuntimePoolsEnabled,
@@ -21,7 +21,7 @@ import {
21
21
  upsertSwarmConfig2,
22
22
  getResolvedConfig2,
23
23
  init_db3
24
- } from "./cli-d3qqdy4c.js";
24
+ } from "./cli-p20r8w42.js";
25
25
  import {
26
26
  runtimeStaleThresholdMinutes,
27
27
  getRuntimeInstanceById,
@@ -31,7 +31,7 @@ import {
31
31
  listRuntimeInstancesForPool,
32
32
  createWorkerTaskFollowUp,
33
33
  canClaim
34
- } from "./cli-5rk36sjf.js";
34
+ } from "./cli-v3yr2gbg.js";
35
35
  import {
36
36
  getRuntimeController2,
37
37
  getRuntimeControllerTarget2,
@@ -42,14 +42,14 @@ import {
42
42
  getPoolForAgent2,
43
43
  resolvePoolDelivery2,
44
44
  init_db
45
- } from "./cli-n85dqg6d.js";
45
+ } from "./cli-w6nadkh4.js";
46
46
  import {
47
47
  workflowEventBus2,
48
48
  init_event_bus
49
49
  } from "./cli-wt645v7q.js";
50
50
  import {
51
51
  isMultiRuntimeEnabled
52
- } from "./cli-7a91w22y.js";
52
+ } from "./cli-e8xyjvfc.js";
53
53
  import {
54
54
  import_websocket
55
55
  } from "./cli-b2mz5mjc.js";
@@ -57,16 +57,16 @@ import {
57
57
  canProvisionKind,
58
58
  createRuntimeProvider,
59
59
  init_runtime_providers
60
- } from "./cli-pw7v69vp.js";
60
+ } from "./cli-625tb7aq.js";
61
61
  import {
62
62
  mintRuntimeToken,
63
63
  init_users
64
- } from "./cli-nmqdc2t3.js";
64
+ } from "./cli-9fhkkpj5.js";
65
65
  import {
66
66
  TERMINAL_TASK_STATUSES,
67
67
  isTerminalTaskStatus,
68
68
  init_types
69
- } from "./cli-fpmsqq59.js";
69
+ } from "./cli-nc35pxb7.js";
70
70
  import {
71
71
  init_zod
72
72
  } from "./cli-4chz1hye.js";
@@ -82,7 +82,7 @@ import {
82
82
  import {
83
83
  resolveWorkerApiUrl,
84
84
  init_worker_api_url
85
- } from "./cli-b1dfr1m4.js";
85
+ } from "./cli-7a6p4e65.js";
86
86
  import {
87
87
  buildImageTemplate,
88
88
  init_dispatch
@@ -522,7 +522,7 @@ async function recoverSessions(runtimeId, reason) {
522
522
  }
523
523
  if (!sessions.length)
524
524
  return;
525
- const { remediateTaskForDeadRuntime } = await import("./heartbeat-gz97r7ac.js");
525
+ const { remediateTaskForDeadRuntime } = await import("./heartbeat-wd03zhn0.js");
526
526
  for (const session of sessions) {
527
527
  try {
528
528
  const task = await getTaskById2(session.taskId);
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  parseEnvFlag,
3
3
  init_env_flag
4
- } from "./cli-0hyhdkdk.js";
4
+ } from "./cli-cebvbc9t.js";
5
5
 
6
6
  // src/utils/multi-runtime.ts
7
7
  init_env_flag();
@@ -9,7 +9,7 @@ import {
9
9
  acquireOAuthRefreshLock,
10
10
  releaseOAuthRefreshLock,
11
11
  init_oauth
12
- } from "./cli-d3qqdy4c.js";
12
+ } from "./cli-p20r8w42.js";
13
13
  import {
14
14
  scrubSecrets,
15
15
  registerVolatileSecret,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  isEnvFlagEnabled,
3
3
  init_env_flag
4
- } from "./cli-0hyhdkdk.js";
4
+ } from "./cli-cebvbc9t.js";
5
5
  import {
6
6
  __esm
7
7
  } from "./cli-242037k3.js";
@@ -10,7 +10,7 @@ import {
10
10
  getMostRecentTaskInThread2,
11
11
  reactionName,
12
12
  init_db3
13
- } from "./cli-d3qqdy4c.js";
13
+ } from "./cli-p20r8w42.js";
14
14
  import {
15
15
  TaskCreationBlockedError,
16
16
  buildEffectiveText,
@@ -23,7 +23,7 @@ import {
23
23
  extractTaskFromMessage,
24
24
  extractSlackMessageText,
25
25
  dispatchPre2
26
- } from "./cli-5rk36sjf.js";
26
+ } from "./cli-v3yr2gbg.js";
27
27
  import {
28
28
  noteSlackInboundSideEffect,
29
29
  ignoreSlackInbound,
@@ -34,14 +34,14 @@ import {
34
34
  isSlackRenderV2Enabled2,
35
35
  ensureSlackThreadTree2,
36
36
  registerTreeMessage
37
- } from "./cli-nn47d7e8.js";
37
+ } from "./cli-qkhc5aqy.js";
38
38
  import {
39
39
  isBlockExternalEnabled2,
40
40
  invalidateChannelExternality2,
41
41
  getChannelBlockReason2,
42
42
  shouldBlockChannel2,
43
43
  leaveExternalChannel2
44
- } from "./cli-pkht5hap.js";
44
+ } from "./cli-1d70crsy.js";
45
45
  import {
46
46
  workflowEventBus2,
47
47
  init_event_bus
@@ -50,7 +50,7 @@ import {
50
50
  enrichSlackUserEmail,
51
51
  resolveSlackUserId,
52
52
  rewriteSlackMentions
53
- } from "./cli-bcj753sq.js";
53
+ } from "./cli-2v045xyf.js";
54
54
  import {
55
55
  wasEventSeen,
56
56
  requestSlackThreadSteering,
@@ -58,7 +58,7 @@ import {
58
58
  bufferThreadMessage,
59
59
  getBufferMessageCount,
60
60
  instantFlush
61
- } from "./cli-0qvtffe9.js";
61
+ } from "./cli-b8k7epj1.js";
62
62
  import {
63
63
  resolveTemplate,
64
64
  init_resolver
@@ -75,7 +75,7 @@ import {
75
75
  import {
76
76
  isEnvFlagEnabled,
77
77
  init_env_flag
78
- } from "./cli-0hyhdkdk.js";
78
+ } from "./cli-cebvbc9t.js";
79
79
  import {
80
80
  scrubSecrets,
81
81
  init_secret_scrubber
@@ -6,7 +6,7 @@ import {
6
6
  getResolvedConfig2,
7
7
  getAllUsers2,
8
8
  init_db3
9
- } from "./cli-d3qqdy4c.js";
9
+ } from "./cli-p20r8w42.js";
10
10
  import {
11
11
  scrubSecrets,
12
12
  init_secret_scrubber
@@ -23,7 +23,7 @@ import {
23
23
  import {
24
24
  MAX_PROFILE_FILE_LENGTH,
25
25
  init_constants2
26
- } from "./cli-w9g4sz81.js";
26
+ } from "./cli-gf2850q7.js";
27
27
  import {
28
28
  __esm
29
29
  } from "./cli-242037k3.js";
@@ -2833,9 +2833,9 @@ var init_types = __esm(() => {
2833
2833
  }).openapi("SwarmScriptNodeConfig");
2834
2834
  WorkflowNodeSchema = object2({
2835
2835
  id: string2().describe("Unique node identifier, used in 'next' and 'inputs' mappings"),
2836
- type: string2().describe("Executor type: 'agent-task', 'script', 'swarm-script', 'raw-llm', 'system-one-decision', 'validate', 'property-match'"),
2836
+ type: string2().describe("Executor type: 'agent-task', 'script', 'swarm-script', 'raw-llm', 'system-one-decision', 'system-one-extraction', 'validate', 'property-match'"),
2837
2837
  label: string2().optional().describe("Human-readable label for UI display"),
2838
- config: record2(string2(), unknown()).describe("Executor-specific config. For agent-task: { template, outputSchema?, agentId?, routingReason?, routingNote?, tags?, priority?, dir?, vcsRepo?, model? }; configured agentId defaults routingReason to human_pinned. " + "For script: { runtime, script, args?, timeout? }. " + "For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. " + "For system-one-decision (typed decisions, Jev by default): { provider? ('typesafe' default | 'openrouter' | 'laya'; a literal, never a {{token}}), state, questions: { <id>: { type: 'noul'|'choice'|'score', instructions, criteria? } }, returns: { <id>: { type } }, model? (provider-specific; unset = the provider's default, and laya has none so it sends no model and picks its own checkpoint), timeoutMs?, maxRetries? (0-3), humanReview? { band: { min, max } (0-1, inclusive), approvers: { users?, roles?, policy }, title?, timeout?, notifications? } }; each provider needs its own global secret (TYPESAFE_API_KEY, OPENROUTER_API_KEY, or LAYA_API_KEY; laya also needs the global config LAYA_URL), and a save warns and a run fails before any node executes when one is missing; system-one-decision nodes must not set retry or validation.retry. With humanReview, an answer whose confidence is inside the band waits for a person (human-in-the-loop approval), and next must map ports { approved, rejected?, timeout? }. " + "Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. " + "SECURITY: executable source for script/swarm-script nodes does not interpolate trigger.* or upstream node outputs; only input/workflow/swarm/run values are allowed in inline script source, and named swarm-script source is not workflow-interpolated. " + 'Pass dynamic values through config.args instead (inline script receives them as argv, with runtime: "bash" running bash -c <script> ...args so args[0] is $0 and args[1] is $1; swarm-script receives its args object). ' + "NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, " + "while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})."),
2838
+ config: record2(string2(), unknown()).describe("Executor-specific config. For agent-task: { template, outputSchema?, agentId?, routingReason?, routingNote?, tags?, priority?, dir?, vcsRepo?, model? }; configured agentId defaults routingReason to human_pinned. " + "For script: { runtime, script, args?, timeout? }. " + "For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. " + "For system-one-decision (typed decisions, Jev by default): { provider? ('typesafe' default | 'openrouter' | 'laya'; a literal, never a {{token}}), state, questions: { <id>: { type: 'noul'|'choice'|'score', instructions, criteria? } }, returns: { <id>: { type } }, model? (provider-specific; unset = the provider's default, and laya has none so it sends no model and picks its own checkpoint), timeoutMs?, maxRetries? (0-3), humanReview? { band: { min, max } (0-1, inclusive), approvers: { users?, roles?, policy }, title?, timeout?, notifications? } }; each provider needs its own global secret (TYPESAFE_API_KEY, OPENROUTER_API_KEY, or LAYA_API_KEY; laya also needs the global config LAYA_URL), and a save warns and a run fails before any node executes when one is missing; system-one-decision nodes must not set retry or validation.retry. With humanReview, an answer whose confidence is inside the band waits for a person (human-in-the-loop approval), and next must map ports { approved, rejected?, timeout? }. " + "For system-one-extraction (typed extraction, Cloudflare Clairic by default): { provider? ('cloudflare'; a literal), state (text to read; may be empty when images are sent), fields: { <id>: { type: 'text'|'number'|'date'|'time'|'datetime'|'duration'|'list'|'estimate'|'forecast', instructions?, ...type options (number: unit?, integer?, decimals?; duration: unit? (seconds..years), integer?, decimals?; list: items ('text'|'number'|'date'); estimate: min, max, step?, scale?, unit?; forecast: min, max, horizon?, interval?, scale?, unit?; text/number/date/time/datetime/duration: null_threshold?) } }, images? (max 4 base64 data: URLs or { content_type, base64 }), referenceDate? (YYYY-MM-DD), model?, timeoutMs?, maxRetries? (0-3) }; output answers.<id> carries value (null when the input does not say), guess, p_null, confidence, span/spans, and for estimate/forecast median/p10/p90. Needs the global secret CLOUDFLARE_API_TOKEN (or CLOUDFLARE_API_KEY) and the global config CLOUDFLARE_ACCOUNT_ID; must not set retry or validation.retry. " + "Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. " + "SECURITY: executable source for script/swarm-script nodes does not interpolate trigger.* or upstream node outputs; only input/workflow/swarm/run values are allowed in inline script source, and named swarm-script source is not workflow-interpolated. " + 'Pass dynamic values through config.args instead (inline script receives them as argv, with runtime: "bash" running bash -c <script> ...args so args[0] is $0 and args[1] is $1; swarm-script receives its args object). ' + "NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, " + "while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})."),
2839
2839
  next: union2([string2(), array2(string2()), record2(string2(), string2())]).optional().describe("Next node(s): string for simple chaining, string[] for fan-out to parallel nodes, or record for port-based routing ({pass: 'a', fail: 'b'})"),
2840
2840
  validation: StepValidationConfigSchema.optional(),
2841
2841
  retry: RetryPolicySchema.optional(),