@desplega.ai/agent-swarm 1.152.2 → 1.154.0

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 (284) hide show
  1. package/README.md +2 -2
  2. package/dist/{acp-adapter-pfeje2v5.js → acp-adapter-eb2aj8xy.js} +4 -4
  3. package/dist/{actions-0sttc7f5.js → actions-kpnwp1kz.js} +31 -27
  4. package/dist/{anthropic-messages-2y8nktar.js → anthropic-messages-9vqsbznt.js} +112 -84
  5. package/dist/{app-p8teva95.js → app-zk1apkf6.js} +10 -7
  6. package/dist/{assistant-r45jnsrt.js → assistant-kwq4y50q.js} +32 -28
  7. package/dist/{azure-openai-responses-f38x2avq.js → azure-openai-responses-04qwdwfq.js} +27 -13
  8. package/dist/{boot-reembed-je26h5y7.js → boot-reembed-22hd3jjn.js} +9 -7
  9. package/dist/{boot-reembed-1qmybsd4.js → boot-reembed-qe168424.js} +10 -8
  10. package/dist/{boot-scrub-logs-gte3h1mm.js → boot-scrub-logs-pkdpsrjd.js} +7 -5
  11. package/dist/{claude-adapter-csc1mzka.js → claude-adapter-3fx90nww.js} +18 -16
  12. package/dist/{claude-managed-adapter-dsmkcrjy.js → claude-managed-adapter-ea2aga6w.js} +3 -3
  13. package/dist/{claude-sdk-session-fcd6f078.js → claude-sdk-session-z7fahf1k.js} +18 -16
  14. package/dist/{cli-r2fpe7cx.js → cli-00w2c66p.js} +61 -55
  15. package/dist/{cli-wbyk465z.js → cli-09y3tjxz.js} +1 -1
  16. package/dist/{cli-ht5rs63n.js → cli-0e31nm4n.js} +16 -7
  17. package/dist/cli-0x5qzvkg.js +4279 -0
  18. package/dist/{cli-d3p82erb.js → cli-18amys3y.js} +9 -9
  19. package/dist/{cli-4ahpr4sw.js → cli-1jpjafw4.js} +5 -5
  20. package/dist/{cli-jbmc0r7r.js → cli-243tzws8.js} +1 -1
  21. package/dist/{cli-ch38q5z4.js → cli-24k806sc.js} +6789 -2542
  22. package/dist/cli-3bkz2p7j.js +2828 -0
  23. package/dist/cli-3er6gcsn.js +1849 -0
  24. package/dist/cli-4k7jazkq.js +3339 -0
  25. package/dist/{cli-c4eeb5q2.js → cli-5b6b62tz.js} +1 -1
  26. package/dist/{cli-qd65dvr6.js → cli-5vs0nh43.js} +65 -44
  27. package/dist/{cli-z3wkng35.js → cli-6r3cgpk2.js} +224 -156
  28. package/dist/{cli-pgj4a5fb.js → cli-71cj99hx.js} +4 -3
  29. package/dist/cli-8sea27q4.js +14075 -0
  30. package/dist/{cli-jvy9qgjs.js → cli-913yakhv.js} +22 -7
  31. package/dist/{cli-pf9q3696.js → cli-927erqqt.js} +5 -2
  32. package/dist/cli-95jnpnqg.js +230 -0
  33. package/dist/{cli-wpv5rgg2.js → cli-abp3g4ax.js} +15 -2
  34. package/dist/{cli-ckz5t2hb.js → cli-acy6bfhr.js} +10 -7
  35. package/dist/{cli-4yc5d8fk.js → cli-avkd6mqv.js} +50 -0
  36. package/dist/{cli-8wrympd7.js → cli-bzr0ftht.js} +26 -7
  37. package/dist/{cli-qn042eh7.js → cli-c1v10xb2.js} +194 -1913
  38. package/dist/cli-cgj4hc12.js +18902 -0
  39. package/dist/{cli-2nnd56zt.js → cli-e0pg4zeh.js} +3 -2
  40. package/dist/{cli-r84ctdxn.js → cli-e31ehqwy.js} +2 -2
  41. package/dist/{cli-gphgnvpf.js → cli-e3229na9.js} +3 -3
  42. package/dist/{cli-gpqcs935.js → cli-e3cyf59d.js} +2 -2
  43. package/dist/{cli-s25avqg9.js → cli-e781c6f9.js} +1 -0
  44. package/dist/{cli-s2qjdd6z.js → cli-eetrvv91.js} +1 -1
  45. package/dist/{cli-j4nv2wqy.js → cli-fdzg6jhf.js} +10 -4
  46. package/dist/{cli-fm4ytsdk.js → cli-g2h29qar.js} +2 -2
  47. package/dist/{cli-zvgj5zg8.js → cli-ge67p080.js} +302 -3497
  48. package/dist/cli-h38x0qhg.js +6912 -0
  49. package/dist/{cli-9xvdm3bx.js → cli-h60qfasa.js} +742 -278
  50. package/dist/{cli-jew3jda5.js → cli-hws0vn86.js} +2 -2
  51. package/dist/{cli-j8dggbcr.js → cli-k0g1sjzm.js} +23 -31
  52. package/dist/{cli-xw7vak96.js → cli-kp3qs53m.js} +5 -5
  53. package/dist/{cli-rgvp6r2x.js → cli-mcnhgnn1.js} +193 -4
  54. package/dist/{cli-zvkq5csn.js → cli-myaxtgh8.js} +7 -6
  55. package/dist/{cli-56h18ng2.js → cli-n62atwh9.js} +1 -1
  56. package/dist/cli-n7h1kqpf.js +29 -0
  57. package/dist/{cli-fmy65jdn.js → cli-pf1v8xhb.js} +7 -5
  58. package/dist/{cli-xy1cchaf.js → cli-q85qhckh.js} +238 -11
  59. package/dist/{cli-3bpzj8me.js → cli-r1d3dzt6.js} +2 -2
  60. package/dist/{pi-mono-adapter-jcqt71cg.js → cli-rxkqvngf.js} +67343 -101083
  61. package/dist/{cli-kj76p1ez.js → cli-scwq51gn.js} +13 -7
  62. package/dist/{cli-b9dd0h3k.js → cli-stwsmd6k.js} +3 -2
  63. package/dist/{cli-c2mk1kgf.js → cli-v4en75c5.js} +8 -1
  64. package/dist/{cli-z61ykvam.js → cli-wg04s9kr.js} +4 -3
  65. package/dist/cli-yn0a417a.js +4069 -0
  66. package/dist/{cli-zfzznn7c.js → cli-ytxs7mn1.js} +26 -2
  67. package/dist/{cli-4j8k1m4w.js → cli-zt1227k1.js} +1162 -192
  68. package/dist/cli.js +28 -35
  69. package/dist/{codex-adapter-fxmpsabw.js → codex-adapter-ttdm995v.js} +12 -11
  70. package/dist/{codex-hook-8jexc34x.js → codex-hook-8gx7bcz0.js} +3 -3
  71. package/dist/{codex-session-runner-rr1e47ea.js → codex-session-runner-3v8nh4c8.js} +12 -11
  72. package/dist/{commands-0f5rxz51.js → commands-1cxwbhhq.js} +7 -5
  73. package/dist/{db-r3jxf3wy.js → db-y9zwsr79.js} +25 -5
  74. package/dist/{dispatcher-06vph6q4.js → dispatcher-9m9zss36.js} +30 -26
  75. package/dist/dsh-adapter-gsb2qqf9.js +19 -0
  76. package/dist/{e2b-413b8t4v.js → e2b-93x1k0j5.js} +6 -7
  77. package/dist/{google-generative-ai-ndjmj5fa.js → google-generative-ai-gwwrnzqn.js} +33 -73
  78. package/dist/{google-vertex-fr665tqs.js → google-vertex-5wfawpwz.js} +38 -68
  79. package/dist/{handlers-0hgtc910.js → handlers-36fm1bwn.js} +33 -29
  80. package/dist/{hook-9kvrv1er.js → hook-pntw4r8h.js} +12 -10
  81. package/dist/{hook-fbfhkat3.js → hook-vwq8y26p.js} +13 -11
  82. package/dist/{http-xbyx8k5j.js → http-20jesakk.js} +357 -261
  83. package/dist/{index-jsw3aynb.js → index-6artrehg.js} +30 -26
  84. package/dist/{cli-pdz9qde4.js → index-9ch1n761.js} +10 -11
  85. package/dist/{index-rnyahfn5.js → index-9n5z2492.js} +30 -26
  86. package/dist/{index-66xz5e9j.js → index-h5gs261z.js} +521 -9
  87. package/dist/{index-tfsdxyv6.js → index-j5wrf1yw.js} +40 -25
  88. package/dist/{index-2sp0384z.js → index-kkeftv5h.js} +738 -21
  89. package/dist/{index-sgk50mbg.js → index-m2xqpz5r.js} +31 -27
  90. package/dist/{index-gpfn1741.js → index-m9ks8a7t.js} +9 -7
  91. package/dist/index-w097eg0x.js +5 -0
  92. package/dist/jiti-loader-b4837mtm.js +34 -0
  93. package/dist/jiti-static-loader-q2g5ds0y.js +31267 -0
  94. package/dist/{keepalive-s3xpr7sw.js → keepalive-pwxvxd2c.js} +9 -7
  95. package/dist/{lead-rq4n5r16.js → lead-m789wqa3.js} +46 -41
  96. package/dist/{maintenance-f0atj1ab.js → maintenance-bvg6w7e2.js} +10 -8
  97. package/dist/{mistral-conversations-qhr84ph3.js → mistral-conversations-zx0kn554.js} +24 -18
  98. package/dist/{node-x1g4v0pq.js → node-5qtycf6a.js} +16 -11
  99. package/dist/{oauth-refresh-sweep-q0t3bxre.js → oauth-refresh-sweep-6v4bd737.js} +8 -6
  100. package/dist/{onboard-br5j1kch.js → onboard-snckpcj1.js} +115 -35
  101. package/dist/{openai-codex-responses-wy6a43wd.js → openai-codex-responses-4vjqzvjp.js} +33 -27
  102. package/dist/{openai-completions-32rdwmze.js → openai-completions-pxsmym7g.js} +52 -64
  103. package/dist/{openai-responses-6xwf7bzg.js → openai-responses-tmn0rqp0.js} +23 -24
  104. package/dist/{opencode-adapter-28axqa09.js → opencode-adapter-qbmv4tpy.js} +6 -6
  105. package/dist/{otel-impl-vdqge2nt.js → otel-impl-e0ytens5.js} +4 -4
  106. package/dist/{pi-messages-b1mbr6gp.js → pi-messages-txpjj39q.js} +3 -3
  107. package/dist/pi-mono-adapter-c4ggemhz.js +1316 -0
  108. package/dist/{pricing-refresh-hb3691fd.js → pricing-refresh-52g2ywrw.js} +9 -7
  109. package/dist/{rbac-roles-t78xt39b.js → rbac-roles-5455kfdn.js} +8 -6
  110. package/dist/{rbac-roles-jh280k9g.js → rbac-roles-hbf0xa52.js} +9 -7
  111. package/dist/{render-v2-7p8r2ymg.js → render-v2-npm8xdzh.js} +16 -9
  112. package/dist/{seed-pricing-hf889enh.js → seed-pricing-650wbr1n.js} +8 -6
  113. package/dist/{setup-w6mb03jv.js → setup-k1mew5rf.js} +4 -5
  114. package/dist/virtual-modules-2q5b2pk4.js +54 -0
  115. package/dist/{work-objects-nt8gy1kj.js → work-objects-2ea3kvwg.js} +33 -29
  116. package/dist/{worker-dwy617t0.js → worker-ec6hvc4m.js} +46 -41
  117. package/openapi.json +109 -16
  118. package/package.json +7 -6
  119. package/plugin/opencode-plugins/lib/memory-raters.ts +7 -0
  120. package/src/be/automation-preflight.ts +6 -4
  121. package/src/be/db/agents.ts +75 -2
  122. package/src/be/db/tasks/read.ts +2 -0
  123. package/src/be/db/tasks/write.ts +7 -1
  124. package/src/be/db.ts +140 -18
  125. package/src/be/extensions/db.ts +35 -4
  126. package/src/be/memory/raters/llm.ts +2 -6
  127. package/src/be/memory/raters/noop.ts +2 -3
  128. package/src/be/memory/raters/registry.ts +4 -10
  129. package/src/be/migrations/157_defer_provenance_and_marker.sql +27 -0
  130. package/src/be/models-catalog.ts +2 -0
  131. package/src/be/modelsdev-cache.json +213 -0
  132. package/src/be/rbac-audit.ts +2 -0
  133. package/src/be/seed/agent-fs-provision.ts +23 -0
  134. package/src/be/seed-pricing.ts +3 -1
  135. package/src/be/swarm-config-guard.ts +1 -0
  136. package/src/commands/onboard/compose-generator.ts +16 -1
  137. package/src/commands/onboard/env-generator.ts +14 -1
  138. package/src/commands/onboard/manifest.ts +1 -0
  139. package/src/commands/onboard/steps/integration-slack.tsx +56 -16
  140. package/src/commands/onboard/steps/review.tsx +5 -0
  141. package/src/commands/onboard/types.ts +6 -0
  142. package/src/commands/onboard.tsx +5 -1
  143. package/src/commands/provider-credentials.ts +14 -2
  144. package/src/commands/runner.ts +18 -2
  145. package/src/extensions/identity.ts +15 -7
  146. package/src/extensions/lifecycle.ts +15 -21
  147. package/src/hooks/codex-hook.ts +7 -1
  148. package/src/http/agents.ts +12 -4
  149. package/src/http/config.ts +1 -1
  150. package/src/http/core.ts +5 -3
  151. package/src/http/extensions.ts +108 -34
  152. package/src/http/poll.ts +7 -0
  153. package/src/http/schedules.ts +10 -0
  154. package/src/http/script-runs.ts +35 -26
  155. package/src/http/status.ts +24 -11
  156. package/src/http/tasks.ts +6 -1
  157. package/src/prompts/base-prompt.ts +15 -7
  158. package/src/prompts/memories.ts +5 -7
  159. package/src/prompts/session-templates.ts +3 -2
  160. package/src/prompts/steering-delivery.ts +2 -0
  161. package/src/providers/claude-managed-models.ts +8 -0
  162. package/src/providers/codex-adapter.ts +3 -6
  163. package/src/providers/codex-models.ts +15 -1
  164. package/src/providers/dsh-adapter.ts +248 -0
  165. package/src/providers/index.ts +5 -1
  166. package/src/providers/modelsdev-reasoning.json +50 -0
  167. package/src/providers/pi-mono-extension.ts +2 -5
  168. package/src/rbac/legacy-policy.ts +15 -1
  169. package/src/rbac/types.ts +2 -0
  170. package/src/server.ts +7 -1
  171. package/src/slack/ack.ts +43 -8
  172. package/src/slack/app.ts +32 -10
  173. package/src/slack/config.ts +29 -0
  174. package/src/slack/handlers.ts +7 -1
  175. package/src/slack/render-v2.ts +186 -17
  176. package/src/slack/responses.ts +1 -3
  177. package/src/slack/task-output.ts +66 -8
  178. package/src/slack/thread-buffer.ts +27 -3
  179. package/src/telemetry.ts +2 -3
  180. package/src/tests/agent-fs-provision-seeder.test.ts +56 -2
  181. package/src/tests/agents-harness-provider.test.ts +19 -0
  182. package/src/tests/agents-list-model-display.test.ts +60 -1
  183. package/src/tests/base-prompt.test.ts +25 -0
  184. package/src/tests/claude-managed-adapter.test.ts +6 -0
  185. package/src/tests/codex-gpt6-release.test.ts +97 -0
  186. package/src/tests/codex-steering-hook.test.ts +2 -2
  187. package/src/tests/config-api-only-keys.test.ts +9 -0
  188. package/src/tests/context-window.test.ts +1 -0
  189. package/src/tests/db-task-read-contract.test.ts +9 -0
  190. package/src/tests/db-task-write-contract.test.ts +9 -0
  191. package/src/tests/defer-task.test.ts +115 -16
  192. package/src/tests/dsh-adapter.test.ts +276 -0
  193. package/src/tests/e2e-nightly-report.test.ts +3 -3
  194. package/src/tests/e2e-redact.test.ts +2 -0
  195. package/src/tests/env-flag.test.ts +6 -0
  196. package/src/tests/extension-agent-visibility.test.ts +474 -0
  197. package/src/tests/extensions-db.test.ts +41 -0
  198. package/src/tests/extensions-http.test.ts +148 -4
  199. package/src/tests/extensions-lifecycle.test.ts +21 -1
  200. package/src/tests/extensions-mcp-tools.test.ts +9 -5
  201. package/src/tests/fetch-resolved-env.test.ts +43 -0
  202. package/src/tests/internal-ai/complete-structured.test.ts +32 -9
  203. package/src/tests/internal-ai/credentials.test.ts +4 -4
  204. package/src/tests/internal-ai/models.test.ts +20 -0
  205. package/src/tests/memory-rate-tool.test.ts +7 -10
  206. package/src/tests/memory-rater-defaults.test.ts +23 -0
  207. package/src/tests/memory-rater-e2e.test.ts +2 -3
  208. package/src/tests/migration-046-budgets.test.ts +2 -0
  209. package/src/tests/model-control.test.ts +2 -2
  210. package/src/tests/onboard-compose.test.ts +14 -0
  211. package/src/tests/onboard-env.test.ts +17 -0
  212. package/src/tests/onboard-manifest.test.ts +12 -0
  213. package/src/tests/opus-5-5-registry.test.ts +48 -0
  214. package/src/tests/pricing-refresh.test.ts +1 -1
  215. package/src/tests/pricing-routes.test.ts +15 -3
  216. package/src/tests/provider-registration.test.ts +5 -2
  217. package/src/tests/rbac-admission-e2e.test.ts +54 -0
  218. package/src/tests/rbac-e2e-helpers.ts +2 -0
  219. package/src/tests/rbac-engine.test.ts +32 -0
  220. package/src/tests/rbac-wire-e2e.test.ts +33 -0
  221. package/src/tests/reasoning-effort.test.ts +8 -0
  222. package/src/tests/reload-config.test.ts +33 -0
  223. package/src/tests/script-connections.test.ts +3 -0
  224. package/src/tests/session-costs-model-key-normalize.test.ts +1 -0
  225. package/src/tests/slack-config.test.ts +136 -0
  226. package/src/tests/slack-mode-lifecycle.test.ts +69 -0
  227. package/src/tests/slack-render-v2.test.ts +446 -16
  228. package/src/tests/slack-steering.test.ts +69 -1
  229. package/src/tests/slack-task-output.test.ts +33 -12
  230. package/src/tests/status.test.ts +22 -2
  231. package/src/tests/steering-core.test.ts +35 -0
  232. package/src/tests/steering-delivery.test.ts +39 -0
  233. package/src/tests/steering-transport.test.ts +2 -2
  234. package/src/tests/task-tool-preload-mcp.test.ts +3 -1
  235. package/src/tests/telemetry-init.test.ts +18 -0
  236. package/src/tests/workflow-live-recovery.test.ts +126 -0
  237. package/src/tests/workflow-llm.test.ts +3 -3
  238. package/src/tools/defer-task.ts +64 -26
  239. package/src/tools/extension-common.ts +4 -0
  240. package/src/tools/extension-install.ts +1 -1
  241. package/src/tools/extension-list.ts +4 -3
  242. package/src/tools/join-swarm.ts +1 -1
  243. package/src/tools/schedules/create-schedule.ts +11 -1
  244. package/src/tools/schedules/patch-schedule.ts +5 -0
  245. package/src/tools/schedules/update-schedule.ts +5 -0
  246. package/src/tools/send-task.ts +6 -0
  247. package/src/tools/utils.ts +1 -1
  248. package/src/types.ts +30 -8
  249. package/src/utils/context-window.ts +1 -0
  250. package/src/utils/credentials.ts +8 -0
  251. package/src/utils/internal-ai/complete-structured.ts +8 -0
  252. package/src/utils/internal-ai/models.ts +5 -5
  253. package/src/utils/memory-raters.ts +3 -0
  254. package/src/workflows/engine.ts +28 -0
  255. package/src/workflows/recovery.ts +7 -4
  256. package/templates/schedules/daily-status-report/content.md +25 -12
  257. package/templates/schedules/daily-workflow-health-audit/content.md +1 -1
  258. package/templates/skills/swarm-extensions/content.md +9 -5
  259. package/dist/cli-4wppfkcm.js +0 -16384
  260. package/dist/cli-55qrx3q8.js +0 -6041
  261. package/dist/cli-cg4vnyh4.js +0 -305
  262. package/dist/cli-jyetr64j.js +0 -52
  263. package/dist/cli-pp9ax9pa.js +0 -520
  264. package/dist/cli-qa66qaf0.js +0 -6076
  265. package/dist/cli-qghpvca2.js +0 -590
  266. package/dist/cli-rembwgt8.js +0 -861
  267. package/dist/cli-tcvj7j2r.js +0 -1971
  268. package/dist/cli-vfcth11k.js +0 -36
  269. package/dist/cli-w1d1bgkk.js +0 -1422
  270. package/dist/cli-y6x0gqtg.js +0 -5977
  271. package/dist/es5-tj3tn4jj.js +0 -844
  272. package/dist/index-1kq5hw2p.js +0 -467
  273. package/dist/index-1p8wdstt.js +0 -7
  274. package/dist/index-8fdjzb2f.js +0 -100
  275. package/dist/index-bxmwzbgw.js +0 -365
  276. package/dist/index-nzerxd5z.js +0 -7
  277. package/dist/index-pyymnzat.js +0 -1168
  278. package/dist/index-qv6atbab.js +0 -619
  279. package/dist/index-rja32qa7.js +0 -801
  280. package/dist/index-tzg5srfp.js +0 -211
  281. package/dist/index-vhncw983.js +0 -90
  282. package/dist/index-xk036zsk.js +0 -859
  283. package/dist/index-zyazbzcb.js +0 -6
  284. package/dist/{claude-managed-setup-48dwg9bv.js → claude-managed-setup-f5pmsyrp.js} +3 -3
@@ -0,0 +1,1316 @@
1
+ import {
2
+ DefaultResourceLoader,
3
+ ModelRuntime,
4
+ SessionManager,
5
+ createAgentSession,
6
+ getAgentDir
7
+ } from "./cli-rxkqvngf.js";
8
+ import"./cli-5bfdm1ah.js";
9
+ import {
10
+ readPkgVersion
11
+ } from "./cli-2djtr51b.js";
12
+ import {
13
+ summarizeSession
14
+ } from "./cli-fdzg6jhf.js";
15
+ import {
16
+ checkToolLoop,
17
+ clearToolHistory
18
+ } from "./cli-hp1n6zq3.js";
19
+ import {
20
+ applyReasoningEffort
21
+ } from "./cli-avkd6mqv.js";
22
+ import"./cli-vj6h9kc2.js";
23
+ import"./cli-7nxes1hs.js";
24
+ import {
25
+ buildRatingsFromLlm,
26
+ fetchRetrievalsForTask,
27
+ getMemoryRaterNames,
28
+ postRatings
29
+ } from "./cli-3bkz2p7j.js";
30
+ import"./cli-e7d20cty.js";
31
+ import {
32
+ swarmRuntimeInstanceId
33
+ } from "./cli-re8z5p8p.js";
34
+ import {
35
+ DEFAULT_OPENROUTER_BASE_URL,
36
+ getOpenRouterBaseUrl
37
+ } from "./cli-3dpj7atn.js";
38
+ import {
39
+ exports_typebox,
40
+ getBuiltinModel,
41
+ getBuiltinModels
42
+ } from "./cli-8sea27q4.js";
43
+ import {
44
+ McpHttpClient
45
+ } from "./cli-epan13p1.js";
46
+ import"./cli-bsakbbkm.js";
47
+ import"./cli-3er6gcsn.js";
48
+ import"./cli-ej6gbxfb.js";
49
+ import"./cli-sd0mxa3c.js";
50
+ import"./cli-w5e1d1vv.js";
51
+ import {
52
+ init_secret_scrubber,
53
+ scrubSecrets
54
+ } from "./cli-r2ap2czm.js";
55
+ import"./cli-pw9rj5t9.js";
56
+ import"./cli-5b6b62tz.js";
57
+ import"./cli-btbzvq95.js";
58
+ import"./cli-1m2e086m.js";
59
+ import"./cli-mcnhgnn1.js";
60
+ import"./cli-bzr0ftht.js";
61
+ import {
62
+ __require,
63
+ __toESM
64
+ } from "./cli-bc05qbss.js";
65
+
66
+ // src/providers/pi-mono-adapter.ts
67
+ import { existsSync, lstatSync, symlinkSync, unlinkSync } from "node:fs";
68
+ import { join } from "node:path";
69
+
70
+ // src/utils/aws-error-classifier.ts
71
+ var AWS_ERROR_RULES = [
72
+ {
73
+ patterns: [
74
+ /ExpiredToken(?:Exception)?/,
75
+ /CredentialsProviderError/,
76
+ /Unable to locate credentials/,
77
+ /security token.*expired/i,
78
+ /expired.*security token/i,
79
+ /InvalidSignatureException/,
80
+ /UnrecognizedClientException/
81
+ ],
82
+ category: "aws-auth",
83
+ message: "AWS credentials have expired or are missing. " + "Run `aws sso login` (or refresh your credentials via `aws configure`) and retry."
84
+ },
85
+ {
86
+ patterns: [
87
+ /ThrottlingException/,
88
+ /TooManyRequestsException/,
89
+ /ServiceQuotaExceededException/,
90
+ /Rate exceeded/
91
+ ],
92
+ category: "aws-throttle",
93
+ message: "AWS Bedrock request was throttled (rate limit or quota exceeded). " + "Wait and retry, or request a quota increase in the AWS Service Quotas console."
94
+ },
95
+ {
96
+ patterns: [/AccessDeniedException/, /not authorized to perform/i],
97
+ category: "aws-access",
98
+ message: "AWS authorization denied for Bedrock. " + "Verify the IAM role/user has the `bedrock:InvokeModel` permission for the target model ARN and region."
99
+ },
100
+ {
101
+ patterns: [
102
+ /ValidationException/,
103
+ /ResourceNotFoundException/,
104
+ /ModelTimeoutException/,
105
+ /ModelNotReadyException/
106
+ ],
107
+ category: "aws-model",
108
+ message: "AWS Bedrock model error: the model ID may be invalid, unavailable in this region, or not yet ready. " + "Verify MODEL_OVERRIDE and the AWS region in your environment."
109
+ }
110
+ ];
111
+ function classifyAwsSdkError(text) {
112
+ if (!text)
113
+ return null;
114
+ for (const rule of AWS_ERROR_RULES) {
115
+ if (rule.patterns.some((re) => re.test(text))) {
116
+ return { category: rule.category, message: rule.message };
117
+ }
118
+ }
119
+ return null;
120
+ }
121
+
122
+ // src/providers/pi-mono-adapter.ts
123
+ init_secret_scrubber();
124
+
125
+ // src/providers/pi-mono-extension.ts
126
+ init_secret_scrubber();
127
+ function apiHeaders(config) {
128
+ return {
129
+ "Content-Type": "application/json",
130
+ ...config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {},
131
+ "X-Agent-ID": config.agentId
132
+ };
133
+ }
134
+ function fireAndForget(url, init) {
135
+ fetch(url, init).catch(() => {});
136
+ }
137
+ async function isTaskCancelled(config) {
138
+ try {
139
+ const resp = await fetch(`${config.apiUrl}/cancelled-tasks?taskId=${encodeURIComponent(config.taskId)}`, { method: "GET", headers: apiHeaders(config) });
140
+ if (!resp.ok)
141
+ return { cancelled: false };
142
+ const data = await resp.json();
143
+ const match = data.cancelled?.find((t) => t.id === config.taskId);
144
+ return match ? { cancelled: true, reason: match.failureReason } : { cancelled: false };
145
+ } catch {
146
+ return { cancelled: false };
147
+ }
148
+ }
149
+ async function checkShouldBlockPolling(config) {
150
+ try {
151
+ const resp = await fetch(`${config.apiUrl}/me`, {
152
+ method: "GET",
153
+ headers: apiHeaders(config)
154
+ });
155
+ if (!resp.ok)
156
+ return false;
157
+ const data = await resp.json();
158
+ return data.shouldBlockPolling === true;
159
+ } catch {
160
+ return false;
161
+ }
162
+ }
163
+ async function fetchTaskDetails(config) {
164
+ try {
165
+ const resp = await fetch(`${config.apiUrl}/api/tasks/${config.taskId}`, {
166
+ method: "GET",
167
+ headers: apiHeaders(config)
168
+ });
169
+ if (!resp.ok)
170
+ return null;
171
+ return await resp.json();
172
+ } catch {
173
+ return null;
174
+ }
175
+ }
176
+ async function syncIdentityFilesToServer(config, changeSource = "session_sync") {
177
+ const updates = {};
178
+ const paths = {
179
+ soulMd: "/workspace/SOUL.md",
180
+ identityMd: "/workspace/IDENTITY.md",
181
+ toolsMd: "/workspace/TOOLS.md"
182
+ };
183
+ for (const [key, path] of Object.entries(paths)) {
184
+ try {
185
+ const file = Bun.file(path);
186
+ if (await file.exists()) {
187
+ const content = await file.text();
188
+ if (content.trim() && content.length <= 65536) {
189
+ updates[key] = content;
190
+ }
191
+ }
192
+ } catch {}
193
+ }
194
+ if (Object.keys(updates).length === 0)
195
+ return;
196
+ try {
197
+ await fetch(`${config.apiUrl}/api/agents/${config.agentId}/profile`, {
198
+ method: "PUT",
199
+ headers: apiHeaders(config),
200
+ body: JSON.stringify({ ...updates, changeSource })
201
+ });
202
+ } catch {}
203
+ }
204
+ async function syncSetupScriptToServer(config, changeSource = "session_sync") {
205
+ try {
206
+ const file = Bun.file("/workspace/start-up.sh");
207
+ if (!await file.exists())
208
+ return;
209
+ const raw = await file.text();
210
+ if (!raw.trim())
211
+ return;
212
+ const markerStart = "# === Agent-managed setup (from DB) ===";
213
+ const markerEnd = "# === End agent-managed setup ===";
214
+ const startIdx = raw.indexOf(markerStart);
215
+ const endIdx = raw.indexOf(markerEnd);
216
+ let content;
217
+ if (startIdx !== -1 && endIdx !== -1) {
218
+ content = raw.substring(startIdx + markerStart.length, endIdx).trim();
219
+ } else {
220
+ content = raw.replace(/^#!\/bin\/bash\n/, "").trim();
221
+ }
222
+ if (!content || content.length > 65536)
223
+ return;
224
+ await fetch(`${config.apiUrl}/api/agents/${config.agentId}/profile`, {
225
+ method: "PUT",
226
+ headers: apiHeaders(config),
227
+ body: JSON.stringify({ setupScript: content, changeSource })
228
+ });
229
+ } catch {}
230
+ }
231
+ async function autoIndexMemoryFile(config, editedPath) {
232
+ try {
233
+ const fileContent = await Bun.file(editedPath).text();
234
+ const isShared = editedPath.startsWith("/workspace/shared/");
235
+ const fileName = editedPath.split("/").pop() ?? "unnamed";
236
+ await fetch(`${config.apiUrl}/api/memory/index`, {
237
+ method: "POST",
238
+ headers: apiHeaders(config),
239
+ body: JSON.stringify({
240
+ agentId: config.agentId,
241
+ content: fileContent,
242
+ name: fileName.replace(/\.\w+$/, ""),
243
+ scope: isShared ? "swarm" : "agent",
244
+ source: "file_index",
245
+ sourcePath: editedPath
246
+ })
247
+ });
248
+ } catch {}
249
+ }
250
+ async function fetchConcurrentContext(config) {
251
+ try {
252
+ const resp = await fetch(`${config.apiUrl}/api/concurrent-context`, {
253
+ method: "GET",
254
+ headers: apiHeaders(config)
255
+ });
256
+ if (!resp.ok)
257
+ return null;
258
+ const data = await resp.json();
259
+ const lines = [];
260
+ if (data.processingInboxMessages.length > 0) {
261
+ lines.push("=== CONCURRENT SESSION AWARENESS ===");
262
+ lines.push("");
263
+ lines.push("**Other sessions are currently processing these inbox messages:**");
264
+ for (const msg of data.processingInboxMessages) {
265
+ const preview = msg.content.length > 120 ? `${msg.content.slice(0, 120)}...` : msg.content;
266
+ lines.push(`- [${msg.source}] "${preview}" (received ${msg.createdAt})`);
267
+ }
268
+ }
269
+ if (data.recentTaskDelegations.length > 0) {
270
+ if (lines.length === 0)
271
+ lines.push("=== CONCURRENT SESSION AWARENESS ===");
272
+ lines.push("");
273
+ lines.push("**Recent task delegations (last 5 min):**");
274
+ for (const task of data.recentTaskDelegations) {
275
+ const preview = task.task.length > 120 ? `${task.task.slice(0, 120)}...` : task.task;
276
+ lines.push(`- "${preview}" → ${task.agentName ?? "unassigned"} [${task.status}]`);
277
+ }
278
+ }
279
+ if (data.activeSwarmTasks.length > 0) {
280
+ if (lines.length === 0)
281
+ lines.push("=== CONCURRENT SESSION AWARENESS ===");
282
+ lines.push("");
283
+ lines.push("**Currently active tasks across the swarm:**");
284
+ for (const task of data.activeSwarmTasks) {
285
+ const preview = task.task.length > 100 ? `${task.task.slice(0, 100)}...` : task.task;
286
+ lines.push(`- ${task.agentName ?? "unassigned"}: "${preview}" [${task.status}]`);
287
+ }
288
+ }
289
+ if (lines.length > 0) {
290
+ lines.push("");
291
+ lines.push("IMPORTANT: Avoid duplicating work that is already being handled by other sessions or agents.");
292
+ lines.push("=== END CONCURRENT SESSION AWARENESS ===");
293
+ return lines.join(`
294
+ `);
295
+ }
296
+ return null;
297
+ } catch {
298
+ return null;
299
+ }
300
+ }
301
+ async function summarizeSessionForPi(config, sessionFile, deps = {}) {
302
+ if (!sessionFile) {
303
+ console.warn("session_summary skipped (pi): session transcript file unavailable");
304
+ return;
305
+ }
306
+ const _runSummarize = deps.runSummarize ?? summarizeSession;
307
+ const _fetchRetrievals = deps.fetchRetrievalsForTask ?? fetchRetrievalsForTask;
308
+ const _postRatings = deps.postRatings ?? postRatings;
309
+ const _buildRatings = deps.buildRatingsFromLlm ?? buildRatingsFromLlm;
310
+ try {
311
+ let transcript = "";
312
+ try {
313
+ const fullTranscript = await Bun.file(sessionFile).text();
314
+ transcript = fullTranscript.length > 20000 ? fullTranscript.slice(-20000) : fullTranscript;
315
+ } catch (err) {
316
+ console.warn(scrubSecrets(`session_summary skipped (pi): cannot read ${sessionFile}: ${String(err)}`));
317
+ return;
318
+ }
319
+ if (transcript.length <= 100) {
320
+ console.warn(`session_summary skipped (pi): transcript too short (${transcript.length} chars)`);
321
+ return;
322
+ }
323
+ const sourceTaskId = config.taskId;
324
+ const agentId = config.agentId;
325
+ if (!sourceTaskId || !agentId) {
326
+ console.warn(`session_summary skipped (pi): ${!sourceTaskId ? "task id unavailable" : "agent id unavailable"}`);
327
+ return;
328
+ }
329
+ const taskDetails = await fetchTaskDetails(config).catch(() => null);
330
+ const wantRatings = getMemoryRaterNames().includes("llm");
331
+ const retrievals = wantRatings ? await _fetchRetrievals({
332
+ apiUrl: config.apiUrl,
333
+ apiKey: config.apiKey,
334
+ agentId,
335
+ taskId: sourceTaskId
336
+ }).catch(() => []) : [];
337
+ const result = await _runSummarize({
338
+ harness: "pi",
339
+ transcript,
340
+ retrievals,
341
+ taskContext: {
342
+ sourceTaskId,
343
+ agentId,
344
+ prompt: taskDetails?.task
345
+ },
346
+ apiUrl: config.apiUrl,
347
+ apiKey: config.apiKey,
348
+ env: config.env
349
+ });
350
+ if (!result) {
351
+ console.warn("session_summary skipped (pi): summarizer returned no result");
352
+ return;
353
+ }
354
+ const summary = result.summary.trim();
355
+ if (summary.length <= 20 || summary.toLowerCase().includes("no significant learnings")) {
356
+ console.debug(`session_summary skipped (pi): summary failed quality gate (${summary.length} chars)`);
357
+ return;
358
+ }
359
+ const indexResp = await fetch(`${config.apiUrl}/api/memory/index`, {
360
+ method: "POST",
361
+ headers: apiHeaders(config),
362
+ body: JSON.stringify({
363
+ scope: "agent",
364
+ source: "session_summary",
365
+ sourceTaskId,
366
+ content: summary,
367
+ name: "session-summary",
368
+ agentId
369
+ })
370
+ });
371
+ if (!indexResp.ok) {
372
+ const text = await indexResp.text().catch(() => "");
373
+ console.error("session_summary: /api/memory/index POST failed (pi):", indexResp.status, text);
374
+ return;
375
+ }
376
+ if (wantRatings && result.ratings && result.ratings.length > 0) {
377
+ const ratingEvents = _buildRatings(result.ratings, retrievals);
378
+ if (ratingEvents.length > 0) {
379
+ await _postRatings({
380
+ apiUrl: config.apiUrl,
381
+ apiKey: config.apiKey,
382
+ agentId,
383
+ taskId: sourceTaskId,
384
+ events: ratingEvents
385
+ }).catch((err) => console.error("session_summary: postRatings failed (pi):", err));
386
+ }
387
+ }
388
+ } catch (err) {
389
+ console.error("session_summary failed (pi):", err);
390
+ }
391
+ }
392
+ function createSwarmHooksExtension(config) {
393
+ return (pi) => {
394
+ let lastContextPostTime = 0;
395
+ pi.on("session_start", async (_event, _ctx) => {
396
+ fireAndForget(`${config.apiUrl}/ping`, {
397
+ method: "POST",
398
+ headers: apiHeaders(config)
399
+ });
400
+ if (config.taskId) {
401
+ await clearToolHistory(config.taskId);
402
+ }
403
+ if (config.isLead) {
404
+ const ctx = await fetchConcurrentContext(config);
405
+ if (ctx) {
406
+ console.log(ctx);
407
+ }
408
+ }
409
+ });
410
+ pi.on("tool_call", async (event, _ctx) => {
411
+ if (!config.isLead && config.taskId) {
412
+ const { cancelled, reason } = await isTaskCancelled(config);
413
+ if (cancelled) {
414
+ const cancelReason = reason || "Task cancelled by lead or creator";
415
+ return {
416
+ block: true,
417
+ reason: `\uD83D\uDED1 TASK CANCELLED: Your current task (${config.taskId.slice(0, 8)}) has been cancelled. Reason: "${cancelReason}". ` + `Stop working on this task immediately. Do NOT continue making tool calls. ` + `Use store-progress to acknowledge the cancellation and mark the task as failed, then wait for new tasks.`
418
+ };
419
+ }
420
+ }
421
+ if (!config.isLead && config.taskId) {
422
+ const toolName = event.toolName;
423
+ const toolInput = "input" in event ? event.input : {};
424
+ const loopResult = await checkToolLoop(config.taskId, toolName, toolInput);
425
+ if (loopResult.blocked) {
426
+ return {
427
+ block: true,
428
+ reason: `LOOP DETECTED: ${loopResult.reason} ` + "Stop repeating this action and try a fundamentally different approach. " + "If you're truly stuck, use store-progress to report the blocker."
429
+ };
430
+ }
431
+ if (loopResult.severity === "warning" && loopResult.reason) {
432
+ console.log(`Warning: ${loopResult.reason}`);
433
+ }
434
+ }
435
+ if (event.toolName?.endsWith("poll-task")) {
436
+ const shouldBlock = await checkShouldBlockPolling(config);
437
+ if (shouldBlock) {
438
+ return {
439
+ block: true,
440
+ reason: "\uD83D\uDED1 POLLING LIMIT REACHED: You have exceeded the maximum empty poll attempts. " + "EXIT NOW - do not make any more tool calls."
441
+ };
442
+ }
443
+ }
444
+ return;
445
+ });
446
+ pi.on("tool_result", async (event, ctx) => {
447
+ if (!config.isLead && config.taskId) {
448
+ fireAndForget(`${config.apiUrl}/api/active-sessions/heartbeat/${config.taskId}`, {
449
+ method: "PUT",
450
+ headers: apiHeaders(config)
451
+ });
452
+ }
453
+ fireAndForget(`${config.apiUrl}/api/agents/${config.agentId}/activity`, {
454
+ method: "PUT",
455
+ headers: apiHeaders(config)
456
+ });
457
+ const usage = ctx.getContextUsage?.();
458
+ if (config.taskId && usage?.tokens != null) {
459
+ const now = Date.now();
460
+ if (now - lastContextPostTime >= 30000) {
461
+ lastContextPostTime = now;
462
+ fireAndForget(`${config.apiUrl}/api/tasks/${config.taskId}/context`, {
463
+ method: "POST",
464
+ headers: apiHeaders(config),
465
+ body: JSON.stringify({
466
+ eventType: "progress",
467
+ sessionId: `pi-${config.taskId}`,
468
+ contextUsedTokens: usage.tokens,
469
+ contextTotalTokens: usage.contextWindow,
470
+ contextPercent: usage.percent
471
+ })
472
+ });
473
+ }
474
+ }
475
+ const toolName = event.toolName;
476
+ const input = event.input;
477
+ const editedPath = input?.file_path || input?.path;
478
+ if ((toolName === "write" || toolName === "edit") && editedPath) {
479
+ if (editedPath === "/workspace/SOUL.md" || editedPath === "/workspace/IDENTITY.md" || editedPath === "/workspace/TOOLS.md") {
480
+ syncIdentityFilesToServer(config, "self_edit");
481
+ }
482
+ if (editedPath.startsWith("/workspace/start-up")) {
483
+ syncSetupScriptToServer(config, "self_edit");
484
+ }
485
+ if (editedPath.startsWith("/workspace/personal/memory/") || editedPath.startsWith("/workspace/shared/memory/")) {
486
+ autoIndexMemoryFile(config, editedPath);
487
+ }
488
+ }
489
+ if (config.isLead && event.toolName?.endsWith("send-task")) {
490
+ console.log("Task sent successfully. Monitor progress using the get-task-details tool periodically.");
491
+ }
492
+ return;
493
+ });
494
+ pi.on("context", async (_event, ctx) => {
495
+ if (!config.taskId)
496
+ return;
497
+ try {
498
+ const taskDetails = await fetchTaskDetails(config);
499
+ if (taskDetails) {
500
+ const reminder = [
501
+ "=== GOAL REMINDER (injected before context compaction) ===",
502
+ `Task ID: ${taskDetails.id}`,
503
+ `Task: ${taskDetails.task}`
504
+ ];
505
+ if (taskDetails.progress) {
506
+ reminder.push(`Current Progress: ${taskDetails.progress}`);
507
+ }
508
+ reminder.push("=== Continue working on this task after compaction ===");
509
+ console.log(reminder.join(`
510
+ `));
511
+ }
512
+ } catch {}
513
+ const usage = ctx.getContextUsage?.();
514
+ if (usage) {
515
+ fireAndForget(`${config.apiUrl}/api/tasks/${config.taskId}/context`, {
516
+ method: "POST",
517
+ headers: apiHeaders(config),
518
+ body: JSON.stringify({
519
+ eventType: "compaction",
520
+ sessionId: `pi-${config.taskId}`,
521
+ contextUsedTokens: usage.tokens ?? undefined,
522
+ contextTotalTokens: usage.contextWindow,
523
+ contextPercent: usage.percent ?? undefined
524
+ })
525
+ });
526
+ }
527
+ return;
528
+ });
529
+ pi.on("input", async (_event, _ctx) => {
530
+ if (!config.isLead && config.taskId) {
531
+ const { cancelled, reason } = await isTaskCancelled(config);
532
+ if (cancelled) {
533
+ const cancelReason = reason || "Task cancelled by lead or creator";
534
+ console.log(`\uD83D\uDED1 TASK CANCELLED: ${cancelReason}. Stop working and use store-progress to acknowledge.`);
535
+ return { action: "handled" };
536
+ }
537
+ }
538
+ return;
539
+ });
540
+ pi.on("session_shutdown", async (_event, ctx) => {
541
+ const usage = ctx.getContextUsage?.();
542
+ if (config.taskId && usage) {
543
+ await fetch(`${config.apiUrl}/api/tasks/${config.taskId}/context`, {
544
+ method: "POST",
545
+ headers: apiHeaders(config),
546
+ body: JSON.stringify({
547
+ eventType: "completion",
548
+ sessionId: `pi-${config.taskId}`,
549
+ contextTotalTokens: usage.contextWindow,
550
+ contextPercent: usage.percent ?? undefined,
551
+ contextUsedTokens: usage.tokens ?? undefined
552
+ })
553
+ }).catch(() => {});
554
+ }
555
+ await syncIdentityFilesToServer(config);
556
+ await syncSetupScriptToServer(config);
557
+ const sessionFile = ctx.sessionManager.getSessionFile?.();
558
+ if (!process.env.SKIP_SESSION_SUMMARY) {
559
+ await summarizeSessionForPi(config, sessionFile);
560
+ } else {
561
+ console.debug("session_summary skipped (pi): SKIP_SESSION_SUMMARY is set");
562
+ }
563
+ fireAndForget(`${config.apiUrl}/close`, {
564
+ method: "POST",
565
+ headers: apiHeaders(config)
566
+ });
567
+ });
568
+ };
569
+ }
570
+ // src/providers/pi-mono-adapter.ts
571
+ function modelToCredKeys(modelStr) {
572
+ if (!modelStr)
573
+ return null;
574
+ const lower = modelStr.toLowerCase();
575
+ if (lower === "opus" || lower === "sonnet" || lower === "haiku") {
576
+ return ["ANTHROPIC_API_KEY", "OPENROUTER_API_KEY"];
577
+ }
578
+ if (modelStr.includes("/")) {
579
+ const provider = modelStr.slice(0, modelStr.indexOf("/")).toLowerCase();
580
+ if (provider === "anthropic")
581
+ return ["ANTHROPIC_API_KEY"];
582
+ if (provider === "openrouter")
583
+ return ["OPENROUTER_API_KEY"];
584
+ if (provider === "openai")
585
+ return ["OPENAI_API_KEY"];
586
+ if (provider === "google")
587
+ return ["GOOGLE_API_KEY"];
588
+ }
589
+ return null;
590
+ }
591
+ function getHarnessDrivableBedrockModels() {
592
+ try {
593
+ return getBuiltinModels("amazon-bedrock").map((m) => ({ id: m.id, name: m.name }));
594
+ } catch {
595
+ return [];
596
+ }
597
+ }
598
+ async function runBedrockSdkProbeAndEnumerate(region) {
599
+ const { BedrockClient, ListFoundationModelsCommand, ListInferenceProfilesCommand } = await import("./index-kkeftv5h.js").then((m)=>__toESM(m.default,1));
600
+ const client = new BedrockClient({ region });
601
+ const invocable = new Set;
602
+ const fmResponse = await client.send(new ListFoundationModelsCommand({ byInferenceType: "ON_DEMAND", byOutputModality: "TEXT" }));
603
+ for (const m of fmResponse.modelSummaries ?? []) {
604
+ if (m.modelId && m.modelLifecycle?.status === "ACTIVE") {
605
+ invocable.add(m.modelId);
606
+ }
607
+ }
608
+ const profileResponse = await client.send(new ListInferenceProfilesCommand({}));
609
+ for (const p of profileResponse.inferenceProfileSummaries ?? []) {
610
+ if (p.inferenceProfileId) {
611
+ invocable.add(p.inferenceProfileId);
612
+ }
613
+ }
614
+ return getHarnessDrivableBedrockModels().filter((m) => invocable.has(m.id));
615
+ }
616
+ async function checkPiMonoCredentials(env, opts = {}) {
617
+ const bedrockAuthMode = env.BEDROCK_AUTH_MODE?.toLowerCase();
618
+ const isBedrockBearer = bedrockAuthMode === "bearer";
619
+ const isBedrockSdk = bedrockAuthMode === "sdk" || bedrockAuthMode === undefined && env.MODEL_OVERRIDE?.toLowerCase().startsWith("amazon-bedrock/");
620
+ if (isBedrockBearer && !env.AWS_BEARER_TOKEN_BEDROCK) {
621
+ return {
622
+ ready: false,
623
+ missing: ["AWS_BEARER_TOKEN_BEDROCK"],
624
+ hint: "BEDROCK_AUTH_MODE=bearer requires AWS_BEARER_TOKEN_BEDROCK (a Bedrock API key); set it, or use BEDROCK_AUTH_MODE=sdk to authenticate through the AWS credential chain.",
625
+ bedrockModels: [],
626
+ bedrockRegion: env.AWS_REGION ?? ""
627
+ };
628
+ }
629
+ if (isBedrockSdk || isBedrockBearer) {
630
+ const region = env.AWS_REGION;
631
+ if (!region) {
632
+ return {
633
+ ready: false,
634
+ missing: [],
635
+ hint: "AWS_REGION is not set — set it to the region where your Bedrock models are accessible so model enumeration matches the inference region.",
636
+ bedrockModels: [],
637
+ bedrockRegion: ""
638
+ };
639
+ }
640
+ const probe = opts.bedrockProbe ?? (() => runBedrockSdkProbeAndEnumerate(region));
641
+ try {
642
+ const probeResult = await probe();
643
+ const bedrockModels = Array.isArray(probeResult) ? probeResult : [];
644
+ return {
645
+ ready: true,
646
+ missing: [],
647
+ satisfiedBy: isBedrockBearer ? "env" : "sdk-delegated",
648
+ hint: `Bedrock models invocable in ${region} enumerated (${bedrockModels.length} usable; ListFoundationModels + ListInferenceProfiles).`,
649
+ bedrockModels,
650
+ bedrockRegion: region
651
+ };
652
+ } catch (err) {
653
+ const errorMessage = err instanceof Error ? err.message : String(err);
654
+ const classification = classifyAwsSdkError(errorMessage);
655
+ return {
656
+ ready: false,
657
+ missing: [],
658
+ hint: classification?.message ?? `AWS Bedrock enumeration failed (region: ${region}): ${errorMessage}`,
659
+ bedrockModels: [],
660
+ bedrockRegion: region
661
+ };
662
+ }
663
+ }
664
+ const homeDir = opts.homeDir ?? env.HOME ?? "/root";
665
+ const fsProbe = opts.fs?.existsSync ?? existsSync;
666
+ const authFile = `${homeDir}/.pi/agent/auth.json`;
667
+ if (fsProbe(authFile)) {
668
+ return { ready: true, missing: [], satisfiedBy: "file" };
669
+ }
670
+ const requiredKeys = modelToCredKeys(env.MODEL_OVERRIDE);
671
+ if (requiredKeys) {
672
+ if (requiredKeys.some((k) => env[k])) {
673
+ return { ready: true, missing: [], satisfiedBy: "env" };
674
+ }
675
+ const keyList = requiredKeys.join(" / ");
676
+ return {
677
+ ready: false,
678
+ missing: [...requiredKeys, authFile],
679
+ hint: `MODEL_OVERRIDE=${env.MODEL_OVERRIDE} requires one of ${keyList}; or run \`pi auth login\` to create ${authFile}.`
680
+ };
681
+ }
682
+ if (env.ANTHROPIC_API_KEY || env.OPENROUTER_API_KEY || env.OPENAI_API_KEY) {
683
+ return { ready: true, missing: [], satisfiedBy: "env" };
684
+ }
685
+ return {
686
+ ready: false,
687
+ missing: ["ANTHROPIC_API_KEY", "OPENROUTER_API_KEY", "OPENAI_API_KEY", authFile],
688
+ hint: "Set one of ANTHROPIC_API_KEY / OPENROUTER_API_KEY / OPENAI_API_KEY (any one suffices), or run `pi auth login` to create ~/.pi/agent/auth.json."
689
+ };
690
+ }
691
+ function jsonSchemaToTypeBox(schema) {
692
+ return exports_typebox.Unsafe(schema);
693
+ }
694
+ function mcpToolsToDefinitions(mcpClient, tools) {
695
+ return tools.map((tool) => ({
696
+ name: tool.name,
697
+ label: tool.name,
698
+ description: tool.description || tool.name,
699
+ parameters: jsonSchemaToTypeBox(tool.inputSchema),
700
+ async execute(_toolCallId, params) {
701
+ const result = await mcpClient.callTool(tool.name, params);
702
+ const text = result.content.map((c) => c.text ?? "").filter(Boolean).join(`
703
+ `);
704
+ if (result.isError) {
705
+ throw new Error(text || `Tool ${tool.name} failed with no error message`);
706
+ }
707
+ return {
708
+ content: [{ type: "text", text: text || "(no output)" }],
709
+ details: undefined
710
+ };
711
+ }
712
+ }));
713
+ }
714
+ var ANTHROPIC_SHORTNAME_OPENROUTER_MIRROR = {
715
+ fable: "anthropic/claude-fable-5",
716
+ opus: "anthropic/claude-opus-4.8",
717
+ sonnet: "anthropic/claude-sonnet-5",
718
+ haiku: "anthropic/claude-haiku-4.5"
719
+ };
720
+ function envHasAnthropicCred(env) {
721
+ return !!(env.ANTHROPIC_API_KEY || env.ANTHROPIC_OAUTH_TOKEN);
722
+ }
723
+ var PI_RUNTIME_API_KEYS = [
724
+ ["OPENROUTER_API_KEY", "openrouter"],
725
+ ["ANTHROPIC_API_KEY", "anthropic"],
726
+ ["OPENAI_API_KEY", "openai"],
727
+ ["GOOGLE_API_KEY", "google"]
728
+ ];
729
+ async function createPiRuntimeAuth(env = process.env) {
730
+ const modelRuntime = await ModelRuntime.create();
731
+ for (const [envKey, provider] of PI_RUNTIME_API_KEYS) {
732
+ const apiKey = env[envKey];
733
+ if (apiKey) {
734
+ await modelRuntime.setRuntimeApiKey(provider, apiKey);
735
+ }
736
+ }
737
+ return modelRuntime;
738
+ }
739
+ var OPENROUTER_OVERRIDE_MARKER = ".agent-swarm-openrouter-override.json";
740
+ async function readJsonFile(path) {
741
+ try {
742
+ const file = Bun.file(path);
743
+ if (!await file.exists())
744
+ return;
745
+ const parsed = JSON.parse(await file.text());
746
+ return typeof parsed === "object" && parsed !== null ? parsed : undefined;
747
+ } catch {
748
+ return;
749
+ }
750
+ }
751
+ async function ensureOpenRouterModelsOverride(agentDir, env = process.env) {
752
+ const baseUrl = getOpenRouterBaseUrl(env);
753
+ const modelsPath = join(agentDir, "models.json");
754
+ const markerPath = join(agentDir, OPENROUTER_OVERRIDE_MARKER);
755
+ if (baseUrl === DEFAULT_OPENROUTER_BASE_URL) {
756
+ await revertOpenRouterModelsOverride(modelsPath, markerPath);
757
+ return;
758
+ }
759
+ let existing = {};
760
+ try {
761
+ const file = Bun.file(modelsPath);
762
+ if (await file.exists()) {
763
+ existing = JSON.parse(await file.text());
764
+ }
765
+ } catch (err) {
766
+ console.warn(`[pi-mono] ${modelsPath} is unreadable/invalid (${err instanceof Error ? err.message : err}); rewriting with the OpenRouter gateway override`);
767
+ existing = {};
768
+ }
769
+ const providers = typeof existing.providers === "object" && existing.providers !== null ? existing.providers : {};
770
+ const openrouter = typeof providers.openrouter === "object" && providers.openrouter !== null ? providers.openrouter : {};
771
+ const priorMarker = await readJsonFile(markerPath);
772
+ const currentBaseUrl = typeof openrouter.baseUrl === "string" ? openrouter.baseUrl : undefined;
773
+ const previous = priorMarker ? priorMarker.previous : currentBaseUrl !== baseUrl ? currentBaseUrl : undefined;
774
+ const next = {
775
+ ...existing,
776
+ providers: {
777
+ ...providers,
778
+ openrouter: { ...openrouter, baseUrl }
779
+ }
780
+ };
781
+ await Bun.write(modelsPath, `${JSON.stringify(next, null, 2)}
782
+ `);
783
+ const marker = {
784
+ baseUrl,
785
+ ...previous !== undefined ? { previous } : {}
786
+ };
787
+ await Bun.write(markerPath, `${JSON.stringify(marker, null, 2)}
788
+ `);
789
+ }
790
+ async function revertOpenRouterModelsOverride(modelsPath, markerPath) {
791
+ const marker = await readJsonFile(markerPath);
792
+ if (!marker)
793
+ return;
794
+ const removeMarker = () => Bun.file(markerPath).delete();
795
+ const existing = await readJsonFile(modelsPath);
796
+ if (!existing) {
797
+ await removeMarker();
798
+ return;
799
+ }
800
+ const providers = typeof existing.providers === "object" && existing.providers !== null ? { ...existing.providers } : undefined;
801
+ const openrouter = providers && typeof providers.openrouter === "object" && providers.openrouter !== null ? { ...providers.openrouter } : undefined;
802
+ if (!providers || !openrouter || openrouter.baseUrl !== marker.baseUrl) {
803
+ await removeMarker();
804
+ return;
805
+ }
806
+ if (marker.previous !== undefined) {
807
+ openrouter.baseUrl = marker.previous;
808
+ } else {
809
+ delete openrouter.baseUrl;
810
+ }
811
+ if (Object.keys(openrouter).length === 0) {
812
+ delete providers.openrouter;
813
+ } else {
814
+ providers.openrouter = openrouter;
815
+ }
816
+ const next = { ...existing, providers };
817
+ if (Object.keys(providers).length === 0) {
818
+ delete next.providers;
819
+ }
820
+ if (Object.keys(next).length === 0) {
821
+ await Bun.file(modelsPath).delete();
822
+ } else {
823
+ await Bun.write(modelsPath, `${JSON.stringify(next, null, 2)}
824
+ `);
825
+ }
826
+ await removeMarker();
827
+ }
828
+ function resolveModel(modelStr, env = process.env) {
829
+ if (!modelStr)
830
+ return;
831
+ const lower = modelStr.toLowerCase();
832
+ const isAnthropicShortname = lower === "opus" || lower === "sonnet" || lower === "haiku" || lower === "fable";
833
+ if (isAnthropicShortname && !envHasAnthropicCred(env) && env.OPENROUTER_API_KEY) {
834
+ const orModelId = ANTHROPIC_SHORTNAME_OPENROUTER_MIRROR[lower];
835
+ if (orModelId) {
836
+ try {
837
+ return getBuiltinModel("openrouter", orModelId);
838
+ } catch {}
839
+ }
840
+ }
841
+ const shortnames = {
842
+ fable: ["anthropic", "claude-fable-5"],
843
+ opus: ["anthropic", "claude-opus-4-8"],
844
+ sonnet: ["anthropic", "claude-sonnet-5"],
845
+ haiku: ["anthropic", "claude-haiku-4-5-20251001"]
846
+ };
847
+ const mapping = shortnames[lower];
848
+ if (mapping) {
849
+ try {
850
+ return getBuiltinModel(mapping[0], mapping[1]);
851
+ } catch {
852
+ return;
853
+ }
854
+ }
855
+ if (modelStr.includes("/")) {
856
+ const slashIdx = modelStr.indexOf("/");
857
+ const provider = modelStr.slice(0, slashIdx);
858
+ const modelId = modelStr.slice(slashIdx + 1);
859
+ try {
860
+ return getBuiltinModel(provider, modelId);
861
+ } catch {
862
+ return;
863
+ }
864
+ }
865
+ for (const provider of ["anthropic", "openai", "google"]) {
866
+ try {
867
+ return getBuiltinModel(provider, modelStr);
868
+ } catch {}
869
+ }
870
+ return;
871
+ }
872
+ function createAgentsMdSymlink(cwd) {
873
+ const claudeMd = join(cwd, "CLAUDE.md");
874
+ const agentsMd = join(cwd, "AGENTS.md");
875
+ if (existsSync(claudeMd) && !existsSync(agentsMd)) {
876
+ try {
877
+ symlinkSync("CLAUDE.md", agentsMd);
878
+ return true;
879
+ } catch {
880
+ return false;
881
+ }
882
+ }
883
+ return false;
884
+ }
885
+ function cleanupAgentsMdSymlink(cwd) {
886
+ const agentsMd = join(cwd, "AGENTS.md");
887
+ try {
888
+ if (existsSync(agentsMd) && lstatSync(agentsMd).isSymbolicLink()) {
889
+ unlinkSync(agentsMd);
890
+ }
891
+ } catch {}
892
+ }
893
+ function extractTextContent(content) {
894
+ if (typeof content === "string")
895
+ return content.trim();
896
+ if (!Array.isArray(content))
897
+ return "";
898
+ return content.filter((c) => typeof c === "object" && c !== null && c.type === "text").map((c) => c.text || "").join("").trim();
899
+ }
900
+ function extractPiAssistantText(message) {
901
+ if (!message || typeof message !== "object")
902
+ return "";
903
+ const msg = message;
904
+ if (msg.role !== "assistant")
905
+ return "";
906
+ return extractTextContent(msg.content);
907
+ }
908
+
909
+ class PiMonoSession {
910
+ listeners = [];
911
+ eventQueue = [];
912
+ _sessionId;
913
+ completionPromise;
914
+ agentSession;
915
+ config;
916
+ createdSymlink;
917
+ logFileHandle;
918
+ lastEmittedMessage = "";
919
+ lastAssistantText = "";
920
+ sessionStartedAt = Date.now();
921
+ prevOutputTokens = 0;
922
+ terminalError = null;
923
+ appliedReasoningEffort;
924
+ sessionEnded = false;
925
+ constructor(agentSession, config, createdSymlink, appliedReasoningEffort = null) {
926
+ this.agentSession = agentSession;
927
+ this.config = config;
928
+ this.createdSymlink = createdSymlink;
929
+ this.appliedReasoningEffort = appliedReasoningEffort;
930
+ this.logFileHandle = Bun.file(config.logFile).writer();
931
+ this._sessionId = agentSession.sessionId;
932
+ this.sessionStartedAt = Date.now();
933
+ const piVersion = readPkgVersion("@earendil-works/pi-coding-agent");
934
+ this.emit({
935
+ type: "session_init",
936
+ sessionId: this._sessionId,
937
+ provider: "pi",
938
+ harnessVariant: "stock",
939
+ ...piVersion ? { harnessVariantMeta: { version: piVersion } } : {}
940
+ });
941
+ this.agentSession.subscribe((event) => this.handleAgentEvent(event));
942
+ this.completionPromise = this.runSession();
943
+ }
944
+ reportedModel() {
945
+ const m = this.agentSession.model;
946
+ if (m)
947
+ return `${m.provider}/${m.id}`;
948
+ return this.config.model;
949
+ }
950
+ emit(event) {
951
+ const scrubbed = event.type === "raw_log" || event.type === "raw_stderr" ? { ...event, content: scrubSecrets(event.content) } : event;
952
+ this.logFileHandle.write(`${JSON.stringify({ ...scrubbed, timestamp: new Date().toISOString() })}
953
+ `);
954
+ if (this.listeners.length > 0) {
955
+ for (const listener of this.listeners) {
956
+ listener(scrubbed);
957
+ }
958
+ } else {
959
+ this.eventQueue.push(scrubbed);
960
+ }
961
+ }
962
+ handleAgentEvent(event) {
963
+ switch (event.type) {
964
+ case "message_end": {
965
+ const endMsg = event.message;
966
+ if (endMsg.role === "assistant") {
967
+ if (endMsg.stopReason === "error") {
968
+ this.terminalError = endMsg.errorMessage ?? this.terminalError ?? "Unknown error";
969
+ break;
970
+ }
971
+ this.terminalError = null;
972
+ }
973
+ const text = extractPiAssistantText(event.message);
974
+ if (text) {
975
+ this.lastAssistantText = text;
976
+ }
977
+ if (text && text !== this.lastEmittedMessage) {
978
+ const model = this.reportedModel();
979
+ this.emit({
980
+ type: "raw_log",
981
+ content: JSON.stringify({
982
+ type: "assistant",
983
+ message: {
984
+ role: "assistant",
985
+ content: [{ type: "text", text }],
986
+ model
987
+ }
988
+ })
989
+ });
990
+ this.emit({ type: "message", role: "assistant", content: text });
991
+ this.lastEmittedMessage = text;
992
+ }
993
+ const usage = this.agentSession.getContextUsage();
994
+ if (usage && usage.tokens != null) {
995
+ const stats = this.agentSession.getSessionStats();
996
+ const currOutput = stats?.tokens?.output ?? 0;
997
+ const outputDelta = Math.max(0, currOutput - this.prevOutputTokens);
998
+ this.prevOutputTokens = currOutput;
999
+ this.emit({
1000
+ type: "context_usage",
1001
+ contextUsedTokens: usage.tokens,
1002
+ contextTotalTokens: usage.contextWindow,
1003
+ contextPercent: usage.percent ?? 0,
1004
+ outputTokens: outputDelta,
1005
+ contextFormula: "pi-delegated"
1006
+ });
1007
+ }
1008
+ break;
1009
+ }
1010
+ case "tool_execution_start": {
1011
+ const model = this.reportedModel();
1012
+ this.emit({
1013
+ type: "raw_log",
1014
+ content: JSON.stringify({
1015
+ type: "assistant",
1016
+ message: {
1017
+ role: "assistant",
1018
+ content: [
1019
+ { type: "tool_use", id: event.toolCallId, name: event.toolName, input: event.args }
1020
+ ],
1021
+ model
1022
+ }
1023
+ })
1024
+ });
1025
+ this.emit({
1026
+ type: "tool_start",
1027
+ toolCallId: event.toolCallId,
1028
+ toolName: event.toolName,
1029
+ args: event.args
1030
+ });
1031
+ break;
1032
+ }
1033
+ case "tool_execution_end":
1034
+ this.emit({
1035
+ type: "raw_log",
1036
+ content: JSON.stringify({
1037
+ type: "assistant",
1038
+ message: {
1039
+ role: "assistant",
1040
+ content: [
1041
+ {
1042
+ type: "tool_result",
1043
+ tool_use_id: event.toolCallId,
1044
+ content: typeof event.result === "string" ? event.result : JSON.stringify(event.result)
1045
+ }
1046
+ ]
1047
+ }
1048
+ })
1049
+ });
1050
+ this.emit({
1051
+ type: "tool_end",
1052
+ toolCallId: event.toolCallId,
1053
+ toolName: event.toolName,
1054
+ result: event.result
1055
+ });
1056
+ break;
1057
+ case "auto_retry_end": {
1058
+ if (event.success) {
1059
+ this.terminalError = null;
1060
+ } else {
1061
+ this.terminalError = event.finalError ?? this.terminalError ?? "Unknown error";
1062
+ }
1063
+ break;
1064
+ }
1065
+ }
1066
+ }
1067
+ async runSession() {
1068
+ try {
1069
+ await this.agentSession.prompt(this.config.prompt, {
1070
+ source: "rpc"
1071
+ });
1072
+ await this.waitForIdle();
1073
+ const stats = this.agentSession.getSessionStats();
1074
+ const cost = this.buildCostData(stats);
1075
+ if (this.terminalError) {
1076
+ const classification = classifyAwsSdkError(this.terminalError);
1077
+ const message = classification?.message ?? this.terminalError;
1078
+ const category = classification?.category;
1079
+ this.emit({ type: "error", message, category });
1080
+ return {
1081
+ exitCode: 1,
1082
+ sessionId: this._sessionId,
1083
+ cost,
1084
+ isError: true,
1085
+ errorCategory: category,
1086
+ failureReason: message,
1087
+ appliedReasoningEffort: this.appliedReasoningEffort
1088
+ };
1089
+ }
1090
+ this.emit({
1091
+ type: "result",
1092
+ cost,
1093
+ isError: false
1094
+ });
1095
+ return {
1096
+ exitCode: 0,
1097
+ sessionId: this._sessionId,
1098
+ cost,
1099
+ output: this.lastAssistantText || undefined,
1100
+ isError: false,
1101
+ appliedReasoningEffort: this.appliedReasoningEffort
1102
+ };
1103
+ } catch (err) {
1104
+ const errorMessage = err instanceof Error ? err.message : String(err);
1105
+ const awsCatchError = classifyAwsSdkError(errorMessage);
1106
+ if (awsCatchError) {
1107
+ this.emit({
1108
+ type: "error",
1109
+ message: awsCatchError.message,
1110
+ category: awsCatchError.category
1111
+ });
1112
+ }
1113
+ this.emit({ type: "raw_stderr", content: `[pi-mono] Error: ${errorMessage}
1114
+ ` });
1115
+ return {
1116
+ exitCode: 1,
1117
+ sessionId: this._sessionId,
1118
+ isError: true,
1119
+ errorCategory: awsCatchError?.category,
1120
+ failureReason: awsCatchError?.message ?? errorMessage,
1121
+ appliedReasoningEffort: this.appliedReasoningEffort
1122
+ };
1123
+ } finally {
1124
+ this.sessionEnded = true;
1125
+ await this.logFileHandle.end();
1126
+ if (this.createdSymlink) {
1127
+ cleanupAgentsMdSymlink(this.config.cwd);
1128
+ }
1129
+ this.agentSession.dispose();
1130
+ }
1131
+ }
1132
+ waitForIdle() {
1133
+ return new Promise((resolve) => {
1134
+ if (!this.agentSession.isStreaming) {
1135
+ resolve();
1136
+ return;
1137
+ }
1138
+ const unsub = this.agentSession.subscribe((event) => {
1139
+ if (event.type === "agent_end") {
1140
+ unsub();
1141
+ resolve();
1142
+ }
1143
+ });
1144
+ });
1145
+ }
1146
+ buildCostData(stats) {
1147
+ return {
1148
+ sessionId: "",
1149
+ taskId: this.config.taskId,
1150
+ agentId: this.config.agentId,
1151
+ totalCostUsd: stats.cost || 0,
1152
+ inputTokens: stats.tokens.input,
1153
+ outputTokens: stats.tokens.output,
1154
+ cacheReadTokens: stats.tokens.cacheRead,
1155
+ cacheWriteTokens: stats.tokens.cacheWrite,
1156
+ durationMs: Date.now() - this.sessionStartedAt,
1157
+ numTurns: stats.userMessages + stats.assistantMessages,
1158
+ model: this.reportedModel(),
1159
+ isError: false,
1160
+ provider: "pi"
1161
+ };
1162
+ }
1163
+ get sessionId() {
1164
+ return this._sessionId;
1165
+ }
1166
+ onEvent(listener) {
1167
+ this.listeners.push(listener);
1168
+ for (const event of this.eventQueue) {
1169
+ listener(event);
1170
+ }
1171
+ this.eventQueue = [];
1172
+ }
1173
+ async waitForCompletion() {
1174
+ return this.completionPromise;
1175
+ }
1176
+ async abort() {
1177
+ await this.agentSession.abort();
1178
+ }
1179
+ async deliverSteering({ mode, text }) {
1180
+ if (this.sessionEnded) {
1181
+ return { delivered: false, reason: "pi session already completed" };
1182
+ }
1183
+ try {
1184
+ if (mode === "steer")
1185
+ await this.agentSession.steer(text);
1186
+ else
1187
+ await this.agentSession.followUp(text);
1188
+ return { delivered: true, mode };
1189
+ } catch (err) {
1190
+ return { delivered: false, reason: String(err) };
1191
+ }
1192
+ }
1193
+ }
1194
+
1195
+ class PiMonoAdapter {
1196
+ name = "pi";
1197
+ traits = {
1198
+ hasMcp: true,
1199
+ nativeSkillDiscovery: true,
1200
+ hasLocalEnvironment: true,
1201
+ steerModes: ["steer", "queue"]
1202
+ };
1203
+ lastCwd = ".";
1204
+ async createSession(config) {
1205
+ this.lastCwd = config.cwd;
1206
+ console.log(`\x1B[2m[${config.role}]\x1B[0m \x1B[35m▸\x1B[0m Spawning pi-mono for task ${config.taskId.slice(0, 8)}`);
1207
+ const createdSymlink = createAgentsMdSymlink(config.cwd);
1208
+ let customTools = [];
1209
+ if (config.apiUrl && config.apiKey) {
1210
+ try {
1211
+ const mcpClient = new McpHttpClient(config.apiUrl, config.apiKey, config.agentId, config.taskId);
1212
+ const runtimeInstanceId = swarmRuntimeInstanceId();
1213
+ if (runtimeInstanceId) {
1214
+ mcpClient.customHeaders["X-Runtime-Instance-ID"] = runtimeInstanceId;
1215
+ }
1216
+ await mcpClient.initialize();
1217
+ const tools = await mcpClient.listTools();
1218
+ customTools = mcpToolsToDefinitions(mcpClient, tools);
1219
+ console.log(`\x1B[2m[${config.role}]\x1B[0m Discovered ${tools.length} MCP tools from swarm`);
1220
+ } catch (err) {
1221
+ console.warn(`\x1B[33m[${config.role}] Failed to discover MCP tools: ${err}\x1B[0m`);
1222
+ }
1223
+ try {
1224
+ const mcpServersRes = await fetch(`${config.apiUrl}/api/agents/${config.agentId}/mcp-servers?resolveSecrets=true`, {
1225
+ headers: {
1226
+ Authorization: `Bearer ${config.apiKey}`,
1227
+ "X-Agent-ID": config.agentId
1228
+ }
1229
+ });
1230
+ if (mcpServersRes.ok) {
1231
+ const mcpServersData = await mcpServersRes.json();
1232
+ const httpServers = mcpServersData.servers.filter((s) => s.isActive && s.isEnabled && (s.transport === "http" || s.transport === "sse") && s.url);
1233
+ for (const srv of httpServers) {
1234
+ try {
1235
+ const srvClient = new McpHttpClient(srv.url, "", "");
1236
+ srvClient.useRawUrl = true;
1237
+ let parsedHeaders = {};
1238
+ try {
1239
+ parsedHeaders = srv.headers ? JSON.parse(srv.headers) : {};
1240
+ } catch {}
1241
+ srvClient.customHeaders = {
1242
+ ...parsedHeaders,
1243
+ ...srv.resolvedHeaders || {}
1244
+ };
1245
+ await srvClient.initialize();
1246
+ const srvTools = await srvClient.listTools();
1247
+ const prefixed = mcpToolsToDefinitions(srvClient, srvTools).map((t) => ({
1248
+ ...t,
1249
+ name: `mcp__${srv.name}__${t.name}`
1250
+ }));
1251
+ customTools.push(...prefixed);
1252
+ console.log(`\x1B[2m[${config.role}]\x1B[0m Discovered ${srvTools.length} tools from MCP server "${srv.name}"`);
1253
+ } catch (srvErr) {
1254
+ console.warn(`\x1B[33m[${config.role}] Failed to discover tools from MCP server "${srv.name}": ${srvErr}\x1B[0m`);
1255
+ }
1256
+ }
1257
+ }
1258
+ } catch {}
1259
+ }
1260
+ const sessionEnv = config.env ?? process.env;
1261
+ await ensureOpenRouterModelsOverride(getAgentDir(), sessionEnv);
1262
+ const builtinModel = resolveModel(config.model, sessionEnv);
1263
+ const modelRuntime = await createPiRuntimeAuth(sessionEnv);
1264
+ const model = builtinModel ? modelRuntime.getModel(builtinModel.provider, builtinModel.id) ?? builtinModel : builtinModel;
1265
+ const swarmExtension = createSwarmHooksExtension({
1266
+ apiUrl: config.apiUrl,
1267
+ apiKey: config.apiKey,
1268
+ agentId: config.agentId,
1269
+ taskId: config.taskId,
1270
+ isLead: config.role === "lead",
1271
+ env: sessionEnv
1272
+ });
1273
+ const resourceLoader = new DefaultResourceLoader({
1274
+ cwd: config.cwd,
1275
+ agentDir: getAgentDir(),
1276
+ appendSystemPrompt: config.systemPrompt ? [config.systemPrompt] : undefined,
1277
+ extensionFactories: [swarmExtension]
1278
+ });
1279
+ const reasoningApplication = applyReasoningEffort("pi", config.model, config.reasoningEffort);
1280
+ const reasoningSessionOptions = reasoningApplication.kind === "pi-session" ? reasoningApplication.sessionOptions : {};
1281
+ const appliedReasoningEffort = reasoningApplication.kind === "pi-session" ? config.reasoningEffort ?? null : null;
1282
+ const sessionOptions = {
1283
+ cwd: config.cwd,
1284
+ model,
1285
+ customTools,
1286
+ resourceLoader,
1287
+ modelRuntime,
1288
+ ...reasoningSessionOptions
1289
+ };
1290
+ const { session } = await createAgentSession(sessionOptions);
1291
+ return new PiMonoSession(session, config, createdSymlink, appliedReasoningEffort);
1292
+ }
1293
+ async canResume(sessionId) {
1294
+ try {
1295
+ const sessionManager = SessionManager.create(this.lastCwd);
1296
+ const sessions = await sessionManager.list?.();
1297
+ return sessions?.some((s) => s.id === sessionId) ?? false;
1298
+ } catch {
1299
+ return false;
1300
+ }
1301
+ }
1302
+ formatCommand(commandName) {
1303
+ return `/skill:${commandName}`;
1304
+ }
1305
+ }
1306
+ export {
1307
+ PiMonoAdapter,
1308
+ PiMonoSession,
1309
+ checkPiMonoCredentials,
1310
+ createPiRuntimeAuth,
1311
+ ensureOpenRouterModelsOverride,
1312
+ extractPiAssistantText,
1313
+ mcpToolsToDefinitions,
1314
+ resolveModel,
1315
+ runBedrockSdkProbeAndEnumerate
1316
+ };