chainlesschain 0.166.109 → 0.166.114

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 (207) hide show
  1. package/README.md +14 -6
  2. package/package.json +3 -2
  3. package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
  4. package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
  5. package/src/assets/web-panel/.build-hash +1 -1
  6. package/src/assets/web-panel/assets/{AIOps-DkrNbDzS.js → AIOps-CVac3rIN.js} +1 -1
  7. package/src/assets/web-panel/assets/{ActionButton-DJjFXDhv.js → ActionButton-ChM9GxMl.js} +1 -1
  8. package/src/assets/web-panel/assets/{Analytics-DyUbagRn.js → Analytics-CV5399Js.js} +3 -3
  9. package/src/assets/web-panel/assets/{AppLayout-p7kJWSvn.js → AppLayout-CuonVXhg.js} +3 -3
  10. package/src/assets/web-panel/assets/{Artifacts-C3rVh4Ak.js → Artifacts-D9qKfgb6.js} +1 -1
  11. package/src/assets/web-panel/assets/{Audit-Bch_L_YO.js → Audit-DUvLysQc.js} +1 -1
  12. package/src/assets/web-panel/assets/{BackgroundAgents-BNHy8zP6.js → BackgroundAgents-DfKohQeT.js} +1 -1
  13. package/src/assets/web-panel/assets/{Backup-BUaye_Ys.js → Backup-CohoEI8R.js} +1 -1
  14. package/src/assets/web-panel/assets/{BaseInput-D49mzAVz.js → BaseInput-BwdoA3xv.js} +1 -1
  15. package/src/assets/web-panel/assets/{Chat-2MDzM_us.js → Chat-DRkuz1d2.js} +5 -5
  16. package/src/assets/web-panel/assets/ChatBubbleRenderer-v3pzeHNC.js +1 -0
  17. package/src/assets/web-panel/assets/{Checkbox-5p1T_KEq.js → Checkbox-B-GNGpKv.js} +1 -1
  18. package/src/assets/web-panel/assets/{Codegen-TKtiLaoZ.js → Codegen-Bs2lAsoZ.js} +1 -1
  19. package/src/assets/web-panel/assets/{Col-BVCMG9mS.js → Col-Bk1mJKDZ.js} +1 -1
  20. package/src/assets/web-panel/assets/{Community-D09-QczH.js → Community-B_FDSCOo.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compact-QuRMCnj7.js → Compact-No1qSLLH.js} +1 -1
  22. package/src/assets/web-panel/assets/{Compliance-CN0PV7fk.js → Compliance-CcrG43-d.js} +1 -1
  23. package/src/assets/web-panel/assets/{Cowork-5N2zhAty.js → Cowork-DLkj2ywK.js} +3 -3
  24. package/src/assets/web-panel/assets/{Cron-BxT8UZ0S.js → Cron-sQHELVEz.js} +2 -2
  25. package/src/assets/web-panel/assets/{Crosschain-Dp-noQl4.js → Crosschain-CRTZ3GZg.js} +1 -1
  26. package/src/assets/web-panel/assets/{DID-B7MZFkjG.js → DID-Ds2bjvxE.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dashboard-DulJ3rKV.js → Dashboard-DOONG2NX.js} +2 -2
  28. package/src/assets/web-panel/assets/{Dropdown-DV4ov4zF.js → Dropdown-Br3PNA2L.js} +1 -1
  29. package/src/assets/web-panel/assets/{EmailListRenderer-DB2-ooz6.js → EmailListRenderer-DT6UUqjZ.js} +1 -1
  30. package/src/assets/web-panel/assets/{EvolutionSettings-B1Rb6p7q.js → EvolutionSettings-BSLuEjlT.js} +1 -1
  31. package/src/assets/web-panel/assets/{FamilyGuardDashboard-U8aHayx-.js → FamilyGuardDashboard-2aEM9avE.js} +1 -1
  32. package/src/assets/web-panel/assets/{Federation-BkQULBHY.js → Federation-D3B0tlQU.js} +1 -1
  33. package/src/assets/web-panel/assets/{FormItemContext-CtviG260.js → FormItemContext-DTVkVVQP.js} +1 -1
  34. package/src/assets/web-panel/assets/{GenericCardRenderer-DnPirB24.js → GenericCardRenderer-BgFEgP4y.js} +1 -1
  35. package/src/assets/web-panel/assets/{Git-CK57Oro6.js → Git-3t71m6Xd.js} +2 -2
  36. package/src/assets/web-panel/assets/{Governance-DbI-LB8-.js → Governance-DS7WvlaX.js} +1 -1
  37. package/src/assets/web-panel/assets/{Inference-sEG4T1Jg.js → Inference-CeT-xWrI.js} +1 -1
  38. package/src/assets/web-panel/assets/{KnowledgeGraph-9SLJR3h9.js → KnowledgeGraph-BQzMncp5.js} +1 -1
  39. package/src/assets/web-panel/assets/{Logs-BIZYcISQ.js → Logs-CC5DOKhV.js} +2 -2
  40. package/src/assets/web-panel/assets/{MarkdownRenderer-9nfWupWP.js → MarkdownRenderer-5jYM4kYG.js} +1 -1
  41. package/src/assets/web-panel/assets/{Marketplace-CRmLLwAE.js → Marketplace-CpYDyy3o.js} +1 -1
  42. package/src/assets/web-panel/assets/{McpTools-DkOFkSO1.js → McpTools-DRdAZPMr.js} +3 -3
  43. package/src/assets/web-panel/assets/{Memory-M29Kd9TU.js → Memory-CBLRr-l8.js} +2 -2
  44. package/src/assets/web-panel/assets/{MobileBridge-Tl6JvPw_.js → MobileBridge-Bnj9veNN.js} +1 -1
  45. package/src/assets/web-panel/assets/{MobileProjects-Bq-FPDzS.js → MobileProjects-lYFPD24p.js} +1 -1
  46. package/src/assets/web-panel/assets/{Mtc-DkUjX1F5.js → Mtc-BMU_C9vD.js} +2 -2
  47. package/src/assets/web-panel/assets/{MtcAudit-BCqr1I4q.js → MtcAudit-DQV-zumU.js} +4 -4
  48. package/src/assets/web-panel/assets/{Multisig-DmoqYGQ5.js → Multisig-LpqpqV1d.js} +3 -3
  49. package/src/assets/web-panel/assets/{NLProgramming-DNRQeRke.js → NLProgramming-C4OMklSO.js} +1 -1
  50. package/src/assets/web-panel/assets/{Notes-CQSBeiY6.js → Notes-Cg0QCinP.js} +3 -3
  51. package/src/assets/web-panel/assets/{NotificationSettings-gNY9bbH6.js → NotificationSettings-amoZoMna.js} +1 -1
  52. package/src/assets/web-panel/assets/{OrderTableRenderer-DW0CNjh8.js → OrderTableRenderer-CxNvhf5n.js} +1 -1
  53. package/src/assets/web-panel/assets/{Organization-CthnbKag.js → Organization-BetJmyX5.js} +4 -4
  54. package/src/assets/web-panel/assets/{Overflow-_GQ3sbXu.js → Overflow-DbeoPtVD.js} +1 -1
  55. package/src/assets/web-panel/assets/{P2P-BTr7ea6W.js → P2P-B5sitQWT.js} +2 -2
  56. package/src/assets/web-panel/assets/PdhVaultBrowser-AP9SG2ic.js +7 -0
  57. package/src/assets/web-panel/assets/{Permissions-DMny2Cjs.js → Permissions-Bc7fgNKx.js} +4 -4
  58. package/src/assets/web-panel/assets/{PersonalDataHub-CyYlMSoI.js → PersonalDataHub-BwdGMcWZ.js} +3 -3
  59. package/src/assets/web-panel/assets/{Pipeline-FASu2Oc4.js → Pipeline-DVuJA9BA.js} +1 -1
  60. package/src/assets/web-panel/assets/{Privacy-9bC5FnsJ.js → Privacy-BGzwOYRG.js} +1 -1
  61. package/src/assets/web-panel/assets/{ProjectInit-BOYZwB5G.js → ProjectInit-BpHcC5br.js} +2 -2
  62. package/src/assets/web-panel/assets/{ProjectSettings-45DViNG-.js → ProjectSettings-BI5G5gsc.js} +2 -2
  63. package/src/assets/web-panel/assets/{Projects-C2fZzMZc.js → Projects-Ce92-l1V.js} +1 -1
  64. package/src/assets/web-panel/assets/{Providers-BgjvZx9F.js → Providers-CRHCcLFS.js} +1 -1
  65. package/src/assets/web-panel/assets/{QrScannerModal-Brw-3csB.js → QrScannerModal-qSeg5xag.js} +1 -1
  66. package/src/assets/web-panel/assets/QuickAsk-CA8oSceR.js +1 -0
  67. package/src/assets/web-panel/assets/{Recommend-DuQGxjIR.js → Recommend-DMvPodNo.js} +1 -1
  68. package/src/assets/web-panel/assets/{RemoteSession-T1cdSSRL.js → RemoteSession-BWsapEyN.js} +2 -2
  69. package/src/assets/web-panel/assets/{Reputation-9FT2dI4G.js → Reputation-BZJETVmC.js} +1 -1
  70. package/src/assets/web-panel/assets/{Row-yNIbNftX.js → Row-CUE1OSMp.js} +1 -1
  71. package/src/assets/web-panel/assets/{RssFeed-BIchNoPd.js → RssFeed-DvMazcUD.js} +2 -2
  72. package/src/assets/web-panel/assets/{Search-msDJ8UTZ.js → Search-e1c-NXWv.js} +1 -1
  73. package/src/assets/web-panel/assets/{Security-DE46oBYT.js → Security-Dc9GZsx2.js} +3 -3
  74. package/src/assets/web-panel/assets/{Services-Dori7vc3.js → Services-AFz6ke-4.js} +2 -2
  75. package/src/assets/web-panel/assets/{Skeleton-D3O3sUFz.js → Skeleton-gow6MYcY.js} +1 -1
  76. package/src/assets/web-panel/assets/{Skills-BV0ct8SO.js → Skills-h6AxYjUP.js} +1 -1
  77. package/src/assets/web-panel/assets/{Sla-DflIVOrh.js → Sla-Cr4CkJ0O.js} +1 -1
  78. package/src/assets/web-panel/assets/{SpeechSettings-Cpbv2Zz6.js → SpeechSettings-Bd5yuBtH.js} +1 -1
  79. package/src/assets/web-panel/assets/{SyncSettings-Dgg6-wbe.js → SyncSettings-1t4QZMLW.js} +2 -2
  80. package/src/assets/web-panel/assets/{Tasks-Cb6e4Klx.js → Tasks-u-DrjLRM.js} +1 -1
  81. package/src/assets/web-panel/assets/{Templates-GfdAATGz.js → Templates-C0yLUC9b.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tenant-D0gecLXl.js → Tenant-ds1YT5iS.js} +1 -1
  83. package/src/assets/web-panel/assets/{Terminal-BFRPJt-0.js → Terminal-BoIskW2m.js} +2 -2
  84. package/src/assets/web-panel/assets/{TimelineRenderer-BobtChxX.js → TimelineRenderer-BkdVK24X.js} +1 -1
  85. package/src/assets/web-panel/assets/{Tokens-CifeZtHV.js → Tokens-djyDgmfk.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trigger-BHBvbBCf.js → Trigger-CYefDS3H.js} +1 -1
  87. package/src/assets/web-panel/assets/{Trust-6lvqjKYp.js → Trust-CE_dbep_.js} +1 -1
  88. package/src/assets/web-panel/assets/{UkeySign-CqzMc-G5.js → UkeySign-DwVs_fey.js} +1 -1
  89. package/src/assets/web-panel/assets/{VideoEditing-OIiRG582.js → VideoEditing-BTUqMHAV.js} +1 -1
  90. package/src/assets/web-panel/assets/{Wallet-4MeKq0q_.js → Wallet-Bu_E7Rrc.js} +4 -4
  91. package/src/assets/web-panel/assets/{WebAuthn-eHBRjGQG.js → WebAuthn-DTbre5AB.js} +4 -4
  92. package/src/assets/web-panel/assets/{WorkflowEditor-DlzYdEqW.js → WorkflowEditor-BsBzd3gt.js} +1 -1
  93. package/src/assets/web-panel/assets/{chat-CBcjOzkX.js → chat-tdifQQvu.js} +1 -1
  94. package/src/assets/web-panel/assets/{colors-zgwsYQSa.js → colors-D3SNW2Vx.js} +1 -1
  95. package/src/assets/web-panel/assets/{compact-item-Dcd9H5Bn.js → compact-item-UBlCjrAW.js} +1 -1
  96. package/src/assets/web-panel/assets/{createContext-DR1tO-8r.js → createContext-DKsnEnFt.js} +1 -1
  97. package/src/assets/web-panel/assets/devWarning-BBnVfJHh.js +1 -0
  98. package/src/assets/web-panel/assets/{hasIn-CtfbUH_p.js → hasIn-BkeySXWe.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BXfGHUz_.js → index-6Nvzgytx.js} +1 -1
  100. package/src/assets/web-panel/assets/index-B2w_3mtS.js +1 -0
  101. package/src/assets/web-panel/assets/{index-DYPMJ5Mb.js → index-BEiHKah0.js} +25 -25
  102. package/src/assets/web-panel/assets/{index-LN7Hkl1C.js → index-BIeFLaMV.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DA2-Bhy8.js → index-BV2zQteq.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-CwHgaYVH.js → index-BVvz3ntc.js} +1 -1
  105. package/src/assets/web-panel/assets/index-BoHurydC.js +1 -0
  106. package/src/assets/web-panel/assets/{index-DVpp9YSQ.js → index-Bw0k3VgD.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CaGNqkY0.js → index-C-KTHSUE.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DWuCGhHa.js → index-C9ImNw5O.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DTx4FyLU.js → index-CG_b1xyX.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Cur8LNNn.js → index-CUjyL0ZS.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DfzOYmOj.js → index-CXkn77ZN.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-Cdhy5ckh.js → index-CZ6JUooI.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-D1GxtY-h.js → index-Cuz2QCFT.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-C0kP88Pb.js → index-D5Umd_Z-.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DHEiuvhA.js → index-D6es7MSG.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CPLLgPxA.js → index-D93iSDUw.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-B3QUK1ks.js → index-D9m1HQzl.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-DWG98orp.js → index-D9um0YVl.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-hTcre7U9.js → index-DD6dD3LV.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-C5XGvJb0.js → index-DFMrIEIt.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DvPOpvvH.js → index-DSCiZJXb.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-D8WPohye.js → index-DSe_7MSy.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-JSfldpw4.js → index-DYFjOyTH.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-5XaB_Tjg.js → index-DdyTv6yc.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BoxowMYS.js → index-DfrW-iVs.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DSvcz0RO.js → index-Dg8-Duze.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-J-ORW1i6.js → index-DiDgwRty.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CT7zIkqP.js → index-DlEIp1gJ.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-D7ZOiIKb.js → index-DlO6HdD9.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DeAi4CNt.js → index-DtxUSZSS.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-CmVIM-m2.js → index-DugZRCiI.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-oWOlF7CM.js → index-P-ailFQY.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-dvF6C39V.js → index-PWScrdlX.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-CSQCHpDo.js → index-SpQ26gD6.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-CmzQzTY5.js → index-TLBpgN30.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-z8lrkcb-.js → index-bOIcWW8F.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-BndPtS9D.js → index-pgGKNvmm.js} +1 -1
  138. package/src/assets/web-panel/assets/{initDefaultProps-CVMtDrWZ.js → initDefaultProps-CVCXG2Hv.js} +1 -1
  139. package/src/assets/web-panel/assets/{motion-Dye3IU8k.js → motion-Dv00jw87.js} +1 -1
  140. package/src/assets/web-panel/assets/{move-C251Zo34.js → move-BFz51iHf.js} +1 -1
  141. package/src/assets/web-panel/assets/{mtc-parser-BDiOORoQ.js → mtc-parser-BK2woIDE.js} +1 -1
  142. package/src/assets/web-panel/assets/{omit-DTDA_RHv.js → omit-D2X_Gwoo.js} +1 -1
  143. package/src/assets/web-panel/assets/{pickAttrs-CqEUTPcT.js → pickAttrs-CLmFyJ1q.js} +1 -1
  144. package/src/assets/web-panel/assets/{placementArrow-BOB8QWH3.js → placementArrow-CCzPddQm.js} +1 -1
  145. package/src/assets/web-panel/assets/{responsiveObserve-CZDXP1d9.js → responsiveObserve-hcm_Zlxd.js} +1 -1
  146. package/src/assets/web-panel/assets/{slide-DPaRw3E9.js → slide-BxfZEFVp.js} +1 -1
  147. package/src/assets/web-panel/assets/{statusUtils-Ba9d7XZ7.js → statusUtils-kzB9pT-t.js} +1 -1
  148. package/src/assets/web-panel/assets/{styleChecker-mZKU3lvW.js → styleChecker-CDFd7YCI.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFlexGapSupport-VcauLq0M.js → useFlexGapSupport-Czl7NNhS.js} +1 -1
  150. package/src/assets/web-panel/assets/{useFs-Cal9KRcx.js → useFs-y0SAzirG.js} +1 -1
  151. package/src/assets/web-panel/assets/{usePersonalDataHub-DISoRyQB.js → usePersonalDataHub-BvdPznrA.js} +1 -1
  152. package/src/assets/web-panel/assets/{vnode-B58C6w6B.js → vnode-D8mNbyZ7.js} +1 -1
  153. package/src/assets/web-panel/assets/{zoom-BPlBAMKB.js → zoom-_hun6w9W.js} +1 -1
  154. package/src/assets/web-panel/index.html +1 -1
  155. package/src/command-help-index.json +1 -1
  156. package/src/commands/agent.js +12 -5
  157. package/src/commands/ask.js +96 -21
  158. package/src/commands/complete.js +14 -10
  159. package/src/commands/llm.js +23 -41
  160. package/src/commands/session.js +2 -2
  161. package/src/commands/stream.js +9 -5
  162. package/src/commands/ui.js +30 -2
  163. package/src/data/changelog.json +65 -0
  164. package/src/gateways/ws/llm-chat-protocol.js +131 -40
  165. package/src/gateways/ws/llm-creds.js +29 -79
  166. package/src/gateways/ws/message-dispatcher.js +2 -0
  167. package/src/gateways/ws/ws-agent-handler.js +1 -1
  168. package/src/gateways/ws/ws-session-gateway.js +26 -12
  169. package/src/lib/__tests__/provider-stream.test.js +70 -4
  170. package/src/lib/chat-core.js +186 -24
  171. package/src/lib/cowork-adapter.js +29 -15
  172. package/src/lib/evolution/agent-evolution-runtime-composition.js +10 -7
  173. package/src/lib/evolution/evolution-deployment-config.js +36 -4
  174. package/src/lib/evolution/evolution-deployment-loader.js +117 -4
  175. package/src/lib/evolution/evolution-deployment-profile.js +2 -2
  176. package/src/lib/evolution/evolution-evidence-projector.js +18 -3
  177. package/src/lib/evolution/evolution-file-witness.js +10 -0
  178. package/src/lib/evolution/evolution-ledger.js +237 -28
  179. package/src/lib/evolution/evolution-windows-directory-durability.js +322 -0
  180. package/src/lib/evolution/governed-hub-llm.js +2 -1
  181. package/src/lib/evolution/governed-model-turn.js +4 -1
  182. package/src/lib/evolution/local-ui-evolution-deployment.js +768 -0
  183. package/src/lib/evolution/local-ui-evolution-host.mjs +44 -0
  184. package/src/lib/evolution/local-ui-evolution-runtime.js +624 -0
  185. package/src/lib/evolution/opaque-hex-id.js +28 -0
  186. package/src/lib/hub-llm-client.js +22 -14
  187. package/src/lib/image-input.js +19 -3
  188. package/src/lib/llm-config-defaults.js +19 -30
  189. package/src/lib/llm-connection-config.js +4 -0
  190. package/src/lib/llm-connection-probe.js +5 -1
  191. package/src/lib/llm-connection-resolution.js +94 -0
  192. package/src/lib/llm-providers.js +33 -11
  193. package/src/lib/ollama-base-url.js +14 -0
  194. package/src/lib/provider-protocol.js +104 -0
  195. package/src/lib/provider-stream.js +163 -4
  196. package/src/lib/runnable-provider.js +1 -0
  197. package/src/repl/chat-repl.js +58 -11
  198. package/src/runtime/agent-core.js +26 -43
  199. package/src/runtime/headless-runner.js +11 -4
  200. package/src/runtime/headless-stream.js +10 -4
  201. package/src/runtime/policies/agent-policy.js +17 -11
  202. package/src/assets/web-panel/assets/ChatBubbleRenderer-DOX3Y5EJ.js +0 -1
  203. package/src/assets/web-panel/assets/PdhVaultBrowser-D9McHF9I.js +0 -7
  204. package/src/assets/web-panel/assets/QuickAsk-DWG-A5zB.js +0 -1
  205. package/src/assets/web-panel/assets/devWarning-DYhpRtve.js +0 -1
  206. package/src/assets/web-panel/assets/index-DPJXFIY7.js +0 -1
  207. package/src/assets/web-panel/assets/index-DjBhR5M_.js +0 -1
@@ -11,6 +11,13 @@ import { providerFetch } from "./formal-budget-provider-scope.js";
11
11
  */
12
12
 
13
13
  import { BUILT_IN_PROVIDERS } from "./llm-providers.js";
14
+ import { normalizeOllamaBaseUrl } from "./ollama-base-url.js";
15
+ import {
16
+ geminiGenerateContentUrl,
17
+ geminiRequestBody,
18
+ geminiUsage,
19
+ normalizeProviderBaseUrl,
20
+ } from "./provider-protocol.js";
14
21
  import { appendTokenUsage } from "../harness/jsonl-session-store.js";
15
22
  import {
16
23
  isRetryableStreamError,
@@ -134,18 +141,21 @@ export async function streamOllama(
134
141
  guard.bump();
135
142
  let response;
136
143
  try {
137
- response = await providerFetch(`${baseUrl}/api/chat`, {
138
- method: "POST",
139
- headers: { "Content-Type": "application/json" },
140
- body: JSON.stringify({
141
- model,
142
- messages,
143
- stream: true,
144
- }),
145
- signal: options.signal
146
- ? AbortSignal.any([guard.signal, options.signal])
147
- : guard.signal,
148
- });
144
+ response = await providerFetch(
145
+ `${normalizeOllamaBaseUrl(baseUrl)}/api/chat`,
146
+ {
147
+ method: "POST",
148
+ headers: { "Content-Type": "application/json" },
149
+ body: JSON.stringify({
150
+ model,
151
+ messages,
152
+ stream: true,
153
+ }),
154
+ signal: options.signal
155
+ ? AbortSignal.any([guard.signal, options.signal])
156
+ : guard.signal,
157
+ },
158
+ );
149
159
  } catch (e) {
150
160
  guard.stop();
151
161
  throw guard.stalled() && !isFormalBudgetError(e)
@@ -249,7 +259,9 @@ export async function streamOpenAI(
249
259
  guard.bump();
250
260
  let response;
251
261
  try {
252
- response = await providerFetch(`${baseUrl}/chat/completions`, {
262
+ response = await providerFetch(
263
+ `${normalizeProviderBaseUrl(baseUrl)}/chat/completions`,
264
+ {
253
265
  method: "POST",
254
266
  headers: {
255
267
  "Content-Type": "application/json",
@@ -266,7 +278,8 @@ export async function streamOpenAI(
266
278
  signal: options.signal
267
279
  ? AbortSignal.any([guard.signal, options.signal])
268
280
  : guard.signal,
269
- });
281
+ },
282
+ );
270
283
  } catch (e) {
271
284
  guard.stop();
272
285
  throw guard.stalled() && !isFormalBudgetError(e)
@@ -394,7 +407,9 @@ export async function streamAnthropic(
394
407
  guard.bump();
395
408
  let response;
396
409
  try {
397
- response = await providerFetch(`${baseUrl}/messages`, {
410
+ response = await providerFetch(
411
+ `${normalizeProviderBaseUrl(baseUrl)}/messages`,
412
+ {
398
413
  method: "POST",
399
414
  headers: {
400
415
  "Content-Type": "application/json",
@@ -411,7 +426,8 @@ export async function streamAnthropic(
411
426
  signal: options.signal
412
427
  ? AbortSignal.any([guard.signal, options.signal])
413
428
  : guard.signal,
414
- });
429
+ },
430
+ );
415
431
  } catch (e) {
416
432
  guard.stop();
417
433
  throw guard.stalled() && !isFormalBudgetError(e)
@@ -517,6 +533,128 @@ export async function streamAnthropic(
517
533
  return fullResponse;
518
534
  }
519
535
 
536
+ /** Stream Google's native Gemini generateContent SSE API. */
537
+ export async function streamGemini(
538
+ messages,
539
+ model,
540
+ baseUrl,
541
+ apiKey,
542
+ onToken,
543
+ onUsage,
544
+ onStall,
545
+ options = {},
546
+ ) {
547
+ const guard = makeStallGuard(STREAM_STALL_MS, { onHint: onStall });
548
+ guard.bump();
549
+ let response;
550
+ try {
551
+ response = await providerFetch(
552
+ geminiGenerateContentUrl(baseUrl, model, { stream: true }),
553
+ {
554
+ method: "POST",
555
+ headers: {
556
+ "Content-Type": "application/json",
557
+ "x-goog-api-key": apiKey,
558
+ },
559
+ body: JSON.stringify(geminiRequestBody(messages)),
560
+ signal: options.signal
561
+ ? AbortSignal.any([guard.signal, options.signal])
562
+ : guard.signal,
563
+ },
564
+ );
565
+ } catch (error) {
566
+ guard.stop();
567
+ throw guard.stalled() && !isFormalBudgetError(error)
568
+ ? new Error(
569
+ `Gemini request stalled (no response in ${STREAM_STALL_MS / 1000}s)`,
570
+ )
571
+ : error;
572
+ }
573
+
574
+ if (!response.ok || !response.body) {
575
+ guard.stop();
576
+ throw attachStreamRetryMetadata(
577
+ new Error(`Gemini error: ${response.status} ${response.statusText}`),
578
+ captureStreamRetryMetadata(response),
579
+ );
580
+ }
581
+
582
+ const retryMetadata = captureStreamRetryMetadata(response);
583
+ const reader = response.body.getReader();
584
+ const decoder = new TextDecoder();
585
+ let buffer = "";
586
+ let fullResponse = "";
587
+ let completed = false;
588
+ let latestUsage = null;
589
+
590
+ const consumeLine = async (raw) => {
591
+ const line = raw.trim();
592
+ if (!line.startsWith("data:")) return;
593
+ const payload = line.slice(5).trim();
594
+ if (!payload || payload === "[DONE]") return;
595
+ const data = JSON.parse(payload);
596
+ if (data.error) {
597
+ throw new Error(
598
+ typeof data.error.message === "string"
599
+ ? data.error.message
600
+ : "Gemini stream returned an error",
601
+ );
602
+ }
603
+ const candidate = data.candidates?.[0];
604
+ if (candidate?.finishReason || data.promptFeedback?.blockReason)
605
+ completed = true;
606
+ const usage = geminiUsage(data);
607
+ if (usage) latestUsage = usage;
608
+ for (const part of candidate?.content?.parts || []) {
609
+ if (part?.thought === true || typeof part?.text !== "string") continue;
610
+ fullResponse += part.text;
611
+ await _deliverToken(onToken, part.text, guard, options);
612
+ }
613
+ };
614
+
615
+ try {
616
+ while (true) {
617
+ const { done, value } = await reader.read();
618
+ if (done) break;
619
+ guard.bump();
620
+ buffer += decoder.decode(value, { stream: true });
621
+ const lines = buffer.split("\n");
622
+ buffer = lines.pop() || "";
623
+ for (const line of lines) {
624
+ try {
625
+ await consumeLine(line);
626
+ } catch (error) {
627
+ if (
628
+ options.requireCompletion ||
629
+ error?.isOutputBackpressureFailure === true
630
+ )
631
+ throw error;
632
+ // Non-governed streaming keeps its historical best-effort parsing.
633
+ }
634
+ }
635
+ }
636
+ buffer += decoder.decode();
637
+ if (buffer.trim()) await consumeLine(buffer);
638
+ } catch (error) {
639
+ throw attachStreamRetryMetadata(
640
+ guard.stalled() && !isFormalBudgetError(error)
641
+ ? new Error(
642
+ `Gemini stream stalled (no data in ${STREAM_STALL_MS / 1000}s)`,
643
+ )
644
+ : error,
645
+ retryMetadata,
646
+ );
647
+ } finally {
648
+ guard.stop();
649
+ }
650
+
651
+ if (latestUsage && onUsage) onUsage(latestUsage);
652
+ options.signal?.throwIfAborted();
653
+ if (options.requireCompletion && !completed)
654
+ throw new Error("Model stream ended before its completion marker");
655
+ return fullResponse;
656
+ }
657
+
520
658
  /**
521
659
  * Async generator that streams a chat response.
522
660
  *
@@ -578,10 +716,9 @@ export async function* chatStream(messages, options) {
578
716
  );
579
717
  } else if (provider === "anthropic") {
580
718
  const providerDef = BUILT_IN_PROVIDERS.anthropic;
581
- const url =
582
- baseUrl && baseUrl !== "http://localhost:11434"
583
- ? baseUrl
584
- : providerDef?.baseUrl || "https://api.anthropic.com/v1";
719
+ const url = normalizeProviderBaseUrl(
720
+ baseUrl || providerDef?.baseUrl || "https://api.anthropic.com/v1",
721
+ );
585
722
  const key =
586
723
  apiKey ||
587
724
  (providerDef?.apiKeyEnv ? process.env[providerDef.apiKeyEnv] : null);
@@ -601,12 +738,37 @@ export async function* chatStream(messages, options) {
601
738
  options.onStall,
602
739
  options,
603
740
  );
741
+ } else if (provider === "gemini") {
742
+ const providerDef = BUILT_IN_PROVIDERS.gemini;
743
+ const url = normalizeProviderBaseUrl(
744
+ baseUrl ||
745
+ providerDef?.baseUrl ||
746
+ "https://generativelanguage.googleapis.com/v1beta",
747
+ );
748
+ const key =
749
+ apiKey ||
750
+ (providerDef?.apiKeyEnv ? process.env[providerDef.apiKeyEnv] : null);
751
+ if (!key) {
752
+ throw new Error(
753
+ `API key required for gemini (set ${providerDef?.apiKeyEnv || "GEMINI_API_KEY"})`,
754
+ );
755
+ }
756
+ providerCall = () =>
757
+ streamGemini(
758
+ messages,
759
+ model,
760
+ url,
761
+ key,
762
+ onToken,
763
+ onUsage,
764
+ options.onStall,
765
+ options,
766
+ );
604
767
  } else {
605
768
  const providerDef = BUILT_IN_PROVIDERS[provider];
606
- const url =
607
- baseUrl !== "http://localhost:11434"
608
- ? baseUrl
609
- : providerDef?.baseUrl || "https://api.openai.com/v1";
769
+ const url = normalizeProviderBaseUrl(
770
+ baseUrl || providerDef?.baseUrl || "https://api.openai.com/v1",
771
+ );
610
772
  const key =
611
773
  apiKey ||
612
774
  (providerDef?.apiKeyEnv ? process.env[providerDef.apiKeyEnv] : null);
@@ -12,6 +12,11 @@ import { LLMProviderRegistry, BUILT_IN_PROVIDERS } from "./llm-providers.js";
12
12
  import { loadConfig } from "./config-manager.js";
13
13
  import { applyConfigLlmDefaults } from "./llm-config-defaults.js";
14
14
  import { captureAgentEvolutionIngress } from "./evolution/agent-evolution-ingress.js";
15
+ import { normalizeOllamaBaseUrl } from "./ollama-base-url.js";
16
+ import {
17
+ normalizeProviderBaseUrl,
18
+ openAICompatibleBaseUrl,
19
+ } from "./provider-protocol.js";
15
20
 
16
21
  function plainUsage(value) {
17
22
  return value && typeof value === "object" && !Array.isArray(value)
@@ -175,17 +180,20 @@ export function createChatFn(options = {}) {
175
180
  currentModel,
176
181
  async ({ signal = opts.signal || resolved.signal } = {}) => {
177
182
  const modelMessages = await prepareMessages();
178
- const res = await providerFetch(`${baseUrl}/api/chat`, {
179
- method: "POST",
180
- signal: requestSignal(signal),
181
- headers: { "Content-Type": "application/json" },
182
- body: JSON.stringify({
183
- model: currentModel,
184
- messages: modelMessages,
185
- stream: false,
186
- options: { num_predict: maxTokens },
187
- }),
188
- });
183
+ const res = await providerFetch(
184
+ `${normalizeOllamaBaseUrl(baseUrl)}/api/chat`,
185
+ {
186
+ method: "POST",
187
+ signal: requestSignal(signal),
188
+ headers: { "Content-Type": "application/json" },
189
+ body: JSON.stringify({
190
+ model: currentModel,
191
+ messages: modelMessages,
192
+ stream: false,
193
+ options: { num_predict: maxTokens },
194
+ }),
195
+ },
196
+ );
189
197
  if (!res.ok) throw new Error(`Ollama error: ${res.status}`);
190
198
  const data = await res.json();
191
199
  return chatEnvelope(
@@ -215,7 +223,9 @@ export function createChatFn(options = {}) {
215
223
  ? { system: systemMsgs.map((m) => m.content).join("\n") }
216
224
  : {}),
217
225
  };
218
- const res = await providerFetch(`${baseUrl}/messages`, {
226
+ const res = await providerFetch(
227
+ `${normalizeProviderBaseUrl(baseUrl)}/messages`,
228
+ {
219
229
  method: "POST",
220
230
  signal: requestSignal(signal),
221
231
  headers: {
@@ -224,7 +234,8 @@ export function createChatFn(options = {}) {
224
234
  "anthropic-version": "2023-06-01",
225
235
  },
226
236
  body: JSON.stringify(body),
227
- });
237
+ },
238
+ );
228
239
  if (!res.ok) throw new Error(`Anthropic error: ${res.status}`);
229
240
  const data = await res.json();
230
241
  return chatEnvelope(
@@ -246,7 +257,9 @@ export function createChatFn(options = {}) {
246
257
  currentModel,
247
258
  async ({ signal = opts.signal || resolved.signal } = {}) => {
248
259
  const modelMessages = await prepareMessages();
249
- const res = await providerFetch(`${baseUrl}/chat/completions`, {
260
+ const res = await providerFetch(
261
+ `${openAICompatibleBaseUrl(provider, baseUrl)}/chat/completions`,
262
+ {
250
263
  method: "POST",
251
264
  signal: requestSignal(signal),
252
265
  headers: {
@@ -258,7 +271,8 @@ export function createChatFn(options = {}) {
258
271
  messages: modelMessages,
259
272
  max_tokens: maxTokens,
260
273
  }),
261
- });
274
+ },
275
+ );
262
276
  if (!res.ok) throw new Error(`API error: ${res.status}`);
263
277
  const data = await res.json();
264
278
  return chatEnvelope(
@@ -22,6 +22,7 @@ import { EvolutionRunLedgerAdapter } from "./evolution-run-ledger-adapter.js";
22
22
  import { createEvolutionRunWikiEvidenceResolver } from "./evolution-run-wiki-evidence-resolver.js";
23
23
  import { WikiMaintainerLedgerAdapter } from "./wiki-maintainer-ledger-adapter.js";
24
24
  import { EvidenceBackedWikiMaintainer } from "./evidence-backed-wiki-maintainer.js";
25
+ import { ensureDirectoryTreeDurable } from "./evolution-windows-directory-durability.js";
25
26
  import { createWikiEvidenceCommitGuard } from "./wiki-evidence-commit-guard.js";
26
27
  import { EvolutionWorkbenchMetricsLedgerAdapter } from "./evolution-workbench-metrics-ledger-adapter.js";
27
28
  import { EvolutionReleaseTrainLedgerAdapter } from "./evolution-release-train-ledger-adapter.js";
@@ -158,7 +159,7 @@ function normalizeClock(clock) {
158
159
  });
159
160
  }
160
161
 
161
- function layout(stateRootDir, tenantId, runId, initialize = true) {
162
+ function layout(stateRootDir, tenantId, runId, initialize = true, fsImpl = fs) {
162
163
  if (typeof stateRootDir !== "string" || stateRootDir.trim() === "") {
163
164
  throw new TypeError("stateRootDir is required");
164
165
  }
@@ -176,11 +177,12 @@ function layout(stateRootDir, tenantId, runId, initialize = true) {
176
177
  ledgerAuthorityRootDir: path.join(scope, "ledger-authority"),
177
178
  witnessFilePath: path.join(scope, "witness", "checkpoint.json"),
178
179
  });
179
- if (initialize)
180
- fs.mkdirSync(path.dirname(result.witnessFilePath), {
181
- recursive: true,
182
- mode: 0o700,
183
- });
180
+ if (initialize) {
181
+ ensureDirectoryTreeDurable(
182
+ fsImpl,
183
+ path.dirname(result.witnessFilePath),
184
+ );
185
+ }
184
186
  return result;
185
187
  }
186
188
 
@@ -408,7 +410,7 @@ export function createAgentEvolutionRuntimeComposition({
408
410
  capture(authorities.witness?.signer, "sign", "witness signer");
409
411
  capture(authorities.witness?.verifier, "verify", "witness verifier");
410
412
  assertIndependentSigningAuthorities(authorities.ledger, authorities.witness);
411
- const storage = layout(stateRootDir, tenantId, runId);
413
+ const storage = layout(stateRootDir, tenantId, runId, true, fsImpl ?? fs);
412
414
  const artifactPorts = new EvolutionArtifactPorts({
413
415
  tenantId,
414
416
  audience,
@@ -712,6 +714,7 @@ export function createAgentEvolutionRuntimeComposition({
712
714
  tenantId,
713
715
  sourceRunId,
714
716
  false,
717
+ fsImpl ?? fs,
715
718
  );
716
719
  if (!fs.existsSync(sourceStorage.witnessFilePath))
717
720
  throw new Error("Cache source Run witness does not exist");
@@ -103,6 +103,9 @@ function withDeploymentReadiness(status) {
103
103
  return Object.freeze({
104
104
  ...status,
105
105
  readiness: Object.freeze({
106
+ ui: assessEvolutionDeploymentReadiness(status, {
107
+ requiredCommands: ["ui"],
108
+ }),
106
109
  ask: assessEvolutionDeploymentReadiness(status, {
107
110
  requiredCommands: ["ask"],
108
111
  }),
@@ -197,6 +200,23 @@ export async function configureEvolutionDeployment(
197
200
  options,
198
201
  );
199
202
  updateEvolutionDeploymentProfile((current) => {
203
+ if (
204
+ options.expectedProfile &&
205
+ JSON.stringify(current) !== JSON.stringify(options.expectedProfile)
206
+ ) {
207
+ const error = new Error(
208
+ "Evolution deployment profile changed during local migration",
209
+ );
210
+ error.code = "EVOLUTION_DEPLOYMENT_PROFILE_CHANGED";
211
+ throw error;
212
+ }
213
+ if (options.expectedProfileAbsent === true && current) {
214
+ const error = new Error(
215
+ "Evolution deployment profile was configured during local initialization",
216
+ );
217
+ error.code = "EVOLUTION_DEPLOYMENT_PROFILE_ALREADY_CONFIGURED";
218
+ throw error;
219
+ }
200
220
  if (
201
221
  current?.activeTrustRootDigest &&
202
222
  current.activeTrustRootDigest !== verified.descriptor.trustRootDigest
@@ -245,6 +265,11 @@ export async function configureEvolutionDeployment(
245
265
  verified.descriptor.revision,
246
266
  ),
247
267
  };
268
+ const preserveLocalMode =
269
+ deploymentMode === undefined &&
270
+ current?.deploymentMode === "local" &&
271
+ current.descriptorPath === verified.descriptorPath &&
272
+ current.trustRootPath === verified.trustRootPath;
248
273
  const preserveTestMode =
249
274
  deploymentMode === undefined &&
250
275
  current?.deploymentMode === "test" &&
@@ -257,10 +282,17 @@ export async function configureEvolutionDeployment(
257
282
  revisionFloors,
258
283
  activeTrustRootDigest: verified.descriptor.trustRootDigest,
259
284
  revokedDescriptorRevisions,
260
- deploymentMode: preserveTestMode ? "test" : deploymentMode || "managed",
261
- testPrivateKeyPath: preserveTestMode
262
- ? current.testPrivateKeyPath
263
- : testPrivateKeyPath || null,
285
+ deploymentMode: preserveLocalMode
286
+ ? "local"
287
+ : preserveTestMode
288
+ ? "test"
289
+ : deploymentMode || "managed",
290
+ testPrivateKeyPath:
291
+ deploymentMode === "test"
292
+ ? testPrivateKeyPath || null
293
+ : preserveTestMode
294
+ ? current.testPrivateKeyPath
295
+ : null,
264
296
  };
265
297
  }, options);
266
298
  return getEvolutionDeploymentStatus(options);
@@ -1,6 +1,6 @@
1
1
  import { createHash, createPublicKey, verify } from "node:crypto";
2
2
  import { readFile, realpath } from "node:fs/promises";
3
- import { isAbsolute } from "node:path";
3
+ import { dirname, isAbsolute, join } from "node:path";
4
4
  import { types as utilTypes } from "node:util";
5
5
  import {
6
6
  assertEvolutionDeploymentActiveTrustRoot,
@@ -622,7 +622,9 @@ async function loadBuiltInFactories(commandName) {
622
622
  import("./evolution-eval-process-supervisor.js"),
623
623
  import("./governed-skill-synthesis-attestor-trust-approval-client.js"),
624
624
  import("./governed-skill-synthesis-attestor-trust-operations-client.js"),
625
- import("./governed-skill-synthesis-attestor-trust-operations-cli-host.js"),
625
+ import(
626
+ "./governed-skill-synthesis-attestor-trust-operations-cli-host.js"
627
+ ),
626
628
  ]);
627
629
  factories.createEvolutionWorkbenchCliHost = createEvolutionWorkbenchCliHost;
628
630
  factories.createEvolutionWorkbenchReviewRuntime =
@@ -840,6 +842,15 @@ function bindFactoriesToModule(factories, moduleDigest) {
840
842
  return factories[name](options);
841
843
  };
842
844
  }
845
+ if (typeof factories.createLocalUiEvolutionComposition === "function") {
846
+ result.createLocalUiEvolutionComposition = (options = {}) => {
847
+ if (options?.handlerArtifactDigest !== moduleDigest)
848
+ throw new Error(
849
+ "Local UI Evolution host digest must equal the authenticated deployment module digest",
850
+ );
851
+ return factories.createLocalUiEvolutionComposition(options);
852
+ };
853
+ }
843
854
  for (const name of [
844
855
  "createSkillEvaluatedPromotionProvider",
845
856
  "createSkillPromotionReviewProvider",
@@ -1012,19 +1023,62 @@ export async function loadEvolutionDeploymentCommandDependencies(
1012
1023
  commandName,
1013
1024
  {
1014
1025
  env = process.env,
1026
+ cwd = process.cwd(),
1015
1027
  read = readFile,
1016
1028
  resolveRealPath = realpath,
1017
1029
  importModule = (url) => import(url),
1018
1030
  additionalFactories = {},
1031
+ initializeDefaultLocalUi = false,
1032
+ initializeDefaultLocalModels = true,
1019
1033
  } = {},
1020
1034
  ) {
1021
1035
  if (!SUPPORTED_COMMANDS.has(commandName)) return null;
1036
+ const localModelDependencies = () =>
1037
+ dependencies(
1038
+ {
1039
+ evolutionCompositionFactory: async (context) => {
1040
+ const { initializeDefaultLocalUiEvolutionDeployment } = await import(
1041
+ "./local-ui-evolution-deployment.js"
1042
+ );
1043
+ await initializeDefaultLocalUiEvolutionDeployment({ env, cwd });
1044
+ const admitted = await loadEvolutionDeploymentCommandDependencies(
1045
+ commandName,
1046
+ {
1047
+ env,
1048
+ cwd,
1049
+ read,
1050
+ resolveRealPath,
1051
+ importModule,
1052
+ additionalFactories,
1053
+ initializeDefaultLocalModels: false,
1054
+ },
1055
+ );
1056
+ if (typeof admitted?.evolutionCompositionFactory !== "function")
1057
+ throw new Error(
1058
+ "Local model command requires an authenticated Evolution deployment",
1059
+ );
1060
+ return admitted.evolutionCompositionFactory(context);
1061
+ },
1062
+ },
1063
+ commandName,
1064
+ );
1022
1065
  let descriptorPath = env.CHAINLESSCHAIN_EVOLUTION_DEPLOYMENT_DESCRIPTOR;
1023
1066
  let trustRootPath = env.CHAINLESSCHAIN_EVOLUTION_DEPLOYMENT_TRUST_ROOT;
1067
+ if (
1068
+ initializeDefaultLocalUi === true &&
1069
+ commandName === "ui" &&
1070
+ !descriptorPath &&
1071
+ !trustRootPath
1072
+ ) {
1073
+ const { initializeDefaultLocalUiEvolutionDeployment } = await import(
1074
+ "./local-ui-evolution-deployment.js"
1075
+ );
1076
+ await initializeDefaultLocalUiEvolutionDeployment({ env, cwd });
1077
+ }
1024
1078
  let fromSavedProfile = false;
1025
1079
  let saved = null;
1026
1080
  if (!descriptorPath && !trustRootPath) {
1027
- saved = await readEvolutionDeploymentProfile({ env });
1081
+ saved = await readEvolutionDeploymentProfile({ env, cwd });
1028
1082
  if (saved.error) {
1029
1083
  return deniedAgentDependencies(
1030
1084
  commandName,
@@ -1039,6 +1093,15 @@ export async function loadEvolutionDeploymentCommandDependencies(
1039
1093
  "Saved evolution deployment profile is disabled",
1040
1094
  );
1041
1095
  }
1096
+ if (
1097
+ initializeDefaultLocalModels &&
1098
+ ["agent", "ask", "chat"].includes(commandName) &&
1099
+ !saved.profile
1100
+ ) {
1101
+ // Registration/help is read-only. Bootstrap only when a real command
1102
+ // requests its authenticated composition, then re-read current policy.
1103
+ return localModelDependencies();
1104
+ }
1042
1105
  if (!saved.error && saved.profile?.enabled) {
1043
1106
  descriptorPath = saved.profile.descriptorPath;
1044
1107
  trustRootPath = saved.profile.trustRootPath;
@@ -1086,6 +1149,39 @@ export async function loadEvolutionDeploymentCommandDependencies(
1086
1149
  throw error;
1087
1150
  }
1088
1151
  const { descriptor, moduleBytes } = verified;
1152
+ const localProfile =
1153
+ fromSavedProfile && saved.profile.deploymentMode === "local";
1154
+ if (localProfile) {
1155
+ const generation = saved.profile.descriptorPath.endsWith(
1156
+ "deployment-v2.json",
1157
+ )
1158
+ ? 2
1159
+ : 1;
1160
+ const localHostPath = join(
1161
+ dirname(saved.filePath),
1162
+ "local-ui-host",
1163
+ generation === 2 ? "ui-host-v2.mjs" : "ui-host.mjs",
1164
+ );
1165
+ const canonicalLocalHostPath = await realpath(localHostPath);
1166
+ if (
1167
+ !(
1168
+ ["ui"].join(",") === descriptor.commands.join(",") ||
1169
+ "agent,ask,chat,ui" === descriptor.commands.join(",")
1170
+ ) ||
1171
+ verified.modulePath !== canonicalLocalHostPath
1172
+ ) {
1173
+ throw new Error(
1174
+ "Local Evolution deployment is not the protected UI host",
1175
+ );
1176
+ }
1177
+ if (
1178
+ initializeDefaultLocalModels &&
1179
+ ["agent", "ask", "chat", "ui"].includes(commandName) &&
1180
+ descriptor.commands.length === 1 &&
1181
+ descriptor.commands[0] === "ui"
1182
+ )
1183
+ return localModelDependencies();
1184
+ }
1089
1185
  if (!descriptor.commands.includes(commandName)) {
1090
1186
  return deniedAgentDependencies(
1091
1187
  commandName,
@@ -1105,8 +1201,25 @@ export async function loadEvolutionDeploymentCommandDependencies(
1105
1201
  throw new Error(
1106
1202
  "evolution deployment module must export createChainlessChainCommandDependencies",
1107
1203
  );
1204
+ const builtIn = await loadBuiltInFactories(commandName);
1205
+ let localFactories = null;
1206
+ if (localProfile) {
1207
+ const { createLocalUiEvolutionComposition } = await import(
1208
+ "./local-ui-evolution-runtime.js"
1209
+ );
1210
+ localFactories = {
1211
+ createLocalUiEvolutionComposition: (options = {}) =>
1212
+ createLocalUiEvolutionComposition({
1213
+ ...options,
1214
+ commandName,
1215
+ localDirectory: join(dirname(saved.filePath), "local-ui-host"),
1216
+ env,
1217
+ cwd,
1218
+ }),
1219
+ };
1220
+ }
1108
1221
  const builtInFactories = bindFactoriesToModule(
1109
- await loadBuiltInFactories(commandName),
1222
+ { ...builtIn, ...(localFactories || {}) },
1110
1223
  descriptor.moduleDigest,
1111
1224
  );
1112
1225
  if (
@@ -124,7 +124,7 @@ function normalizeProfile(value) {
124
124
  const deploymentMode = beforeDeploymentMode
125
125
  ? "managed"
126
126
  : value.deploymentMode;
127
- if (!["managed", "test"].includes(deploymentMode))
127
+ if (!["managed", "test", "local"].includes(deploymentMode))
128
128
  throw new TypeError("evolution deployment profile mode is invalid");
129
129
  const testPrivateKeyPath = beforeDeploymentMode
130
130
  ? null
@@ -133,7 +133,7 @@ function normalizeProfile(value) {
133
133
  (deploymentMode === "test" &&
134
134
  (typeof testPrivateKeyPath !== "string" ||
135
135
  !isAbsolute(testPrivateKeyPath))) ||
136
- (deploymentMode === "managed" && testPrivateKeyPath !== null)
136
+ (deploymentMode !== "test" && testPrivateKeyPath !== null)
137
137
  ) {
138
138
  throw new TypeError(
139
139
  "evolution deployment profile test private key path is invalid",