@desplega.ai/agent-swarm 2.7.0 → 2.7.1

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 (236) hide show
  1. package/dist/{acp-adapter-ma1js5n7.js → acp-adapter-8dn5tq56.js} +6 -6
  2. package/dist/{actions-1vhmtvg9.js → actions-3r6gw7dy.js} +18 -18
  3. package/dist/{amp-adapter-sxqqvmdk.js → amp-adapter-wjtq413p.js} +3 -3
  4. package/dist/{anthropic-messages-txs190dd.js → anthropic-messages-n4cby1rz.js} +4 -4
  5. package/dist/{app-mwx1d5a9.js → app-d53yhykk.js} +3 -3
  6. package/dist/{assistant-yx1p6g82.js → assistant-ksrawj3k.js} +20 -20
  7. package/dist/{boot-reembed-7h78vmvv.js → boot-reembed-fxfw17m2.js} +10 -3
  8. package/dist/{boot-reembed-5h37a2c2.js → boot-reembed-k5y5xbj0.js} +15 -8
  9. package/dist/{boot-scrub-sweep-8mawd4gw.js → boot-scrub-sweep-se41j9fd.js} +3 -3
  10. package/dist/{boot-seeds-ca84dhnn.js → boot-seeds-r3kwwv8b.js} +4 -4
  11. package/dist/{claude-adapter-wqt4hfkq.js → claude-adapter-ahmyf231.js} +7 -7
  12. package/dist/{claude-managed-adapter-6fjqtr2z.js → claude-managed-adapter-5knamegc.js} +3 -3
  13. package/dist/{claude-managed-setup-rqv98sea.js → claude-managed-setup-mdc7dy6b.js} +2 -2
  14. package/dist/{claude-sdk-session-f29f3b2x.js → claude-sdk-session-n5wen9zk.js} +8728 -8599
  15. package/dist/{cli-m5e802r7.js → cli-0dqtv2jg.js} +2 -2
  16. package/dist/{cli-e1595bgx.js → cli-0tww7dnz.js} +2 -2
  17. package/dist/{cli-2y7v133v.js → cli-0w4e4v58.js} +7 -7
  18. package/dist/{cli-d20qvpr2.js → cli-2sjm3t4r.js} +1 -1
  19. package/dist/{cli-gf2850q7.js → cli-3cywb44q.js} +18 -1
  20. package/dist/{cli-8wkb09q5.js → cli-3k9jej0c.js} +2 -2
  21. package/dist/{cli-twctnkng.js → cli-3v2cyqb8.js} +3 -3
  22. package/dist/{cli-he9gbdx0.js → cli-5qt9vzmq.js} +39 -20
  23. package/dist/{cli-a6ds2epe.js → cli-5rp1w4cr.js} +1 -1
  24. package/dist/{cli-6srv653c.js → cli-6vwjsetx.js} +4 -4
  25. package/dist/{cli-1hhbzkbb.js → cli-6w2yrrc0.js} +8 -8
  26. package/dist/{cli-f12mr20z.js → cli-75tdydgv.js} +1 -1
  27. package/dist/{cli-j3y0x2n4.js → cli-8feswf2v.js} +43 -33
  28. package/dist/{cli-07q03xm2.js → cli-8wd3mbyj.js} +1 -1
  29. package/dist/{cli-ymjpkxgn.js → cli-9csfthbw.js} +8 -6
  30. package/dist/{cli-f1e0ptjj.js → cli-b41p764a.js} +21 -2
  31. package/dist/{cli-kv7sbc2c.js → cli-c1t533hh.js} +3 -3
  32. package/dist/{cli-54sj64fc.js → cli-c28jxpcv.js} +1 -1
  33. package/dist/{cli-8mbc9za9.js → cli-cb50g9cd.js} +1 -1
  34. package/dist/{cli-c668vvcf.js → cli-d8gaphtr.js} +1 -1
  35. package/dist/{cli-86ehn4s5.js → cli-dgtfysne.js} +2 -2
  36. package/dist/{cli-sjctjr48.js → cli-dscnhn18.js} +1 -1
  37. package/dist/{cli-j0ppywdr.js → cli-dv11pgpv.js} +12 -12
  38. package/dist/{cli-1m9x8dr5.js → cli-ekptgk2m.js} +5 -5
  39. package/dist/{cli-9gsm2rzp.js → cli-f3mzy662.js} +17 -17
  40. package/dist/{cli-s0mgx214.js → cli-fk7k8s9x.js} +2 -2
  41. package/dist/{cli-vbhgkw9h.js → cli-h3e7bhvn.js} +3 -3
  42. package/dist/{cli-yd2nreqw.js → cli-hkxqdmnb.js} +2 -2
  43. package/dist/{cli-8wmj18cz.js → cli-hpkvgdad.js} +7 -4
  44. package/dist/{cli-wqr7cea4.js → cli-hq2v4rr5.js} +37 -9
  45. package/dist/{cli-sgqm2582.js → cli-k1zb7raw.js} +5 -5
  46. package/dist/{cli-4rvr7zfx.js → cli-k4awgvzm.js} +5 -0
  47. package/dist/{cli-ay40dnj3.js → cli-k7d3hvya.js} +2 -2
  48. package/dist/{cli-j9bpmykh.js → cli-kbtdftbw.js} +5 -5
  49. package/dist/{cli-x37r7qwf.js → cli-kj69b9tw.js} +25 -5
  50. package/dist/{cli-gsfk58nw.js → cli-kk9jy4nm.js} +1 -1
  51. package/dist/{cli-39aet655.js → cli-m52t4cta.js} +1 -1
  52. package/dist/{cli-h5jeg46p.js → cli-mdadewqp.js} +5 -5
  53. package/dist/{cli-a89zdqz9.js → cli-nf6k60sn.js} +1 -1
  54. package/dist/{cli-v6shg7na.js → cli-nzdf09js.js} +1 -1
  55. package/dist/{cli-rr7zx19j.js → cli-prcyzecg.js} +12 -12
  56. package/dist/{cli-6a9qfa8b.js → cli-pzafyqtk.js} +118 -48
  57. package/dist/{cli-48gxjmcz.js → cli-qvaa1gjp.js} +87 -24
  58. package/dist/{cli-qj442fws.js → cli-rg4b2g6j.js} +1 -1
  59. package/dist/{cli-aypd09nf.js → cli-rm66vqdz.js} +1 -1
  60. package/dist/{cli-9pshx6rd.js → cli-s504c3w7.js} +1 -1
  61. package/dist/{cli-ptfq202x.js → cli-swkx9jm2.js} +3 -3
  62. package/dist/{cli-m30k9777.js → cli-thsaq4pd.js} +16 -16
  63. package/dist/{cli-60sty27p.js → cli-twjnyvs8.js} +2 -2
  64. package/dist/{cli-rd5m70gj.js → cli-typdpe8g.js} +4 -4
  65. package/dist/{cli-yxbsmx56.js → cli-vg8pwmsd.js} +6 -6
  66. package/dist/{cli-s09j9vp5.js → cli-vhpckzvp.js} +1 -1
  67. package/dist/{cli-dv97kdzv.js → cli-wdxgsdz5.js} +2 -2
  68. package/dist/{cli-7a6p4e65.js → cli-wtjg6je3.js} +1 -1
  69. package/dist/{cli-b3yzyc57.js → cli-x3cngb1h.js} +44 -12
  70. package/dist/{cli-6mgdba42.js → cli-xbz6mcg4.js} +2 -2
  71. package/dist/{cli-2pvzmas1.js → cli-y4tdxsqb.js} +3 -3
  72. package/dist/{cli-f4dbh7a5.js → cli-yqrsp3ny.js} +7 -7
  73. package/dist/cli.js +27 -19
  74. package/dist/{codex-adapter-zk59x2zh.js → codex-adapter-7wepzq15.js} +5 -5
  75. package/dist/{codex-hook-xyjhvxwd.js → codex-hook-pbdh4xhx.js} +2 -2
  76. package/dist/{codex-session-runner-kh6s4j3n.js → codex-session-runner-02sb49e4.js} +5 -5
  77. package/dist/{commands-68et1qv2.js → commands-3rcspxct.js} +2 -2
  78. package/dist/{controller-fyrbnzg4.js → controller-8ar4avd6.js} +3 -3
  79. package/dist/{controllers-connect-nep9h2xv.js → controllers-connect-ajvh9h0v.js} +19 -19
  80. package/dist/{cursor-adapter-yss3pg7t.js → cursor-adapter-gd0sa7bh.js} +1 -1
  81. package/dist/{db-28gjyvxj.js → db-dv9j7ts5.js} +2 -2
  82. package/dist/{db-8ftwvzba.js → db-z26vgdvj.js} +3 -3
  83. package/dist/{dispatcher-hayexmkr.js → dispatcher-8m0htjq8.js} +17 -17
  84. package/dist/{dsh-adapter-46wawff9.js → dsh-adapter-y8gyk130.js} +1 -1
  85. package/dist/{e2b-fn3zacvt.js → e2b-74vg9b7e.js} +1 -1
  86. package/dist/{e2b-222hsajc.js → e2b-jyay8wzn.js} +1 -1
  87. package/dist/{easter-egg-3d-8d1e0h4m.js → easter-egg-3d-28f880xx.js} +1 -1
  88. package/dist/{execute-cjrfxfnm.js → execute-9seb79vh.js} +1 -1
  89. package/dist/{external-channel-xbmxcg09.js → external-channel-smz7jyth.js} +2 -2
  90. package/dist/{getMachineId-bsd-brn0xym3.js → getMachineId-bsd-whfre6gr.js} +3 -3
  91. package/dist/{getMachineId-darwin-t339sfxm.js → getMachineId-darwin-5zjynb19.js} +3 -3
  92. package/dist/{getMachineId-linux-5eq95d8b.js → getMachineId-linux-8mksrrsq.js} +3 -3
  93. package/dist/{getMachineId-unsupported-qavrtc7j.js → getMachineId-unsupported-fxtqsdt2.js} +3 -3
  94. package/dist/{getMachineId-win-q7fe1wx7.js → getMachineId-win-nzfmz857.js} +3 -3
  95. package/dist/{grok-adapter-ag4wks2a.js → grok-adapter-z0nnvtbn.js} +7 -7
  96. package/dist/handlers-pspryh6g.js +41 -0
  97. package/dist/{heartbeat-psfvcgwp.js → heartbeat-f928aqyp.js} +20 -20
  98. package/dist/{hook-cyq4mryn.js → hook-d7c605r4.js} +7 -7
  99. package/dist/{hook-8pz04697.js → hook-q9hv5xf9.js} +5 -5
  100. package/dist/{http-haj1nd6k.js → http-q6j4k989.js} +934 -180
  101. package/dist/{index-z5h22pes.js → index-5nb266jr.js} +17 -17
  102. package/dist/{index-ysd45kgc.js → index-8fxt5eah.js} +10 -10
  103. package/dist/{index-zgvqzjsw.js → index-cekzwhez.js} +5 -5
  104. package/dist/{index-zyq8ct52.js → index-ch0c1xff.js} +17 -17
  105. package/dist/{index-syvhnvtw.js → index-ebnjhxh1.js} +1 -1
  106. package/dist/{index-y1ajx04a.js → index-ed8dy8rn.js} +20 -20
  107. package/dist/{index-jwt2bj6f.js → index-ejqdkkqx.js} +11 -10
  108. package/dist/{index-dr94zbnh.js → index-farm1zsn.js} +32661 -29443
  109. package/dist/{index-q52f47pe.js → index-yn1yxg85.js} +1 -1
  110. package/dist/{keepalive-xdvsamvj.js → keepalive-zzc3hks1.js} +3 -3
  111. package/dist/{lead-hqg57kdp.js → lead-c0pjcaw4.js} +36 -36
  112. package/dist/{maintenance-4y2xzh3a.js → maintenance-kqsxzpzx.js} +1 -1
  113. package/dist/{oauth-refresh-sweep-jd4r7zbs.js → oauth-refresh-sweep-7qt0g55z.js} +2 -2
  114. package/dist/{onboard-18447q9q.js → onboard-k7x13fqg.js} +118 -5
  115. package/dist/{opencode-adapter-26b2frdf.js → opencode-adapter-tqvrtter.js} +5 -5
  116. package/dist/{otel-impl-f9tgr8yw.js → otel-impl-sqkf6k3b.js} +97 -97
  117. package/dist/{pi-mono-adapter-qn6qbga1.js → pi-mono-adapter-m2qnafxm.js} +63 -9
  118. package/dist/{pricing-refresh-dw2tgb53.js → pricing-refresh-wkpwhgvs.js} +3 -3
  119. package/dist/{rbac-roles-s4nwj2m3.js → rbac-roles-dpn0c0wj.js} +7 -4
  120. package/dist/{rbac-roles-aygm2760.js → rbac-roles-wk7xd6a6.js} +2 -2
  121. package/dist/{render-v2-yfvdfr0x.js → render-v2-ex2m4g2k.js} +3 -3
  122. package/dist/{resume-1bmvjbf3.js → resume-725g9b0b.js} +7 -7
  123. package/dist/{runtime-f7tpzedy.js → runtime-kajas15g.js} +1 -1
  124. package/dist/{session-access-r5garej6.js → session-access-0j2ezjje.js} +8 -4
  125. package/dist/{session-source-backfill-424wzv0r.js → session-source-backfill-62202awe.js} +2 -2
  126. package/dist/{setup-8tygvxkq.js → setup-9sj11ax6.js} +1 -1
  127. package/dist/{virtual-modules-xsw323b3.js → virtual-modules-c6fcq6zr.js} +2 -2
  128. package/dist/{work-objects-ggnghpgf.js → work-objects-0y07495y.js} +20 -20
  129. package/dist/{worker-sqjd1nqf.js → worker-d4q9sqbc.js} +36 -36
  130. package/openapi.json +1070 -9
  131. package/package.json +3 -3
  132. package/src/be/connector-codes.ts +65 -22
  133. package/src/be/memory/boot-reembed.ts +4 -1
  134. package/src/be/memory/constants.ts +6 -0
  135. package/src/be/memory/embedding-recovery.ts +48 -0
  136. package/src/be/memory/index-content.ts +5 -2
  137. package/src/be/memory/providers/openai-embedding.ts +65 -14
  138. package/src/be/memory/task-learning.ts +110 -8
  139. package/src/be/memory/types.ts +13 -2
  140. package/src/be/migrations/246_connector_code_kind.sql +11 -0
  141. package/src/be/onboarding.ts +125 -15
  142. package/src/be/rbac-roles.ts +4 -1
  143. package/src/be/scripts/embeddings.ts +2 -2
  144. package/src/be/seed/agent-fs-provision.ts +75 -14
  145. package/src/be/swarm-config-guard.ts +3 -0
  146. package/src/cli.tsx +9 -0
  147. package/src/comb/config.ts +6 -1
  148. package/src/commands/onboard/agent-fs-version.ts +5 -0
  149. package/src/commands/onboard/compose-generator.ts +112 -1
  150. package/src/commands/onboard/env-generator.ts +9 -0
  151. package/src/commands/onboard/tei-image.ts +12 -0
  152. package/src/commands/onboard/types.ts +7 -0
  153. package/src/commands/onboard.tsx +11 -1
  154. package/src/commands/runner.ts +14 -1
  155. package/src/http/agentfs-proxy.ts +369 -0
  156. package/src/http/all-routes.ts +1 -0
  157. package/src/http/codex-oauth-device.ts +8 -1
  158. package/src/http/fs.ts +64 -10
  159. package/src/http/inbox-state.ts +27 -1
  160. package/src/http/index.ts +4 -1
  161. package/src/http/memory.ts +7 -4
  162. package/src/http/onboarding.ts +139 -11
  163. package/src/http/session-access.ts +24 -0
  164. package/src/http/sessions.ts +10 -6
  165. package/src/http/tasks.ts +85 -11
  166. package/src/http/telemetry-ui.ts +1 -1
  167. package/src/http/user-roles.ts +4 -1
  168. package/src/http/users.ts +272 -3
  169. package/src/http/utils.ts +22 -3
  170. package/src/prompts/base-prompt.ts +24 -9
  171. package/src/prompts/session-templates.ts +26 -2
  172. package/src/providers/amp-adapter.ts +1 -1
  173. package/src/providers/codex-adapter.ts +6 -1
  174. package/src/providers/cursor-adapter.ts +1 -1
  175. package/src/providers/pi-mono-adapter.ts +58 -3
  176. package/src/rbac/legacy-policy.ts +1 -0
  177. package/src/rbac/permissions.ts +4 -0
  178. package/src/tests/agent-fs-provision-seeder.test.ts +261 -92
  179. package/src/tests/agentfs-proxy.test.ts +1106 -0
  180. package/src/tests/base-prompt.test.ts +69 -2
  181. package/src/tests/codex-adapter.test.ts +46 -8
  182. package/src/tests/codex-oauth-device.test.ts +12 -1
  183. package/src/tests/comb-config-guard.test.ts +20 -0
  184. package/src/tests/comb-links.test.ts +79 -1
  185. package/src/tests/comb-status.test.ts +44 -0
  186. package/src/tests/docs-index-footprint.test.js +3 -3
  187. package/src/tests/fixtures/onboard/baseline-states.ts +68 -0
  188. package/src/tests/fixtures/onboard/content.compose.yml.txt +190 -0
  189. package/src/tests/fixtures/onboard/content.env.txt +29 -0
  190. package/src/tests/fixtures/onboard/dev.compose.yml.txt +155 -0
  191. package/src/tests/fixtures/onboard/dev.env.txt +28 -0
  192. package/src/tests/fixtures/onboard/full-all.compose.yml.txt +582 -0
  193. package/src/tests/fixtures/onboard/full-all.env.txt +59 -0
  194. package/src/tests/fixtures/onboard/full.compose.yml.txt +435 -0
  195. package/src/tests/fixtures/onboard/full.env.txt +36 -0
  196. package/src/tests/fixtures/onboard/research.compose.yml.txt +155 -0
  197. package/src/tests/fixtures/onboard/research.env.txt +28 -0
  198. package/src/tests/fixtures/onboard/solo.compose.yml.txt +85 -0
  199. package/src/tests/fixtures/onboard/solo.env.txt +26 -0
  200. package/src/tests/http-log-scrubbing.test.ts +34 -1
  201. package/src/tests/http-task-write-ownership.test.ts +5 -1
  202. package/src/tests/invites-http.test.ts +464 -0
  203. package/src/tests/memory-embedding-input-cap.test.ts +122 -1
  204. package/src/tests/memory-embedding-recovery.test.ts +137 -0
  205. package/src/tests/onboard-compose.test.ts +142 -0
  206. package/src/tests/onboard-env.test.ts +24 -0
  207. package/src/tests/onboard-non-interactive.test.ts +29 -0
  208. package/src/tests/onboard-tei-image.test.ts +36 -0
  209. package/src/tests/onboarding.test.ts +451 -4
  210. package/src/tests/openai-embedding-provider.test.ts +105 -2
  211. package/src/tests/pi-mono-session-cost-on-abort.test.ts +270 -0
  212. package/src/tests/preload-env.test.ts +4 -0
  213. package/src/tests/preload.ts +4 -0
  214. package/src/tests/prompt-template-session.test.ts +19 -3
  215. package/src/tests/rbac-admission-e2e.test.ts +22 -6
  216. package/src/tests/rbac-admission.test.ts +342 -4
  217. package/src/tests/rbac-engine.test.ts +1 -0
  218. package/src/tests/rbac-roles.test.ts +9 -1
  219. package/src/tests/send-task-requester-gate.test.ts +64 -3
  220. package/src/tests/sessions-move.test.ts +39 -1
  221. package/src/tests/store-progress-learning.test.ts +95 -2
  222. package/src/tests/whoami-route.test.ts +41 -0
  223. package/src/tools/inject-learning.ts +1 -1
  224. package/src/tools/memory-edit.ts +1 -1
  225. package/src/tools/memory-search.ts +1 -1
  226. package/src/tools/store-progress.ts +5 -1
  227. package/src/tools/utils.ts +12 -1
  228. package/src/utils/constants.ts +39 -0
  229. package/src/utils/task-attachment-links.ts +15 -3
  230. package/templates/skills/swarm-docs/content.md +1 -1
  231. package/dist/handlers-tzmevqb5.js +0 -41
  232. package/dist/{azure-openai-responses-9kfwhmn7.js → azure-openai-responses-43asa23s.js} +0 -0
  233. package/dist/{node-vxx896fa.js → node-t28cc56b.js} +0 -0
  234. package/dist/{openai-codex-responses-79s8xnbh.js → openai-codex-responses-jhr3sjtm.js} +3 -3
  235. package/dist/{openai-completions-tdbyts0x.js → openai-completions-gs6yn37k.js} +3 -3
  236. /package/dist/{openai-responses-dm3t5vqp.js → openai-responses-jqm9vwwk.js} +0 -0
@@ -2,7 +2,13 @@ import { telemetry } from "../telemetry";
2
2
  import { ProviderNameSchema } from "../types";
3
3
  import { getCurrentRequestUserId } from "../utils/request-auth-context";
4
4
  import { z } from "../utils/zod-openapi";
5
- import { getDbClient, getSwarmConfigs, getTaskById, upsertSwarmConfig } from "./db";
5
+ import {
6
+ deleteSwarmConfigByKey,
7
+ getDbClient,
8
+ getSwarmConfigs,
9
+ getTaskById,
10
+ upsertSwarmConfig,
11
+ } from "./db";
6
12
  import { validateConfigValue } from "./swarm-config-guard";
7
13
 
8
14
  const ONBOARDING_CONFIG_KEY = "onboarding_state";
@@ -14,6 +20,7 @@ export const OnboardingStepIdSchema = z.enum([
14
20
  "agents",
15
21
  "memory",
16
22
  "integrations",
23
+ "files",
17
24
  "first_task",
18
25
  ]);
19
26
  export type OnboardingStepId = z.infer<typeof OnboardingStepIdSchema>;
@@ -54,6 +61,19 @@ export const OnboardingMemoryPresetSchema = z.enum([
54
61
  "custom",
55
62
  "existing",
56
63
  ]);
64
+ /**
65
+ * Where the embeddings endpoint runs: `local` (this server or its private
66
+ * network), the hosted preset whose host it calls, or `custom` (another host).
67
+ */
68
+ export const OnboardingMemoryProviderSchema = z.enum([
69
+ "local",
70
+ "openai",
71
+ "openrouter",
72
+ "vercel",
73
+ "azure",
74
+ "custom",
75
+ ]);
76
+ export type OnboardingMemoryProvider = z.infer<typeof OnboardingMemoryProviderSchema>;
57
77
  export const OnboardingIntegrationMethodSchema = z.enum([
58
78
  "slack",
59
79
  "github",
@@ -62,6 +82,8 @@ export const OnboardingIntegrationMethodSchema = z.enum([
62
82
  "linear_oauth",
63
83
  "jira_oauth",
64
84
  ]);
85
+ /** `created`: the Files step registered a new agent-fs account. `connected`: it reused one. */
86
+ export const OnboardingFilesMethodSchema = z.enum(["created", "connected"]);
65
87
  export const OnboardingFirstTaskMethodSchema = z.enum(["suggestion", "free_form"]);
66
88
  export const OnboardingStepMethodSchema = z.union([
67
89
  OnboardingConnectMethodSchema,
@@ -70,6 +92,7 @@ export const OnboardingStepMethodSchema = z.union([
70
92
  OnboardingAgentsMethodSchema,
71
93
  OnboardingMemoryPresetSchema,
72
94
  OnboardingIntegrationMethodSchema,
95
+ OnboardingFilesMethodSchema,
73
96
  OnboardingFirstTaskMethodSchema,
74
97
  ]);
75
98
  export type OnboardingStepMethod = z.infer<typeof OnboardingStepMethodSchema>;
@@ -98,6 +121,7 @@ const OnboardingMemoryStepStateSchema = onboardingStepStateSchema(OnboardingMemo
98
121
  const OnboardingIntegrationStepStateSchema = onboardingStepStateSchema(
99
122
  OnboardingIntegrationMethodSchema,
100
123
  );
124
+ const OnboardingFilesStepStateSchema = onboardingStepStateSchema(OnboardingFilesMethodSchema);
101
125
  const OnboardingFirstTaskStepStateSchema = onboardingStepStateSchema(
102
126
  OnboardingFirstTaskMethodSchema,
103
127
  );
@@ -118,6 +142,7 @@ export const OnboardingStateSchema = z.object({
118
142
  agents: OnboardingAgentsStepStateSchema,
119
143
  memory: OnboardingMemoryStepStateSchema,
120
144
  integrations: OnboardingIntegrationStepStateSchema,
145
+ files: OnboardingFilesStepStateSchema,
121
146
  first_task: OnboardingFirstTaskStepStateSchema,
122
147
  }),
123
148
  });
@@ -139,6 +164,21 @@ export const OnboardingSignalsSchema = z.object({
139
164
  embeddings: z.object({
140
165
  configured: z.boolean(),
141
166
  dimensions: z.number().int().positive(),
167
+ /** The embedding model memory search uses. Null while it is off. */
168
+ model: z.string().nullable(),
169
+ /**
170
+ * The endpoint runs on this server or its private network (loopback, a
171
+ * private address, or a single-label host such as `tei`). False while off.
172
+ */
173
+ local: z.boolean(),
174
+ /** Where the endpoint runs, from its host only (never the URL). Null while off. */
175
+ provider: OnboardingMemoryProviderSchema.nullable(),
176
+ /**
177
+ * The local setup of the deployment environment, also while a stored
178
+ * hosted setup replaces it, so `/setup` can offer it again: the model of
179
+ * its local endpoint. Null when the environment has no local endpoint.
180
+ */
181
+ localDefault: z.object({ model: z.string() }).nullable(),
142
182
  }),
143
183
  integrations: z.object({
144
184
  slack: z.boolean(),
@@ -153,6 +193,8 @@ export const OnboardingSignalsSchema = z.object({
153
193
  workersOnline: z.number().int().nonnegative(),
154
194
  }),
155
195
  firstTask: z.object({ id: z.string(), status: z.string() }).nullable(),
196
+ /** The Files step applies: Comb is on, so the browser can create an agent-fs account. */
197
+ files: z.object({ enabled: z.boolean() }),
156
198
  });
157
199
  export type OnboardingSignals = z.infer<typeof OnboardingSignalsSchema>;
158
200
 
@@ -198,10 +240,17 @@ export const OnboardingActionSchema = z.union([
198
240
  method: OnboardingIntegrationMethodSchema,
199
241
  })
200
242
  .strict(),
243
+ z
244
+ .object({
245
+ action: z.literal("complete"),
246
+ step: z.literal("files"),
247
+ method: OnboardingFilesMethodSchema,
248
+ })
249
+ .strict(),
201
250
  z
202
251
  .object({
203
252
  action: z.literal("skip"),
204
- step: z.enum(["name", "ai", "agents", "memory", "integrations", "first_task"]),
253
+ step: z.enum(["name", "ai", "agents", "memory", "integrations", "files", "first_task"]),
205
254
  })
206
255
  .strict(),
207
256
  z
@@ -243,8 +292,18 @@ export const OnboardingMemoryRequestSchema = z
243
292
  model: z.string().trim().min(1).optional(),
244
293
  apiKey: z.string().min(1).optional(),
245
294
  reuseKey: z.enum(["OPENAI_API_KEY", "OPENROUTER_API_KEY"]).optional(),
295
+ /**
296
+ * With preset `existing`: test the setup of the deployment environment,
297
+ * and when it works, delete the stored embeddings config so that setup
298
+ * applies again. A failed test changes no config.
299
+ */
300
+ restoreDefault: z.boolean().optional(),
246
301
  })
247
- .strict();
302
+ .strict()
303
+ .refine((body) => !body.restoreDefault || body.preset === "existing", {
304
+ message: "restoreDefault needs preset existing",
305
+ path: ["restoreDefault"],
306
+ });
248
307
  export type OnboardingMemoryRequest = z.infer<typeof OnboardingMemoryRequestSchema>;
249
308
 
250
309
  export const OnboardingMemoryResponseSchema = z.object({
@@ -320,6 +379,7 @@ function freshState(now: string, autoCompleted: boolean): OnboardingState {
320
379
  agents: emptyStep(),
321
380
  memory: emptyStep(),
322
381
  integrations: emptyStep(),
382
+ files: emptyStep(),
323
383
  first_task: emptyStep(),
324
384
  },
325
385
  };
@@ -535,6 +595,20 @@ function deriveState(
535
595
  return changed;
536
596
  }
537
597
 
598
+ /**
599
+ * The response view of the state. Without Comb the Files step cannot run, so a
600
+ * stored `todo` reads as `skipped`. Response only: never persisted and never a
601
+ * `step_skipped` event, so installs without Comb send no funnel noise and the
602
+ * step comes back as `todo` once Comb is turned on.
603
+ */
604
+ function presentState(state: OnboardingState, signals: OnboardingSignals): OnboardingState {
605
+ if (signals.files.enabled || state.steps.files.status !== "todo") return state;
606
+ return {
607
+ ...state,
608
+ steps: { ...state.steps, files: { ...state.steps.files, status: "skipped" } },
609
+ };
610
+ }
611
+
538
612
  export class OnboardingTaskNotFoundError extends Error {}
539
613
 
540
614
  async function applyAction(
@@ -612,7 +686,8 @@ export async function readOrUpdateOnboarding(
612
686
  const read = await client.transaction(async () => await loadAndDerive(loadSignals, []), {
613
687
  readOnly: true,
614
688
  });
615
- if (!read.dirty) return { state: read.state, signals: read.signals };
689
+ if (!read.dirty)
690
+ return { state: presentState(read.state, read.signals), signals: read.signals };
616
691
  }
617
692
 
618
693
  return await client.transaction(async () => {
@@ -627,14 +702,43 @@ export async function readOrUpdateOnboarding(
627
702
  }
628
703
  if (dirty) await persistState(state);
629
704
  queueTelemetry(events);
630
- return { state, signals };
705
+ return { state: presentState(state, signals), signals };
631
706
  });
632
707
  }
633
708
 
709
+ /** The embeddings rows a memory probe writes or deletes. */
710
+ export const EMBEDDING_PREFIX_KEYS = [
711
+ "EMBEDDING_QUERY_PREFIX",
712
+ "EMBEDDING_DOCUMENT_PREFIX",
713
+ ] as const;
714
+ export const EMBEDDING_CONFIG_KEYS = [
715
+ "EMBEDDING_API_BASE_URL",
716
+ "EMBEDDING_MODEL",
717
+ "EMBEDDING_API_KEY",
718
+ ...EMBEDDING_PREFIX_KEYS,
719
+ ] as const;
720
+
721
+ /**
722
+ * The config change of a passed memory probe:
723
+ * - `save`: store the tested endpoint. `prefixes` sets a task prefix to an
724
+ * empty value (`""`), or deletes its stored row (`null`).
725
+ * - `restore`: delete the stored embeddings rows, so the deployment
726
+ * environment applies again.
727
+ */
728
+ export type MemoryConfigChange =
729
+ | {
730
+ kind: "save";
731
+ baseUrl: string;
732
+ model: string;
733
+ apiKey?: string;
734
+ prefixes: ReadonlyArray<{ key: (typeof EMBEDDING_PREFIX_KEYS)[number]; value: "" | null }>;
735
+ }
736
+ | { kind: "restore" };
737
+
634
738
  export async function updateOnboardingMemory(
635
739
  preset: OnboardingMemoryPreset,
636
740
  result: { ok: true } | { ok: false; errorClass: OnboardingErrorClass },
637
- saveConfig?: { baseUrl: string; model: string; apiKey?: string },
741
+ change?: MemoryConfigChange,
638
742
  ): Promise<boolean> {
639
743
  return await getDbClient().transaction(async () => {
640
744
  const events: PendingTelemetry[] = [];
@@ -642,11 +746,11 @@ export async function updateOnboardingMemory(
642
746
  let dirty = loaded.dirty;
643
747
  const eventsForState = loaded.state.autoCompleted ? [] : events;
644
748
 
645
- if (saveConfig) {
749
+ if (change?.kind === "save") {
646
750
  const configValues = [
647
- ["EMBEDDING_API_BASE_URL", saveConfig.baseUrl],
648
- ["EMBEDDING_MODEL", saveConfig.model],
649
- ...(saveConfig.apiKey ? [["EMBEDDING_API_KEY", saveConfig.apiKey]] : []),
751
+ ["EMBEDDING_API_BASE_URL", change.baseUrl],
752
+ ["EMBEDDING_MODEL", change.model],
753
+ ...(change.apiKey ? [["EMBEDDING_API_KEY", change.apiKey]] : []),
650
754
  ] as const;
651
755
  for (const [key, value] of configValues) {
652
756
  const validationError = validateConfigValue(key, value);
@@ -655,17 +759,23 @@ export async function updateOnboardingMemory(
655
759
  await upsertSwarmConfig({
656
760
  scope: "global",
657
761
  key: "EMBEDDING_API_BASE_URL",
658
- value: saveConfig.baseUrl,
762
+ value: change.baseUrl,
659
763
  });
660
- await upsertSwarmConfig({ scope: "global", key: "EMBEDDING_MODEL", value: saveConfig.model });
661
- if (saveConfig.apiKey) {
764
+ await upsertSwarmConfig({ scope: "global", key: "EMBEDDING_MODEL", value: change.model });
765
+ if (change.apiKey) {
662
766
  await upsertSwarmConfig({
663
767
  scope: "global",
664
768
  key: "EMBEDDING_API_KEY",
665
- value: saveConfig.apiKey,
769
+ value: change.apiKey,
666
770
  isSecret: true,
667
771
  });
668
772
  }
773
+ for (const { key, value } of change.prefixes) {
774
+ if (value === null) await deleteSwarmConfigByKey("global", null, key);
775
+ else await upsertSwarmConfig({ scope: "global", key, value });
776
+ }
777
+ } else if (change?.kind === "restore") {
778
+ for (const key of EMBEDDING_CONFIG_KEYS) await deleteSwarmConfigByKey("global", null, key);
669
779
  }
670
780
 
671
781
  if (result.ok) {
@@ -676,7 +786,7 @@ export async function updateOnboardingMemory(
676
786
 
677
787
  if (dirty) await persistState(loaded.state);
678
788
  queueTelemetry(events);
679
- return saveConfig !== undefined;
789
+ return change !== undefined;
680
790
  });
681
791
  }
682
792
 
@@ -38,6 +38,9 @@ export const BUILTIN_ROLES = [
38
38
  "favorite.write.own",
39
39
  "session.share",
40
40
  "session.presence",
41
+ "task.steer.own",
42
+ "comb.presence",
43
+ "fs.join.own",
41
44
  ],
42
45
  },
43
46
  {
@@ -46,7 +49,7 @@ export const BUILTIN_ROLES = [
46
49
  description: "Read-only: no task, approval or script writes.",
47
50
  isBuiltin: true,
48
51
  grantsAll: false,
49
- verbs: ["favorite.write.own", "session.presence"],
52
+ verbs: ["favorite.write.own", "session.presence", "comb.presence", "fs.join.own"],
50
53
  },
51
54
  ] satisfies (BuiltinRoleDefinition & { isBuiltin: true })[];
52
55
 
@@ -81,7 +81,7 @@ function rowToScript(row: ScriptEmbeddingCandidateRow): ScriptRecord {
81
81
  export async function embedScript(script: ScriptRecord): Promise<void> {
82
82
  const text = scriptEmbeddingText(script);
83
83
  const provider = embeddingProvider();
84
- const embedding = await provider.embed(text);
84
+ const embedding = await provider.embed(text, { kind: "document" });
85
85
  if (!embedding) return;
86
86
 
87
87
  if (embedding.length !== provider.dimensions) {
@@ -207,7 +207,7 @@ export async function searchScripts(args: {
207
207
  limit?: number;
208
208
  }): Promise<ScriptSearchResult[]> {
209
209
  const provider = embeddingProvider();
210
- const queryEmbedding = await provider.embed(args.query);
210
+ const queryEmbedding = await provider.embed(args.query, { kind: "query" });
211
211
  if (!queryEmbedding) return lexicalFallback(args);
212
212
 
213
213
  const candidates = await candidateRows(args.scope, args.scopeId);
@@ -8,6 +8,7 @@ import {
8
8
  getSwarmConfigs,
9
9
  upsertSwarmConfig,
10
10
  } from "../db";
11
+ import { getUserGrant } from "../rbac-roles";
11
12
  import type { Seeder, SeedItem } from "./types";
12
13
 
13
14
  const KIND = "agent-fs-provision";
@@ -16,6 +17,10 @@ const PROVISION_VERSION = 1;
16
17
  const ORG_NAME = "swarm";
17
18
  const DRIVE_NAME = "shared";
18
19
  const PROVISION_HASH_KEY = "AGENT_FS_PROVISION_HASH";
20
+ // Stored in place of the hash when invites failed transiently. upstreamHash() maps it to
21
+ // null, so the next boot re-applies even when the org, drive and key rows already exist
22
+ // (otherwise the adopt-current-state fallback below would mark the failed run as in sync).
23
+ const PROVISION_RETRY_MARKER = "retry-pending";
19
24
  const API_KEY_CONFIG = "API_AGENT_FS_API_KEY";
20
25
  const LEGACY_SHARED_KEY_CONFIG = "AGENT_FS_API_KEY";
21
26
 
@@ -80,6 +85,7 @@ export const agentFsProvisionSeeder: Seeder<AgentFsSeedItem> = {
80
85
 
81
86
  async upstreamHash(): Promise<string | null> {
82
87
  const existingHash = await getConfigValue(PROVISION_HASH_KEY);
88
+ if (existingHash === PROVISION_RETRY_MARKER) return null;
83
89
  if (existingHash) return existingHash;
84
90
 
85
91
  const hasOrg = !!(await getConfigValue("AGENT_FS_DEFAULT_ORG_ID"));
@@ -113,16 +119,33 @@ async function provisionAgentFs(item: AgentFsSeedItem): Promise<void> {
113
119
  shared.orgId,
114
120
  );
115
121
 
122
+ let transientFailures = 0;
116
123
  for (const invite of item.invites) {
117
124
  const currentRole = currentRoles.get(invite.email.toLowerCase());
118
125
  if (currentRole && roleRank(currentRole) >= roleRank(invite.role)) continue;
119
- await inviteToSharedOrg(item.apiUrl, shared.authHeaders, shared.orgId, invite);
126
+ const outcome = await inviteToSharedOrg(item.apiUrl, shared.authHeaders, shared.orgId, invite);
127
+ if (outcome === "transient-failure") transientFailures++;
120
128
  }
129
+ // "no-account" is not a failure to retry: agent-fs has no pending invites. The person's
130
+ // account is created later in the browser, by the /setup Files step or Comb's connect card,
131
+ // and both invite in the same flow. A transient failure (network, 5xx other than not-found,
132
+ // 401/403) must not store the hash, so the next boot re-runs the invites. The org and drive
133
+ // config rows were already written by ensureAgentFsSharedProvisioning above.
134
+ if (transientFailures > 0) {
135
+ await storeProvisionHash(PROVISION_RETRY_MARKER);
136
+ throw new Error(
137
+ `agent-fs invites failed for ${transientFailures} member(s); will retry on next boot`,
138
+ );
139
+ }
140
+
141
+ await storeProvisionHash(item.contentHash);
142
+ }
121
143
 
144
+ async function storeProvisionHash(value: string): Promise<void> {
122
145
  await upsertSwarmConfig({
123
146
  scope: "global",
124
147
  key: PROVISION_HASH_KEY,
125
- value: item.contentHash,
148
+ value,
126
149
  isSecret: false,
127
150
  description: "Internal hash for agent-fs provisioning reconciliation",
128
151
  });
@@ -203,17 +226,31 @@ export async function ensureAgentFsSharedProvisioning(options?: {
203
226
  return { apiUrl, apiKey, orgId, driveId, authHeaders };
204
227
  }
205
228
 
229
+ export type SharedOrgInviteResult = {
230
+ orgId: string;
231
+ invited: boolean;
232
+ status: "already_member" | "added" | "pending";
233
+ inviteId?: string;
234
+ expiresAt?: string;
235
+ acceptUrl?: string;
236
+ };
237
+
206
238
  /**
207
239
  * Invite an external (non-agent) member into the shared org using the
208
240
  * API-owned bootstrap credentials. Powers `POST /api/fs/members/invite` so
209
241
  * callers holding the tenant API key (e.g. the cloud control plane's
210
242
  * Connect-to-Drive flow) never need the bootstrap key itself — it is
211
243
  * API-only and never served over HTTP.
244
+ *
245
+ * agent-fs (>= 0.18.9) adds an email that has an account directly
246
+ * (`status: "added"`) and answers an email without one with a pending invite
247
+ * (`status: "pending"`, plus `acceptUrl` when its app URL is configured).
248
+ * agent-fs sends no email, so the accept link is passed back to the caller.
212
249
  */
213
250
  export async function inviteEmailToSharedOrg(
214
251
  email: string,
215
252
  role: Role,
216
- ): Promise<{ orgId: string; invited: boolean }> {
253
+ ): Promise<SharedOrgInviteResult> {
217
254
  const shared = await ensureAgentFsSharedProvisioning();
218
255
  const currentRoles = await getCurrentOrgMemberRoles(
219
256
  shared.apiUrl,
@@ -222,15 +259,31 @@ export async function inviteEmailToSharedOrg(
222
259
  );
223
260
  const currentRole = currentRoles.get(email.trim().toLowerCase());
224
261
  if (currentRole && roleRank(currentRole) >= roleRank(role)) {
225
- return { orgId: shared.orgId, invited: false };
262
+ return { orgId: shared.orgId, invited: false, status: "already_member" };
226
263
  }
227
- await agentFsRequest(shared.apiUrl, `/orgs/${encodeURIComponent(shared.orgId)}/members/invite`, {
264
+ const response = await agentFsRequest<{
265
+ status?: unknown;
266
+ inviteId?: unknown;
267
+ expiresAt?: unknown;
268
+ acceptUrl?: unknown;
269
+ }>(shared.apiUrl, `/orgs/${encodeURIComponent(shared.orgId)}/members/invite`, {
228
270
  method: "POST",
229
271
  headers: shared.authHeaders,
230
272
  body: { email: email.trim(), role },
231
273
  allowConflict: true,
232
274
  });
233
- return { orgId: shared.orgId, invited: true };
275
+ // Older agent-fs answers a direct add with a bare `{ ok: true }`.
276
+ if (response.status !== "pending") {
277
+ return { orgId: shared.orgId, invited: true, status: "added" };
278
+ }
279
+ return {
280
+ orgId: shared.orgId,
281
+ invited: true,
282
+ status: "pending",
283
+ ...(typeof response.inviteId === "string" ? { inviteId: response.inviteId } : {}),
284
+ ...(typeof response.expiresAt === "string" ? { expiresAt: response.expiresAt } : {}),
285
+ ...(typeof response.acceptUrl === "string" ? { acceptUrl: response.acceptUrl } : {}),
286
+ };
234
287
  }
235
288
 
236
289
  export async function ensureAgentFsCredentialsForAgent(agentId: string): Promise<{
@@ -396,7 +449,7 @@ async function inviteToSharedOrg(
396
449
  headers: Record<string, string>,
397
450
  orgId: string,
398
451
  invite: InviteTarget,
399
- ): Promise<void> {
452
+ ): Promise<"invited" | "no-account" | "transient-failure"> {
400
453
  try {
401
454
  await agentFsRequest(apiUrl, `/orgs/${encodeURIComponent(orgId)}/members/invite`, {
402
455
  method: "POST",
@@ -404,6 +457,7 @@ async function inviteToSharedOrg(
404
457
  body: invite,
405
458
  allowConflict: true,
406
459
  });
460
+ return "invited";
407
461
  } catch (error) {
408
462
  console.warn(
409
463
  scrubSecrets(
@@ -412,6 +466,12 @@ async function inviteToSharedOrg(
412
466
  }`,
413
467
  ),
414
468
  );
469
+ // agent-fs answers an unregistered invitee with HTTP 500 "User with email ... not found".
470
+ const noAccount =
471
+ error instanceof AgentFsRequestError &&
472
+ error.status === 500 &&
473
+ /not found/i.test(error.message);
474
+ return noAccount ? "no-account" : "transient-failure";
415
475
  }
416
476
  }
417
477
 
@@ -499,18 +559,19 @@ async function resolveInviteTargets(): Promise<InviteTarget[]> {
499
559
  const targets = new Map<string, InviteTarget>();
500
560
 
501
561
  for (const user of await getAllUsers()) {
502
- if (!user.email) continue;
503
- const role = isExplicitViewerRole(user.role) ? "viewer" : "editor";
504
- targets.set(user.email.toLowerCase(), { email: user.email, role });
562
+ const email = user.email?.trim();
563
+ if (!email) continue;
564
+ // Only active users get a seat: invited and suspended users cannot sign in yet.
565
+ if ((user.status ?? "active") !== "active") continue;
566
+ // Follow the RBAC grant, not the free-text profile role, so an RBAC Viewer stays a viewer.
567
+ const grant = await getUserGrant(user.id);
568
+ const role: Role = grant.grantsAll || grant.verbs.has("task.fs.mutate") ? "editor" : "viewer";
569
+ targets.set(email.toLowerCase(), { email, role });
505
570
  }
506
571
 
507
572
  return [...targets.values()].sort((a, b) => a.email.localeCompare(b.email));
508
573
  }
509
574
 
510
- function isExplicitViewerRole(role: string | undefined): boolean {
511
- return /\b(viewer|read[-\s]?only|guest)\b/i.test(role ?? "");
512
- }
513
-
514
575
  async function provisionHashFromCurrentState(): Promise<string> {
515
576
  return provisionHash({
516
577
  apiUrl: await resolveApiUrl(),
@@ -410,6 +410,8 @@ const VALIDATED_KEYS: Record<string, ConfigValidator> = {
410
410
  value,
411
411
  "Invalid AGENT_FS_PUBLIC_URL (must be an http(s) URL with no query string or fragment, e.g. https://agent-fs.example.com. Leave blank to use AGENT_FS_API_URL)",
412
412
  ),
413
+ // Where people-facing file links point. Blank keeps the automatic choice.
414
+ ...enumValidator("AGENT_FS_LINK_TARGET", ["dashboard", "live", ""]),
413
415
  HARNESS_PROVIDER: (value) => {
414
416
  const parsed = ProviderNameSchema.safeParse(value);
415
417
  if (parsed.success) return null;
@@ -520,6 +522,7 @@ const VALIDATED_KEYS: Record<string, ConfigValidator> = {
520
522
  "DB_RETENTION_DRY_RUN",
521
523
  "MODEL_AUTO_UPGRADE",
522
524
  "COMB_ENABLED",
525
+ "AGENT_FS_PROXY",
523
526
  ]),
524
527
  ...enumValidator("SLACK_MODE", ["socket", "http"]),
525
528
  ...enumValidator("SLACK_THREAD_STEERING", ["off", "lead", "all"]),
package/src/cli.tsx CHANGED
@@ -41,6 +41,7 @@ interface ParsedArgs {
41
41
  maxConcurrentTasks: string | undefined;
42
42
  pullPolicy: string | undefined;
43
43
  containerEngine: string | undefined;
44
+ noAgentFs: boolean;
44
45
  open: boolean;
45
46
  showHelp: boolean;
46
47
  dbPath: string;
@@ -63,6 +64,7 @@ function parseArgs(args: string[]): ParsedArgs {
63
64
  let maxConcurrentTasks: string | undefined;
64
65
  let pullPolicy: string | undefined;
65
66
  let containerEngine: string | undefined;
67
+ let noAgentFs = false;
66
68
  let open = false;
67
69
  let showHelp = false;
68
70
  let dbPath = "";
@@ -122,6 +124,8 @@ function parseArgs(args: string[]): ParsedArgs {
122
124
  if (value && !value.startsWith("-")) i++;
123
125
  } else if (arg?.startsWith("--container-engine=")) {
124
126
  containerEngine = arg.slice("--container-engine=".length);
127
+ } else if (arg === "--no-agent-fs") {
128
+ noAgentFs = true;
125
129
  } else if (arg === "--open") {
126
130
  open = true;
127
131
  } else if (arg === "--help" || arg === "-h") {
@@ -149,6 +153,7 @@ function parseArgs(args: string[]): ParsedArgs {
149
153
  maxConcurrentTasks,
150
154
  pullPolicy,
151
155
  containerEngine,
156
+ noAgentFs,
152
157
  open,
153
158
  showHelp,
154
159
  dbPath,
@@ -185,6 +190,7 @@ const COMMAND_HELP: Record<
185
190
  " --max-concurrent-tasks <n> Tasks per agent (1-100; default: lead 2, worker 1)",
186
191
  " --pull-policy <policy> Pull policy: always, missing, never (default: always)",
187
192
  " --container-engine <engine> auto, docker, podman (default: $AGENT_SWARM_CONTAINER_ENGINE, else auto; auto prefers Docker)",
193
+ " --no-agent-fs With --yes: skip the bundled agent-fs (files, Comb) and TEI (memory embeddings)",
188
194
  " -h, --help Show this help",
189
195
  ].join("\n"),
190
196
  examples: [
@@ -192,6 +198,7 @@ const COMMAND_HELP: Record<
192
198
  ` ${binName} onboard --dry-run`,
193
199
  ` ${binName} onboard --yes --preset=full`,
194
200
  ` ${binName} onboard --yes --preset=dev`,
201
+ ` ${binName} onboard --yes --preset=solo --no-agent-fs`,
195
202
  ` ${binName} onboard --container-engine=podman`,
196
203
  ` ANTHROPIC_API_KEY=sk-... ${binName} onboard --yes --preset=solo`,
197
204
  ].join("\n"),
@@ -693,6 +700,7 @@ function App({ args }: { args: ParsedArgs }) {
693
700
  maxConcurrentTasks,
694
701
  pullPolicy,
695
702
  containerEngine,
703
+ noAgentFs,
696
704
  } = args;
697
705
 
698
706
  switch (command) {
@@ -707,6 +715,7 @@ function App({ args }: { args: ParsedArgs }) {
707
715
  maxConcurrentTasks,
708
716
  pullPolicy,
709
717
  containerEngine,
718
+ noAgentFs,
710
719
  }}
711
720
  />
712
721
  );
@@ -2,6 +2,8 @@ import {
2
2
  getAgentFsDefaultDriveId,
3
3
  getAgentFsDefaultOrgId,
4
4
  getAgentFsLiveUrl,
5
+ getPublicMcpBaseUrl,
6
+ isAgentFsProxyEnabled,
5
7
  isCombEnabled,
6
8
  } from "../utils/constants";
7
9
 
@@ -27,9 +29,12 @@ function trimUrl(value: string | undefined): string | null {
27
29
  */
28
30
  export function getCombConfig(): CombConfig {
29
31
  const internalUrl = trimUrl(process.env.AGENT_FS_API_URL);
32
+ // With the proxy on, the browser reaches agent-fs through the API itself.
33
+ const browserDefault =
34
+ isAgentFsProxyEnabled() && internalUrl ? `${getPublicMcpBaseUrl()}/agentfs` : internalUrl;
30
35
  return {
31
36
  enabled: isCombEnabled(),
32
- apiUrl: trimUrl(process.env.AGENT_FS_PUBLIC_URL) ?? internalUrl,
37
+ apiUrl: trimUrl(process.env.AGENT_FS_PUBLIC_URL) ?? browserDefault,
33
38
  liveUrl: getAgentFsLiveUrl(),
34
39
  orgId: getAgentFsDefaultOrgId() ?? null,
35
40
  driveId: getAgentFsDefaultDriveId() ?? null,
@@ -0,0 +1,5 @@
1
+ /**
2
+ * agent-fs image tag bundled by `agent-swarm onboard --yes`.
3
+ * `bun run bump:agent-fs` rewrites it together with the other pins.
4
+ */
5
+ export const AGENT_FS_VERSION = "0.18.9";