@nomix-ai/nomix-harness 0.2.5 → 0.2.6

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 (1017) hide show
  1. package/README.md +2 -9
  2. package/dist/assets/web/assets/index-BnapMmQ_.css +1 -0
  3. package/dist/assets/web/assets/index-Dx7Ws_OC.js +96 -0
  4. package/dist/assets/web/assets/langs/{php-D-uCvoST.js → php-DDkx9sim.js} +2 -2
  5. package/dist/{kernel/web-frontend/dist/assets/langs/ruby-DEItuUFs.js → assets/web/assets/langs/ruby-DCxyoPen.js} +2 -2
  6. package/dist/assets/web/assets/{vendor-Cjbwl5VI.js → vendor-D22_Mp1f.js} +2 -2
  7. package/dist/assets/web/favicon.svg +8 -0
  8. package/dist/assets/web/index.html +5 -5
  9. package/dist/bundles/base/cordis.patch.yml +31 -6
  10. package/dist/bundles/web-app/cordis.patch.yml +27 -6
  11. package/dist/cli/bin.js +4 -5
  12. package/dist/cli/builtin-registry.js +34 -4
  13. package/dist/cli/{dump-config-d3ECray2.js → dump-config-BEj2GlJo.js} +1 -1
  14. package/dist/cli/{plugin-Bw9wgrmj.js → plugin-D_gLgCYL.js} +1 -1
  15. package/dist/cli/profile-boot-BSrYtiQI.js +2 -0
  16. package/dist/cli/{profile-boot-DFHdh9Xq.js → profile-boot-CByqUxLM.js} +0 -2
  17. package/dist/cli/runtime.js +0 -2
  18. package/dist/config/agent-presets/code/agent.cordis.yml +4 -3
  19. package/dist/config/agent-presets/cordis/agent.cordis.yml +4 -3
  20. package/dist/config/agent-presets/cordis/skills/editing-cordis-compositions/SKILL.md +13 -2
  21. package/dist/config/agent-presets/minimal/agent.cordis.yml +27 -1
  22. package/dist/config/agent-presets/standard/agent.cordis.yml +4 -3
  23. package/dist/kernel/acp/package.json +1 -1
  24. package/dist/kernel/agent/package.json +1 -1
  25. package/dist/kernel/agent-default-model/package.json +1 -1
  26. package/dist/kernel/agent-instructions/package.json +1 -1
  27. package/dist/kernel/agent-loop/lib/index.js +33 -10
  28. package/dist/kernel/agent-loop/lib/types/agent.js +26 -6
  29. package/dist/kernel/agent-loop/package.json +1 -1
  30. package/dist/kernel/agent-presets/package.json +1 -1
  31. package/dist/kernel/agent-tool-presentation/package.json +1 -1
  32. package/dist/kernel/anonymous-user-id/package.json +1 -1
  33. package/dist/kernel/api-gateway/lib/client.js +84 -55
  34. package/dist/kernel/api-gateway/lib/types/client/index.js +93 -61
  35. package/dist/kernel/api-gateway/package.json +1 -1
  36. package/dist/kernel/api-remotes/lib/client.js +166 -27
  37. package/dist/kernel/api-remotes/lib/index.js +1 -1
  38. package/dist/kernel/api-remotes/lib/types/client/index.d.ts +4 -0
  39. package/dist/kernel/api-remotes/lib/types/client/index.js +4 -1
  40. package/dist/kernel/api-remotes/lib/types/remote-events.d.ts +1 -1
  41. package/dist/kernel/api-remotes/lib/types/remote-events.js +1 -1
  42. package/dist/kernel/api-remotes/package.json +11 -7
  43. package/dist/kernel/app-boot/lib/index.js +19 -41
  44. package/dist/kernel/app-boot/lib/types/index.d.ts +0 -1
  45. package/dist/kernel/app-boot/lib/types/index.js +2 -3
  46. package/dist/kernel/app-boot/lib/types/profile.d.ts +15 -12
  47. package/dist/kernel/app-boot/lib/types/profile.js +15 -25
  48. package/dist/kernel/app-boot/package.json +1 -1
  49. package/dist/kernel/atomic-write/lib/index.js +36 -16
  50. package/dist/kernel/atomic-write/lib/types/index.d.ts +21 -5
  51. package/dist/kernel/atomic-write/lib/types/index.js +40 -16
  52. package/dist/kernel/atomic-write/package.json +1 -1
  53. package/dist/kernel/attachment/lib/index.js +62 -3
  54. package/dist/kernel/attachment/lib/types/admission.d.ts +15 -0
  55. package/dist/kernel/attachment/lib/types/admission.js +33 -0
  56. package/dist/kernel/attachment/lib/types/brand.d.ts +8 -0
  57. package/dist/kernel/attachment/lib/types/brand.js +8 -0
  58. package/dist/kernel/attachment/lib/types/error.d.ts +2 -2
  59. package/dist/kernel/attachment/lib/types/error.js +1 -0
  60. package/dist/kernel/attachment/lib/types/index.d.ts +23 -5
  61. package/dist/kernel/attachment/lib/types/index.js +24 -2
  62. package/dist/kernel/attachment/lib/types/types.d.ts +47 -2
  63. package/dist/kernel/attachment/package.json +3 -2
  64. package/dist/kernel/attachment-local/lib/index.js +640 -48
  65. package/dist/kernel/attachment-local/lib/types/compression-limiter.d.ts +18 -0
  66. package/dist/kernel/attachment-local/lib/types/compression-limiter.js +43 -0
  67. package/dist/kernel/attachment-local/lib/types/encoding.d.ts +23 -0
  68. package/dist/kernel/attachment-local/lib/types/encoding.js +33 -0
  69. package/dist/kernel/attachment-local/lib/types/image.d.ts +31 -2
  70. package/dist/kernel/attachment-local/lib/types/image.js +43 -4
  71. package/dist/kernel/attachment-local/lib/types/index.d.ts +45 -10
  72. package/dist/kernel/attachment-local/lib/types/index.js +140 -10
  73. package/dist/kernel/attachment-local/lib/types/normalization.d.ts +44 -0
  74. package/dist/kernel/attachment-local/lib/types/normalization.js +148 -0
  75. package/dist/kernel/attachment-local/lib/types/request-image.d.ts +35 -0
  76. package/dist/kernel/attachment-local/lib/types/request-image.js +208 -0
  77. package/dist/kernel/attachment-local/lib/types/store.d.ts +36 -9
  78. package/dist/kernel/attachment-local/lib/types/store.js +60 -24
  79. package/dist/kernel/attachment-local/package.json +1 -1
  80. package/dist/kernel/authorization/lib/index.js +248 -0
  81. package/dist/kernel/authorization/lib/invariant.js +36 -0
  82. package/dist/kernel/authorization/lib/types/index.d.ts +223 -0
  83. package/dist/kernel/authorization/lib/types/index.js +299 -0
  84. package/dist/kernel/authorization/lib/types/invariant.d.ts +16 -0
  85. package/dist/kernel/authorization/lib/types/invariant.js +38 -0
  86. package/dist/kernel/authorization/lib/types/types.d.ts +83 -0
  87. package/dist/kernel/authorization/lib/types/types.js +8 -0
  88. package/dist/kernel/{client-web-react → authorization}/package.json +19 -16
  89. package/dist/kernel/base/cordis.patch.yml +31 -6
  90. package/dist/kernel/base/package.json +3 -1
  91. package/dist/kernel/bash-local/package.json +1 -1
  92. package/dist/kernel/bash-sandbox/package.json +1 -1
  93. package/dist/kernel/brand/package.json +1 -1
  94. package/dist/kernel/client-connection/lib/client.js +148 -28
  95. package/dist/kernel/client-connection/lib/index.js +4 -4
  96. package/dist/kernel/client-connection/lib/types/client/fixture.js +112 -20
  97. package/dist/kernel/client-connection/lib/types/client/index.d.ts +21 -1
  98. package/dist/kernel/client-connection/lib/types/client/index.js +3 -2
  99. package/dist/kernel/client-connection/lib/types/client/rpc.d.ts +4 -1
  100. package/dist/kernel/client-connection/lib/types/client/rpc.js +4 -2
  101. package/dist/kernel/client-connection/lib/types/http-bridge.d.ts +2 -2
  102. package/dist/kernel/client-connection/lib/types/http-bridge.js +3 -3
  103. package/dist/kernel/client-connection/lib/types/index.d.ts +1 -1
  104. package/dist/kernel/client-connection/package.json +15 -9
  105. package/dist/kernel/client-hmr/package.json +1 -1
  106. package/dist/kernel/client-locale/lib/client.js +48 -9
  107. package/dist/kernel/client-locale/lib/types/client/index.d.ts +19 -3
  108. package/dist/kernel/client-locale/lib/types/client/index.js +48 -7
  109. package/dist/kernel/client-locale/package.json +6 -6
  110. package/dist/kernel/client-modules/lib/client.js +188 -123
  111. package/dist/kernel/client-modules/lib/index.js +177 -31
  112. package/dist/kernel/client-modules/lib/types/client/index.d.ts +19 -8
  113. package/dist/kernel/client-modules/lib/types/client/index.js +25 -8
  114. package/dist/kernel/client-modules/lib/types/client/manifest.d.ts +90 -41
  115. package/dist/kernel/client-modules/lib/types/client/manifest.js +45 -12
  116. package/dist/kernel/client-modules/lib/types/client/system.d.ts +15 -17
  117. package/dist/kernel/client-modules/lib/types/client/system.js +85 -56
  118. package/dist/kernel/client-modules/lib/types/index.d.ts +28 -12
  119. package/dist/kernel/client-modules/lib/types/index.js +128 -34
  120. package/dist/kernel/client-modules/package.json +4 -2
  121. package/dist/kernel/client-runtime/lib/client.js +43 -8
  122. package/dist/kernel/client-runtime/lib/types/client/contract/session.d.ts +1 -1
  123. package/dist/kernel/client-runtime/lib/types/client/contract/store.d.ts +1 -1
  124. package/dist/kernel/client-runtime/lib/types/client/contract/store.js +2 -2
  125. package/dist/kernel/client-runtime/lib/types/client/index.d.ts +2 -2
  126. package/dist/kernel/client-runtime/lib/types/client/index.js +3 -3
  127. package/dist/kernel/client-runtime/lib/types/client/sessions/context-provenance.d.ts +8 -0
  128. package/dist/kernel/client-runtime/lib/types/client/sessions/context-provenance.js +13 -0
  129. package/dist/kernel/client-runtime/lib/types/client/sessions/conversation.d.ts +11 -7
  130. package/dist/kernel/client-runtime/lib/types/client/sessions/projection-store.d.ts +1 -1
  131. package/dist/kernel/client-runtime/lib/types/client/sessions/session.d.ts +1 -1
  132. package/dist/kernel/client-runtime/lib/types/client/sessions/session.js +4 -4
  133. package/dist/kernel/client-runtime/lib/types/client/slots.d.ts +1 -1
  134. package/dist/kernel/client-runtime/lib/types/client/slots.js +1 -1
  135. package/dist/kernel/client-runtime/lib/types/client/workspaces/path.d.ts +9 -0
  136. package/dist/kernel/client-runtime/lib/types/client/workspaces/path.js +27 -1
  137. package/dist/kernel/client-runtime/package.json +25 -14
  138. package/dist/kernel/client-ui-agent-preset/lib/client.js +55 -55
  139. package/dist/kernel/client-ui-agent-preset/lib/types/client/index.js +2 -2
  140. package/dist/kernel/client-ui-agent-preset/lib/types/client/settings-store.d.ts +7 -1
  141. package/dist/kernel/client-ui-agent-preset/lib/types/client/settings-store.js +21 -20
  142. package/dist/kernel/client-ui-agent-preset/package.json +2 -7
  143. package/dist/kernel/client-ui-attachment/lib/client.js +782 -0
  144. package/dist/kernel/client-ui-attachment/lib/index.js +5 -505
  145. package/dist/kernel/client-ui-attachment/lib/invariant.js +2 -3
  146. package/dist/kernel/client-ui-attachment/lib/types/client/ComposerAttachments.d.ts +4 -0
  147. package/dist/kernel/client-ui-attachment/lib/types/client/ComposerAttachments.js +85 -0
  148. package/dist/kernel/client-ui-attachment/lib/types/client/MessageImages.d.ts +4 -0
  149. package/dist/kernel/client-ui-attachment/lib/types/client/MessageImages.js +8 -0
  150. package/dist/kernel/client-ui-attachment/lib/types/client/index.d.ts +7 -0
  151. package/dist/kernel/client-ui-attachment/lib/types/client/index.js +16 -0
  152. package/dist/kernel/client-ui-attachment/lib/types/client/labels.d.ts +35 -0
  153. package/dist/kernel/client-ui-attachment/lib/types/client/labels.js +52 -0
  154. package/dist/kernel/client-ui-attachment/lib/types/index.d.ts +3 -15
  155. package/dist/kernel/client-ui-attachment/lib/types/index.js +3 -11
  156. package/dist/kernel/client-ui-attachment/lib/types/invariant.js +2 -3
  157. package/dist/kernel/client-ui-attachment/package.json +32 -9
  158. package/dist/kernel/client-ui-brand-official/lib/client.js +50 -0
  159. package/dist/kernel/client-ui-brand-official/lib/index.js +9 -0
  160. package/dist/kernel/{client-web-react → client-ui-brand-official}/lib/invariant.js +6 -8
  161. package/dist/kernel/client-ui-brand-official/lib/types/client/Brand.d.ts +16 -0
  162. package/dist/kernel/client-ui-brand-official/lib/types/client/Brand.js +18 -0
  163. package/dist/kernel/client-ui-brand-official/lib/types/client/index.d.ts +10 -0
  164. package/dist/kernel/client-ui-brand-official/lib/types/client/index.js +17 -0
  165. package/dist/kernel/client-ui-brand-official/lib/types/index.d.ts +7 -0
  166. package/dist/kernel/client-ui-brand-official/lib/types/index.js +7 -0
  167. package/dist/kernel/client-ui-brand-official/lib/types/invariant.d.ts +16 -0
  168. package/dist/kernel/{client-web-react → client-ui-brand-official}/lib/types/invariant.js +6 -8
  169. package/dist/kernel/client-ui-brand-official/package.json +72 -0
  170. package/dist/kernel/client-ui-commands/lib/client.js +44 -15
  171. package/dist/kernel/client-ui-commands/lib/types/client/locales.d.ts +2 -0
  172. package/dist/kernel/client-ui-commands/lib/types/client/locales.js +2 -0
  173. package/dist/kernel/client-ui-commands/lib/types/client/service.d.ts +11 -1
  174. package/dist/kernel/client-ui-commands/lib/types/client/service.js +39 -7
  175. package/dist/kernel/client-ui-commands/package.json +2 -5
  176. package/dist/kernel/client-ui-conversation/lib/client.js +949 -531
  177. package/dist/kernel/client-ui-conversation/lib/types/client/apply.js +6 -4
  178. package/dist/kernel/client-ui-conversation/lib/types/client/chat/AssistantMarkdown.d.ts +4 -5
  179. package/dist/kernel/client-ui-conversation/lib/types/client/chat/AssistantMarkdown.js +6 -6
  180. package/dist/kernel/client-ui-conversation/lib/types/client/chat/AssistantNodeView.d.ts +1 -1
  181. package/dist/kernel/client-ui-conversation/lib/types/client/chat/AssistantNodeView.js +2 -2
  182. package/dist/kernel/client-ui-conversation/lib/types/client/chat/ChatNodeSeat.d.ts +1 -1
  183. package/dist/kernel/client-ui-conversation/lib/types/client/chat/ChatNodeSeat.js +5 -3
  184. package/dist/kernel/client-ui-conversation/lib/types/client/chat/ChatView.js +53 -10
  185. package/dist/kernel/client-ui-conversation/lib/types/client/chat/ContextInjectionRow.js +4 -1
  186. package/dist/kernel/client-ui-conversation/lib/types/client/chat/MessageItem.d.ts +4 -5
  187. package/dist/kernel/client-ui-conversation/lib/types/client/chat/MessageItem.js +46 -16
  188. package/dist/kernel/client-ui-conversation/lib/types/client/chat/StatsLine.d.ts +5 -3
  189. package/dist/kernel/client-ui-conversation/lib/types/client/chat/StatsLine.js +54 -5
  190. package/dist/kernel/client-ui-conversation/lib/types/client/contract/slots.d.ts +90 -8
  191. package/dist/kernel/client-ui-conversation/lib/types/client/conversation-nodes/assistant.js +1 -0
  192. package/dist/kernel/client-ui-conversation/lib/types/client/conversation-nodes/chat-snapshot-builder.d.ts +1 -0
  193. package/dist/kernel/client-ui-conversation/lib/types/client/conversation-nodes/chat-snapshot-builder.js +95 -6
  194. package/dist/kernel/client-ui-conversation/lib/types/client/conversation-nodes/message.d.ts +11 -3
  195. package/dist/kernel/client-ui-conversation/lib/types/client/conversation-nodes/turn-error.d.ts +6 -3
  196. package/dist/kernel/client-ui-conversation/lib/types/client/conversation-nodes/turn-error.js +10 -26
  197. package/dist/kernel/client-ui-conversation/lib/types/client/image-labels.d.ts +1 -33
  198. package/dist/kernel/client-ui-conversation/lib/types/client/image-labels.js +5 -54
  199. package/dist/kernel/client-ui-conversation/lib/types/client/index.d.ts +1 -1
  200. package/dist/kernel/client-ui-conversation/lib/types/client/input/contract.d.ts +17 -14
  201. package/dist/kernel/client-ui-conversation/lib/types/client/input/decorations.d.ts +13 -5
  202. package/dist/kernel/client-ui-conversation/lib/types/client/input/decorations.js +26 -10
  203. package/dist/kernel/client-ui-conversation/lib/types/client/input/facade.d.ts +34 -14
  204. package/dist/kernel/client-ui-conversation/lib/types/client/input/facade.js +116 -34
  205. package/dist/kernel/client-ui-conversation/lib/types/client/input/hub.d.ts +1 -1
  206. package/dist/kernel/client-ui-conversation/lib/types/client/input/hub.js +21 -19
  207. package/dist/kernel/client-ui-conversation/lib/types/client/input/machine.d.ts +35 -14
  208. package/dist/kernel/client-ui-conversation/lib/types/client/input/machine.js +71 -34
  209. package/dist/kernel/client-ui-conversation/lib/types/client/locales.d.ts +16 -0
  210. package/dist/kernel/client-ui-conversation/lib/types/client/locales.js +16 -0
  211. package/dist/kernel/client-ui-conversation/lib/types/client/reference/ReferenceIcon.d.ts +16 -0
  212. package/dist/kernel/client-ui-conversation/lib/types/client/reference/ReferenceIcon.js +16 -0
  213. package/dist/kernel/client-ui-conversation/lib/types/client/service.d.ts +14 -1
  214. package/dist/kernel/client-ui-conversation/lib/types/client/service.js +26 -6
  215. package/dist/kernel/client-ui-conversation/lib/types/client/skeleton/ConversationRoot.js +1 -1
  216. package/dist/kernel/client-ui-conversation/lib/types/client/skeleton/ConversationSession.js +18 -3
  217. package/dist/kernel/client-ui-conversation/lib/types/client/skeleton/EmptyHero.d.ts +3 -1
  218. package/dist/kernel/client-ui-conversation/lib/types/client/skeleton/EmptyHero.js +4 -2
  219. package/dist/kernel/client-ui-conversation/lib/types/client/skeleton/InputBar.js +141 -126
  220. package/dist/kernel/client-ui-conversation/package.json +9 -8
  221. package/dist/kernel/client-ui-cordis/lib/client.js +48 -48
  222. package/dist/kernel/client-ui-cordis/package.json +2 -5
  223. package/dist/kernel/client-ui-deliverables/lib/client.js +5 -5
  224. package/dist/kernel/client-ui-deliverables/package.json +4 -6
  225. package/dist/kernel/client-ui-directory-picker-browse/lib/client.js +26 -26
  226. package/dist/kernel/client-ui-directory-picker-browse/package.json +2 -5
  227. package/dist/kernel/client-ui-directory-picker-native/package.json +2 -5
  228. package/dist/kernel/client-ui-goal/lib/client.js +8 -8
  229. package/dist/kernel/client-ui-goal/package.json +6 -5
  230. package/dist/kernel/client-ui-input-trigger/lib/client.js +82 -26
  231. package/dist/kernel/client-ui-input-trigger/lib/types/client/MenuView.js +13 -9
  232. package/dist/kernel/client-ui-input-trigger/lib/types/client/controller.d.ts +5 -3
  233. package/dist/kernel/client-ui-input-trigger/lib/types/client/controller.js +19 -7
  234. package/dist/kernel/client-ui-input-trigger/lib/types/client/index.d.ts +1 -1
  235. package/dist/kernel/client-ui-input-trigger/lib/types/core/contract.d.ts +7 -2
  236. package/dist/kernel/client-ui-input-trigger/lib/types/core/detect.d.ts +4 -4
  237. package/dist/kernel/client-ui-input-trigger/lib/types/core/detect.js +24 -6
  238. package/dist/kernel/client-ui-input-trigger/lib/types/core/menu.d.ts +15 -2
  239. package/dist/kernel/client-ui-input-trigger/lib/types/core/menu.js +13 -4
  240. package/dist/kernel/client-ui-input-trigger/lib/types/types.d.ts +52 -8
  241. package/dist/kernel/client-ui-input-trigger/package.json +4 -5
  242. package/dist/kernel/client-ui-jobs/lib/client.js +10 -10
  243. package/dist/kernel/client-ui-jobs/package.json +3 -7
  244. package/dist/kernel/client-ui-layout/lib/client.js +3 -3
  245. package/dist/kernel/client-ui-layout/package.json +2 -4
  246. package/dist/kernel/client-ui-message-feedback/lib/client.js +174 -58
  247. package/dist/kernel/client-ui-message-feedback/lib/types/client/MessageFeedbackActions.d.ts +9 -3
  248. package/dist/kernel/client-ui-message-feedback/lib/types/client/MessageFeedbackActions.js +164 -25
  249. package/dist/kernel/client-ui-message-feedback/lib/types/client/locales.d.ts +2 -0
  250. package/dist/kernel/client-ui-message-feedback/lib/types/client/locales.js +2 -0
  251. package/dist/kernel/client-ui-message-feedback/package.json +3 -5
  252. package/dist/kernel/client-ui-model-selection/lib/client.js +18 -18
  253. package/dist/kernel/client-ui-model-selection/package.json +7 -9
  254. package/dist/kernel/client-ui-permission-presets/lib/client.js +97 -83
  255. package/dist/kernel/client-ui-permission-presets/lib/types/client/index.js +6 -19
  256. package/dist/kernel/client-ui-permission-presets/lib/types/client/settings-store.d.ts +27 -18
  257. package/dist/kernel/client-ui-permission-presets/lib/types/client/settings-store.js +95 -68
  258. package/dist/kernel/client-ui-permission-presets/package.json +2 -8
  259. package/dist/kernel/client-ui-plan/lib/client.js +1 -1
  260. package/dist/kernel/client-ui-plan/lib/types/client/index.js +1 -1
  261. package/dist/kernel/client-ui-plan/package.json +2 -6
  262. package/dist/kernel/client-ui-primitives/lib/Button.module.css +79 -0
  263. package/dist/kernel/client-ui-primitives/lib/ConnectionBanner.module.css +13 -0
  264. package/dist/kernel/client-ui-primitives/lib/DiffBlock.module.css +107 -0
  265. package/dist/kernel/client-ui-primitives/lib/DisclosureRow.module.css +69 -0
  266. package/dist/kernel/client-ui-primitives/lib/HoverCard.module.css +54 -0
  267. package/dist/kernel/client-ui-primitives/lib/Input.module.css +38 -0
  268. package/dist/kernel/client-ui-primitives/lib/JsonTree.module.css +222 -0
  269. package/dist/kernel/client-ui-primitives/lib/Menu.module.css +242 -0
  270. package/dist/kernel/client-ui-primitives/lib/Modal.module.css +103 -0
  271. package/dist/kernel/client-ui-primitives/lib/OnboardingSurface.module.css +29 -0
  272. package/dist/kernel/client-ui-primitives/lib/Pill.module.css +27 -0
  273. package/dist/kernel/client-ui-primitives/lib/ReadBlock.module.css +117 -0
  274. package/dist/kernel/client-ui-primitives/lib/RiskConfirmation.module.css +73 -0
  275. package/dist/kernel/client-ui-primitives/lib/SearchBlock.module.css +120 -0
  276. package/dist/kernel/client-ui-primitives/lib/StateDot.module.css +65 -0
  277. package/dist/kernel/client-ui-primitives/lib/TerminalBlock.module.css +211 -0
  278. package/dist/kernel/client-ui-primitives/lib/Toast.module.css +70 -0
  279. package/dist/kernel/client-ui-primitives/lib/Tooltip.module.css +49 -0
  280. package/dist/kernel/client-ui-primitives/lib/WebBlock.module.css +130 -0
  281. package/dist/kernel/client-ui-primitives/lib/index.js +291 -261
  282. package/dist/kernel/client-ui-primitives/lib/invariant.js +2 -0
  283. package/dist/kernel/client-ui-primitives/lib/markdown/CodeBlock.module.css +96 -0
  284. package/dist/kernel/client-ui-primitives/lib/markdown/JsonBlock.module.css +32 -0
  285. package/dist/kernel/client-ui-primitives/lib/markdown/MarkdownText.module.css +304 -0
  286. package/dist/kernel/client-ui-primitives/lib/markdown/MessageText.module.css +9 -0
  287. package/dist/kernel/client-ui-primitives/lib/types/BrandWordmark.d.ts +7 -1
  288. package/dist/kernel/client-ui-primitives/lib/types/BrandWordmark.js +4 -2
  289. package/dist/kernel/client-ui-primitives/lib/types/index.d.ts +4 -1
  290. package/dist/kernel/client-ui-primitives/lib/types/index.js +2 -1
  291. package/dist/kernel/client-ui-primitives/lib/types/markdown/render.d.ts +2 -0
  292. package/dist/kernel/client-ui-primitives/lib/types/markdown/render.js +10 -2
  293. package/dist/kernel/client-ui-primitives/lib/types/useAnchoredPosition.d.ts +32 -0
  294. package/dist/kernel/client-ui-primitives/lib/types/useAnchoredPosition.js +69 -0
  295. package/dist/kernel/client-ui-primitives/package.json +2 -1
  296. package/dist/kernel/client-ui-reference/lib/client.js +149 -0
  297. package/dist/kernel/client-ui-reference/lib/index.js +11 -0
  298. package/dist/kernel/{client-schema-form → client-ui-reference}/lib/invariant.js +7 -8
  299. package/dist/kernel/client-ui-reference/lib/types/client/index.d.ts +9 -0
  300. package/dist/kernel/client-ui-reference/lib/types/client/index.js +106 -0
  301. package/dist/kernel/client-ui-reference/lib/types/client/locales.d.ts +30 -0
  302. package/dist/kernel/client-ui-reference/lib/types/client/locales.js +22 -0
  303. package/dist/kernel/client-ui-reference/lib/types/index.d.ts +9 -0
  304. package/dist/kernel/client-ui-reference/lib/types/index.js +9 -0
  305. package/dist/kernel/{client-schema-form → client-ui-reference}/lib/types/invariant.d.ts +3 -3
  306. package/dist/kernel/{client-schema-form → client-ui-reference}/lib/types/invariant.js +7 -8
  307. package/dist/kernel/client-ui-reference/package.json +77 -0
  308. package/dist/kernel/client-ui-renderer/lib/client.js +989 -0
  309. package/dist/kernel/client-ui-renderer/lib/index.js +6 -0
  310. package/dist/kernel/client-ui-renderer/lib/invariant.js +23 -0
  311. package/dist/kernel/{client-web/lib/types → client-ui-renderer/lib/types/client}/DocumentTitle.d.ts +4 -4
  312. package/dist/kernel/client-ui-renderer/lib/types/client/DocumentTitle.js +17 -0
  313. package/dist/kernel/client-ui-renderer/lib/types/client/app.d.ts +18 -0
  314. package/dist/kernel/{client-web/lib/types → client-ui-renderer/lib/types/client}/app.js +5 -5
  315. package/dist/kernel/{client-web-react/lib/types → client-ui-renderer/lib/types/client}/bind.d.ts +1 -1
  316. package/dist/kernel/client-ui-renderer/lib/types/client/index.d.ts +29 -0
  317. package/dist/kernel/client-ui-renderer/lib/types/client/index.js +51 -0
  318. package/dist/kernel/{client-web-react/lib/types → client-ui-renderer/lib/types/client}/scoped-slots.d.ts +1 -1
  319. package/dist/kernel/{client-web-react/lib/types → client-ui-renderer/lib/types/client}/scoped-slots.js +1 -1
  320. package/dist/kernel/{client-web-react/lib/types → client-ui-renderer/lib/types/client}/session-provider.d.ts +1 -1
  321. package/dist/kernel/client-ui-renderer/lib/types/index.d.ts +4 -0
  322. package/dist/kernel/client-ui-renderer/lib/types/index.js +4 -0
  323. package/dist/kernel/{client-web-react → client-ui-renderer}/lib/types/invariant.d.ts +3 -3
  324. package/dist/kernel/client-ui-renderer/lib/types/invariant.js +22 -0
  325. package/dist/kernel/client-ui-renderer/package.json +71 -0
  326. package/dist/kernel/client-ui-settings/lib/client.js +1177 -67
  327. package/dist/kernel/client-ui-settings/lib/types/client/index.d.ts +20 -12
  328. package/dist/kernel/client-ui-settings/lib/types/client/index.js +25 -6
  329. package/dist/kernel/client-ui-settings/lib/types/client/schema.d.ts +72 -0
  330. package/dist/kernel/client-ui-settings/lib/types/client/schema.js +152 -0
  331. package/dist/kernel/client-ui-settings/lib/types/client/settings-mirror.d.ts +118 -0
  332. package/dist/kernel/client-ui-settings/lib/types/client/settings-mirror.js +160 -0
  333. package/dist/kernel/client-ui-settings/lib/types/client/settings-scope.d.ts +51 -24
  334. package/dist/kernel/client-ui-settings/lib/types/client/settings-scope.js +88 -71
  335. package/dist/kernel/client-ui-settings/package.json +7 -7
  336. package/dist/kernel/client-ui-settings-general/lib/client.js +60 -64
  337. package/dist/kernel/client-ui-settings-general/lib/types/client/SettingsDocumentAction.d.ts +7 -6
  338. package/dist/kernel/client-ui-settings-general/lib/types/client/index.js +10 -11
  339. package/dist/kernel/client-ui-settings-general/lib/types/client/settings-document-store.d.ts +13 -11
  340. package/dist/kernel/client-ui-settings-general/lib/types/client/settings-document-store.js +37 -40
  341. package/dist/kernel/client-ui-settings-general/package.json +4 -8
  342. package/dist/kernel/client-ui-settings-models/lib/client.js +280 -210
  343. package/dist/kernel/client-ui-settings-models/lib/types/client/DeepSeekOnboardingDialog.d.ts +3 -0
  344. package/dist/kernel/client-ui-settings-models/lib/types/client/DeepSeekOnboardingDialog.js +2 -2
  345. package/dist/kernel/client-ui-settings-models/lib/types/client/ModelListEditor.js +11 -1
  346. package/dist/kernel/client-ui-settings-models/lib/types/client/ModelsSection.d.ts +10 -5
  347. package/dist/kernel/client-ui-settings-models/lib/types/client/ModelsSection.js +9 -6
  348. package/dist/kernel/client-ui-settings-models/lib/types/client/ProviderEditor.d.ts +3 -0
  349. package/dist/kernel/client-ui-settings-models/lib/types/client/ProviderEditor.js +30 -29
  350. package/dist/kernel/client-ui-settings-models/lib/types/client/index.js +27 -22
  351. package/dist/kernel/client-ui-settings-models/lib/types/client/locales.d.ts +2 -0
  352. package/dist/kernel/client-ui-settings-models/lib/types/client/locales.js +4 -0
  353. package/dist/kernel/client-ui-settings-models/lib/types/client/schema-operations.d.ts +10 -0
  354. package/dist/kernel/client-ui-settings-models/lib/types/client/schema-operations.js +17 -0
  355. package/dist/kernel/client-ui-settings-models/lib/types/client/store.d.ts +15 -7
  356. package/dist/kernel/client-ui-settings-models/lib/types/client/store.js +30 -21
  357. package/dist/kernel/client-ui-settings-models/lib/types/client/welcome-store.d.ts +35 -18
  358. package/dist/kernel/client-ui-settings-models/lib/types/client/welcome-store.js +89 -82
  359. package/dist/kernel/client-ui-settings-models/package.json +3 -8
  360. package/dist/kernel/client-ui-settings-plugin-inventory/lib/client.js +11 -11
  361. package/dist/kernel/client-ui-settings-plugin-inventory/package.json +2 -5
  362. package/dist/kernel/client-ui-settings-plugins/lib/client.js +42 -65
  363. package/dist/kernel/client-ui-settings-plugins/lib/types/client/index.js +5 -8
  364. package/dist/kernel/client-ui-settings-plugins/lib/types/client/tab-store.d.ts +8 -17
  365. package/dist/kernel/client-ui-settings-plugins/lib/types/client/tab-store.js +22 -44
  366. package/dist/kernel/client-ui-settings-plugins/package.json +2 -7
  367. package/dist/kernel/client-ui-sidebar/lib/client.js +50 -20
  368. package/dist/kernel/client-ui-sidebar/lib/types/client/SidebarRoot.js +7 -3
  369. package/dist/kernel/client-ui-sidebar/lib/types/client/contract/slots.d.ts +30 -1
  370. package/dist/kernel/client-ui-sidebar/lib/types/client/index.d.ts +1 -1
  371. package/dist/kernel/client-ui-sidebar/lib/types/client/index.js +2 -0
  372. package/dist/kernel/client-ui-sidebar/package.json +2 -4
  373. package/dist/kernel/client-ui-skill/lib/client.js +12 -12
  374. package/dist/kernel/client-ui-skill/package.json +2 -5
  375. package/dist/kernel/client-ui-slots/lib/index.js +2 -0
  376. package/dist/kernel/client-ui-slots/lib/invariant.js +2 -0
  377. package/dist/kernel/client-ui-slots/lib/types/renderer.d.ts +1 -1
  378. package/dist/kernel/client-ui-slots/lib/types/store.d.ts +1 -1
  379. package/dist/kernel/client-ui-slots/package.json +1 -1
  380. package/dist/kernel/client-ui-subagent/lib/client.js +289 -157
  381. package/dist/kernel/client-ui-subagent/lib/types/client/SubagentHeaderLineage.d.ts +18 -0
  382. package/dist/kernel/client-ui-subagent/lib/types/client/{SubagentCatalogAction.js → SubagentHeaderLineage.js} +153 -25
  383. package/dist/kernel/client-ui-subagent/lib/types/client/index.d.ts +4 -16
  384. package/dist/kernel/client-ui-subagent/lib/types/client/index.js +7 -45
  385. package/dist/kernel/client-ui-subagent/lib/types/client/locales.d.ts +1 -0
  386. package/dist/kernel/client-ui-subagent/lib/types/client/locales.js +2 -0
  387. package/dist/kernel/client-ui-subagent/package.json +6 -8
  388. package/dist/kernel/client-ui-theme/lib/client.js +46 -3
  389. package/dist/kernel/client-ui-theme/lib/index.js +22 -23
  390. package/dist/kernel/client-ui-theme/lib/types/boot-theme.d.ts +9 -10
  391. package/dist/kernel/client-ui-theme/lib/types/boot-theme.js +12 -19
  392. package/dist/kernel/client-ui-theme/lib/types/client/index.d.ts +1 -1
  393. package/dist/kernel/client-ui-theme/lib/types/client/index.js +3 -1
  394. package/dist/kernel/client-ui-theme/lib/types/client/styles.d.ts +7 -0
  395. package/dist/kernel/client-ui-theme/lib/types/client/styles.js +32 -0
  396. package/dist/kernel/client-ui-theme/lib/types/index.d.ts +4 -3
  397. package/dist/kernel/client-ui-theme/lib/types/index.js +7 -6
  398. package/dist/kernel/client-ui-theme/package.json +4 -6
  399. package/dist/kernel/client-ui-tool/lib/client.js +105 -65
  400. package/dist/kernel/client-ui-tool/lib/types/client/apply.d.ts +1 -2
  401. package/dist/kernel/client-ui-tool/lib/types/client/apply.js +6 -2
  402. package/dist/kernel/client-ui-tool/lib/types/client/contract/slots.d.ts +13 -3
  403. package/dist/kernel/client-ui-tool/lib/types/client/index.d.ts +1 -1
  404. package/dist/kernel/client-ui-tool/lib/types/client/tool/ToolCallTree.d.ts +1 -1
  405. package/dist/kernel/client-ui-tool/lib/types/client/tool/ToolCallTree.js +8 -6
  406. package/dist/kernel/client-ui-tool/lib/types/client/tool/ToolDetails.d.ts +2 -9
  407. package/dist/kernel/client-ui-tool/lib/types/client/tool/ToolDetails.js +4 -3
  408. package/dist/kernel/client-ui-tool/lib/types/client/tool/models/read-card-model.d.ts +4 -18
  409. package/dist/kernel/client-ui-tool/lib/types/client/tool/models/read-card-model.js +21 -4
  410. package/dist/kernel/client-ui-tool/lib/types/client/tool/models/tool-call-model.d.ts +2 -9
  411. package/dist/kernel/client-ui-tool/lib/types/client/tool/models/tool-call-model.js +22 -2
  412. package/dist/kernel/client-ui-tool/lib/types/client/tool/toolviews/GenericToolCard.d.ts +1 -1
  413. package/dist/kernel/client-ui-tool/lib/types/client/tool/toolviews/GenericToolCard.js +3 -3
  414. package/dist/kernel/client-ui-tool/lib/types/client/tool/toolviews/file-mutation-row.d.ts +1 -1
  415. package/dist/kernel/client-ui-tool/lib/types/client/tool/toolviews/file-mutation-row.js +2 -2
  416. package/dist/kernel/client-ui-tool/lib/types/client/tool/toolviews/read-row.d.ts +1 -1
  417. package/dist/kernel/client-ui-tool/lib/types/client/tool/toolviews/read-row.js +3 -3
  418. package/dist/kernel/client-ui-tool/package.json +4 -6
  419. package/dist/kernel/client-ui-trajectory/lib/client.js +144 -143
  420. package/dist/kernel/client-ui-trajectory/lib/types/client/trajectory-assistant-definition.js +2 -1
  421. package/dist/kernel/client-ui-trajectory/package.json +2 -4
  422. package/dist/kernel/client-ui-user-questions/lib/client.js +73 -36
  423. package/dist/kernel/client-ui-user-questions/lib/types/client/QuestionComposer.js +24 -6
  424. package/dist/kernel/client-ui-user-questions/package.json +12 -10
  425. package/dist/kernel/client-ui-workflow-run/lib/client.js +262 -87
  426. package/dist/kernel/client-ui-workflow-run/lib/types/client/WorkflowRunPanel.js +162 -23
  427. package/dist/kernel/client-ui-workflow-run/package.json +3 -7
  428. package/dist/kernel/client-ui-workspace/lib/client.js +96 -60
  429. package/dist/kernel/client-ui-workspace/lib/types/client/WorkspaceBrowser.d.ts +1 -1
  430. package/dist/kernel/client-ui-workspace/lib/types/client/WorkspaceBrowser.js +38 -6
  431. package/dist/kernel/client-ui-workspace/lib/types/client/contract/slots.d.ts +9 -7
  432. package/dist/kernel/client-ui-workspace/lib/types/client/index.js +4 -2
  433. package/dist/kernel/client-ui-workspace/lib/types/client/rows/Rows.d.ts +4 -1
  434. package/dist/kernel/client-ui-workspace/lib/types/client/rows/Rows.js +5 -3
  435. package/dist/kernel/client-ui-workspace/package.json +6 -4
  436. package/dist/kernel/client-web/lib/base.css +41 -0
  437. package/dist/kernel/client-web/lib/boot-page.module.css +104 -0
  438. package/dist/kernel/client-web/lib/index.js +154 -308
  439. package/dist/kernel/client-web/lib/invariant.js +2 -0
  440. package/dist/kernel/client-web/lib/types/boot-page.d.ts +46 -0
  441. package/dist/kernel/client-web/lib/types/boot-page.js +93 -0
  442. package/dist/kernel/client-web/lib/types/boot.d.ts +20 -33
  443. package/dist/kernel/client-web/lib/types/boot.js +76 -149
  444. package/dist/kernel/client-web/lib/types/index.d.ts +5 -11
  445. package/dist/kernel/client-web/lib/types/index.js +4 -10
  446. package/dist/kernel/client-web/lib/types/loader-status.d.ts +3 -51
  447. package/dist/kernel/client-web/lib/types/loader-status.js +0 -35
  448. package/dist/kernel/client-web/lib/types/platform.d.ts +3 -1
  449. package/dist/kernel/client-web/lib/types/platform.js +4 -3
  450. package/dist/kernel/client-web/lib/types/seed.js +0 -6
  451. package/dist/kernel/client-web/package.json +8 -15
  452. package/dist/kernel/cmdline/package.json +1 -1
  453. package/dist/kernel/code-runtime/package.json +1 -1
  454. package/dist/kernel/code-runtime-python/lib/index.js +413 -0
  455. package/dist/kernel/code-runtime-python/lib/invariant.js +24 -0
  456. package/dist/kernel/code-runtime-python/lib/types/index.d.ts +12 -0
  457. package/dist/kernel/code-runtime-python/lib/types/index.js +11 -0
  458. package/dist/kernel/code-runtime-python/lib/types/invariant.d.ts +16 -0
  459. package/dist/kernel/code-runtime-python/lib/types/invariant.js +23 -0
  460. package/dist/kernel/code-runtime-python/lib/types/protocol.d.ts +329 -0
  461. package/dist/kernel/code-runtime-python/lib/types/protocol.js +496 -0
  462. package/dist/kernel/{client-schema-form → code-runtime-python}/package.json +11 -14
  463. package/dist/kernel/code-runtime-python/py/protocol.py +138 -0
  464. package/dist/kernel/code-runtime-worker-thread/package.json +1 -1
  465. package/dist/kernel/command-compact/package.json +1 -1
  466. package/dist/kernel/command-feedback/package.json +1 -1
  467. package/dist/kernel/command-goal/lib/index.js +40 -6
  468. package/dist/kernel/command-goal/lib/types/index.js +35 -6
  469. package/dist/kernel/command-goal/package.json +2 -1
  470. package/dist/kernel/commands/lib/index.js +78 -21
  471. package/dist/kernel/commands/lib/typert.host.js +53 -9
  472. package/dist/kernel/commands/lib/typert.remote-client.d.ts +4 -3
  473. package/dist/kernel/commands/lib/typert.remote-client.js +18 -2
  474. package/dist/kernel/commands/lib/types/index.d.ts +20 -1
  475. package/dist/kernel/commands/lib/types/index.js +77 -20
  476. package/dist/kernel/commands/lib/types/types.d.ts +8 -0
  477. package/dist/kernel/commands/package.json +5 -1
  478. package/dist/kernel/compaction/package.json +1 -1
  479. package/dist/kernel/compaction-basic/package.json +1 -1
  480. package/dist/kernel/compaction-tool-result-pruner/package.json +1 -1
  481. package/dist/kernel/cordis/package.json +3 -1
  482. package/dist/kernel/cordis-client-runner/lib/client.js +171 -37
  483. package/dist/kernel/cordis-client-runner/lib/types/client/api-catalog.js +3 -3
  484. package/dist/kernel/cordis-client-runner/lib/types/client/slot-catalog.js +208 -30
  485. package/dist/kernel/cordis-client-runner/package.json +2 -5
  486. package/dist/kernel/cordis-host-runner/lib/index.js +28 -5
  487. package/dist/kernel/cordis-host-runner/lib/typert.host.js +54 -6
  488. package/dist/kernel/cordis-host-runner/lib/types/sandbox.d.ts +9 -3
  489. package/dist/kernel/cordis-host-runner/lib/types/sandbox.js +34 -6
  490. package/dist/kernel/cordis-host-runner/package.json +1 -1
  491. package/dist/kernel/cordis-plugin-group/package.json +3 -1
  492. package/dist/kernel/cordis-plugin-hmr/lib/types/index.js +1 -1
  493. package/dist/kernel/cordis-plugin-hmr/package.json +3 -1
  494. package/dist/kernel/cordis-plugin-include/lib/index.js +2 -2
  495. package/dist/kernel/cordis-plugin-include/lib/types/index.d.ts +2 -2
  496. package/dist/kernel/cordis-plugin-include/lib/types/index.js +2 -2
  497. package/dist/kernel/cordis-plugin-include/package.json +3 -1
  498. package/dist/kernel/cordis-plugin-loader/package.json +3 -1
  499. package/dist/kernel/cordis-plugin-logger-console/package.json +3 -1
  500. package/dist/kernel/cordis-plugin-timer/package.json +3 -1
  501. package/dist/kernel/cosmokit/package.json +3 -1
  502. package/dist/kernel/credentials/lib/index.js +104 -13
  503. package/dist/kernel/credentials/lib/invariant.js +3 -3
  504. package/dist/kernel/credentials/lib/types/index.d.ts +136 -7
  505. package/dist/kernel/credentials/lib/types/index.js +114 -15
  506. package/dist/kernel/credentials/lib/types/invariant.js +3 -3
  507. package/dist/kernel/credentials/lib/types/types.d.ts +58 -5
  508. package/dist/kernel/credentials/lib/types/types.js +4 -4
  509. package/dist/kernel/credentials/package.json +1 -1
  510. package/dist/kernel/credentials-local/lib/index.js +387 -29
  511. package/dist/kernel/credentials-local/lib/invariant.js +1 -1
  512. package/dist/kernel/credentials-local/lib/types/index.d.ts +57 -12
  513. package/dist/kernel/credentials-local/lib/types/index.js +445 -30
  514. package/dist/kernel/credentials-local/lib/types/invariant.js +1 -1
  515. package/dist/kernel/credentials-local/package.json +1 -1
  516. package/dist/kernel/e2b/package.json +1 -1
  517. package/dist/kernel/experimental-agent-team/lib/index.js +1728 -0
  518. package/dist/kernel/experimental-agent-team/lib/invariant.js +354 -0
  519. package/dist/kernel/experimental-agent-team/lib/types/activity.d.ts +23 -0
  520. package/dist/kernel/experimental-agent-team/lib/types/activity.js +85 -0
  521. package/dist/kernel/experimental-agent-team/lib/types/error.d.ts +13 -0
  522. package/dist/kernel/experimental-agent-team/lib/types/error.js +23 -0
  523. package/dist/kernel/experimental-agent-team/lib/types/fold.d.ts +44 -0
  524. package/dist/kernel/experimental-agent-team/lib/types/fold.js +243 -0
  525. package/dist/kernel/experimental-agent-team/lib/types/index.d.ts +115 -0
  526. package/dist/kernel/experimental-agent-team/lib/types/index.js +205 -0
  527. package/dist/kernel/experimental-agent-team/lib/types/invariant.d.ts +9 -0
  528. package/dist/kernel/experimental-agent-team/lib/types/invariant.js +29 -0
  529. package/dist/kernel/experimental-agent-team/lib/types/journal.d.ts +39 -0
  530. package/dist/kernel/experimental-agent-team/lib/types/journal.js +59 -0
  531. package/dist/kernel/experimental-agent-team/lib/types/lifecycle.d.ts +33 -0
  532. package/dist/kernel/experimental-agent-team/lib/types/lifecycle.js +85 -0
  533. package/dist/kernel/experimental-agent-team/lib/types/mailbox.d.ts +79 -0
  534. package/dist/kernel/experimental-agent-team/lib/types/mailbox.js +303 -0
  535. package/dist/kernel/experimental-agent-team/lib/types/roster.d.ts +113 -0
  536. package/dist/kernel/experimental-agent-team/lib/types/roster.js +445 -0
  537. package/dist/kernel/experimental-agent-team/lib/types/session-message.d.ts +11 -0
  538. package/dist/kernel/experimental-agent-team/lib/types/session-message.js +23 -0
  539. package/dist/kernel/experimental-agent-team/lib/types/task-board.d.ts +62 -0
  540. package/dist/kernel/experimental-agent-team/lib/types/task-board.js +275 -0
  541. package/dist/kernel/experimental-agent-team/lib/types/task-graph.d.ts +21 -0
  542. package/dist/kernel/experimental-agent-team/lib/types/task-graph.js +62 -0
  543. package/dist/kernel/experimental-agent-team/lib/types/types.d.ts +192 -0
  544. package/dist/kernel/experimental-agent-team/lib/types/types.js +26 -0
  545. package/dist/kernel/experimental-agent-team/lib/types/validation.d.ts +16 -0
  546. package/dist/kernel/experimental-agent-team/lib/types/validation.js +33 -0
  547. package/dist/kernel/experimental-agent-team/package.json +62 -0
  548. package/dist/kernel/experimental-tool-agent-team/lib/index.js +555 -0
  549. package/dist/kernel/experimental-tool-agent-team/lib/invariant.js +13 -0
  550. package/dist/kernel/experimental-tool-agent-team/lib/types/index.d.ts +19 -0
  551. package/dist/kernel/experimental-tool-agent-team/lib/types/index.js +379 -0
  552. package/dist/kernel/experimental-tool-agent-team/lib/types/invariant.d.ts +9 -0
  553. package/dist/kernel/experimental-tool-agent-team/lib/types/invariant.js +11 -0
  554. package/dist/kernel/experimental-tool-agent-team/package.json +61 -0
  555. package/dist/kernel/file-reference/lib/index.js +138 -0
  556. package/dist/kernel/file-reference/lib/invariant.js +23 -0
  557. package/dist/kernel/file-reference/lib/typert.host.d.ts +3 -0
  558. package/dist/kernel/file-reference/lib/typert.host.js +436 -0
  559. package/dist/kernel/file-reference/lib/typert.remote-client.d.ts +26 -0
  560. package/dist/kernel/file-reference/lib/typert.remote-client.js +59 -0
  561. package/dist/kernel/file-reference/lib/types/grammar.d.ts +33 -0
  562. package/dist/kernel/file-reference/lib/types/grammar.js +43 -0
  563. package/dist/kernel/file-reference/lib/types/index.d.ts +42 -0
  564. package/dist/kernel/file-reference/lib/types/index.js +75 -0
  565. package/dist/kernel/file-reference/lib/types/invariant.d.ts +16 -0
  566. package/dist/kernel/file-reference/lib/types/invariant.js +22 -0
  567. package/dist/kernel/file-reference/lib/types/types.d.ts +13 -0
  568. package/dist/kernel/file-reference/lib/types/types.js +7 -0
  569. package/dist/kernel/file-reference/package.json +70 -0
  570. package/dist/kernel/file-reference-local/lib/index.js +327 -0
  571. package/dist/kernel/file-reference-local/lib/invariant.js +23 -0
  572. package/dist/kernel/file-reference-local/lib/types/index.d.ts +35 -0
  573. package/dist/kernel/file-reference-local/lib/types/index.js +105 -0
  574. package/dist/kernel/file-reference-local/lib/types/invariant.d.ts +16 -0
  575. package/dist/kernel/file-reference-local/lib/types/invariant.js +22 -0
  576. package/dist/kernel/file-reference-local/lib/types/search.d.ts +52 -0
  577. package/dist/kernel/file-reference-local/lib/types/search.js +258 -0
  578. package/dist/kernel/file-reference-local/package.json +58 -0
  579. package/dist/kernel/fs/package.json +1 -1
  580. package/dist/kernel/fs-e2b/package.json +1 -1
  581. package/dist/kernel/fs-local/package.json +1 -1
  582. package/dist/kernel/fs-observation-policy/package.json +1 -1
  583. package/dist/kernel/fs-sandbox/package.json +1 -1
  584. package/dist/kernel/goal/lib/index.js +5 -2
  585. package/dist/kernel/goal/lib/typert.host.js +27 -3
  586. package/dist/kernel/goal/lib/types/index.js +2 -2
  587. package/dist/kernel/goal/lib/types/types.d.ts +3 -0
  588. package/dist/kernel/goal/package.json +1 -1
  589. package/dist/kernel/goal-round-driver/package.json +1 -1
  590. package/dist/kernel/headless/package.json +1 -1
  591. package/dist/kernel/home-paths/package.json +1 -1
  592. package/dist/kernel/hook-protocol/package.json +1 -1
  593. package/dist/kernel/hooks-claude-code/package.json +1 -1
  594. package/dist/kernel/hooks-codex/package.json +1 -1
  595. package/dist/kernel/host-apiproxy/lib/index.js +25 -57
  596. package/dist/kernel/host-apiproxy/lib/types/api/host.d.ts +2 -0
  597. package/dist/kernel/host-apiproxy/lib/types/api/host.schema.d.ts +1 -0
  598. package/dist/kernel/host-apiproxy/lib/types/api/host.schema.js +1 -0
  599. package/dist/kernel/host-apiproxy/lib/types/api/sessions.d.ts +4 -0
  600. package/dist/kernel/host-apiproxy/lib/types/api/sessions.schema.js +1 -0
  601. package/dist/kernel/host-apiproxy/lib/types/api-proxy.js +15 -53
  602. package/dist/kernel/host-apiproxy/package.json +1 -1
  603. package/dist/kernel/host-directory-picker/package.json +1 -1
  604. package/dist/kernel/host-directory-picker-auto/package.json +1 -1
  605. package/dist/kernel/host-directory-picker-browse/package.json +1 -1
  606. package/dist/kernel/host-directory-picker-native/package.json +1 -1
  607. package/dist/kernel/host-frontend-static/lib/index.js +34 -26
  608. package/dist/kernel/host-frontend-static/lib/types/index.d.ts +10 -10
  609. package/dist/kernel/host-frontend-static/lib/types/index.js +38 -27
  610. package/dist/kernel/host-frontend-static/package.json +2 -2
  611. package/dist/kernel/host-plugin-inventory/package.json +1 -1
  612. package/dist/kernel/host-webserver/lib/index.js +102 -6
  613. package/dist/kernel/host-webserver/lib/types/index.d.ts +33 -5
  614. package/dist/kernel/host-webserver/lib/types/index.js +28 -5
  615. package/dist/kernel/host-webserver/lib/types/injections.d.ts +56 -0
  616. package/dist/kernel/host-webserver/lib/types/injections.js +82 -0
  617. package/dist/kernel/host-webserver/package.json +1 -1
  618. package/dist/kernel/invariants/package.json +1 -1
  619. package/dist/kernel/jobs/package.json +1 -1
  620. package/dist/kernel/jobs-local/package.json +1 -1
  621. package/dist/kernel/launch-environment/package.json +1 -1
  622. package/dist/kernel/llm/lib/index.js +247 -25
  623. package/dist/kernel/llm/lib/types/assembler.d.ts +10 -1
  624. package/dist/kernel/llm/lib/types/assembler.js +20 -1
  625. package/dist/kernel/llm/lib/types/content.d.ts +59 -0
  626. package/dist/kernel/llm/lib/types/content.js +149 -0
  627. package/dist/kernel/llm/lib/types/index.d.ts +24 -1
  628. package/dist/kernel/llm/lib/types/index.js +61 -8
  629. package/dist/kernel/llm/lib/types/retry-policy.d.ts +1 -1
  630. package/dist/kernel/llm/lib/types/retry-policy.js +6 -2
  631. package/dist/kernel/llm/package.json +1 -1
  632. package/dist/kernel/llm-deepseek/lib/index.js +1100 -70
  633. package/dist/kernel/llm-deepseek/lib/types/adapter.d.ts +69 -1
  634. package/dist/kernel/llm-deepseek/lib/types/adapter.js +296 -60
  635. package/dist/kernel/llm-deepseek/lib/types/file-id.d.ts +19 -0
  636. package/dist/kernel/llm-deepseek/lib/types/file-id.js +18 -0
  637. package/dist/kernel/llm-deepseek/lib/types/file-store.d.ts +83 -0
  638. package/dist/kernel/llm-deepseek/lib/types/file-store.js +261 -0
  639. package/dist/kernel/llm-deepseek/lib/types/files-api.d.ts +103 -0
  640. package/dist/kernel/llm-deepseek/lib/types/files-api.js +206 -0
  641. package/dist/kernel/llm-deepseek/lib/types/index.d.ts +31 -3
  642. package/dist/kernel/llm-deepseek/lib/types/index.js +139 -3
  643. package/dist/kernel/llm-deepseek/lib/types/serialize.d.ts +55 -6
  644. package/dist/kernel/llm-deepseek/lib/types/serialize.js +179 -23
  645. package/dist/kernel/llm-deepseek/lib/types/types.d.ts +28 -5
  646. package/dist/kernel/llm-deepseek/lib/types/upload-index.d.ts +68 -0
  647. package/dist/kernel/llm-deepseek/lib/types/upload-index.js +171 -0
  648. package/dist/kernel/llm-deepseek/package.json +9 -1
  649. package/dist/kernel/llm-pi-ai/lib/index.js +1758 -1171
  650. package/dist/kernel/llm-pi-ai/lib/types/adapter.d.ts +30 -5
  651. package/dist/kernel/llm-pi-ai/lib/types/adapter.js +43 -23
  652. package/dist/kernel/llm-pi-ai/lib/types/auth.d.ts +60 -0
  653. package/dist/kernel/llm-pi-ai/lib/types/auth.js +196 -0
  654. package/dist/kernel/llm-pi-ai/lib/types/catalog.d.ts +176 -38
  655. package/dist/kernel/llm-pi-ai/lib/types/catalog.js +245 -50
  656. package/dist/kernel/llm-pi-ai/lib/types/config.d.ts +37 -5
  657. package/dist/kernel/llm-pi-ai/lib/types/config.js +67 -2
  658. package/dist/kernel/llm-pi-ai/lib/types/context.d.ts +8 -3
  659. package/dist/kernel/llm-pi-ai/lib/types/context.js +60 -16
  660. package/dist/kernel/llm-pi-ai/lib/types/index.d.ts +1 -0
  661. package/dist/kernel/llm-pi-ai/lib/types/index.js +21 -19
  662. package/dist/kernel/llm-pi-ai/lib/types/login.d.ts +21 -0
  663. package/dist/kernel/llm-pi-ai/lib/types/login.js +154 -0
  664. package/dist/kernel/llm-pi-ai/lib/types/stream.js +4 -0
  665. package/dist/kernel/llm-pi-ai/package.json +3 -1
  666. package/dist/kernel/llm-retry/package.json +1 -1
  667. package/dist/kernel/lsp/package.json +1 -1
  668. package/dist/kernel/lsp-stdio/package.json +1 -1
  669. package/dist/kernel/manifest.json +10 -2
  670. package/dist/kernel/mcp-client/package.json +1 -1
  671. package/dist/kernel/message-feedback/package.json +1 -1
  672. package/dist/kernel/native-command/package.json +1 -1
  673. package/dist/kernel/node-addon-landlock-run/lib/index.js +1 -1
  674. package/dist/kernel/node-addon-landlock-run/package.json +4 -2
  675. package/dist/kernel/output-retention/package.json +1 -1
  676. package/dist/kernel/permission-presets/lib/index.js +14 -2
  677. package/dist/kernel/permission-presets/lib/types/index.d.ts +5 -0
  678. package/dist/kernel/permission-presets/lib/types/index.js +11 -2
  679. package/dist/kernel/permission-presets/package.json +1 -1
  680. package/dist/kernel/persona/package.json +1 -1
  681. package/dist/kernel/plan-mode/lib/index.js +49 -15
  682. package/dist/kernel/plan-mode/lib/types/index.d.ts +22 -0
  683. package/dist/kernel/plan-mode/lib/types/index.js +45 -19
  684. package/dist/kernel/plan-mode/lib/types/types.d.ts +5 -4
  685. package/dist/kernel/plan-mode/package.json +1 -1
  686. package/dist/kernel/pwsh-local/package.json +1 -1
  687. package/dist/kernel/pwsh-sandbox/package.json +1 -1
  688. package/dist/kernel/repeat-tool-reminder/lib/index.js +1 -1
  689. package/dist/kernel/repeat-tool-reminder/package.json +1 -1
  690. package/dist/kernel/sandbox/package.json +1 -1
  691. package/dist/kernel/sandbox-local/lib/index.js +8 -13
  692. package/dist/kernel/sandbox-local/lib/types/index.d.ts +1 -3
  693. package/dist/kernel/sandbox-local/lib/types/index.js +4 -7
  694. package/dist/kernel/sandbox-local/lib/types/profiles.js +1 -1
  695. package/dist/kernel/sandbox-local/package.json +1 -1
  696. package/dist/kernel/sandbox-policy/package.json +1 -1
  697. package/dist/kernel/sandbox-windows-acl/package.json +1 -1
  698. package/dist/kernel/schedule/package.json +1 -1
  699. package/dist/kernel/schemastery/package.json +3 -1
  700. package/dist/kernel/scope/package.json +1 -1
  701. package/dist/kernel/sdk-client/lib/index.js +2 -2
  702. package/dist/kernel/sdk-client/lib/types/api.js +2 -2
  703. package/dist/kernel/sdk-client/lib/types/types.d.ts +4 -4
  704. package/dist/kernel/sdk-client/package.json +1 -1
  705. package/dist/kernel/sdk-jsonrpc-server/lib/index.js +12 -5
  706. package/dist/kernel/sdk-jsonrpc-server/lib/types/index.js +7 -0
  707. package/dist/kernel/sdk-jsonrpc-server/lib/types/server.d.ts +2 -1
  708. package/dist/kernel/sdk-jsonrpc-server/lib/types/server.js +15 -6
  709. package/dist/kernel/sdk-jsonrpc-server/package.json +2 -1
  710. package/dist/kernel/sdk-protocol/package.json +1 -1
  711. package/dist/kernel/session/lib/index.js +4 -0
  712. package/dist/kernel/session/lib/types/known-event-types.js +4 -0
  713. package/dist/kernel/session/lib/types/types.d.ts +6 -1
  714. package/dist/kernel/session/package.json +1 -1
  715. package/dist/kernel/session-checkpoint-policy/package.json +1 -1
  716. package/dist/kernel/session-log-export/package.json +2 -5
  717. package/dist/kernel/session-persistence/lib/index.js +1 -1
  718. package/dist/kernel/session-persistence/lib/types/coordinator.js +2 -1
  719. package/dist/kernel/session-persistence/package.json +1 -1
  720. package/dist/kernel/session-persistence-jsonl/package.json +1 -1
  721. package/dist/kernel/session-persistence-sqlite/lib/index.js +1105 -375
  722. package/dist/kernel/session-persistence-sqlite/lib/invariant.js +2 -2
  723. package/dist/kernel/session-persistence-sqlite/lib/types/codec.d.ts +72 -0
  724. package/dist/kernel/session-persistence-sqlite/lib/types/codec.js +304 -0
  725. package/dist/kernel/session-persistence-sqlite/lib/types/compression.d.ts +46 -0
  726. package/dist/kernel/session-persistence-sqlite/lib/types/compression.js +234 -0
  727. package/dist/kernel/session-persistence-sqlite/lib/types/index.d.ts +22 -80
  728. package/dist/kernel/session-persistence-sqlite/lib/types/index.js +27 -278
  729. package/dist/kernel/session-persistence-sqlite/lib/types/invariant.js +2 -2
  730. package/dist/kernel/session-persistence-sqlite/lib/types/schema.d.ts +63 -85
  731. package/dist/kernel/session-persistence-sqlite/lib/types/schema.js +293 -159
  732. package/dist/kernel/session-persistence-sqlite/lib/types/sql.d.ts +15 -0
  733. package/dist/kernel/session-persistence-sqlite/lib/types/sql.js +57 -0
  734. package/dist/kernel/session-persistence-sqlite/lib/types/store.d.ts +66 -0
  735. package/dist/kernel/session-persistence-sqlite/lib/types/store.js +394 -0
  736. package/dist/kernel/session-persistence-sqlite/package.json +9 -3
  737. package/dist/kernel/session-persistence-sqlite/resources/sql/begin-immediate.sql +1 -0
  738. package/dist/kernel/session-persistence-sqlite/resources/sql/begin.sql +1 -0
  739. package/dist/kernel/session-persistence-sqlite/resources/sql/commit.sql +1 -0
  740. package/dist/kernel/session-persistence-sqlite/resources/sql/delete-events-from.sql +2 -0
  741. package/dist/kernel/session-persistence-sqlite/resources/sql/foreign-keys-on.sql +1 -0
  742. package/dist/kernel/session-persistence-sqlite/resources/sql/insert-event.sql +3 -0
  743. package/dist/kernel/session-persistence-sqlite/resources/sql/insert-persistence-state.sql +2 -0
  744. package/dist/kernel/session-persistence-sqlite/resources/sql/journal-mode-delete.sql +1 -0
  745. package/dist/kernel/session-persistence-sqlite/resources/sql/journal-mode-persist.sql +1 -0
  746. package/dist/kernel/session-persistence-sqlite/resources/sql/journal-mode-truncate.sql +1 -0
  747. package/dist/kernel/session-persistence-sqlite/resources/sql/journal-mode-wal.sql +1 -0
  748. package/dist/kernel/session-persistence-sqlite/resources/sql/mmap-off.sql +1 -0
  749. package/dist/kernel/session-persistence-sqlite/resources/sql/rollback.sql +1 -0
  750. package/dist/kernel/session-persistence-sqlite/resources/sql/schema.sql +30 -0
  751. package/dist/kernel/session-persistence-sqlite/resources/sql/select-application-id.sql +1 -0
  752. package/dist/kernel/session-persistence-sqlite/resources/sql/select-events-from.sql +4 -0
  753. package/dist/kernel/session-persistence-sqlite/resources/sql/select-events.sql +4 -0
  754. package/dist/kernel/session-persistence-sqlite/resources/sql/select-mmap-size.sql +1 -0
  755. package/dist/kernel/session-persistence-sqlite/resources/sql/select-packed-predecessors.sql +6 -0
  756. package/dist/kernel/session-persistence-sqlite/resources/sql/select-schema-objects.sql +4 -0
  757. package/dist/kernel/session-persistence-sqlite/resources/sql/select-session.sql +4 -0
  758. package/dist/kernel/session-persistence-sqlite/resources/sql/select-sessions.sql +3 -0
  759. package/dist/kernel/session-persistence-sqlite/resources/sql/select-store-id.sql +3 -0
  760. package/dist/kernel/session-persistence-sqlite/resources/sql/select-synchronous.sql +1 -0
  761. package/dist/kernel/session-persistence-sqlite/resources/sql/select-tail-events.sql +5 -0
  762. package/dist/kernel/session-persistence-sqlite/resources/sql/select-trusted-schema.sql +1 -0
  763. package/dist/kernel/session-persistence-sqlite/resources/sql/select-user-object-count.sql +3 -0
  764. package/dist/kernel/session-persistence-sqlite/resources/sql/select-user-version.sql +1 -0
  765. package/dist/kernel/session-persistence-sqlite/resources/sql/set-application-id.sql +1 -0
  766. package/dist/kernel/session-persistence-sqlite/resources/sql/set-user-version-17.sql +1 -0
  767. package/dist/kernel/session-persistence-sqlite/resources/sql/synchronous-full.sql +1 -0
  768. package/dist/kernel/session-persistence-sqlite/resources/sql/trusted-schema-off.sql +1 -0
  769. package/dist/kernel/session-persistence-sqlite/resources/sql/update-session-revision.sql +3 -0
  770. package/dist/kernel/session-persistence-sqlite/resources/sql/upsert-session.sql +13 -0
  771. package/dist/kernel/session-projection/lib/index.js +55 -30
  772. package/dist/kernel/session-projection/lib/types/index.d.ts +57 -34
  773. package/dist/kernel/session-projection/lib/types/index.js +61 -36
  774. package/dist/kernel/session-projection/lib/types/types.d.ts +11 -4
  775. package/dist/kernel/session-projection/package.json +1 -1
  776. package/dist/kernel/session-projection-cache/lib/index.js +1 -1
  777. package/dist/kernel/session-projection-cache/lib/types/index.d.ts +1 -1
  778. package/dist/kernel/session-projection-cache/lib/types/index.js +4 -5
  779. package/dist/kernel/session-projection-cache/package.json +1 -1
  780. package/dist/kernel/session-query/package.json +1 -1
  781. package/dist/kernel/session-query-sqlite/package.json +1 -1
  782. package/dist/kernel/session-reference/lib/index.js +232 -110
  783. package/dist/kernel/session-reference/lib/typert.host.d.ts +3 -0
  784. package/dist/kernel/session-reference/lib/typert.host.js +458 -0
  785. package/dist/kernel/session-reference/lib/typert.remote-client.d.ts +26 -0
  786. package/dist/kernel/session-reference/lib/typert.remote-client.js +62 -0
  787. package/dist/kernel/session-reference/lib/types/index.d.ts +25 -5
  788. package/dist/kernel/session-reference/lib/types/index.js +230 -126
  789. package/dist/kernel/session-reference/lib/types/types.d.ts +14 -3
  790. package/dist/kernel/session-reference/lib/types/types.js +6 -1
  791. package/dist/kernel/session-reference/package.json +23 -3
  792. package/dist/kernel/session-stats/lib/index.js +31 -12
  793. package/dist/kernel/session-stats/lib/types/projection.d.ts +64 -2
  794. package/dist/kernel/session-stats/lib/types/projection.js +31 -12
  795. package/dist/kernel/session-stats/package.json +1 -1
  796. package/dist/kernel/session-telemetry/package.json +1 -1
  797. package/dist/kernel/session-telemetry-otel/package.json +1 -1
  798. package/dist/kernel/session-title/lib/index.js +6 -2
  799. package/dist/kernel/session-title/lib/types/index.js +3 -2
  800. package/dist/kernel/session-title/lib/types/types.d.ts +3 -0
  801. package/dist/kernel/session-title/package.json +1 -1
  802. package/dist/kernel/session-title-all-prompts-llm/package.json +1 -1
  803. package/dist/kernel/session-title-first-prompt-llm/package.json +1 -1
  804. package/dist/kernel/session-title-llm/package.json +1 -1
  805. package/dist/kernel/settings/package.json +1 -1
  806. package/dist/kernel/settings-file/package.json +1 -1
  807. package/dist/kernel/shell/package.json +1 -1
  808. package/dist/kernel/shell-env/package.json +1 -1
  809. package/dist/kernel/skill/package.json +1 -1
  810. package/dist/kernel/skill-badge/assets/nomix-badge.md +6 -6
  811. package/dist/kernel/skill-badge/assets/nomix-badge.png +0 -0
  812. package/dist/kernel/skill-badge/lib/index.js +1 -1
  813. package/dist/kernel/skill-badge/lib/types/index.js +1 -1
  814. package/dist/kernel/skill-badge/package.json +1 -1
  815. package/dist/kernel/skill-filesystem/package.json +1 -1
  816. package/dist/kernel/spill/package.json +1 -1
  817. package/dist/kernel/spill-local/package.json +1 -1
  818. package/dist/kernel/spill-policy/package.json +1 -1
  819. package/dist/kernel/storage/package.json +1 -1
  820. package/dist/kernel/storage-domain/package.json +1 -1
  821. package/dist/kernel/storage-json/package.json +1 -1
  822. package/dist/kernel/storage-sqlite/package.json +1 -1
  823. package/dist/kernel/subagent/lib/index.js +123 -20
  824. package/dist/kernel/subagent/lib/types/continuation.d.ts +21 -2
  825. package/dist/kernel/subagent/lib/types/continuation.js +58 -7
  826. package/dist/kernel/subagent/lib/types/index.d.ts +11 -0
  827. package/dist/kernel/subagent/lib/types/index.js +16 -0
  828. package/dist/kernel/subagent/lib/types/out-of-process.d.ts +2 -0
  829. package/dist/kernel/subagent/lib/types/out-of-process.js +31 -1
  830. package/dist/kernel/subagent/lib/types/projection.d.ts +55 -8
  831. package/dist/kernel/subagent/lib/types/projection.js +30 -15
  832. package/dist/kernel/subagent/lib/types/run-settlement.js +10 -3
  833. package/dist/kernel/subagent/lib/types/types.d.ts +7 -0
  834. package/dist/kernel/subagent/package.json +1 -1
  835. package/dist/kernel/subagent-acp/package.json +1 -1
  836. package/dist/kernel/subagent-claude-code/cordis.patch.yml +6 -0
  837. package/dist/kernel/subagent-claude-code/lib/index.js +267 -73
  838. package/dist/kernel/subagent-claude-code/lib/types/index.d.ts +16 -6
  839. package/dist/kernel/subagent-claude-code/lib/types/index.js +35 -14
  840. package/dist/kernel/subagent-claude-code/lib/types/process.d.ts +5 -7
  841. package/dist/kernel/subagent-claude-code/lib/types/process.js +12 -24
  842. package/dist/kernel/subagent-claude-code/lib/types/run.d.ts +24 -7
  843. package/dist/kernel/subagent-claude-code/lib/types/run.js +266 -40
  844. package/dist/kernel/subagent-claude-code/package.json +10 -2
  845. package/dist/kernel/subagent-codex/cordis.patch.yml +5 -0
  846. package/dist/kernel/subagent-codex/lib/index.js +482 -91
  847. package/dist/kernel/subagent-codex/lib/types/index.d.ts +11 -6
  848. package/dist/kernel/subagent-codex/lib/types/index.js +33 -12
  849. package/dist/kernel/subagent-codex/lib/types/run.d.ts +17 -8
  850. package/dist/kernel/subagent-codex/lib/types/run.js +235 -42
  851. package/dist/kernel/subagent-codex/lib/types/wire.d.ts +49 -1
  852. package/dist/kernel/subagent-codex/lib/types/wire.js +280 -33
  853. package/dist/kernel/subagent-codex/package.json +10 -5
  854. package/dist/kernel/subagent-fork-in-process/package.json +1 -1
  855. package/dist/kernel/subagent-in-process-driver/package.json +1 -1
  856. package/dist/kernel/subagent-nomix-sdk/package.json +1 -1
  857. package/dist/kernel/subagent-spawn-in-process/package.json +1 -1
  858. package/dist/kernel/subprocess/package.json +1 -1
  859. package/dist/kernel/subprocess-e2b/package.json +1 -1
  860. package/dist/kernel/subprocess-local/lib/index.js +303 -1
  861. package/dist/kernel/subprocess-local/lib/types/process-inspector.js +3 -0
  862. package/dist/kernel/subprocess-local/lib/types/terminal.d.ts +6 -1
  863. package/dist/kernel/subprocess-local/lib/types/terminal.js +78 -1
  864. package/dist/kernel/subprocess-local/lib/types/windows-inspector.d.ts +80 -0
  865. package/dist/kernel/subprocess-local/lib/types/windows-inspector.js +259 -0
  866. package/dist/kernel/subprocess-local/package.json +2 -1
  867. package/dist/kernel/system-prompt/package.json +1 -1
  868. package/dist/kernel/terminal/package.json +1 -1
  869. package/dist/kernel/terminal-bash/lib/index.js +85 -20
  870. package/dist/kernel/terminal-bash/lib/types/config.d.ts +29 -5
  871. package/dist/kernel/terminal-bash/lib/types/config.js +33 -3
  872. package/dist/kernel/terminal-bash/lib/types/index.d.ts +7 -0
  873. package/dist/kernel/terminal-bash/lib/types/index.js +65 -13
  874. package/dist/kernel/terminal-bash/package.json +2 -1
  875. package/dist/kernel/time-context/lib/index.js +1 -1
  876. package/dist/kernel/time-context/lib/invariant.js +1 -1
  877. package/dist/kernel/time-context/package.json +1 -1
  878. package/dist/kernel/timeout/package.json +1 -1
  879. package/dist/kernel/tmux-context/lib/index.js +1 -1
  880. package/dist/kernel/tmux-context/package.json +1 -1
  881. package/dist/kernel/token-meter/lib/index.js +77 -21
  882. package/dist/kernel/token-meter/lib/types/breakdown-projection.d.ts +76 -9
  883. package/dist/kernel/token-meter/lib/types/breakdown-projection.js +22 -6
  884. package/dist/kernel/token-meter/lib/types/usage-projection.d.ts +186 -25
  885. package/dist/kernel/token-meter/lib/types/usage-projection.js +44 -15
  886. package/dist/kernel/token-meter/package.json +1 -1
  887. package/dist/kernel/tool-ask-user/package.json +1 -1
  888. package/dist/kernel/tool-bash/package.json +1 -1
  889. package/dist/kernel/tool-bash-persistent/lib/index.js +15 -5
  890. package/dist/kernel/tool-bash-persistent/lib/types/index.js +23 -6
  891. package/dist/kernel/tool-bash-persistent/package.json +1 -1
  892. package/dist/kernel/tool-call-timeout-policy/package.json +1 -1
  893. package/dist/kernel/tool-cordis/lib/index.js +655 -83
  894. package/dist/kernel/tool-cordis/lib/types/api-catalog.js +439 -41
  895. package/dist/kernel/tool-cordis/package.json +1 -1
  896. package/dist/kernel/tool-fs/lib/index.js +80 -52
  897. package/dist/kernel/tool-fs/lib/types/read-image.d.ts +16 -12
  898. package/dist/kernel/tool-fs/lib/types/read-image.js +73 -29
  899. package/dist/kernel/tool-fs/package.json +1 -1
  900. package/dist/kernel/tool-fs-search/lib/index.js +11 -7
  901. package/dist/kernel/tool-fs-search/lib/types/search-core.d.ts +5 -6
  902. package/dist/kernel/tool-fs-search/lib/types/search-core.js +12 -7
  903. package/dist/kernel/tool-fs-search/package.json +1 -1
  904. package/dist/kernel/tool-goal/package.json +1 -1
  905. package/dist/kernel/tool-jobs/package.json +1 -1
  906. package/dist/kernel/tool-lsp/package.json +1 -1
  907. package/dist/kernel/tool-pwsh/package.json +1 -1
  908. package/dist/kernel/tool-pwsh-persistent/lib/index.js +407 -0
  909. package/dist/kernel/tool-pwsh-persistent/lib/invariant.js +24 -0
  910. package/dist/kernel/tool-pwsh-persistent/lib/types/index.d.ts +24 -0
  911. package/dist/kernel/tool-pwsh-persistent/lib/types/index.js +465 -0
  912. package/dist/kernel/tool-pwsh-persistent/lib/types/invariant.d.ts +16 -0
  913. package/dist/kernel/tool-pwsh-persistent/lib/types/invariant.js +23 -0
  914. package/dist/kernel/tool-pwsh-persistent/package.json +62 -0
  915. package/dist/kernel/tool-ralph/package.json +1 -1
  916. package/dist/kernel/tool-session-query/package.json +1 -1
  917. package/dist/kernel/tool-skill/package.json +1 -1
  918. package/dist/kernel/tool-str-replace-editor/package.json +1 -1
  919. package/dist/kernel/tool-subagent/lib/index.js +10 -8
  920. package/dist/kernel/tool-subagent/lib/types/index.js +15 -8
  921. package/dist/kernel/tool-subagent/package.json +1 -1
  922. package/dist/kernel/tool-subagent-control/package.json +1 -1
  923. package/dist/kernel/tool-subagent-report/lib/index.js +1 -1
  924. package/dist/kernel/tool-subagent-report/lib/types/index.d.ts +3 -3
  925. package/dist/kernel/tool-subagent-report/lib/types/index.js +1 -1
  926. package/dist/kernel/tool-subagent-report/package.json +1 -1
  927. package/dist/kernel/tool-terminal/package.json +1 -1
  928. package/dist/kernel/tool-todo/lib/index.js +5 -2
  929. package/dist/kernel/tool-todo/lib/types/index.js +2 -2
  930. package/dist/kernel/tool-todo/lib/types/types.d.ts +3 -0
  931. package/dist/kernel/tool-todo/package.json +1 -1
  932. package/dist/kernel/tool-web/lib/index.js +101 -26
  933. package/dist/kernel/tool-web/lib/types/index.d.ts +4 -2
  934. package/dist/kernel/tool-web/lib/types/index.js +5 -3
  935. package/dist/kernel/tool-web/lib/types/search.d.ts +23 -20
  936. package/dist/kernel/tool-web/lib/types/search.js +109 -20
  937. package/dist/kernel/tool-web/package.json +1 -1
  938. package/dist/kernel/tool-workflow/package.json +1 -1
  939. package/dist/kernel/tools/package.json +1 -1
  940. package/dist/kernel/typert-generator/lib/index.js +8 -3
  941. package/dist/kernel/typert-generator/lib/types/cordis-catalog.js +8 -3
  942. package/dist/kernel/typert-generator/package.json +1 -1
  943. package/dist/kernel/typert-loader/package.json +1 -1
  944. package/dist/kernel/typert-protocol/package.json +1 -1
  945. package/dist/kernel/typert-registry/package.json +1 -1
  946. package/dist/kernel/user-approval/package.json +1 -1
  947. package/dist/kernel/user-questions/package.json +1 -1
  948. package/dist/kernel/web/lib/types/types.d.ts +4 -3
  949. package/dist/kernel/web/package.json +1 -1
  950. package/dist/kernel/web-app/cordis.patch.yml +27 -6
  951. package/dist/kernel/web-app/lib/index.js +111 -15
  952. package/dist/kernel/web-app/lib/startup.js +4 -2
  953. package/dist/kernel/web-app/lib/types/index.d.ts +8 -4
  954. package/dist/kernel/web-app/lib/types/index.js +116 -23
  955. package/dist/kernel/web-app/lib/types/startup.d.ts +3 -1
  956. package/dist/kernel/web-app/lib/types/startup.js +4 -1
  957. package/dist/kernel/web-app/package.json +12 -2
  958. package/dist/kernel/web-fetch-http/lib/index.js +1 -1
  959. package/dist/kernel/web-fetch-http/lib/types/index.d.ts +1 -1
  960. package/dist/kernel/web-fetch-http/lib/types/index.js +1 -1
  961. package/dist/kernel/web-fetch-http/package.json +1 -1
  962. package/dist/kernel/web-frontend/dist/assets/index-BnapMmQ_.css +1 -0
  963. package/dist/kernel/web-frontend/dist/assets/index-Dx7Ws_OC.js +96 -0
  964. package/dist/kernel/web-frontend/dist/assets/langs/{php-D-uCvoST.js → php-DDkx9sim.js} +2 -2
  965. package/dist/{assets/web/assets/langs/ruby-DEItuUFs.js → kernel/web-frontend/dist/assets/langs/ruby-DCxyoPen.js} +2 -2
  966. package/dist/kernel/web-frontend/dist/assets/{vendor-Cjbwl5VI.js → vendor-D22_Mp1f.js} +2 -2
  967. package/dist/kernel/web-frontend/dist/favicon.svg +8 -0
  968. package/dist/kernel/web-frontend/dist/index.html +5 -5
  969. package/dist/kernel/web-frontend/package.json +5 -8
  970. package/dist/kernel/web-search-deepseek/lib/index.js +1 -1
  971. package/dist/kernel/web-search-deepseek/lib/types/provider.js +1 -1
  972. package/dist/kernel/web-search-deepseek/package.json +1 -1
  973. package/dist/kernel/web-search-exa/lib/index.js +1 -1
  974. package/dist/kernel/web-search-exa/lib/types/provider.js +1 -1
  975. package/dist/kernel/web-search-exa/package.json +1 -1
  976. package/dist/kernel/web-search-perplexity/lib/index.js +1 -1
  977. package/dist/kernel/web-search-perplexity/lib/types/provider.js +1 -1
  978. package/dist/kernel/web-search-perplexity/package.json +1 -1
  979. package/dist/kernel/workflow/package.json +1 -1
  980. package/dist/kernel/workflow-worker-thread/package.json +1 -1
  981. package/dist/kernel/workspace/package.json +1 -1
  982. package/dist/plugins/manifest.json +50 -10
  983. package/dist/runtime/index.js +0 -2
  984. package/package.json +8 -6
  985. package/dist/assets/web/assets/index-B_fSXASy.css +0 -1
  986. package/dist/assets/web/assets/index-B_sZ-Gsu.js +0 -112
  987. package/dist/cli/builtin-registry.d.ts +0 -5
  988. package/dist/cli/profile-boot-CeU09iFc.js +0 -2
  989. package/dist/kernel/app-boot/lib/types/legacy-branding.d.ts +0 -6
  990. package/dist/kernel/app-boot/lib/types/legacy-branding.js +0 -18
  991. package/dist/kernel/client-schema-form/lib/index.js +0 -137
  992. package/dist/kernel/client-schema-form/lib/types/index.d.ts +0 -10
  993. package/dist/kernel/client-schema-form/lib/types/index.js +0 -9
  994. package/dist/kernel/client-schema-form/lib/types/model.d.ts +0 -66
  995. package/dist/kernel/client-schema-form/lib/types/model.js +0 -153
  996. package/dist/kernel/client-ui-subagent/lib/types/client/SubagentCatalogAction.d.ts +0 -18
  997. package/dist/kernel/client-ui-theme/lib/styles/base.css +0 -15
  998. package/dist/kernel/client-ui-theme/lib/styles/design-platform.css +0 -338
  999. package/dist/kernel/client-ui-theme/lib/styles/gradient-shadow-text.css +0 -232
  1000. package/dist/kernel/client-ui-theme/lib/styles/scrollbar.css +0 -90
  1001. package/dist/kernel/client-ui-theme/lib/styles/shiki.css +0 -31
  1002. package/dist/kernel/client-web/lib/types/AppRoot.d.ts +0 -16
  1003. package/dist/kernel/client-web/lib/types/AppRoot.js +0 -27
  1004. package/dist/kernel/client-web/lib/types/DocumentTitle.js +0 -16
  1005. package/dist/kernel/client-web/lib/types/app-shell.d.ts +0 -28
  1006. package/dist/kernel/client-web/lib/types/app-shell.js +0 -27
  1007. package/dist/kernel/client-web/lib/types/app.d.ts +0 -21
  1008. package/dist/kernel/client-web-react/lib/index.js +0 -810
  1009. package/dist/kernel/client-web-react/lib/types/index.d.ts +0 -16
  1010. package/dist/kernel/client-web-react/lib/types/index.js +0 -6
  1011. package/dist/kernel/client-web-react/lib/types/use-invoke.d.ts +0 -9
  1012. package/dist/kernel/client-web-react/lib/types/use-invoke.js +0 -52
  1013. package/dist/kernel/skill-badge/assets/nomix-badge.svg +0 -8
  1014. package/dist/kernel/web-frontend/dist/assets/index-B_fSXASy.css +0 -1
  1015. package/dist/kernel/web-frontend/dist/assets/index-B_sZ-Gsu.js +0 -112
  1016. /package/dist/kernel/{client-web-react/lib/types → client-ui-renderer/lib/types/client}/bind.js +0 -0
  1017. /package/dist/kernel/{client-web-react/lib/types → client-ui-renderer/lib/types/client}/session-provider.js +0 -0
@@ -1,14 +1,17 @@
1
1
  import { launchEnvironmentOf } from "../../launch-environment/lib/index.js";
2
- import { CONTEXT_WINDOW_EXCEEDED_CODE, CallId, EMPTY_RESPONSE_CODE, INVALID_CREDENTIAL_CODE, LlmAdapter, LlmError, QUOTA_EXCEEDED_CODE, ReasoningEffortId, RetryPolicySchema, assertUsableApiKey, attributionHeaders, contentHasImage, isContextWindowExceededError, isQuotaExceededError, normalizeApiKey, resolveRetryPolicy } from "../../llm/lib/index.js";
2
+ import { CONTEXT_WINDOW_EXCEEDED_CODE, CallId, EMPTY_RESPONSE_CODE, INVALID_CREDENTIAL_CODE, LlmAdapter, LlmError, QUOTA_EXCEEDED_CODE, ReasoningEffortId, RetryPolicySchema, assertUsableApiKey, attributionHeaders, contentHasImage, isContextWindowExceededError, isQuotaExceededError, normalizeApiKey, offloadRequestImagesWithPolicy, requestImageHandleText, resolveRetryPolicy } from "../../llm/lib/index.js";
3
3
  import { deepEqualJson, installSettingsSection, settingsNamespace } from "../../settings/lib/index.js";
4
4
  import { createModels, createProvider, getSupportedThinkingLevels, isContextOverflow } from "@earendil-works/pi-ai";
5
5
  import { MAX_TIMER_DELAY_MS, idleWatchdog, timeoutOf } from "../../timeout/lib/index.js";
6
- import { builtinProviders, getBuiltinModels, getBuiltinProviders } from "@earendil-works/pi-ai/providers/all";
7
6
  import z from "../../schemastery/lib/index.mjs";
8
- import { credentialRef } from "../../credentials/lib/index.js";
7
+ import { credentialKey, credentialKeyId, credentialKeyScope, credentialRef, isCredentialKeySegment, isCredentialRefName } from "../../credentials/lib/index.js";
8
+ import { builtinProviders, getBuiltinModels, getBuiltinProviders } from "@earendil-works/pi-ai/providers/all";
9
9
  import { anthropicMessagesApi } from "@earendil-works/pi-ai/api/anthropic-messages.lazy";
10
10
  import { openAICompletionsApi } from "@earendil-works/pi-ai/api/openai-completions.lazy";
11
11
  import { openAIResponsesApi } from "@earendil-works/pi-ai/api/openai-responses.lazy";
12
+ import { homedir } from "node:os";
13
+ import { access } from "node:fs/promises";
14
+ import { resolve } from "node:path";
12
15
  //#region lib/types/replay.js
13
16
  /**
14
17
  * Durable pi-ai replay metadata and assistant-history reconstruction.
@@ -241,1269 +244,1700 @@ function toPiAssistant(message, onDegrade) {
241
244
  }
242
245
  }
243
246
  //#endregion
244
- //#region lib/types/context.js
247
+ //#region lib/types/catalog.js
245
248
  /**
246
- * Harness request-history conversion into pi-ai's Context vocabulary.
249
+ * Materialization of one provider route's model catalog. The installed pi-ai
250
+ * catalog supplies defaults keyed by model id, and a profile's own model
251
+ * entries override them field by field, so a route naming a catalog provider
252
+ * stays configuration-free while a route pi-ai has never heard of is fully
253
+ * describable from `settings.yaml`.
247
254
  *
248
- * @module nomix-llm-pi-ai/context
255
+ * Every pi-ai `Model` field the harness cannot default is required here rather
256
+ * than at request time: an unserviceable route fails while its configuration is
257
+ * being resolved, which is the earliest point that can name the offending key.
258
+ *
259
+ * @module nomix-llm-pi-ai/catalog
249
260
  */
250
- /** Join the text blocks of a harness message. */
251
- function flattenText(message) {
252
- return message.content.filter((block) => block.type === "text").map((block) => block.text).join("");
253
- }
254
- /** Flatten text recursively inside one tool result. */
255
- function toolResultText(blocks) {
256
- return blocks.map((block) => block.type === "text" ? block.text : block.type === "tool-result" ? toolResultText(block.content) : "").join("");
257
- }
258
- async function userContent(blocks, attachments) {
259
- const content = [];
260
- for (const block of blocks) switch (block.type) {
261
- case "text":
262
- if (block.text.length > 0) content.push({
263
- type: "text",
264
- text: block.text
265
- });
266
- break;
267
- case "image": {
268
- const stored = await attachments.readImage(block.attachment);
269
- content.push({
270
- type: "image",
271
- data: Buffer.from(stored.data).toString("base64"),
272
- mimeType: stored.ref.mediaType
273
- });
274
- break;
275
- }
276
- case "tool-result":
277
- {
278
- const nested = await userContent(block.content, attachments);
279
- if (typeof nested === "string") {
280
- if (nested.length > 0) content.push({
281
- type: "text",
282
- text: nested
283
- });
284
- } else content.push(...nested);
285
- }
286
- break;
287
- default: break;
288
- }
289
- if (content.every((block) => block.type === "text")) return content.map((block) => block.text).join("");
290
- return content;
291
- }
292
- function toolsOf(options) {
293
- return options.tools?.map((tool) => ({
294
- name: tool.name,
295
- description: tool.description,
296
- parameters: tool.parameters
297
- }));
261
+ /**
262
+ * Pricing for a model the installed catalog does not describe. The harness
263
+ * never reads pi-ai's cost metadata — `replay.ts` zeroes it and no consumer
264
+ * reports spend — so this is the absence of a fact, not a configurable rate.
265
+ */
266
+ const NO_COST = {
267
+ input: 0,
268
+ output: 0,
269
+ cacheRead: 0,
270
+ cacheWrite: 0
271
+ };
272
+ /** Every request modality a profile may declare. */
273
+ const MODALITIES = Object.keys({
274
+ text: true,
275
+ image: true
276
+ });
277
+ /**
278
+ * One entry's modality list, or `undefined` when it states no answer. Absent
279
+ * and empty mean the same thing — `[]` describes a model that accepts nothing
280
+ * and could serve no request — which is what makes an entry naming a catalog
281
+ * model without declaring modalities keep the catalog's, since the config
282
+ * schema materializes `[]` for an absent array.
283
+ * @param configured - the list a `models` or `modelOverrides` entry supplied.
284
+ * @returns the declared modalities, or `undefined` to ask the next level.
285
+ */
286
+ function declaredInput(configured) {
287
+ return configured === void 0 || configured.length === 0 ? void 0 : [...configured];
298
288
  }
299
- /** Assemble the request-level pi-ai context envelope shared by both conversion paths. */
300
- function piContext(options, messages) {
301
- const tools = toolsOf(options);
302
- return {
303
- ...options.system !== void 0 ? { systemPrompt: options.system } : {},
304
- messages,
305
- ...tools !== void 0 && tools.length > 0 ? { tools } : {}
306
- };
289
+ /** Every pi-ai thinking level a profile may declare, in escalation order. */
290
+ const THINKING_LEVELS = Object.keys({
291
+ off: true,
292
+ minimal: true,
293
+ low: true,
294
+ medium: true,
295
+ high: true,
296
+ xhigh: true,
297
+ max: true
298
+ });
299
+ /** Reasoning-dispatch wire formats a profile may name, most-reached first. */
300
+ const SUPPORTED_THINKING_FORMATS = Object.keys({
301
+ "openai": true,
302
+ "deepseek": true,
303
+ "openrouter": true,
304
+ "together": true,
305
+ "zai": true,
306
+ "qwen": true,
307
+ "chat-template": true,
308
+ "qwen-chat-template": true,
309
+ "string-thinking": true,
310
+ "ant-ling": true
311
+ });
312
+ /** The output-cap field spellings a profile may name. */
313
+ const MAX_TOKENS_FIELDS = Object.keys({
314
+ max_completion_tokens: true,
315
+ max_tokens: true
316
+ });
317
+ /** The prompt-cache marker conventions a profile may name. */
318
+ const CACHE_CONTROL_FORMATS = Object.keys({ anthropic: true });
319
+ /** The request-state placeholders a profile may name. */
320
+ const CHAT_TEMPLATE_VARS = Object.keys({
321
+ "thinking.enabled": true,
322
+ "thinking.effort": true
323
+ });
324
+ let providerIndex;
325
+ /**
326
+ * Installed catalog providers by id, constructed once. Each entry owns the API
327
+ * implementations for its own models, which is why a catalog route reuses this
328
+ * provider instead of being rebuilt from parts.
329
+ * @returns the catalog provider index.
330
+ */
331
+ function catalogProviders() {
332
+ providerIndex ??= new Map(builtinProviders().map((provider) => [provider.id, provider]));
333
+ return providerIndex;
307
334
  }
308
- function textOnlyContext(options, onReplayDegrade) {
309
- const toolNames = /* @__PURE__ */ new Map();
310
- const messages = [];
311
- for (const message of options.messages) {
312
- if (contentHasImage(message.content)) throw new LlmError("pi-ai image conversion requires the durable attachment service", "UNSUPPORTED_CONTENT");
313
- if (message.role === "system") {
314
- messages.push({
315
- role: "user",
316
- content: flattenText(message),
317
- timestamp: 0
318
- });
319
- continue;
320
- }
321
- if (message.role === "assistant") {
322
- const assistant = toPiAssistant(message, onReplayDegrade);
323
- for (const block of assistant.content) if (block.type === "toolCall") toolNames.set(CallId(block.id), block.name);
324
- messages.push(assistant);
325
- continue;
326
- }
327
- const text = flattenText(message);
328
- const results = message.content.filter((block) => block.type === "tool-result");
329
- if (text.length > 0 || results.length === 0) messages.push({
330
- role: "user",
331
- content: text,
332
- timestamp: 0
333
- });
334
- for (const result of results) messages.push({
335
- role: "toolResult",
336
- toolCallId: result.toolCallId,
337
- toolName: toolNames.get(result.toolCallId) ?? "unknown",
338
- content: [{
339
- type: "text",
340
- text: toolResultText(result.content) || "(no output)"
341
- }],
342
- isError: result.isError ?? false,
343
- timestamp: 0
344
- });
345
- }
346
- return piContext(options, messages);
335
+ /**
336
+ * The installed catalog provider for one route, when pi-ai ships one.
337
+ * @param provider - provider route key.
338
+ * @returns the catalog provider, or `undefined` for a route pi-ai does not ship.
339
+ */
340
+ function catalogProvider(provider) {
341
+ return catalogProviders().get(provider);
347
342
  }
348
- function toPiContext(options, attachments, onReplayDegrade) {
349
- return attachments === void 0 ? textOnlyContext(options, onReplayDegrade) : toPiContextWithImages(options, attachments, onReplayDegrade);
343
+ /**
344
+ * Every provider route the installed pi-ai catalog ships.
345
+ * @returns the catalog provider ids.
346
+ */
347
+ function catalogProviderIds() {
348
+ return getBuiltinProviders();
350
349
  }
351
- async function toPiContextWithImages(options, attachments, onReplayDegrade) {
352
- const toolNames = /* @__PURE__ */ new Map();
353
- const messages = [];
354
- for (const message of options.messages) {
355
- if (message.role === "system") {
356
- if (contentHasImage(message.content)) throw new LlmError("pi-ai cannot represent an image in an in-history system message", "UNSUPPORTED_CONTENT");
357
- messages.push({
358
- role: "user",
359
- content: flattenText(message),
360
- timestamp: 0
361
- });
362
- continue;
363
- }
364
- if (message.role === "assistant") {
365
- const assistant = toPiAssistant(message, onReplayDegrade);
366
- for (const block of assistant.content) if (block.type === "toolCall") toolNames.set(CallId(block.id), block.name);
367
- messages.push(assistant);
368
- continue;
369
- }
370
- const content = await userContent(message.content.filter((block) => block.type !== "tool-result"), attachments);
371
- const results = message.content.filter((block) => block.type === "tool-result");
372
- if (content.length > 0 || results.length === 0) messages.push({
373
- role: "user",
374
- content,
375
- timestamp: 0
376
- });
377
- for (const result of results) {
378
- const resultContent = await userContent(result.content, attachments);
379
- messages.push({
380
- role: "toolResult",
381
- toolCallId: result.toolCallId,
382
- toolName: toolNames.get(result.toolCallId) ?? "unknown",
383
- content: typeof resultContent === "string" ? [{
384
- type: "text",
385
- text: resultContent || "(no output)"
386
- }] : resultContent,
387
- isError: result.isError ?? false,
388
- timestamp: 0
389
- });
390
- }
391
- }
392
- return piContext(options, messages);
350
+ /**
351
+ * The installed catalog models for one route, indexed by model id.
352
+ * @param provider - provider route key.
353
+ * @returns catalog models by id; empty for a route pi-ai does not ship.
354
+ */
355
+ function catalogModels(provider) {
356
+ if (!catalogProviders().has(provider)) return /* @__PURE__ */ new Map();
357
+ const models = getBuiltinModels(provider);
358
+ return new Map(models.map((model) => [model.id, model]));
393
359
  }
394
- //#endregion
395
- //#region lib/types/stream.js
396
360
  /**
397
- * pi-ai assistant event translation into the Harness streaming protocol.
361
+ * Disposition of every `OpenAICompletionsCompat` field. The `Record` key type
362
+ * is a drift gate: a pi-ai upgrade that adds a field fails compilation here
363
+ * until it is classified, so the offer never silently lags the upstream set.
364
+ */
365
+ const COMPLETIONS_COMPAT_GATE = {
366
+ supportsStore: "offer",
367
+ supportsDeveloperRole: "offer",
368
+ supportsReasoningEffort: "offer",
369
+ supportsUsageInStreaming: "offer",
370
+ maxTokensField: "offer",
371
+ requiresToolResultName: "offer",
372
+ requiresAssistantAfterToolResult: "offer",
373
+ requiresThinkingAsText: "offer",
374
+ requiresReasoningContentOnAssistantMessages: "offer",
375
+ thinkingFormat: "offer",
376
+ chatTemplateKwargs: "offer",
377
+ supportsStrictMode: "offer",
378
+ cacheControlFormat: "offer",
379
+ supportsLongCacheRetention: "offer",
380
+ openRouterRouting: "withhold",
381
+ vercelGatewayRouting: "withhold",
382
+ zaiToolStream: "withhold",
383
+ supportsOpenAIGrammarTools: "withhold",
384
+ sendSessionAffinityHeaders: "withhold",
385
+ deferredToolsMode: "withhold",
386
+ sessionAffinityFormat: "withhold"
387
+ };
388
+ /** Disposition of every `OpenAIResponsesCompat` field; a drift gate like the one above. */
389
+ const RESPONSES_COMPAT_GATE = {
390
+ supportsDeveloperRole: "offer",
391
+ supportsStrictMode: "offer",
392
+ supportsLongCacheRetention: "offer",
393
+ sessionAffinityFormat: "withhold",
394
+ supportsOpenAIGrammarTools: "withhold",
395
+ supportsToolSearch: "withhold",
396
+ supportsExplicitPromptCacheMode: "withhold"
397
+ };
398
+ /**
399
+ * The compat gate of every wire protocol a profile may configure.
398
400
  *
399
- * pi-ai tool-call arguments are parsed objects while the Harness keeps their
400
- * raw JSON representation. pi-ai also reports failures as terminal stream
401
- * events, which this module maps into Harness finish chunks.
401
+ * Keyed by protocol, but grouped by pi-ai's compat *type*: the three Responses
402
+ * protocols share `OpenAIResponsesCompat`, so a switch settable on one is
403
+ * settable on all three. Keying by protocol alone would refuse
404
+ * `azure-openai-responses` and `openai-codex-responses` the fields their own
405
+ * models declare.
406
+ */
407
+ const COMPAT_GATES = {
408
+ "openai-completions": COMPLETIONS_COMPAT_GATE,
409
+ "openai-responses": RESPONSES_COMPAT_GATE,
410
+ "azure-openai-responses": RESPONSES_COMPAT_GATE,
411
+ "openai-codex-responses": RESPONSES_COMPAT_GATE,
412
+ "anthropic-messages": {
413
+ supportsEagerToolInputStreaming: "offer",
414
+ supportsLongCacheRetention: "offer",
415
+ supportsCacheControlOnTools: "offer",
416
+ supportsTemperature: "offer",
417
+ forceAdaptiveThinking: "offer",
418
+ allowEmptySignature: "offer",
419
+ supportsStrictTools: "offer",
420
+ sendSessionAffinityHeaders: "withhold",
421
+ supportsToolReferences: "withhold"
422
+ },
423
+ "bedrock-converse-stream": { supportsStrictMode: "offer" }
424
+ };
425
+ /**
426
+ * The compat gate of one resolved protocol. A `string` lookup rather than a
427
+ * keyed read: a route's `api` is configuration, so it may name a protocol
428
+ * pi-ai gives no compat type — or none at all.
429
+ * @param api - resolved wire protocol.
430
+ * @returns that protocol's field gate, or `undefined` when it takes no compat.
431
+ */
432
+ function compatGate(api) {
433
+ return COMPAT_GATES[api];
434
+ }
435
+ /**
436
+ * The compat entries a profile actually set.
402
437
  *
403
- * @module nomix-llm-pi-ai/stream
438
+ * schemastery materializes an absent dict as `{}` — the behavior
439
+ * `reasoningEfforts` works around with a union — so every parsed profile
440
+ * carries a `chatTemplateKwargs` key whether or not anyone wrote one. An empty
441
+ * one states nothing here: it would send no kwargs, which is exactly what
442
+ * leaving the field out does, so absent and empty are the same request and
443
+ * neither may make a route look like it configured a switch. A valueless
444
+ * scalar is the other thing schemastery lets through, and it is refused by
445
+ * {@link assertOfferedCompatFields} before this runs rather than filtered.
446
+ * @param compat - the configured switches, when any.
447
+ * @returns the entries carrying a value, in declaration order.
404
448
  */
449
+ function configuredCompatEntries(compat) {
450
+ return Object.entries(compat ?? {}).flatMap(([field, value]) => {
451
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).length === 0 ? [] : [[field, value]];
452
+ });
453
+ }
405
454
  /**
406
- * Map pi-ai usage (reasoning folded into output by pi-ai).
407
- * @param usage - cumulative usage from the terminal pi-ai event.
408
- * @returns harness counts; cache fields appear only when non-zero (pi-ai reports zeros, not absence).
455
+ * The protocols offering one compat field, in {@link COMPAT_GATES} order.
456
+ * @param field - configured compat field name.
457
+ * @returns the protocols whose compat takes it; empty when none does, which
458
+ * is either a withheld field or a name no upstream compat type declares.
409
459
  */
410
- function mapUsage(usage) {
411
- return {
412
- inputTokens: usage.input,
413
- outputTokens: usage.output,
414
- ...usage.cacheRead > 0 ? { cacheReadTokens: usage.cacheRead } : {},
415
- ...usage.cacheWrite > 0 ? { cacheWriteTokens: usage.cacheWrite } : {}
416
- };
460
+ function compatProtocols(field) {
461
+ return Object.entries(COMPAT_GATES).flatMap(([api, gate]) => gate[field] === "offer" ? [api] : []);
417
462
  }
418
- function classifyPiAiError(message) {
419
- if (/\b(?:401|403)\b/.test(message)) return "AUTH";
420
- if (isQuotaExceededError(message)) return QUOTA_EXCEEDED_CODE;
421
- if (/\b429\b|rate.?limit/i.test(message)) return "RATE_LIMIT";
422
- if (/\b400\b|invalid.?request/i.test(message)) return "INVALID_REQUEST";
423
- if (/\b5\d\d\b/.test(message)) return "SERVER";
424
- if (/\btime(?:d)?\s*out\b|timeout/i.test(message)) return "TIMEOUT";
425
- if (/stream ended (?:before|without)\b/i.test(message)) return "TRANSPORT";
426
- if (/\b(?:network|connection|socket|fetch)\b|\bECONN[A-Z]+\b/i.test(message) || /\b(?:other side closed|HTTP2 request did not get a response|WebSocket closed unexpectedly)\b/i.test(message) || /\bterminated\b|premature close/i.test(message)) return "TRANSPORT";
427
- return "PI_AI_ERROR";
463
+ /**
464
+ * The compat fields one protocol offers, for a diagnostic that has to show
465
+ * what was available instead of the name that missed.
466
+ * @param api - wire protocol.
467
+ * @returns the offered field names, or an empty list for a protocol taking no compat.
468
+ */
469
+ function offeredCompatFields(api) {
470
+ return Object.entries(compatGate(api) ?? {}).flatMap(([field, disposition]) => disposition === "offer" ? [field] : []);
428
471
  }
429
472
  /**
430
- * Map a terminal pi-ai event to the harness finish reason.
431
- * @param message - the assistant message carried by the `done` or `error` event.
432
- * @param contextWindow - resolved catalog capacity for usage-based overflow detection.
433
- * @returns the mapped harness reason. Recognized error text, `stop` usage above
434
- * `contextWindow`, and zero-output `length` usage that fills the window map
435
- * to `CONTEXT_WINDOW_EXCEEDED`; a `stop` with no content blocks maps to an
436
- * `EMPTY_RESPONSE` error.
473
+ * Every offered field name, deduplicated, for the one diagnostic that cannot
474
+ * narrow by protocol: the vocabulary check runs before any protocol resolves,
475
+ * which is what lets it refuse a misspelling on a route whose models would
476
+ * never have reached the protocol that declares the intended field.
477
+ * @returns the offered field names across every protocol, in gate order.
437
478
  */
438
- function mapStopReason(message, contextWindow) {
439
- const piAiOverflow = isContextOverflow(message, contextWindow);
440
- const harnessOverflow = message.stopReason === "error" && message.errorMessage !== void 0 && isContextWindowExceededError(message.errorMessage);
441
- if (piAiOverflow || harnessOverflow) return {
442
- kind: "error",
443
- failure: {
444
- message: message.errorMessage ?? `pi-ai detected context overflow for model "${message.model}"`,
445
- code: CONTEXT_WINDOW_EXCEEDED_CODE
446
- }
447
- };
448
- switch (message.stopReason) {
449
- case "stop":
450
- if (message.content.length === 0) return {
451
- kind: "error",
452
- failure: {
453
- message: `model "${message.model}" returned a completed response with no content`,
454
- code: EMPTY_RESPONSE_CODE
455
- }
456
- };
457
- return { kind: "stop" };
458
- case "length": return { kind: "max-tokens" };
459
- case "toolUse": return { kind: "tool-calls" };
460
- case "aborted": return {
461
- kind: "aborted",
462
- failure: {
463
- message: message.errorMessage ?? "pi-ai stream aborted",
464
- code: "ABORTED"
465
- }
466
- };
467
- case "error": {
468
- const text = message.errorMessage ?? "pi-ai stream error";
469
- return {
470
- kind: "error",
471
- failure: {
472
- message: text,
473
- code: classifyPiAiError(text)
474
- }
475
- };
476
- }
477
- }
479
+ function allOfferedCompatFields() {
480
+ const fields = /* @__PURE__ */ new Set();
481
+ for (const api of Object.keys(COMPAT_GATES)) for (const field of offeredCompatFields(api)) fields.add(field);
482
+ return [...fields];
478
483
  }
479
484
  /**
480
- * Translate the pi-ai event stream into StreamChunks. pi-ai never throws
481
- * mid-stream failures arrive as `error` events, which become error/aborted
482
- * `finish` chunks (the harness protocol's other error-delivery style).
483
- * @param events - one assistant turn's pi-ai event stream.
484
- * @param contextWindow - resolved catalog capacity for usage-based overflow detection.
485
- * @returns the harness chunks, ending with `usage` then `finish`; throws
486
- * `LlmError` (`STREAM_CLOSED`) if the source ends without a terminal event.
485
+ * Reject a compat key no protocol offers. Runs before any protocol is
486
+ * resolved, so a withheld field or a misspelling fails even on a route whose
487
+ * models never reach the protocol that would have taken it — the alternative
488
+ * being the silent drop that let an unreadable switch look applied.
489
+ * @param provider - provider route key, for diagnostics.
490
+ * @param site - the configuration site, for diagnostics.
491
+ * @param compat - the configured switches, when any.
492
+ * @throws Error naming the offending key.
487
493
  */
488
- async function* toStreamChunks(events, contextWindow) {
489
- const toolIds = /* @__PURE__ */ new Map();
490
- for await (const event of events) switch (event.type) {
491
- case "start": break;
492
- case "text_start":
493
- yield {
494
- type: "block-start",
495
- index: event.contentIndex,
496
- blockType: "text"
497
- };
498
- break;
499
- case "text_delta":
500
- yield {
501
- type: "text-delta",
502
- index: event.contentIndex,
503
- text: event.delta
504
- };
505
- break;
506
- case "text_end":
507
- yield {
508
- type: "block-end",
509
- index: event.contentIndex,
510
- block: {
511
- type: "text",
512
- text: event.content
513
- }
514
- };
515
- break;
516
- case "thinking_start":
517
- yield {
518
- type: "block-start",
519
- index: event.contentIndex,
520
- blockType: "reasoning"
521
- };
522
- break;
523
- case "thinking_delta":
524
- yield {
525
- type: "reasoning-delta",
526
- index: event.contentIndex,
527
- text: event.delta
528
- };
529
- break;
530
- case "thinking_end":
531
- yield {
532
- type: "block-end",
533
- index: event.contentIndex,
534
- block: {
535
- type: "reasoning",
536
- text: event.content
537
- }
538
- };
539
- break;
540
- case "toolcall_start": {
541
- const partial = event.partial.content[event.contentIndex];
542
- const id = partial?.type === "toolCall" ? partial.id : "";
543
- const name = partial?.type === "toolCall" ? partial.name : "";
544
- toolIds.set(event.contentIndex, {
545
- id,
546
- name
547
- });
548
- yield {
549
- type: "block-start",
550
- index: event.contentIndex,
551
- blockType: "tool-call"
552
- };
553
- break;
554
- }
555
- case "toolcall_delta": {
556
- const known = toolIds.get(event.contentIndex);
557
- yield {
558
- type: "tool-call-delta",
559
- index: event.contentIndex,
560
- id: CallId(known?.id ?? ""),
561
- ...known?.name !== void 0 && known.name.length > 0 ? { name: known.name } : {},
562
- argumentsDelta: event.delta
563
- };
564
- break;
494
+ function assertOfferedCompatFields(provider, site, compat) {
495
+ for (const [field, value] of Object.entries(compat ?? {})) {
496
+ if (compatProtocols(field).length === 0) {
497
+ if (Object.values(COMPAT_GATES).some((gate) => gate[field] !== void 0)) invalid(provider, `${site} sets compat "${field}", which is not configurable here: pi-ai's installed catalog sets it for the vendors that need it, so name that provider as the route instead`);
498
+ invalid(provider, `${site} sets compat "${field}", which no wire protocol declares; the configurable switches are ${allOfferedCompatFields().join(", ")}`);
565
499
  }
566
- case "toolcall_end":
567
- yield {
568
- type: "block-end",
569
- index: event.contentIndex,
570
- block: {
571
- type: "tool-call",
572
- id: CallId(event.toolCall.id),
573
- name: event.toolCall.name,
574
- arguments: JSON.stringify(event.toolCall.arguments)
575
- }
576
- };
577
- break;
578
- case "done":
579
- yield {
580
- type: "usage",
581
- usage: mapUsage(event.message.usage)
582
- };
583
- yield {
584
- type: "finish",
585
- reason: mapStopReason(event.message, contextWindow),
586
- replayState: toPiReplayState(event.message)
587
- };
588
- return;
589
- case "error":
590
- yield {
591
- type: "usage",
592
- usage: mapUsage(event.error.usage)
593
- };
594
- yield {
595
- type: "finish",
596
- reason: mapStopReason(event.error, contextWindow)
597
- };
598
- return;
500
+ if (value == null) invalid(provider, `${site} sets compat "${field}" with no value; give it one, or remove the key to leave the field to the next layer — the installed catalog entry, then pi-ai's own detection`);
599
501
  }
600
- throw new LlmError("pi-ai event stream ended without done/error", "STREAM_CLOSED");
601
502
  }
602
- //#endregion
603
- //#region lib/types/adapter.js
503
+ /** Report a route the deployment cannot serve, naming the settings key at fault. */
504
+ function invalid(provider, detail) {
505
+ throw new Error(`llm-pi-ai: provider "${provider}" ${detail}`);
506
+ }
604
507
  /**
605
- * Generic pi-ai-backed implementation of the Harness LLM seam.
606
- *
607
- * Each resolution produces one **immutable** snapshot the profiles plus a
608
- * `Models` collection holding the `Provider` each route built and an
609
- * operation captures a whole snapshot before its first `await`. A
610
- * configuration change builds a *new* collection rather than mutating the one
611
- * in use, because `Models.streamSimple()` is lazy: it resolves the provider
612
- * when the stream is first consumed, which is after the credential await, so a
613
- * mutated collection would let a request that started under one configuration
614
- * finish under another or fail with a provider that no longer exists. This is
615
- * what makes the seam's per-step call freeze (`llm.prepareCall()`) hold all the
616
- * way down: switching models mid-reply takes effect on the next step, never
617
- * inside the one in flight.
508
+ * The one wire protocol a catalog route's shipped models agree on. This is what
509
+ * lets a deployment add a model the installed catalog has not caught up with —
510
+ * a provider's newest release without restating the protocol its siblings
511
+ * already use. A route whose shipped models disagree (an OpenAI-style catalog
512
+ * spanning Responses and Chat Completions) has no such answer, so a model it
513
+ * does not describe must name its protocol at the route.
514
+ */
515
+ function sharedCatalogApi(defaults) {
516
+ const apis = /* @__PURE__ */ new Set();
517
+ for (const model of defaults.values()) apis.add(model.api);
518
+ return apis.size === 1 ? [...apis][0] : void 0;
519
+ }
520
+ /**
521
+ * Resolve one model's reasoning capability from its declared efforts.
618
522
  *
619
- * Credentials stay outside that collection. The harness resolves a route's key
620
- * through its own seam and passes it as the request's `apiKey` option, which
621
- * pi-ai treats as the highest-priority auth override so `Models` never holds
622
- * a credential store and the harness keeps its fail-loud reference semantics.
523
+ * A declared dict translates to pi-ai's `thinkingLevelMap` with every level
524
+ * decided explicitly: declared levels carry their wire spelling, undeclared
525
+ * levels are pinned to `null` (unsupported). Pinning matters because pi-ai's
526
+ * own defaulting is asymmetric an absent key means "supported" for the five
527
+ * base levels but "unsupported" for `xhigh`/`max` — and a profile author
528
+ * should not need to know that. A declared `off` with no value is the one
529
+ * exception: it stays absent from the map, which pi-ai reads as "supported,
530
+ * send nothing" — the correct dispatch where not thinking is the parameter's
531
+ * absence — while `off` with a value sends that value.
532
+ * @param provider - provider route key, for diagnostics.
533
+ * @param entry - the configured model entry.
534
+ * @param base - the installed catalog entry of the same id, when one exists.
535
+ * @returns the reasoning fields the materialized model carries.
536
+ */
537
+ function resolveModelReasoning(provider, entry, base) {
538
+ const efforts = entry.reasoningEfforts;
539
+ if (efforts === void 0) return { reasoning: base?.reasoning ?? false };
540
+ if (efforts === false) return { reasoning: false };
541
+ if (efforts === null || Object.keys(efforts).length === 0) invalid(provider, `model "${entry.id}" has an empty reasoningEfforts; declare the offered levels, set false for a non-reasoning model, or omit the field to keep the installed catalog's capability`);
542
+ const declared = THINKING_LEVELS.flatMap((level) => {
543
+ const wire = efforts[level];
544
+ return wire === void 0 ? [] : [[level, wire]];
545
+ });
546
+ for (const [level, wire] of declared) if (wire === null) {
547
+ if (level !== "off") invalid(provider, `model "${entry.id}" reasoningEfforts.${level} needs the wire value dispatch should send; only "off" may leave it empty`);
548
+ } else if (wire.length === 0) invalid(provider, `model "${entry.id}" reasoningEfforts.${level} must not be an empty string`);
549
+ if (!declared.some(([level]) => level !== "off")) invalid(provider, `model "${entry.id}" reasoningEfforts offers no level beyond "off"; declare a thinking level, or set reasoningEfforts to false for a non-reasoning model`);
550
+ const map = {};
551
+ for (const level of THINKING_LEVELS) {
552
+ const wire = efforts[level];
553
+ if (wire === void 0) map[level] = null;
554
+ else if (wire !== null) map[level] = wire;
555
+ }
556
+ return {
557
+ reasoning: true,
558
+ thinkingLevelMap: map
559
+ };
560
+ }
561
+ /**
562
+ * Resolve one model's compat block from the profile's switches.
623
563
  *
624
- * @module nomix-llm-pi-ai/adapter
564
+ * A model switch wins over the route switch field by field; whatever neither
565
+ * sets keeps the installed entry's value, and a field no layer decides falls
566
+ * through to pi-ai's own detection. A model-level switch its protocol does not
567
+ * take fails resolution — about one named model it can only be a mistake —
568
+ * while a route-level one skips past such models, since a route default must
569
+ * stay settable on a route whose models do not all speak one protocol. Every
570
+ * field reaching here is offered by some protocol; {@link
571
+ * assertOfferedCompatFields} has already refused the rest.
572
+ * @param provider - provider route key, for diagnostics.
573
+ * @param entry - the configured model entry.
574
+ * @param route - the route-level switches, when any.
575
+ * @param base - the installed catalog entry of the same id, when one exists.
576
+ * @param api - the model's resolved wire protocol.
577
+ * @returns a `compat` field to spread into the model, or nothing.
625
578
  */
626
- var __addDisposableResource = function(env, value, async) {
627
- if (value !== null && value !== void 0) {
628
- if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
629
- var dispose, inner;
630
- if (async) {
631
- if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
632
- dispose = value[Symbol.asyncDispose];
633
- }
634
- if (dispose === void 0) {
635
- if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
636
- dispose = value[Symbol.dispose];
637
- if (async) inner = dispose;
579
+ function resolveModelCompat(provider, entry, route, base, api) {
580
+ const gate = compatGate(api);
581
+ const configured = {};
582
+ for (const [field, value] of configuredCompatEntries(route)) {
583
+ if (gate?.[field] !== "offer") continue;
584
+ configured[field] = value;
585
+ }
586
+ for (const [field, value] of configuredCompatEntries(entry.compat)) {
587
+ if (gate?.[field] !== "offer") {
588
+ const offered = offeredCompatFields(api);
589
+ invalid(provider, `model "${entry.id}" sets compat "${field}", but its api is "${api}", which does not take it; that switch exists on ${compatProtocols(field).join(", ")}, and "${api}" offers ${offered.length === 0 ? "no configurable compat" : offered.join(", ")}`);
638
590
  }
639
- if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
640
- if (inner) dispose = function() {
641
- try {
642
- inner.call(this);
643
- } catch (e) {
644
- return Promise.reject(e);
645
- }
591
+ configured[field] = value;
592
+ }
593
+ if (Object.keys(configured).length === 0) return {};
594
+ return { compat: {
595
+ ...base?.api === api ? base.compat : void 0,
596
+ ...configured
597
+ } };
598
+ }
599
+ /**
600
+ * Materialize one route's catalog by merging the installed catalog defaults
601
+ * under the configured entries. A route with no configured `models` serves the
602
+ * installed catalog unchanged, which is what keeps an existing
603
+ * `providers: { deepseek: { apiKeyEnv: … } }` profile working untouched.
604
+ * @param request - the route-level catalog facts.
605
+ * @returns the materialized models and the explicitly configured request caps.
606
+ */
607
+ function resolveRouteModels(request) {
608
+ const { provider } = request;
609
+ const defaults = catalogModels(provider);
610
+ const providerBaseUrl = catalogProvider(provider)?.baseUrl;
611
+ const configured = request.models ?? [];
612
+ const overrides = request.modelOverrides ?? {};
613
+ for (const [id, override] of Object.entries(overrides)) {
614
+ if (id.length === 0) invalid(provider, "has a modelOverrides entry with an empty model id");
615
+ if (defaults.size === 0) invalid(provider, `sets modelOverrides for "${id}", but the installed catalog does not describe this route; a declared route spells every model out in its models list`);
616
+ if (configured.length > 0) invalid(provider, `sets modelOverrides for "${id}" beside a models list; models already replaces the served catalog, so declare the fields on its entries`);
617
+ if (!defaults.has(id)) invalid(provider, `modelOverrides names "${id}", which the installed catalog does not describe`);
618
+ if ("id" in override) invalid(provider, `modelOverrides entry "${id}" sets "id", which is the dict key`);
619
+ }
620
+ const entries = configured.length > 0 ? configured : [...defaults.values()].map((model) => ({
621
+ id: model.id,
622
+ ...overrides[model.id]
623
+ }));
624
+ if (entries.length === 0) invalid(provider, "resolves no models; the installed catalog does not describe this route, so its models must be listed in configuration");
625
+ const routeApi = sharedCatalogApi(defaults);
626
+ assertOfferedCompatFields(provider, "route", request.compat);
627
+ for (const entry of entries) assertOfferedCompatFields(provider, `model "${entry.id}"`, entry.compat);
628
+ const seen = /* @__PURE__ */ new Set();
629
+ const configuredMaxTokens = /* @__PURE__ */ new Map();
630
+ const models = entries.map((entry) => {
631
+ if (entry.id.length === 0) invalid(provider, "has a model with an empty id");
632
+ if (seen.has(entry.id)) invalid(provider, `lists model "${entry.id}" more than once`);
633
+ seen.add(entry.id);
634
+ const base = defaults.get(entry.id);
635
+ const api = request.api ?? base?.api ?? routeApi;
636
+ if (api === void 0) invalid(provider, `model "${entry.id}" needs an api; the installed catalog does not describe it, so set the route's api to the wire protocol its endpoint speaks`);
637
+ const baseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;
638
+ if (baseUrl === void 0) invalid(provider, `model "${entry.id}" needs a baseURL; the installed catalog does not describe this route`);
639
+ const contextWindow = entry.contextWindow ?? base?.contextWindow ?? request.defaultContextWindow;
640
+ if (!Number.isInteger(contextWindow) || contextWindow <= 0) invalid(provider, `model "${entry.id}" contextWindow must be a positive integer`);
641
+ const maxTokens = entry.maxTokens ?? base?.maxTokens ?? request.defaultMaxTokens;
642
+ if (!Number.isInteger(maxTokens) || maxTokens <= 0) invalid(provider, `model "${entry.id}" maxTokens must be a positive integer`);
643
+ if (entry.maxTokens !== void 0) configuredMaxTokens.set(entry.id, entry.maxTokens);
644
+ return {
645
+ ...base,
646
+ id: entry.id,
647
+ name: entry.name ?? base?.name ?? entry.id,
648
+ api,
649
+ provider,
650
+ baseUrl,
651
+ input: declaredInput(entry.input) ?? base?.input ?? [...request.defaultInput],
652
+ cost: base?.cost ?? NO_COST,
653
+ contextWindow,
654
+ maxTokens,
655
+ ...resolveModelReasoning(provider, entry, base),
656
+ ...resolveModelCompat(provider, entry, request.compat, base, api)
646
657
  };
647
- env.stack.push({
648
- value,
649
- dispose,
650
- async
651
- });
652
- } else if (async) env.stack.push({ async: true });
653
- return value;
654
- };
655
- var __disposeResources = (function(SuppressedError) {
656
- return function(env) {
657
- function fail(e) {
658
- env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
659
- env.hasError = true;
660
- }
661
- var r, s = 0;
662
- function next() {
663
- while (r = env.stack.pop()) try {
664
- if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
665
- if (r.dispose) {
666
- var result = r.dispose.call(r.value);
667
- if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
668
- fail(e);
669
- return next();
670
- });
671
- } else s |= 1;
672
- } catch (e) {
673
- fail(e);
674
- }
675
- if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
676
- if (env.hasError) throw env.error;
677
- }
678
- return next();
679
- };
680
- })(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
681
- var e = new Error(message);
682
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
683
- });
684
- /** Copy profile stream knobs into pi-ai's common option vocabulary. */
685
- function profileOptions(profile, reasoning, apiKey) {
686
- const enabledReasoning = reasoning === "off" ? void 0 : reasoning;
658
+ });
659
+ for (const [field] of configuredCompatEntries(request.compat)) {
660
+ const takers = compatProtocols(field);
661
+ if (models.some((model) => takers.includes(model.api))) continue;
662
+ invalid(provider, `sets compat "${field}", but no model on the route speaks a protocol that takes it; it exists on ${takers.join(", ")}`);
663
+ }
687
664
  return {
688
- ...apiKey === void 0 ? {} : { apiKey },
689
- ...enabledReasoning === void 0 ? {} : { reasoning: enabledReasoning },
690
- ...profile.thinkingBudgets === void 0 ? {} : { thinkingBudgets: profile.thinkingBudgets },
691
- ...profile.cacheRetention === void 0 ? {} : { cacheRetention: profile.cacheRetention },
692
- ...profile.transport === void 0 ? {} : { transport: profile.transport },
693
- ...profile.timeoutMs === void 0 ? {} : { timeoutMs: profile.timeoutMs },
694
- ...profile.websocketConnectTimeoutMs === void 0 ? {} : { websocketConnectTimeoutMs: profile.websocketConnectTimeoutMs },
695
- maxRetries: 0
665
+ models,
666
+ configuredMaxTokens
696
667
  };
697
668
  }
669
+ //#endregion
670
+ //#region lib/types/provider.js
698
671
  /**
699
- * The profile default this exact model can actually take, for DESCRIBING it.
700
- * A configured level the model does not support yields none rather than
701
- * throwing: `resolveModel` builds the model catalog, and a catalog that fails
702
- * takes its whole provider out of every picker so one mis-set profile field
703
- * would hide every model on the route, including the ones that support the
704
- * level. The request path still refuses, which is where a bad configuration
705
- * belongs: describing what a model can do must not fail because a deployment
706
- * asked it for something it cannot.
707
- * @param model - the resolved model descriptor.
708
- * @param effort - the profile's configured level, if any.
709
- * @returns the level when this model supports it, otherwise undefined.
672
+ * Construction of the pi-ai `Provider` that one configured route registers into
673
+ * the adapter's `Models` collection.
674
+ *
675
+ * Two constructions, one decision: a route the installed catalog ships, whose
676
+ * profile does not override the wire protocol, **reuses that catalog provider**
677
+ * with its models replaced the catalog provider owns API implementations this
678
+ * package cannot reconstruct (Bedrock loads its Smithy module through a
679
+ * separate entry point), so rebuilding it from parts would silently narrow
680
+ * which providers work. Every other route — one pi-ai has never heard of, or a
681
+ * catalog route pointed at a different protocol is built by `createProvider`
682
+ * over the protocol table below.
683
+ *
684
+ * Credentials never reach this module's storage: the harness resolves a route's
685
+ * key through `ctx.credentials` before the request enters pi-ai and hands it
686
+ * over as a stream option, which `Models` presents to `resolve()` as the
687
+ * credential key.
688
+ *
689
+ * @module nomix-llm-pi-ai/provider
710
690
  */
711
- function describableReasoningLevel(model, effort) {
712
- if (effort === void 0) return void 0;
713
- return getSupportedThinkingLevels(model).some((level) => level === effort) ? effort : void 0;
714
- }
715
- /** Validate an explicit Harness/profile effort without invoking pi-ai's clamp. */
716
- function resolveReasoningLevel(model, effort) {
717
- if (effort === void 0) return void 0;
718
- if (getSupportedThinkingLevels(model).some((level) => level === effort)) return effort;
719
- throw new LlmError(`pi-ai provider "${model.provider}" model "${model.id}" does not support reasoning effort "${effort}"`, "UNSUPPORTED_REASONING_EFFORT");
720
- }
721
691
  /**
722
- * Selectable reasoning efforts for one model, or nothing at all.
692
+ * Wire protocols a configured route may name, mapped to pi-ai's lazily loaded
693
+ * implementations. Each entry is the factory that pi-ai's matching provider
694
+ * factory uses, so a hand-declared route reaches exactly the implementation a
695
+ * catalog route would.
723
696
  *
724
- * A model that carries no reasoning metadata every hand-declared one, and
725
- * every catalog model pi-ai marks as non-reasoning is reported by pi-ai as
726
- * supporting the single level `off`. Passing that through would offer a control
727
- * that cannot do what it says: `off` is translated to *omitting* the reasoning
728
- * option, which for such a model is byte-for-byte the same request as naming no
729
- * effort so a provider whose own default is to think would keep thinking with
730
- * `off` selected. Omitting `reasoning` entirely is the seam's way of saying the
731
- * capability is unavailable, which leaves the surface offering only the
732
- * provider's default.
733
- * @param model - the resolved model descriptor.
734
- * @param defaultLevel - the profile's configured effort, already validated.
735
- * @returns the `reasoning` field, or an empty object when none can be offered.
697
+ * The table is deliberately narrow: the protocols a hand-declared route
698
+ * actually reaches for today, each completely describable with a key, an
699
+ * endpoint, and headers. Bedrock signs with SigV4 over AWS credentials and a
700
+ * region, Vertex needs a project, a location, and application-default
701
+ * credentials, Azure needs provider environment plus an api-version, and Codex
702
+ * authenticates through OAuth none of which this configuration shape can
703
+ * express, so offering them would hand back a provider that cannot
704
+ * authenticate. The remainder are absent for want of a consumer rather than a
705
+ * blocker: each is one line here once a deployment needs it. Catalog routes
706
+ * still reach every protocol through their own provider; only an explicit
707
+ * override is refused.
736
708
  */
737
- function reasoningInfo(model, defaultLevel) {
738
- if (!model.reasoning) return {};
739
- return { reasoning: {
740
- efforts: getSupportedThinkingLevels(model).map((level) => ({
741
- id: ReasoningEffortId(level),
742
- name: `${level.charAt(0).toUpperCase()}${level.slice(1)}`
743
- })),
744
- ...defaultLevel === void 0 ? {} : { defaultEffort: ReasoningEffortId(defaultLevel) }
745
- } };
709
+ const PROTOCOLS = {
710
+ "openai-completions": openAICompletionsApi,
711
+ "openai-responses": openAIResponsesApi,
712
+ "anthropic-messages": anthropicMessagesApi
713
+ };
714
+ /**
715
+ * Every wire protocol a configured route may name, most-reached first. The
716
+ * order is the table's and therefore stable; a configuration surface offering
717
+ * a choice presents the first as its default, which is why the protocol a
718
+ * hand-declared gateway most often speaks — and the one endpoint interrogation
719
+ * can read — leads.
720
+ * @returns the supported protocol identifiers.
721
+ */
722
+ function supportedProtocols() {
723
+ return Object.keys(PROTOCOLS);
746
724
  }
747
- /** Merge deployment headers while removing case-insensitive attribution collisions. */
748
- function requestHeaders(headers) {
749
- const attribution = attributionHeaders();
750
- const reserved = new Set(Object.keys(attribution).map((name) => name.toLowerCase()));
725
+ /**
726
+ * Api-key auth for a route the harness authenticates itself. `Models` calls
727
+ * this after the adapter has already resolved the route's credential, so a
728
+ * missing key here is not this layer's failure: a named-but-unresolvable
729
+ * reference has already failed the request with `MISSING_CREDENTIAL`, and a
730
+ * route naming no credential at all is deliberately unauthenticated. Reporting
731
+ * it as configured hands the decision to the protocol, which is where the
732
+ * requirement actually lives — pi-ai's OpenAI-compatible implementation, for
733
+ * one, still insists on a key or an `Authorization` header of its own.
734
+ * @param name - display name used as the resolution's status label.
735
+ * @returns the api-key auth for a harness-authenticated route.
736
+ */
737
+ function harnessApiKeyAuth(name) {
751
738
  return {
752
- ...Object.fromEntries(Object.entries(headers ?? {}).filter(([name]) => !reserved.has(name.toLowerCase()))),
753
- ...attribution
739
+ name,
740
+ resolve: ({ credential }) => Promise.resolve({
741
+ auth: credential?.key === void 0 ? {} : { apiKey: credential.key },
742
+ source: name
743
+ })
754
744
  };
755
745
  }
756
746
  /**
757
- * pi-ai-backed multi-provider adapter. Each operation reads the current
758
- * profiles, so a configuration change reaches the next request without a
759
- * restart; model descriptors come from the collection those profiles built.
760
- */
761
- var PiAiAdapter = class extends LlmAdapter {
762
- config;
763
- snapshot;
764
- constructor(config) {
765
- super();
766
- this.config = config;
767
- }
768
- /**
769
- * The snapshot for the current profiles. Resolution memoizes its result, so
770
- * an unchanged configuration is recognized by identity; a changed one gets a
771
- * brand-new collection, leaving any snapshot an operation already captured
772
- * untouched for as long as that operation holds it.
773
- */
774
- current() {
775
- const profiles = this.config.profiles();
776
- if (this.snapshot?.profiles === profiles) return this.snapshot;
777
- const models = createModels();
778
- for (const profile of profiles.values()) models.setProvider(profile.piProvider);
779
- this.snapshot = {
780
- profiles,
781
- models
782
- };
783
- return this.snapshot;
784
- }
785
- /** The profile for one route within one snapshot, or the not-owned failure. */
786
- profileOf(snapshot, provider) {
787
- const profile = snapshot.profiles.get(provider);
788
- if (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider "${provider}"`, "NO_ADAPTER");
789
- return profile;
790
- }
791
- /** The configured descriptor for one exact route/model pair within one snapshot. */
792
- modelOf(snapshot, provider, model) {
793
- this.profileOf(snapshot, provider);
794
- const resolved = snapshot.models.getModel(provider, model);
795
- if (resolved === void 0) throw new LlmError(`pi-ai provider "${provider}" has no configured model "${model}"`, "UNKNOWN_MODEL");
796
- return resolved;
797
- }
798
- providerInfo(provider) {
799
- return {
800
- id: provider,
801
- name: this.current().profiles.get(provider)?.displayName ?? provider
802
- };
803
- }
804
- providerRetryPolicy(provider) {
805
- return this.current().profiles.get(provider)?.retryPolicy;
806
- }
807
- listModels(provider) {
808
- return Promise.resolve().then(() => {
809
- const snapshot = this.current();
810
- this.profileOf(snapshot, provider);
811
- return snapshot.models.getModels(provider).map((model) => ({
812
- provider,
813
- id: model.id,
814
- name: model.name,
815
- inputModalities: [...model.input]
816
- }));
817
- });
818
- }
819
- resolveModel(provider, model, _signal) {
820
- return Promise.resolve().then(() => {
821
- const snapshot = this.current();
822
- const profile = this.profileOf(snapshot, provider);
823
- const resolvedModel = this.modelOf(snapshot, provider, model);
824
- const defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);
825
- const configuredMaxTokens = profile.configuredMaxTokens.get(model);
826
- return {
827
- provider,
828
- id: model,
829
- name: resolvedModel.name,
830
- inputModalities: [...resolvedModel.input],
831
- context: { contextWindow: resolvedModel.contextWindow },
832
- ...configuredMaxTokens === void 0 ? {} : { defaultMaxTokens: configuredMaxTokens },
833
- ...reasoningInfo(resolvedModel, defaultLevel)
834
- };
835
- });
836
- }
837
- async *stream(options) {
838
- const env_1 = {
839
- stack: [],
840
- error: void 0,
841
- hasError: false
842
- };
843
- try {
844
- if (options.stop !== void 0) throw new LlmError("llm-pi-ai does not support GenerateOptions.stop", "UNSUPPORTED_OPTION");
845
- const snapshot = this.current();
846
- const profile = this.profileOf(snapshot, options.provider);
847
- const model = this.modelOf(snapshot, options.provider, options.model);
848
- const reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);
849
- const apiKey = await this.config.resolveApiKey(options.provider, profile);
850
- const consumer = new AbortController();
851
- const upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);
852
- const streamIdleTimeoutMs = profile.streamIdleTimeoutMs;
853
- const watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, "LLM_STREAM_IDLE_TIMEOUT"), false);
854
- try {
855
- const containsImage = options.messages.some((message) => contentHasImage(message.content));
856
- if (containsImage && !model.input.includes("image")) throw new LlmError(`pi-ai model "${model.id}" does not support image input`, "UNSUPPORTED_CONTENT");
857
- const attachments = containsImage ? this.config.resolveAttachments?.() : void 0;
858
- if (containsImage && attachments === void 0) throw new LlmError("pi-ai image input requires the durable attachment service", "UNSUPPORTED_CONTENT");
859
- const onReplayDegrade = (reason) => {
860
- this.config.onReplayDegrade?.({
861
- provider: options.provider,
862
- model: options.model,
863
- reason
864
- });
865
- };
866
- const context = attachments === void 0 ? toPiContext(options, void 0, onReplayDegrade) : await toPiContext(options, attachments, onReplayDegrade);
867
- const iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {
868
- ...profileOptions(profile, reasoning, apiKey),
869
- ...options.temperature === void 0 ? {} : { temperature: options.temperature },
870
- ...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },
871
- ...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },
872
- signal: watchdog.signal,
873
- headers: requestHeaders(profile.headers)
874
- }), model.contextWindow)[Symbol.asyncIterator]();
875
- let exhausted = false;
876
- try {
877
- while (true) {
878
- const result = await watchdog.next(iterator);
879
- const timeout = timeoutOf(watchdog.signal, "LLM_STREAM_IDLE_TIMEOUT");
880
- if (timeout !== void 0) throw timeout;
881
- if (result.done) {
882
- exhausted = true;
883
- return;
884
- }
885
- yield result.value;
886
- }
887
- } finally {
888
- if (!exhausted) {
889
- consumer.abort("pi-ai stream consumer stopped");
890
- try {
891
- await iterator.return(void 0);
892
- } catch (_abortedSdkTeardown) {}
893
- }
894
- }
895
- } catch (error) {
896
- if (timeoutOf(watchdog.signal, "LLM_STREAM_IDLE_TIMEOUT") !== void 0) throw new LlmError(`pi-ai stream idle timeout after ${streamIdleTimeoutMs}ms`, "TIMEOUT", { cause: error });
897
- if (options.signal?.aborted) throw new LlmError("pi-ai request aborted by caller", "ABORTED", { cause: error });
898
- throw error;
899
- } finally {
900
- consumer.abort("pi-ai stream consumer stopped");
901
- }
902
- } catch (e_1) {
903
- env_1.error = e_1;
904
- env_1.hasError = true;
905
- } finally {
906
- __disposeResources(env_1);
907
- }
908
- }
909
- };
910
- //#endregion
911
- //#region lib/types/catalog.js
912
- /**
913
- * Materialization of one provider route's model catalog. The installed pi-ai
914
- * catalog supplies defaults keyed by model id, and a profile's own model
915
- * entries override them field by field, so a route naming a catalog provider
916
- * stays configuration-free while a route pi-ai has never heard of is fully
917
- * describable from `settings.yaml`.
747
+ * The auth one route resolves its credential through.
918
748
  *
919
- * Every pi-ai `Model` field the harness cannot default is required here rather
920
- * than at request time: an unserviceable route fails while its configuration is
921
- * being resolved, which is the earliest point that can name the offending key.
749
+ * A catalog route keeps the installed provider's own auth, which is what
750
+ * preserves provider-native ambient discovery for a profile naming no
751
+ * credential. That holds even when the profile repoints the protocol: which
752
+ * environment a provider reads is a property of the provider, not of the wire
753
+ * format its models speak.
922
754
  *
923
- * @module nomix-llm-pi-ai/catalog
755
+ * The single addition covers a catalog provider that offers no api-key method
756
+ * at all. pi-ai resolves a request's `apiKey` override only when the provider
757
+ * declares one (`resolveProviderAuth` checks `provider.auth.apiKey` before
758
+ * honouring the override), so an OAuth-only provider — `openai-codex` is the
759
+ * one the installed catalog ships — would refuse a profile's explicit key with
760
+ * `Provider is not configured` before any request went out. Adding the harness
761
+ * method beside the provider's own restores that route. A keyless profile adds
762
+ * nothing and still reports the honest refusal, because this adapter resolves
763
+ * credentials through its own seam and holds no OAuth store to fall back on.
764
+ * @param spec - the resolved route facts.
765
+ * @param catalog - the installed catalog provider, when pi-ai ships one.
766
+ * @returns the auth to construct this route's provider with.
924
767
  */
768
+ function routeAuth(spec, catalog) {
769
+ if (catalog === void 0) return { apiKey: harnessApiKeyAuth(spec.displayName) };
770
+ if (catalog.auth.apiKey !== void 0 || !spec.namesCredential) return catalog.auth;
771
+ return {
772
+ ...catalog.auth,
773
+ apiKey: harnessApiKeyAuth(spec.displayName)
774
+ };
775
+ }
925
776
  /**
926
- * Pricing for a model the installed catalog does not describe. The harness
927
- * never reads pi-ai's cost metadata `replay.ts` zeroes it and no consumer
928
- * reports spend so this is the absence of a fact, not a configurable rate.
777
+ * Reuse an installed catalog provider with this route's models and identity.
778
+ * Model dispatch stays with the catalog provider, so its API implementations,
779
+ * compatibility quirks, and ambient credential discovery are preserved exactly.
780
+ * Catalog-owned dynamic refresh is dropped: this route's catalog is the
781
+ * settings document, and a background refresh would contradict it.
929
782
  */
930
- const NO_COST = {
931
- input: 0,
932
- output: 0,
933
- cacheRead: 0,
934
- cacheWrite: 0
935
- };
936
- /** Every request modality a profile may declare. */
937
- const MODALITIES = Object.keys({
938
- text: true,
939
- image: true
940
- });
783
+ function reuseCatalogProvider(base, spec) {
784
+ const baseUrl = spec.baseURL ?? base.baseUrl;
785
+ return {
786
+ id: spec.provider,
787
+ name: spec.displayName,
788
+ ...baseUrl === void 0 ? {} : { baseUrl },
789
+ auth: routeAuth(spec, base),
790
+ getModels: () => spec.models,
791
+ stream: (model, context, options) => base.stream(model, context, options),
792
+ streamSimple: (model, context, options) => base.streamSimple(model, context, options)
793
+ };
794
+ }
941
795
  /**
942
- * One entry's modality list, or `undefined` when it states no answer. Absent
943
- * and empty mean the same thing — `[]` describes a model that accepts nothing
944
- * and could serve no request which is what makes an entry naming a catalog
945
- * model without declaring modalities keep the catalog's, since the config
946
- * schema materializes `[]` for an absent array.
947
- * @param configured - the list a `models` or `modelOverrides` entry supplied.
948
- * @returns the declared modalities, or `undefined` to ask the next level.
796
+ * Build the pi-ai provider for one resolved route.
797
+ * @param spec - the resolved route facts.
798
+ * @returns the provider to register in the adapter's `Models` collection.
799
+ * @throws Error when the route names a wire protocol this build cannot serve.
949
800
  */
950
- function declaredInput(configured) {
951
- return configured === void 0 || configured.length === 0 ? void 0 : [...configured];
801
+ function buildProvider(spec) {
802
+ const catalog = catalogProvider(spec.provider);
803
+ if (catalog !== void 0 && spec.api === void 0) return reuseCatalogProvider(catalog, spec);
804
+ const factory = spec.api === void 0 ? void 0 : PROTOCOLS[spec.api];
805
+ if (factory === void 0) throw new Error(`llm-pi-ai: provider "${spec.provider}" names api "${spec.api}", which this build cannot serve; supported protocols are ${supportedProtocols().join(", ")}`);
806
+ return createProvider({
807
+ id: spec.provider,
808
+ name: spec.displayName,
809
+ ...spec.baseURL === void 0 ? {} : { baseUrl: spec.baseURL },
810
+ auth: routeAuth(spec, catalog),
811
+ models: spec.models,
812
+ api: factory()
813
+ });
952
814
  }
953
- /** Every pi-ai thinking level a profile may declare, in escalation order. */
954
- const THINKING_LEVELS = Object.keys({
955
- off: true,
956
- minimal: true,
957
- low: true,
958
- medium: true,
959
- high: true,
960
- xhigh: true,
961
- max: true
962
- });
963
- /** Reasoning-dispatch wire formats a profile may name, most-reached first. */
964
- const SUPPORTED_THINKING_FORMATS = Object.keys({
965
- "openai": true,
966
- "deepseek": true,
967
- "openrouter": true,
968
- "together": true,
969
- "zai": true,
970
- "qwen": true,
971
- "string-thinking": true,
972
- "ant-ling": true
973
- });
974
- let providerIndex;
815
+ //#endregion
816
+ //#region lib/types/config.js
975
817
  /**
976
- * Installed catalog providers by id, constructed once. Each entry owns the API
977
- * implementations for its own models, which is why a catalog route reuses this
978
- * provider instead of being rebuilt from parts.
979
- * @returns the catalog provider index.
818
+ * Configuration schema and provider-profile validation for the pi-ai adapter.
819
+ * Profiles are a dict keyed by provider route, so the composition base and a
820
+ * user-settings layer merge per provider and the route set is structural.
821
+ *
822
+ * A route key is not required to name an installed pi-ai provider. When it does,
823
+ * that provider's endpoint, protocol, display name, and model catalog are the
824
+ * profile's defaults and the profile overrides them field by field; when it does
825
+ * not, the profile is the whole provider declaration. Resolution therefore ends
826
+ * in a built pi-ai `Provider` per route: everything a request needs is decided
827
+ * once, while the configuration key that made a route unserviceable can still be
828
+ * named in the failure.
829
+ *
830
+ * @module nomix-llm-pi-ai/config
980
831
  */
981
- function catalogProviders() {
982
- providerIndex ??= new Map(builtinProviders().map((provider) => [provider.id, provider]));
983
- return providerIndex;
832
+ /** Default maximum idle interval while an adapter stream read is outstanding. */
833
+ const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 3e5;
834
+ /**
835
+ * Default request-level bound on base64-encoded image payload. Every image in
836
+ * history is re-encoded into every request body, so an unbounded conversation
837
+ * eventually exceeds a provider or gateway request-size cap and the session
838
+ * can never complete another request. The 20MiB default admits fifteen 1MiB
839
+ * request versions after base64 expansion and reserves request capacity for
840
+ * system prompts, history, tools, and JSON.
841
+ * Deployments behind stricter gateways lower it per route.
842
+ */
843
+ const DEFAULT_MAX_REQUEST_IMAGE_BYTES = 20 * 1024 * 1024;
844
+ /** Default total-pixel budget preserves the complete 2048px normalized attachment. */
845
+ const DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET = 2048 * 2048;
846
+ /** Default raw encoded-byte cap before inline base64 expansion. */
847
+ const DEFAULT_REQUEST_IMAGE_MAX_BYTES = 1024 * 1024;
848
+ /** Context capacity assumed for a model neither configuration nor the catalog sizes. */
849
+ const DEFAULT_CONTEXT_WINDOW = 262144;
850
+ /** Output capability assumed for a model neither configuration nor the catalog sizes. */
851
+ const DEFAULT_MAX_TOKENS = 32768;
852
+ /**
853
+ * Modalities assumed for a model neither configuration nor the catalog
854
+ * declares. Text is the floor every supported protocol certainly carries, so
855
+ * this is the absence of a declaration rather than a guess at the endpoint:
856
+ * nothing can interrogate a gateway for its modalities, and the two wrong
857
+ * answers do not cost the same. Under-claiming refuses the image before it is
858
+ * attached, naming the model. Over-claiming admits one the provider then
859
+ * rejects mid-turn, after the message is durable, leaving the session
860
+ * repeating a request that cannot succeed.
861
+ */
862
+ const DEFAULT_INPUT = ["text"];
863
+ const thinkingBudgets = z.object({
864
+ minimal: z.number(),
865
+ low: z.number(),
866
+ medium: z.number(),
867
+ high: z.number()
868
+ });
869
+ /**
870
+ * One `chat_template_kwargs` value. The `$var` member is pi-ai's placeholder
871
+ * for a value dispatch fills from the request's thinking state, which is what
872
+ * makes a chat-template gateway configurable without restating its template.
873
+ */
874
+ const chatTemplateKwarg = z.union([
875
+ z.string(),
876
+ z.number(),
877
+ z.boolean(),
878
+ z.const(null),
879
+ z.object({
880
+ $var: z.union(CHAT_TEMPLATE_VARS).required(),
881
+ omitWhenOff: z.boolean()
882
+ })
883
+ ]);
884
+ const compatProfile = z.object({
885
+ supportsStore: z.boolean(),
886
+ supportsDeveloperRole: z.boolean(),
887
+ supportsReasoningEffort: z.boolean(),
888
+ supportsUsageInStreaming: z.boolean(),
889
+ maxTokensField: z.union(MAX_TOKENS_FIELDS),
890
+ requiresToolResultName: z.boolean(),
891
+ requiresAssistantAfterToolResult: z.boolean(),
892
+ requiresThinkingAsText: z.boolean(),
893
+ requiresReasoningContentOnAssistantMessages: z.boolean(),
894
+ thinkingFormat: z.union(SUPPORTED_THINKING_FORMATS),
895
+ chatTemplateKwargs: z.dict(chatTemplateKwarg),
896
+ supportsStrictMode: z.boolean(),
897
+ cacheControlFormat: z.union(CACHE_CONTROL_FORMATS),
898
+ supportsLongCacheRetention: z.boolean(),
899
+ supportsEagerToolInputStreaming: z.boolean(),
900
+ supportsCacheControlOnTools: z.boolean(),
901
+ supportsTemperature: z.boolean(),
902
+ forceAdaptiveThinking: z.boolean(),
903
+ allowEmptySignature: z.boolean(),
904
+ supportsStrictTools: z.boolean()
905
+ });
906
+ /**
907
+ * Keys are the offered levels, values their wire spellings. A valueless key
908
+ * (`off:`) survives validation because schemastery passes nullable data
909
+ * through before any member schema runs — `z.const(null)` only controls the
910
+ * error for non-null wrong values and what a configuration UI renders.
911
+ * Only resolution decides which levels may leave the value empty, so the
912
+ * diagnostic can name the route and model. The assertion narrows
913
+ * schemastery's `Dict`, which types every literal key as required; dict
914
+ * validation checks only present keys, so the runtime value is a partial record.
915
+ */
916
+ const reasoningEfforts = z.dict(z.union([z.string(), z.const(null)]), z.union(THINKING_LEVELS));
917
+ /** The fields a `models` entry and a `modelOverrides` value share; only the id's home differs. */
918
+ const modelFields = {
919
+ name: z.string(),
920
+ contextWindow: z.number().step(1).min(1),
921
+ maxTokens: z.number().step(1).min(1),
922
+ input: z.array(z.union(MODALITIES)),
923
+ reasoningEfforts: z.union([z.const(false), reasoningEfforts]),
924
+ compat: compatProfile
925
+ };
926
+ const modelProfile = z.object({
927
+ id: z.string().required(),
928
+ ...modelFields
929
+ });
930
+ /** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */
931
+ const modelOverride = z.object(modelFields);
932
+ const profile = z.object({
933
+ apiKeyEnv: z.string().role("credential-ref"),
934
+ displayName: z.string(),
935
+ api: z.union(supportedProtocols()),
936
+ baseURL: z.string(),
937
+ models: z.array(modelProfile),
938
+ modelOverrides: z.dict(modelOverride),
939
+ compat: compatProfile,
940
+ defaultContextWindow: z.number().step(1).min(1).default(DEFAULT_CONTEXT_WINDOW),
941
+ defaultMaxTokens: z.number().step(1).min(1).default(DEFAULT_MAX_TOKENS),
942
+ defaultInput: z.array(z.union(MODALITIES)).default([...DEFAULT_INPUT]),
943
+ headers: z.dict(z.string()),
944
+ reasoning: z.union(THINKING_LEVELS),
945
+ thinkingBudgets,
946
+ cacheRetention: z.union([
947
+ "none",
948
+ "short",
949
+ "long"
950
+ ]),
951
+ transport: z.union([
952
+ "sse",
953
+ "websocket",
954
+ "websocket-cached",
955
+ "auto"
956
+ ]),
957
+ timeoutMs: z.natural(),
958
+ websocketConnectTimeoutMs: z.natural(),
959
+ streamIdleTimeoutMs: z.number().min(Number.MIN_VALUE).max(MAX_TIMER_DELAY_MS).default(DEFAULT_STREAM_IDLE_TIMEOUT_MS),
960
+ maxRequestImageBytes: z.number().step(1).min(1).default(DEFAULT_MAX_REQUEST_IMAGE_BYTES),
961
+ requestImagePixelBudget: z.number().step(1).min(1).default(DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET),
962
+ requestImageMaxBytes: z.number().step(1).min(1).default(DEFAULT_REQUEST_IMAGE_MAX_BYTES),
963
+ retryPolicy: RetryPolicySchema
964
+ });
965
+ /** Runtime schema for {@link Config}. */
966
+ const Config = z.object({ providers: z.dict(profile).default({}) });
967
+ /**
968
+ * Reject a section this adapter could not serve. Registered as the settings
969
+ * namespace's validator, so an unserviceable profile is refused where it is
970
+ * *written* — `settings.mutate` answers `settings-rejected` with the offending
971
+ * route and model named — instead of being stored and then quietly disabling
972
+ * every route in the namespace. It stays a validator rather than a schema
973
+ * transform because the schema is also the shape a configuration surface
974
+ * renders and the value an absent section resolves to; wrapping it would break
975
+ * both.
976
+ * @param config - the resolved section to check.
977
+ * @throws Error naming the route and model that cannot be served.
978
+ */
979
+ function assertServiceable(config) {
980
+ resolveProfiles(config.providers);
981
+ }
982
+ /** Reject removed pre-release profile fields and name their replacements. */
983
+ function rejectRemovedFields(provider, source) {
984
+ const legacy = source;
985
+ if ("provider" in legacy) throw new Error(`llm-pi-ai: provider "${provider}" sets "provider", which moved to the providers dict key`);
986
+ if ("maxRetries" in legacy || "maxRetryDelayMs" in legacy) throw new Error(`llm-pi-ai: provider "${provider}" sets maxRetries or maxRetryDelayMs, which were removed; compose agent recovery with nomix-llm-retry`);
987
+ }
988
+ /**
989
+ * Validate profiles and return a detached route-keyed map suitable for
990
+ * per-request reads. This is the one explicit resolve step, so an omitted dict
991
+ * resolves to the empty (dormant) route set here rather than through a hidden
992
+ * fallback, and each route's models and pi-ai provider are materialized once.
993
+ * @param providers - configured provider profiles keyed by route.
994
+ * @returns validated profiles in configuration order.
995
+ */
996
+ function resolveProfiles(providers) {
997
+ if (Array.isArray(providers)) throw new Error("llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles");
998
+ const entries = Object.entries(providers ?? {});
999
+ const resolved = /* @__PURE__ */ new Map();
1000
+ for (const [provider, source] of entries) {
1001
+ rejectRemovedFields(provider, source);
1002
+ if (provider.length === 0) throw new Error("llm-pi-ai: provider names must be non-empty");
1003
+ if (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider "${provider}" has an empty baseURL`);
1004
+ if (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider "${provider}" has an empty displayName`);
1005
+ const streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;
1006
+ if (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider "${provider}" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);
1007
+ const maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;
1008
+ if (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider "${provider}" maxRequestImageBytes must be a positive integer`);
1009
+ const requestImagePixelBudget = source.requestImagePixelBudget ?? 4194304;
1010
+ if (!Number.isSafeInteger(requestImagePixelBudget) || requestImagePixelBudget <= 0) throw new Error(`llm-pi-ai: provider "${provider}" requestImagePixelBudget must be a positive safe integer`);
1011
+ const requestImageMaxBytes = source.requestImageMaxBytes ?? 1048576;
1012
+ if (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider "${provider}" requestImageMaxBytes must be a positive safe integer`);
1013
+ const defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];
1014
+ if (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider "${provider}" defaultInput must name at least one modality`);
1015
+ const displayName = source.displayName ?? provider;
1016
+ const catalog = resolveRouteModels({
1017
+ provider,
1018
+ ...source.api === void 0 ? {} : { api: source.api },
1019
+ ...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },
1020
+ ...source.models === void 0 ? {} : { models: source.models },
1021
+ ...source.modelOverrides === void 0 ? {} : { modelOverrides: source.modelOverrides },
1022
+ ...source.compat === void 0 ? {} : { compat: source.compat },
1023
+ defaultInput,
1024
+ defaultContextWindow: source.defaultContextWindow ?? 262144,
1025
+ defaultMaxTokens: source.defaultMaxTokens ?? 32768
1026
+ });
1027
+ const { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;
1028
+ resolved.set(provider, {
1029
+ ...rest,
1030
+ provider,
1031
+ displayName,
1032
+ ...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },
1033
+ streamIdleTimeoutMs,
1034
+ maxRequestImageBytes,
1035
+ requestImagePixelBudget,
1036
+ requestImageMaxBytes,
1037
+ retryPolicy: resolveRetryPolicy(retryPolicy, `llm-pi-ai: provider "${provider}" retryPolicy`),
1038
+ ...rest.headers === void 0 ? {} : { headers: { ...rest.headers } },
1039
+ ...rest.thinkingBudgets === void 0 ? {} : { thinkingBudgets: { ...rest.thinkingBudgets } },
1040
+ configuredMaxTokens: catalog.configuredMaxTokens,
1041
+ piProvider: buildProvider({
1042
+ provider,
1043
+ displayName,
1044
+ ...source.api === void 0 ? {} : { api: source.api },
1045
+ ...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },
1046
+ models: catalog.models,
1047
+ namesCredential: apiKeyEnv !== void 0
1048
+ })
1049
+ });
1050
+ }
1051
+ return resolved;
1052
+ }
1053
+ //#endregion
1054
+ //#region lib/types/context.js
1055
+ /**
1056
+ * Harness request-history conversion into pi-ai's Context vocabulary.
1057
+ *
1058
+ * @module nomix-llm-pi-ai/context
1059
+ */
1060
+ /** Join the text blocks of a harness message. */
1061
+ function flattenText(message) {
1062
+ return message.content.filter((block) => block.type === "text").map((block) => block.text).join("");
1063
+ }
1064
+ /** Flatten text recursively inside one tool result. */
1065
+ function toolResultText(blocks) {
1066
+ return blocks.map((block) => block.type === "text" ? block.text : block.type === "tool-result" ? toolResultText(block.content) : "").join("");
1067
+ }
1068
+ /** Reject image roles that pi-ai cannot replay before request-size offloading can replace them. */
1069
+ function assertSupportedImageRoles(messages) {
1070
+ for (const message of messages) if (message.role !== "user" && contentHasImage(message.content)) throw new LlmError(`pi-ai cannot represent an image in an in-history ${message.role} message`, "UNSUPPORTED_CONTENT");
1071
+ }
1072
+ async function userContent(blocks, requestImages) {
1073
+ const content = [];
1074
+ for (const block of blocks) switch (block.type) {
1075
+ case "text":
1076
+ if (block.text.length > 0) content.push({
1077
+ type: "text",
1078
+ text: block.text
1079
+ });
1080
+ break;
1081
+ case "image": {
1082
+ const version = requestImages.get(block.attachment.attachmentId);
1083
+ content.push({
1084
+ type: "text",
1085
+ text: requestImageHandleText(version)
1086
+ });
1087
+ content.push({
1088
+ type: "image",
1089
+ data: Buffer.from(version.data).toString("base64"),
1090
+ mimeType: version.mediaType
1091
+ });
1092
+ break;
1093
+ }
1094
+ case "tool-result":
1095
+ {
1096
+ const nested = await userContent(block.content, requestImages);
1097
+ if (typeof nested === "string") {
1098
+ if (nested.length > 0) content.push({
1099
+ type: "text",
1100
+ text: nested
1101
+ });
1102
+ } else content.push(...nested);
1103
+ }
1104
+ break;
1105
+ default: break;
1106
+ }
1107
+ if (content.every((block) => block.type === "text")) return content.map((block) => block.text).join("");
1108
+ return content;
1109
+ }
1110
+ function collectImageRefs(blocks, refs) {
1111
+ for (const block of blocks) if (block.type === "image") refs.set(block.attachment.attachmentId, block.attachment);
1112
+ else if (block.type === "tool-result") collectImageRefs(block.content, refs);
1113
+ }
1114
+ async function prepareRequestImages(messages, attachments, policy, signal) {
1115
+ const refs = /* @__PURE__ */ new Map();
1116
+ for (const message of messages) collectImageRefs(message.content, refs);
1117
+ const orderedRefs = [...refs.values()];
1118
+ const prepared = await Promise.all(orderedRefs.map((ref) => attachments.readImageRequest(ref, policy, signal)));
1119
+ const versions = /* @__PURE__ */ new Map();
1120
+ for (const [index, ref] of orderedRefs.entries()) versions.set(ref.attachmentId, prepared[index]);
1121
+ return versions;
1122
+ }
1123
+ function toolsOf(options) {
1124
+ return options.tools?.map((tool) => ({
1125
+ name: tool.name,
1126
+ description: tool.description,
1127
+ parameters: tool.parameters
1128
+ }));
1129
+ }
1130
+ /** Assemble the request-level pi-ai context envelope shared by both conversion paths. */
1131
+ function piContext(options, messages) {
1132
+ const tools = toolsOf(options);
1133
+ return {
1134
+ ...options.system !== void 0 ? { systemPrompt: options.system } : {},
1135
+ messages,
1136
+ ...tools !== void 0 && tools.length > 0 ? { tools } : {}
1137
+ };
1138
+ }
1139
+ function textOnlyContext(options, onReplayDegrade) {
1140
+ const toolNames = /* @__PURE__ */ new Map();
1141
+ const messages = [];
1142
+ for (const message of options.messages) {
1143
+ if (contentHasImage(message.content)) throw new LlmError("pi-ai image conversion requires the durable attachment service", "UNSUPPORTED_CONTENT");
1144
+ if (message.role === "system") {
1145
+ messages.push({
1146
+ role: "user",
1147
+ content: flattenText(message),
1148
+ timestamp: 0
1149
+ });
1150
+ continue;
1151
+ }
1152
+ if (message.role === "assistant") {
1153
+ const assistant = toPiAssistant(message, onReplayDegrade);
1154
+ for (const block of assistant.content) if (block.type === "toolCall") toolNames.set(CallId(block.id), block.name);
1155
+ messages.push(assistant);
1156
+ continue;
1157
+ }
1158
+ const text = flattenText(message);
1159
+ const results = message.content.filter((block) => block.type === "tool-result");
1160
+ if (text.length > 0 || results.length === 0) messages.push({
1161
+ role: "user",
1162
+ content: text,
1163
+ timestamp: 0
1164
+ });
1165
+ for (const result of results) messages.push({
1166
+ role: "toolResult",
1167
+ toolCallId: result.toolCallId,
1168
+ toolName: toolNames.get(result.toolCallId) ?? "unknown",
1169
+ content: [{
1170
+ type: "text",
1171
+ text: toolResultText(result.content) || "(no output)"
1172
+ }],
1173
+ isError: result.isError ?? false,
1174
+ timestamp: 0
1175
+ });
1176
+ }
1177
+ return piContext(options, messages);
984
1178
  }
985
- /**
986
- * The installed catalog provider for one route, when pi-ai ships one.
987
- * @param provider - provider route key.
988
- * @returns the catalog provider, or `undefined` for a route pi-ai does not ship.
989
- */
990
- function catalogProvider(provider) {
991
- return catalogProviders().get(provider);
1179
+ function toPiContext(options, attachments, onReplayDegrade, maxRequestImageBytes, requestImagePolicy) {
1180
+ return attachments === void 0 ? textOnlyContext(options, onReplayDegrade) : toPiContextWithImages(options, attachments, onReplayDegrade, maxRequestImageBytes, requestImagePolicy);
992
1181
  }
993
- /**
994
- * Every provider route the installed pi-ai catalog ships.
995
- * @returns the catalog provider ids.
996
- */
997
- function catalogProviderIds() {
998
- return getBuiltinProviders();
1182
+ async function toPiContextWithImages(options, attachments, onReplayDegrade, maxRequestImageBytes, requestImagePolicy = {
1183
+ maxPixels: DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET,
1184
+ maxBytes: DEFAULT_REQUEST_IMAGE_MAX_BYTES
1185
+ }) {
1186
+ assertSupportedImageRoles(options.messages);
1187
+ const requestMessages = offloadRequestImagesWithPolicy(options.messages, {
1188
+ representation: "base64",
1189
+ ...maxRequestImageBytes === void 0 ? {} : { maxBytes: maxRequestImageBytes },
1190
+ byteQuantum: 1,
1191
+ byteLength: (ref) => Math.min(ref.bytes, requestImagePolicy.maxBytes)
1192
+ });
1193
+ const requestImages = await prepareRequestImages(requestMessages, attachments, requestImagePolicy, options.signal);
1194
+ const exactMessages = offloadRequestImagesWithPolicy(requestMessages, {
1195
+ representation: "base64",
1196
+ ...maxRequestImageBytes === void 0 ? {} : { maxBytes: maxRequestImageBytes },
1197
+ byteQuantum: 1,
1198
+ byteLength: (ref) => requestImages.get(ref.attachmentId).bytes
1199
+ });
1200
+ const toolNames = /* @__PURE__ */ new Map();
1201
+ const messages = [];
1202
+ for (const message of exactMessages) {
1203
+ if (message.role === "system") {
1204
+ messages.push({
1205
+ role: "user",
1206
+ content: flattenText(message),
1207
+ timestamp: 0
1208
+ });
1209
+ continue;
1210
+ }
1211
+ if (message.role === "assistant") {
1212
+ const assistant = toPiAssistant(message, onReplayDegrade);
1213
+ for (const block of assistant.content) if (block.type === "toolCall") toolNames.set(CallId(block.id), block.name);
1214
+ messages.push(assistant);
1215
+ continue;
1216
+ }
1217
+ const content = await userContent(message.content.filter((block) => block.type !== "tool-result"), requestImages);
1218
+ const results = message.content.filter((block) => block.type === "tool-result");
1219
+ if (content.length > 0 || results.length === 0) messages.push({
1220
+ role: "user",
1221
+ content,
1222
+ timestamp: 0
1223
+ });
1224
+ for (const result of results) {
1225
+ const resultContent = await userContent(result.content, requestImages);
1226
+ messages.push({
1227
+ role: "toolResult",
1228
+ toolCallId: result.toolCallId,
1229
+ toolName: toolNames.get(result.toolCallId) ?? "unknown",
1230
+ content: typeof resultContent === "string" ? [{
1231
+ type: "text",
1232
+ text: resultContent || "(no output)"
1233
+ }] : resultContent,
1234
+ isError: result.isError ?? false,
1235
+ timestamp: 0
1236
+ });
1237
+ }
1238
+ }
1239
+ return piContext(options, messages);
999
1240
  }
1241
+ //#endregion
1242
+ //#region lib/types/stream.js
1000
1243
  /**
1001
- * Whether the installed catalog provider for one route declares an api-key
1002
- * method — the only authentication this adapter obtains on its own.
1244
+ * pi-ai assistant event translation into the Harness streaming protocol.
1003
1245
  *
1004
- * A key is what the harness resolves through its own credential seam and hands
1005
- * pi-ai per request. pi-ai's other method, OAuth, resolves from a *stored*
1006
- * OAuth credential alone: `resolveProviderAuth` has no ambient path for it,
1007
- * this adapter builds its `Models` collection with no credential store, and
1008
- * nothing here runs a login flow. So a provider offering OAuth by itself
1009
- * leaves nothing for this adapter to authenticate with, and the posture such a
1010
- * provider invites — no key configured, credentials discovered by the provider
1011
- * — fails every request with `Provider is not configured`.
1012
- * @param provider - provider route key.
1013
- * @returns whether the catalog provider takes an api key; false for a route
1014
- * pi-ai does not ship, which the caller answers for separately.
1015
- */
1016
- function catalogProviderTakesApiKey(provider) {
1017
- return catalogProvider(provider)?.auth.apiKey !== void 0;
1018
- }
1019
- /**
1020
- * The installed catalog models for one route, indexed by model id.
1021
- * @param provider - provider route key.
1022
- * @returns catalog models by id; empty for a route pi-ai does not ship.
1023
- */
1024
- function catalogModels(provider) {
1025
- if (!catalogProviders().has(provider)) return /* @__PURE__ */ new Map();
1026
- const models = getBuiltinModels(provider);
1027
- return new Map(models.map((model) => [model.id, model]));
1028
- }
1029
- /** Report a route the deployment cannot serve, naming the settings key at fault. */
1030
- function invalid(provider, detail) {
1031
- throw new Error(`llm-pi-ai: provider "${provider}" ${detail}`);
1032
- }
1033
- /**
1034
- * The one wire protocol a catalog route's shipped models agree on. This is what
1035
- * lets a deployment add a model the installed catalog has not caught up with —
1036
- * a provider's newest release — without restating the protocol its siblings
1037
- * already use. A route whose shipped models disagree (an OpenAI-style catalog
1038
- * spanning Responses and Chat Completions) has no such answer, so a model it
1039
- * does not describe must name its protocol at the route.
1246
+ * pi-ai tool-call arguments are parsed objects while the Harness keeps their
1247
+ * raw JSON representation. pi-ai also reports failures as terminal stream
1248
+ * events, which this module maps into Harness finish chunks.
1249
+ *
1250
+ * @module nomix-llm-pi-ai/stream
1040
1251
  */
1041
- function sharedCatalogApi(defaults) {
1042
- const apis = /* @__PURE__ */ new Set();
1043
- for (const model of defaults.values()) apis.add(model.api);
1044
- return apis.size === 1 ? [...apis][0] : void 0;
1045
- }
1046
1252
  /**
1047
- * Resolve one model's reasoning capability from its declared efforts.
1048
- *
1049
- * A declared dict translates to pi-ai's `thinkingLevelMap` with every level
1050
- * decided explicitly: declared levels carry their wire spelling, undeclared
1051
- * levels are pinned to `null` (unsupported). Pinning matters because pi-ai's
1052
- * own defaulting is asymmetric — an absent key means "supported" for the five
1053
- * base levels but "unsupported" for `xhigh`/`max` — and a profile author
1054
- * should not need to know that. A declared `off` with no value is the one
1055
- * exception: it stays absent from the map, which pi-ai reads as "supported,
1056
- * send nothing" — the correct dispatch where not thinking is the parameter's
1057
- * absence — while `off` with a value sends that value.
1058
- * @param provider - provider route key, for diagnostics.
1059
- * @param entry - the configured model entry.
1060
- * @param base - the installed catalog entry of the same id, when one exists.
1061
- * @returns the reasoning fields the materialized model carries.
1253
+ * Map pi-ai usage (reasoning folded into output by pi-ai).
1254
+ * @param usage - cumulative usage from the terminal pi-ai event.
1255
+ * @returns harness counts; cache fields appear only when non-zero (pi-ai reports zeros, not absence).
1062
1256
  */
1063
- function resolveModelReasoning(provider, entry, base) {
1064
- const efforts = entry.reasoningEfforts;
1065
- if (efforts === void 0) return { reasoning: base?.reasoning ?? false };
1066
- if (efforts === false) return { reasoning: false };
1067
- if (efforts === null || Object.keys(efforts).length === 0) invalid(provider, `model "${entry.id}" has an empty reasoningEfforts; declare the offered levels, set false for a non-reasoning model, or omit the field to keep the installed catalog's capability`);
1068
- const declared = THINKING_LEVELS.flatMap((level) => {
1069
- const wire = efforts[level];
1070
- return wire === void 0 ? [] : [[level, wire]];
1071
- });
1072
- for (const [level, wire] of declared) if (wire === null) {
1073
- if (level !== "off") invalid(provider, `model "${entry.id}" reasoningEfforts.${level} needs the wire value dispatch should send; only "off" may leave it empty`);
1074
- } else if (wire.length === 0) invalid(provider, `model "${entry.id}" reasoningEfforts.${level} must not be an empty string`);
1075
- if (!declared.some(([level]) => level !== "off")) invalid(provider, `model "${entry.id}" reasoningEfforts offers no level beyond "off"; declare a thinking level, or set reasoningEfforts to false for a non-reasoning model`);
1076
- const map = {};
1077
- for (const level of THINKING_LEVELS) {
1078
- const wire = efforts[level];
1079
- if (wire === void 0) map[level] = null;
1080
- else if (wire !== null) map[level] = wire;
1081
- }
1257
+ function mapUsage(usage) {
1082
1258
  return {
1083
- reasoning: true,
1084
- thinkingLevelMap: map
1259
+ inputTokens: usage.input,
1260
+ outputTokens: usage.output,
1261
+ ...usage.cacheRead > 0 ? { cacheReadTokens: usage.cacheRead } : {},
1262
+ ...usage.cacheWrite > 0 ? { cacheWriteTokens: usage.cacheWrite } : {}
1085
1263
  };
1086
1264
  }
1265
+ function classifyPiAiError(message) {
1266
+ if (/\b(?:401|403)\b/.test(message)) return "AUTH";
1267
+ if (isQuotaExceededError(message)) return QUOTA_EXCEEDED_CODE;
1268
+ if (/\b429\b|rate.?limit/i.test(message)) return "RATE_LIMIT";
1269
+ if (/\b413\b|failed to buffer the request body:\s*length limit exceeded|payload too large|request body too large/i.test(message)) return "INVALID_REQUEST";
1270
+ if (/\b400\b|invalid.?request/i.test(message)) return "INVALID_REQUEST";
1271
+ if (/\b5\d\d\b/.test(message)) return "SERVER";
1272
+ if (/\btime(?:d)?\s*out\b|timeout/i.test(message)) return "TIMEOUT";
1273
+ if (/stream ended (?:before|without)\b/i.test(message)) return "TRANSPORT";
1274
+ if (/\b(?:network|connection|socket|fetch)\b|\bECONN[A-Z]+\b/i.test(message) || /\b(?:other side closed|HTTP2 request did not get a response|WebSocket closed unexpectedly)\b/i.test(message) || /\bterminated\b|premature close/i.test(message)) return "TRANSPORT";
1275
+ return "PI_AI_ERROR";
1276
+ }
1087
1277
  /**
1088
- * Resolve one model's compat block from the profile's reasoning switches.
1089
- *
1090
- * A model switch wins over the route switch; whatever neither sets keeps the
1091
- * installed entry's value, and a field no layer decides falls through to
1092
- * pi-ai's baseURL-derived detection. Only an `openai-completions` model takes
1093
- * the switches at all: a model-level switch on any other protocol fails
1094
- * resolution, while a route-level default skips past such models — the same
1095
- * posture as the route-level `reasoning` default, which also must not fail
1096
- * models it does not fit.
1097
- * @param provider - provider route key, for diagnostics.
1098
- * @param entry - the configured model entry.
1099
- * @param route - the route-level switches, when any.
1100
- * @param base - the installed catalog entry of the same id, when one exists.
1101
- * @param api - the model's resolved wire protocol.
1102
- * @returns a `compat` field to spread into the model, or nothing.
1278
+ * Map a terminal pi-ai event to the harness finish reason.
1279
+ * @param message - the assistant message carried by the `done` or `error` event.
1280
+ * @param contextWindow - resolved catalog capacity for usage-based overflow detection.
1281
+ * @returns the mapped harness reason. Recognized error text, `stop` usage above
1282
+ * `contextWindow`, and zero-output `length` usage that fills the window map
1283
+ * to `CONTEXT_WINDOW_EXCEEDED`; a `stop` with no content blocks maps to an
1284
+ * `EMPTY_RESPONSE` error.
1103
1285
  */
1104
- function resolveModelCompat(provider, entry, route, base, api) {
1105
- const thinkingFormat = entry.compat?.thinkingFormat ?? route?.thinkingFormat;
1106
- const supportsReasoningEffort = entry.compat?.supportsReasoningEffort ?? route?.supportsReasoningEffort;
1107
- if (thinkingFormat === void 0 && supportsReasoningEffort === void 0) return {};
1108
- if (api !== "openai-completions") {
1109
- if (entry.compat?.thinkingFormat !== void 0 || entry.compat?.supportsReasoningEffort !== void 0) invalid(provider, `model "${entry.id}" sets compat reasoning switches, but its api is "${api}"; thinkingFormat and supportsReasoningEffort exist only on openai-completions`);
1110
- return {};
1286
+ function mapStopReason(message, contextWindow) {
1287
+ const piAiOverflow = isContextOverflow(message, contextWindow);
1288
+ const harnessOverflow = message.stopReason === "error" && message.errorMessage !== void 0 && isContextWindowExceededError(message.errorMessage);
1289
+ if (piAiOverflow || harnessOverflow) return {
1290
+ kind: "error",
1291
+ failure: {
1292
+ message: message.errorMessage ?? `pi-ai detected context overflow for model "${message.model}"`,
1293
+ code: CONTEXT_WINDOW_EXCEEDED_CODE
1294
+ }
1295
+ };
1296
+ switch (message.stopReason) {
1297
+ case "stop":
1298
+ if (message.content.length === 0) return {
1299
+ kind: "error",
1300
+ failure: {
1301
+ message: `model "${message.model}" returned a completed response with no content`,
1302
+ code: EMPTY_RESPONSE_CODE
1303
+ }
1304
+ };
1305
+ return { kind: "stop" };
1306
+ case "length": return { kind: "max-tokens" };
1307
+ case "toolUse": return { kind: "tool-calls" };
1308
+ case "aborted": return {
1309
+ kind: "aborted",
1310
+ failure: {
1311
+ message: message.errorMessage ?? "pi-ai stream aborted",
1312
+ code: "ABORTED"
1313
+ }
1314
+ };
1315
+ case "error": {
1316
+ const text = message.errorMessage ?? "pi-ai stream error";
1317
+ return {
1318
+ kind: "error",
1319
+ failure: {
1320
+ message: text,
1321
+ code: classifyPiAiError(text)
1322
+ }
1323
+ };
1324
+ }
1111
1325
  }
1112
- return { compat: {
1113
- ...base?.api === api ? base.compat : void 0,
1114
- ...thinkingFormat === void 0 ? {} : { thinkingFormat },
1115
- ...supportsReasoningEffort === void 0 ? {} : { supportsReasoningEffort }
1116
- } };
1117
1326
  }
1118
1327
  /**
1119
- * Materialize one route's catalog by merging the installed catalog defaults
1120
- * under the configured entries. A route with no configured `models` serves the
1121
- * installed catalog unchanged, which is what keeps an existing
1122
- * `providers: { deepseek: { apiKeyEnv: } }` profile working untouched.
1123
- * @param request - the route-level catalog facts.
1124
- * @returns the materialized models and the explicitly configured request caps.
1328
+ * Translate the pi-ai event stream into StreamChunks. pi-ai never throws
1329
+ * mid-stream failures arrive as `error` events, which become error/aborted
1330
+ * `finish` chunks (the harness protocol's other error-delivery style).
1331
+ * @param events - one assistant turn's pi-ai event stream.
1332
+ * @param contextWindow - resolved catalog capacity for usage-based overflow detection.
1333
+ * @returns the harness chunks, ending with `usage` then `finish`; throws
1334
+ * `LlmError` (`STREAM_CLOSED`) if the source ends without a terminal event.
1125
1335
  */
1126
- function resolveRouteModels(request) {
1127
- const { provider } = request;
1128
- const defaults = catalogModels(provider);
1129
- const providerBaseUrl = catalogProvider(provider)?.baseUrl;
1130
- const configured = request.models ?? [];
1131
- const overrides = request.modelOverrides ?? {};
1132
- for (const [id, override] of Object.entries(overrides)) {
1133
- if (id.length === 0) invalid(provider, "has a modelOverrides entry with an empty model id");
1134
- if (defaults.size === 0) invalid(provider, `sets modelOverrides for "${id}", but the installed catalog does not describe this route; a declared route spells every model out in its models list`);
1135
- if (configured.length > 0) invalid(provider, `sets modelOverrides for "${id}" beside a models list; models already replaces the served catalog, so declare the fields on its entries`);
1136
- if (!defaults.has(id)) invalid(provider, `modelOverrides names "${id}", which the installed catalog does not describe`);
1137
- if ("id" in override) invalid(provider, `modelOverrides entry "${id}" sets "id", which is the dict key`);
1336
+ async function* toStreamChunks(events, contextWindow) {
1337
+ const toolIds = /* @__PURE__ */ new Map();
1338
+ for await (const event of events) switch (event.type) {
1339
+ case "start": break;
1340
+ case "text_start":
1341
+ yield {
1342
+ type: "block-start",
1343
+ index: event.contentIndex,
1344
+ blockType: "text"
1345
+ };
1346
+ break;
1347
+ case "text_delta":
1348
+ yield {
1349
+ type: "text-delta",
1350
+ index: event.contentIndex,
1351
+ text: event.delta
1352
+ };
1353
+ break;
1354
+ case "text_end":
1355
+ yield {
1356
+ type: "block-end",
1357
+ index: event.contentIndex,
1358
+ block: {
1359
+ type: "text",
1360
+ text: event.content
1361
+ }
1362
+ };
1363
+ break;
1364
+ case "thinking_start":
1365
+ yield {
1366
+ type: "block-start",
1367
+ index: event.contentIndex,
1368
+ blockType: "reasoning"
1369
+ };
1370
+ break;
1371
+ case "thinking_delta":
1372
+ yield {
1373
+ type: "reasoning-delta",
1374
+ index: event.contentIndex,
1375
+ text: event.delta
1376
+ };
1377
+ break;
1378
+ case "thinking_end":
1379
+ yield {
1380
+ type: "block-end",
1381
+ index: event.contentIndex,
1382
+ block: {
1383
+ type: "reasoning",
1384
+ text: event.content
1385
+ }
1386
+ };
1387
+ break;
1388
+ case "toolcall_start": {
1389
+ const partial = event.partial.content[event.contentIndex];
1390
+ const id = partial?.type === "toolCall" ? partial.id : "";
1391
+ const name = partial?.type === "toolCall" ? partial.name : "";
1392
+ toolIds.set(event.contentIndex, {
1393
+ id,
1394
+ name
1395
+ });
1396
+ yield {
1397
+ type: "block-start",
1398
+ index: event.contentIndex,
1399
+ blockType: "tool-call"
1400
+ };
1401
+ break;
1402
+ }
1403
+ case "toolcall_delta": {
1404
+ const known = toolIds.get(event.contentIndex);
1405
+ yield {
1406
+ type: "tool-call-delta",
1407
+ index: event.contentIndex,
1408
+ id: CallId(known?.id ?? ""),
1409
+ ...known?.name !== void 0 && known.name.length > 0 ? { name: known.name } : {},
1410
+ argumentsDelta: event.delta
1411
+ };
1412
+ break;
1413
+ }
1414
+ case "toolcall_end":
1415
+ yield {
1416
+ type: "block-end",
1417
+ index: event.contentIndex,
1418
+ block: {
1419
+ type: "tool-call",
1420
+ id: CallId(event.toolCall.id),
1421
+ name: event.toolCall.name,
1422
+ arguments: JSON.stringify(event.toolCall.arguments)
1423
+ }
1424
+ };
1425
+ break;
1426
+ case "done":
1427
+ yield {
1428
+ type: "usage",
1429
+ usage: mapUsage(event.message.usage)
1430
+ };
1431
+ yield {
1432
+ type: "finish",
1433
+ reason: mapStopReason(event.message, contextWindow),
1434
+ replayState: toPiReplayState(event.message)
1435
+ };
1436
+ return;
1437
+ case "error":
1438
+ yield {
1439
+ type: "usage",
1440
+ usage: mapUsage(event.error.usage)
1441
+ };
1442
+ yield {
1443
+ type: "finish",
1444
+ reason: mapStopReason(event.error, contextWindow)
1445
+ };
1446
+ return;
1138
1447
  }
1139
- const entries = configured.length > 0 ? configured : [...defaults.values()].map((model) => ({
1140
- id: model.id,
1141
- ...overrides[model.id]
1142
- }));
1143
- if (entries.length === 0) invalid(provider, "resolves no models; the installed catalog does not describe this route, so its models must be listed in configuration");
1144
- const routeApi = sharedCatalogApi(defaults);
1145
- const routeCompatDefined = request.compat?.thinkingFormat !== void 0 || request.compat?.supportsReasoningEffort !== void 0;
1146
- const seen = /* @__PURE__ */ new Set();
1147
- const configuredMaxTokens = /* @__PURE__ */ new Map();
1148
- const models = entries.map((entry) => {
1149
- if (entry.id.length === 0) invalid(provider, "has a model with an empty id");
1150
- if (seen.has(entry.id)) invalid(provider, `lists model "${entry.id}" more than once`);
1151
- seen.add(entry.id);
1152
- const base = defaults.get(entry.id);
1153
- const api = request.api ?? base?.api ?? routeApi;
1154
- if (api === void 0) invalid(provider, `model "${entry.id}" needs an api; the installed catalog does not describe it, so set the route's api to the wire protocol its endpoint speaks`);
1155
- const baseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;
1156
- if (baseUrl === void 0) invalid(provider, `model "${entry.id}" needs a baseURL; the installed catalog does not describe this route`);
1157
- const contextWindow = entry.contextWindow ?? base?.contextWindow ?? request.defaultContextWindow;
1158
- if (!Number.isInteger(contextWindow) || contextWindow <= 0) invalid(provider, `model "${entry.id}" contextWindow must be a positive integer`);
1159
- const maxTokens = entry.maxTokens ?? base?.maxTokens ?? request.defaultMaxTokens;
1160
- if (!Number.isInteger(maxTokens) || maxTokens <= 0) invalid(provider, `model "${entry.id}" maxTokens must be a positive integer`);
1161
- if (entry.maxTokens !== void 0) configuredMaxTokens.set(entry.id, entry.maxTokens);
1162
- return {
1163
- ...base,
1164
- id: entry.id,
1165
- name: entry.name ?? base?.name ?? entry.id,
1166
- api,
1167
- provider,
1168
- baseUrl,
1169
- input: declaredInput(entry.input) ?? base?.input ?? [...request.defaultInput],
1170
- cost: base?.cost ?? NO_COST,
1171
- contextWindow,
1172
- maxTokens,
1173
- ...resolveModelReasoning(provider, entry, base),
1174
- ...resolveModelCompat(provider, entry, request.compat, base, api)
1175
- };
1176
- });
1177
- if (routeCompatDefined && !models.some((model) => model.api === "openai-completions")) invalid(provider, "sets compat reasoning switches, but no model on the route speaks openai-completions; thinkingFormat and supportsReasoningEffort exist only on that protocol");
1178
- return {
1179
- models,
1180
- configuredMaxTokens
1181
- };
1448
+ throw new LlmError("pi-ai event stream ended without done/error", "STREAM_CLOSED");
1182
1449
  }
1183
1450
  //#endregion
1184
- //#region lib/types/provider.js
1451
+ //#region lib/types/adapter.js
1185
1452
  /**
1186
- * Construction of the pi-ai `Provider` that one configured route registers into
1187
- * the adapter's `Models` collection.
1188
- *
1189
- * Two constructions, one decision: a route the installed catalog ships, whose
1190
- * profile does not override the wire protocol, **reuses that catalog provider**
1191
- * with its models replaced — the catalog provider owns API implementations this
1192
- * package cannot reconstruct (Bedrock loads its Smithy module through a
1193
- * separate entry point), so rebuilding it from parts would silently narrow
1194
- * which providers work. Every other route — one pi-ai has never heard of, or a
1195
- * catalog route pointed at a different protocol — is built by `createProvider`
1196
- * over the protocol table below.
1453
+ * Generic pi-ai-backed implementation of the Harness LLM seam.
1197
1454
  *
1198
- * Credentials never reach this module's storage: the harness resolves a route's
1199
- * key through `ctx.credentials` before the request enters pi-ai and hands it
1200
- * over as a stream option, which `Models` presents to `resolve()` as the
1201
- * credential key.
1455
+ * Each resolution produces one **immutable** snapshot the profiles plus a
1456
+ * `Models` collection holding the `Provider` each route built and an
1457
+ * operation captures a whole snapshot before its first `await`. A
1458
+ * configuration change builds a *new* collection rather than mutating the one
1459
+ * in use, because `Models.streamSimple()` is lazy: it resolves the provider
1460
+ * when the stream is first consumed, which is after the credential await, so a
1461
+ * mutated collection would let a request that started under one configuration
1462
+ * finish under another — or fail with a provider that no longer exists. This is
1463
+ * what makes the seam's per-step call freeze (`llm.prepareCall()`) hold all the
1464
+ * way down: switching models mid-reply takes effect on the next step, never
1465
+ * inside the one in flight.
1202
1466
  *
1203
- * @module nomix-llm-pi-ai/provider
1204
- */
1205
- /**
1206
- * Wire protocols a configured route may name, mapped to pi-ai's lazily loaded
1207
- * implementations. Each entry is the factory that pi-ai's matching provider
1208
- * factory uses, so a hand-declared route reaches exactly the implementation a
1209
- * catalog route would.
1467
+ * A route naming a credential reference still resolves it through the harness
1468
+ * seam and passes it as the request's `apiKey` option, which pi-ai treats as
1469
+ * the highest-priority auth override — that is what keeps the fail-loud
1470
+ * reference semantics. Everything that override does not cover reaches pi-ai
1471
+ * through the collection's own auth: the credential store holds the records a
1472
+ * login wrote and a refresh rotates, and the auth context answers the ambient
1473
+ * questions a provider asks while resolving. Both are stable across snapshots,
1474
+ * so a configuration change rebuilds the collection without forgetting who is
1475
+ * signed in.
1210
1476
  *
1211
- * The table is deliberately narrow: the protocols a hand-declared route
1212
- * actually reaches for today, each completely describable with a key, an
1213
- * endpoint, and headers. Bedrock signs with SigV4 over AWS credentials and a
1214
- * region, Vertex needs a project, a location, and application-default
1215
- * credentials, Azure needs provider environment plus an api-version, and Codex
1216
- * authenticates through OAuth — none of which this configuration shape can
1217
- * express, so offering them would hand back a provider that cannot
1218
- * authenticate. The remainder are absent for want of a consumer rather than a
1219
- * blocker: each is one line here once a deployment needs it. Catalog routes
1220
- * still reach every protocol through their own provider; only an explicit
1221
- * override is refused.
1477
+ * @module nomix-llm-pi-ai/adapter
1222
1478
  */
1223
- const PROTOCOLS = {
1224
- "openai-completions": openAICompletionsApi,
1225
- "openai-responses": openAIResponsesApi,
1226
- "anthropic-messages": anthropicMessagesApi
1479
+ var __addDisposableResource = function(env, value, async) {
1480
+ if (value !== null && value !== void 0) {
1481
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
1482
+ var dispose, inner;
1483
+ if (async) {
1484
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
1485
+ dispose = value[Symbol.asyncDispose];
1486
+ }
1487
+ if (dispose === void 0) {
1488
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
1489
+ dispose = value[Symbol.dispose];
1490
+ if (async) inner = dispose;
1491
+ }
1492
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
1493
+ if (inner) dispose = function() {
1494
+ try {
1495
+ inner.call(this);
1496
+ } catch (e) {
1497
+ return Promise.reject(e);
1498
+ }
1499
+ };
1500
+ env.stack.push({
1501
+ value,
1502
+ dispose,
1503
+ async
1504
+ });
1505
+ } else if (async) env.stack.push({ async: true });
1506
+ return value;
1227
1507
  };
1228
- /**
1229
- * Every wire protocol a configured route may name, most-reached first. The
1230
- * order is the table's and therefore stable; a configuration surface offering
1231
- * a choice presents the first as its default, which is why the protocol a
1232
- * hand-declared gateway most often speaks — and the one endpoint interrogation
1233
- * can read — leads.
1234
- * @returns the supported protocol identifiers.
1235
- */
1236
- function supportedProtocols() {
1237
- return Object.keys(PROTOCOLS);
1508
+ var __disposeResources = (function(SuppressedError) {
1509
+ return function(env) {
1510
+ function fail(e) {
1511
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
1512
+ env.hasError = true;
1513
+ }
1514
+ var r, s = 0;
1515
+ function next() {
1516
+ while (r = env.stack.pop()) try {
1517
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
1518
+ if (r.dispose) {
1519
+ var result = r.dispose.call(r.value);
1520
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
1521
+ fail(e);
1522
+ return next();
1523
+ });
1524
+ } else s |= 1;
1525
+ } catch (e) {
1526
+ fail(e);
1527
+ }
1528
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
1529
+ if (env.hasError) throw env.error;
1530
+ }
1531
+ return next();
1532
+ };
1533
+ })(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
1534
+ var e = new Error(message);
1535
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1536
+ });
1537
+ /** Copy profile stream knobs into pi-ai's common option vocabulary. */
1538
+ function profileOptions(profile, reasoning, apiKey) {
1539
+ const enabledReasoning = reasoning === "off" ? void 0 : reasoning;
1540
+ return {
1541
+ ...apiKey === void 0 ? {} : { apiKey },
1542
+ ...enabledReasoning === void 0 ? {} : { reasoning: enabledReasoning },
1543
+ ...profile.thinkingBudgets === void 0 ? {} : { thinkingBudgets: profile.thinkingBudgets },
1544
+ ...profile.cacheRetention === void 0 ? {} : { cacheRetention: profile.cacheRetention },
1545
+ ...profile.transport === void 0 ? {} : { transport: profile.transport },
1546
+ ...profile.timeoutMs === void 0 ? {} : { timeoutMs: profile.timeoutMs },
1547
+ ...profile.websocketConnectTimeoutMs === void 0 ? {} : { websocketConnectTimeoutMs: profile.websocketConnectTimeoutMs },
1548
+ maxRetries: 0
1549
+ };
1238
1550
  }
1239
1551
  /**
1240
- * Api-key auth for a route the harness authenticates itself. `Models` calls
1241
- * this after the adapter has already resolved the route's credential, so a
1242
- * missing key here is not this layer's failure: a named-but-unresolvable
1243
- * reference has already failed the request with `MISSING_CREDENTIAL`, and a
1244
- * route naming no credential at all is deliberately unauthenticated. Reporting
1245
- * it as configured hands the decision to the protocol, which is where the
1246
- * requirement actually lives pi-ai's OpenAI-compatible implementation, for
1247
- * one, still insists on a key or an `Authorization` header of its own.
1248
- * @param name - display name used as the resolution's status label.
1249
- * @returns the api-key auth for a harness-authenticated route.
1552
+ * The profile default this exact model can actually take, for DESCRIBING it.
1553
+ * A configured level the model does not support yields none rather than
1554
+ * throwing: `resolveModel` builds the model catalog, and a catalog that fails
1555
+ * takes its whole provider out of every picker so one mis-set profile field
1556
+ * would hide every model on the route, including the ones that support the
1557
+ * level. The request path still refuses, which is where a bad configuration
1558
+ * belongs: describing what a model can do must not fail because a deployment
1559
+ * asked it for something it cannot.
1560
+ * @param model - the resolved model descriptor.
1561
+ * @param effort - the profile's configured level, if any.
1562
+ * @returns the level when this model supports it, otherwise undefined.
1250
1563
  */
1251
- function harnessApiKeyAuth(name) {
1252
- return {
1253
- name,
1254
- resolve: ({ credential }) => Promise.resolve({
1255
- auth: credential?.key === void 0 ? {} : { apiKey: credential.key },
1256
- source: name
1257
- })
1258
- };
1564
+ function describableReasoningLevel(model, effort) {
1565
+ if (effort === void 0) return void 0;
1566
+ return getSupportedThinkingLevels(model).some((level) => level === effort) ? effort : void 0;
1567
+ }
1568
+ /** Validate an explicit Harness/profile effort without invoking pi-ai's clamp. */
1569
+ function resolveReasoningLevel(model, effort) {
1570
+ if (effort === void 0) return void 0;
1571
+ if (getSupportedThinkingLevels(model).some((level) => level === effort)) return effort;
1572
+ throw new LlmError(`pi-ai provider "${model.provider}" model "${model.id}" does not support reasoning effort "${effort}"`, "UNSUPPORTED_REASONING_EFFORT");
1259
1573
  }
1260
1574
  /**
1261
- * The auth one route resolves its credential through.
1262
- *
1263
- * A catalog route keeps the installed provider's own auth, which is what
1264
- * preserves provider-native ambient discovery for a profile naming no
1265
- * credential. That holds even when the profile repoints the protocol: which
1266
- * environment a provider reads is a property of the provider, not of the wire
1267
- * format its models speak.
1575
+ * Selectable reasoning efforts for one model, or nothing at all.
1268
1576
  *
1269
- * The single addition covers a catalog provider that offers no api-key method
1270
- * at all. pi-ai resolves a request's `apiKey` override only when the provider
1271
- * declares one (`resolveProviderAuth` checks `provider.auth.apiKey` before
1272
- * honouring the override), so an OAuth-only provider — `openai-codex` is the
1273
- * one the installed catalog ships would refuse a profile's explicit key with
1274
- * `Provider is not configured` before any request went out. Adding the harness
1275
- * method beside the provider's own restores that route. A keyless profile adds
1276
- * nothing and still reports the honest refusal, because this adapter resolves
1277
- * credentials through its own seam and holds no OAuth store to fall back on.
1278
- * @param spec - the resolved route facts.
1279
- * @param catalog - the installed catalog provider, when pi-ai ships one.
1280
- * @returns the auth to construct this route's provider with.
1577
+ * A model that carries no reasoning metadata every hand-declared one, and
1578
+ * every catalog model pi-ai marks as non-reasoning is reported by pi-ai as
1579
+ * supporting the single level `off`. Passing that through would offer a control
1580
+ * that cannot do what it says: `off` is translated to *omitting* the reasoning
1581
+ * option, which for such a model is byte-for-byte the same request as naming no
1582
+ * effort so a provider whose own default is to think would keep thinking with
1583
+ * `off` selected. Omitting `reasoning` entirely is the seam's way of saying the
1584
+ * capability is unavailable, which leaves the surface offering only the
1585
+ * provider's default.
1586
+ * @param model - the resolved model descriptor.
1587
+ * @param defaultLevel - the profile's configured effort, already validated.
1588
+ * @returns the `reasoning` field, or an empty object when none can be offered.
1281
1589
  */
1282
- function routeAuth(spec, catalog) {
1283
- if (catalog === void 0) return { apiKey: harnessApiKeyAuth(spec.displayName) };
1284
- if (catalog.auth.apiKey !== void 0 || !spec.namesCredential) return catalog.auth;
1590
+ function reasoningInfo(model, defaultLevel) {
1591
+ if (!model.reasoning) return {};
1592
+ return { reasoning: {
1593
+ efforts: getSupportedThinkingLevels(model).map((level) => ({
1594
+ id: ReasoningEffortId(level),
1595
+ name: `${level.charAt(0).toUpperCase()}${level.slice(1)}`
1596
+ })),
1597
+ ...defaultLevel === void 0 ? {} : { defaultEffort: ReasoningEffortId(defaultLevel) }
1598
+ } };
1599
+ }
1600
+ /** Merge deployment headers while removing case-insensitive attribution collisions. */
1601
+ function requestHeaders(headers) {
1602
+ const attribution = attributionHeaders();
1603
+ const reserved = new Set(Object.keys(attribution).map((name) => name.toLowerCase()));
1285
1604
  return {
1286
- ...catalog.auth,
1287
- apiKey: harnessApiKeyAuth(spec.displayName)
1605
+ ...Object.fromEntries(Object.entries(headers ?? {}).filter(([name]) => !reserved.has(name.toLowerCase()))),
1606
+ ...attribution
1288
1607
  };
1289
1608
  }
1290
1609
  /**
1291
- * Reuse an installed catalog provider with this route's models and identity.
1292
- * Model dispatch stays with the catalog provider, so its API implementations,
1293
- * compatibility quirks, and ambient credential discovery are preserved exactly.
1294
- * Catalog-owned dynamic refresh is dropped: this route's catalog is the
1295
- * settings document, and a background refresh would contradict it.
1610
+ * pi-ai-backed multi-provider adapter. Each operation reads the current
1611
+ * profiles, so a configuration change reaches the next request without a
1612
+ * restart; model descriptors come from the collection those profiles built.
1296
1613
  */
1297
- function reuseCatalogProvider(base, spec) {
1298
- const baseUrl = spec.baseURL ?? base.baseUrl;
1299
- return {
1300
- id: spec.provider,
1301
- name: spec.displayName,
1302
- ...baseUrl === void 0 ? {} : { baseUrl },
1303
- auth: routeAuth(spec, base),
1304
- getModels: () => spec.models,
1305
- stream: (model, context, options) => base.stream(model, context, options),
1306
- streamSimple: (model, context, options) => base.streamSimple(model, context, options)
1307
- };
1308
- }
1614
+ var PiAiAdapter = class extends LlmAdapter {
1615
+ config;
1616
+ snapshot;
1617
+ constructor(config) {
1618
+ super();
1619
+ this.config = config;
1620
+ }
1621
+ /**
1622
+ * The snapshot for the current profiles. Resolution memoizes its result, so
1623
+ * an unchanged configuration is recognized by identity; a changed one gets a
1624
+ * brand-new collection, leaving any snapshot an operation already captured
1625
+ * untouched for as long as that operation holds it.
1626
+ */
1627
+ current() {
1628
+ const profiles = this.config.profiles();
1629
+ if (this.snapshot?.profiles === profiles) return this.snapshot;
1630
+ const models = createModels(this.config.auth);
1631
+ for (const profile of profiles.values()) models.setProvider(profile.piProvider);
1632
+ this.snapshot = {
1633
+ profiles,
1634
+ models
1635
+ };
1636
+ return this.snapshot;
1637
+ }
1638
+ /** The profile for one route within one snapshot, or the not-owned failure. */
1639
+ profileOf(snapshot, provider) {
1640
+ const profile = snapshot.profiles.get(provider);
1641
+ if (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider "${provider}"`, "NO_ADAPTER");
1642
+ return profile;
1643
+ }
1644
+ /** The configured descriptor for one exact route/model pair within one snapshot. */
1645
+ modelOf(snapshot, provider, model) {
1646
+ this.profileOf(snapshot, provider);
1647
+ const resolved = snapshot.models.getModel(provider, model);
1648
+ if (resolved === void 0) throw new LlmError(`pi-ai provider "${provider}" has no configured model "${model}"`, "UNKNOWN_MODEL");
1649
+ return resolved;
1650
+ }
1651
+ providerInfo(provider) {
1652
+ return {
1653
+ id: provider,
1654
+ name: this.current().profiles.get(provider)?.displayName ?? provider
1655
+ };
1656
+ }
1657
+ providerRetryPolicy(provider) {
1658
+ return this.current().profiles.get(provider)?.retryPolicy;
1659
+ }
1660
+ listModels(provider) {
1661
+ return Promise.resolve().then(() => {
1662
+ const snapshot = this.current();
1663
+ this.profileOf(snapshot, provider);
1664
+ return snapshot.models.getModels(provider).map((model) => ({
1665
+ provider,
1666
+ id: model.id,
1667
+ name: model.name,
1668
+ inputModalities: [...model.input]
1669
+ }));
1670
+ });
1671
+ }
1672
+ resolveModel(provider, model, _signal) {
1673
+ return Promise.resolve().then(() => {
1674
+ const snapshot = this.current();
1675
+ return this.modelInfo(snapshot, provider, model);
1676
+ });
1677
+ }
1678
+ modelInfo(snapshot, provider, model) {
1679
+ const profile = this.profileOf(snapshot, provider);
1680
+ const resolvedModel = this.modelOf(snapshot, provider, model);
1681
+ const defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);
1682
+ const configuredMaxTokens = profile.configuredMaxTokens.get(model);
1683
+ return {
1684
+ provider,
1685
+ id: model,
1686
+ name: resolvedModel.name,
1687
+ inputModalities: [...resolvedModel.input],
1688
+ context: { contextWindow: resolvedModel.contextWindow },
1689
+ ...configuredMaxTokens === void 0 ? {} : { defaultMaxTokens: configuredMaxTokens },
1690
+ ...reasoningInfo(resolvedModel, defaultLevel)
1691
+ };
1692
+ }
1693
+ prepareCall(provider, model, _signal) {
1694
+ const snapshot = this.current();
1695
+ return Promise.resolve({
1696
+ model: this.modelInfo(snapshot, provider, model),
1697
+ stream: (options) => this.streamWithSnapshot(options, snapshot)
1698
+ });
1699
+ }
1700
+ stream(options) {
1701
+ return this.streamWithSnapshot(options, this.current());
1702
+ }
1703
+ async *streamWithSnapshot(options, snapshot) {
1704
+ const env_1 = {
1705
+ stack: [],
1706
+ error: void 0,
1707
+ hasError: false
1708
+ };
1709
+ try {
1710
+ if (options.stop !== void 0) throw new LlmError("llm-pi-ai does not support GenerateOptions.stop", "UNSUPPORTED_OPTION");
1711
+ const profile = this.profileOf(snapshot, options.provider);
1712
+ const model = this.modelOf(snapshot, options.provider, options.model);
1713
+ const reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);
1714
+ const apiKey = await this.config.resolveApiKey(options.provider, profile);
1715
+ const consumer = new AbortController();
1716
+ const upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);
1717
+ const streamIdleTimeoutMs = profile.streamIdleTimeoutMs;
1718
+ const watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, "LLM_STREAM_IDLE_TIMEOUT"), false);
1719
+ try {
1720
+ const containsImage = options.messages.some((message) => contentHasImage(message.content));
1721
+ if (containsImage && !model.input.includes("image")) throw new LlmError(`pi-ai model "${model.id}" does not support image input`, "UNSUPPORTED_CONTENT");
1722
+ const attachments = containsImage ? this.config.resolveAttachments?.() : void 0;
1723
+ if (containsImage && attachments === void 0) throw new LlmError("pi-ai image input requires the durable attachment service", "UNSUPPORTED_CONTENT");
1724
+ const onReplayDegrade = (reason) => {
1725
+ this.config.onReplayDegrade?.({
1726
+ provider: options.provider,
1727
+ model: options.model,
1728
+ reason
1729
+ });
1730
+ };
1731
+ const context = attachments === void 0 ? toPiContext(options, void 0, onReplayDegrade) : await toPiContext({
1732
+ ...options,
1733
+ signal: watchdog.signal
1734
+ }, attachments, onReplayDegrade, profile.maxRequestImageBytes, {
1735
+ maxPixels: profile.requestImagePixelBudget,
1736
+ maxBytes: profile.requestImageMaxBytes
1737
+ });
1738
+ const iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {
1739
+ ...profileOptions(profile, reasoning, apiKey),
1740
+ ...options.temperature === void 0 ? {} : { temperature: options.temperature },
1741
+ ...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },
1742
+ ...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },
1743
+ signal: watchdog.signal,
1744
+ headers: requestHeaders(profile.headers)
1745
+ }), model.contextWindow)[Symbol.asyncIterator]();
1746
+ let exhausted = false;
1747
+ try {
1748
+ while (true) {
1749
+ const result = await watchdog.next(iterator);
1750
+ const timeout = timeoutOf(watchdog.signal, "LLM_STREAM_IDLE_TIMEOUT");
1751
+ if (timeout !== void 0) throw timeout;
1752
+ if (result.done) {
1753
+ exhausted = true;
1754
+ return;
1755
+ }
1756
+ yield result.value;
1757
+ }
1758
+ } finally {
1759
+ if (!exhausted) {
1760
+ consumer.abort("pi-ai stream consumer stopped");
1761
+ try {
1762
+ await iterator.return(void 0);
1763
+ } catch (_abortedSdkTeardown) {}
1764
+ }
1765
+ }
1766
+ } catch (error) {
1767
+ if (timeoutOf(watchdog.signal, "LLM_STREAM_IDLE_TIMEOUT") !== void 0) throw new LlmError(`pi-ai stream idle timeout after ${streamIdleTimeoutMs}ms`, "TIMEOUT", { cause: error });
1768
+ if (options.signal?.aborted) throw new LlmError("pi-ai request aborted by caller", "ABORTED", { cause: error });
1769
+ throw error;
1770
+ } finally {
1771
+ consumer.abort("pi-ai stream consumer stopped");
1772
+ }
1773
+ } catch (e_1) {
1774
+ env_1.error = e_1;
1775
+ env_1.hasError = true;
1776
+ } finally {
1777
+ __disposeResources(env_1);
1778
+ }
1779
+ }
1780
+ };
1781
+ //#endregion
1782
+ //#region lib/types/auth.js
1309
1783
  /**
1310
- * Build the pi-ai provider for one resolved route.
1311
- * @param spec - the resolved route facts.
1312
- * @returns the provider to register in the adapter's `Models` collection.
1313
- * @throws Error when the route names a wire protocol this build cannot serve.
1784
+ * The three adapters between pi-ai's auth model and the harness credential
1785
+ * plane. Every pi-ai-specific concept stays on this side of them: the harness
1786
+ * seams they consume `ctx.credentials` records and `ctx.authorization` flows —
1787
+ * name nothing from this library, so another adapter family can arrive with a
1788
+ * different auth model and share the same two seams.
1789
+ *
1790
+ * @module nomix-llm-pi-ai/auth
1314
1791
  */
1315
- function buildProvider(spec) {
1316
- const catalog = catalogProvider(spec.provider);
1317
- if (catalog !== void 0 && spec.api === void 0) return reuseCatalogProvider(catalog, spec);
1318
- const factory = spec.api === void 0 ? void 0 : PROTOCOLS[spec.api];
1319
- if (factory === void 0) throw new Error(`llm-pi-ai: provider "${spec.provider}" names api "${spec.api}", which this build cannot serve; supported protocols are ${supportedProtocols().join(", ")}`);
1320
- return createProvider({
1321
- id: spec.provider,
1322
- name: spec.displayName,
1323
- ...spec.baseURL === void 0 ? {} : { baseUrl: spec.baseURL },
1324
- auth: routeAuth(spec, catalog),
1325
- models: spec.models,
1326
- api: factory()
1327
- });
1792
+ /**
1793
+ * The record scope every credential this adapter family stores is written
1794
+ * under. It is the plugin's registered name, which is what tells a later
1795
+ * reader a configuration UI, or a second adapter family serving the same
1796
+ * provider name that this plugin owns the format inside the record.
1797
+ */
1798
+ const RECORD_SCOPE = "llm-pi-ai";
1799
+ /**
1800
+ * The record address for one pi-ai provider id.
1801
+ * @param providerId - pi-ai's own provider id, which is also the harness route key.
1802
+ * @returns the scoped credential key this adapter family reads and writes.
1803
+ */
1804
+ function recordKeyFor(providerId) {
1805
+ return credentialKey(RECORD_SCOPE, providerId);
1328
1806
  }
1329
- //#endregion
1330
- //#region lib/types/config.js
1331
1807
  /**
1332
- * Configuration schema and provider-profile validation for the pi-ai adapter.
1333
- * Profiles are a dict keyed by provider route, so the composition base and a
1334
- * user-settings layer merge per provider and the route set is structural.
1335
- *
1336
- * A route key is not required to name an installed pi-ai provider. When it does,
1337
- * that provider's endpoint, protocol, display name, and model catalog are the
1338
- * profile's defaults and the profile overrides them field by field; when it does
1339
- * not, the profile is the whole provider declaration. Resolution therefore ends
1340
- * in a built pi-ai `Provider` per route: everything a request needs is decided
1341
- * once, while the configuration key that made a route unserviceable can still be
1342
- * named in the failure.
1808
+ * Translate a stored record into the credential pi-ai expects.
1343
1809
  *
1344
- * @module nomix-llm-pi-ai/config
1810
+ * An `api-key` record is structural on both sides, so it is rebuilt field by
1811
+ * field. A `grant` payload is pi-ai's own OAuth credential, stored verbatim:
1812
+ * the seam treats it as opaque JSON precisely so a library that owns a token
1813
+ * format keeps owning it, refresh fields and all.
1814
+ * @param record - the stored record, or undefined when nothing is stored.
1815
+ * @returns the pi-ai credential, or undefined for an absent record.
1345
1816
  */
1346
- /** Default maximum idle interval while an adapter stream read is outstanding. */
1347
- const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 3e5;
1348
- /** Context capacity assumed for a model neither configuration nor the catalog sizes. */
1349
- const DEFAULT_CONTEXT_WINDOW = 262144;
1350
- /** Output capability assumed for a model neither configuration nor the catalog sizes. */
1351
- const DEFAULT_MAX_TOKENS = 32768;
1817
+ function toPiCredential(record) {
1818
+ if (record === void 0) return void 0;
1819
+ if (record.kind === "api-key") return {
1820
+ type: "api_key",
1821
+ ...record.key === void 0 ? {} : { key: record.key },
1822
+ ...record.env === void 0 ? {} : { env: { ...record.env } }
1823
+ };
1824
+ return record.payload;
1825
+ }
1352
1826
  /**
1353
- * Modalities assumed for a model neither configuration nor the catalog
1354
- * declares. Text is the floor every supported protocol certainly carries, so
1355
- * this is the absence of a declaration rather than a guess at the endpoint:
1356
- * nothing can interrogate a gateway for its modalities, and the two wrong
1357
- * answers do not cost the same. Under-claiming refuses the image before it is
1358
- * attached, naming the model. Over-claiming admits one the provider then
1359
- * rejects mid-turn, after the message is durable, leaving the session
1360
- * repeating a request that cannot succeed.
1827
+ * Translate a pi-ai credential into the record to store.
1828
+ * @param credential - what a login or refresh produced.
1829
+ * @returns the record to commit, in the union the credential seam stores.
1361
1830
  */
1362
- const DEFAULT_INPUT = ["text"];
1363
- const thinkingBudgets = z.object({
1364
- minimal: z.number(),
1365
- low: z.number(),
1366
- medium: z.number(),
1367
- high: z.number()
1368
- });
1369
- const compatProfile = z.object({
1370
- thinkingFormat: z.union(SUPPORTED_THINKING_FORMATS),
1371
- supportsReasoningEffort: z.boolean()
1372
- });
1831
+ function toRecord(credential) {
1832
+ if (credential.type === "api_key") return {
1833
+ kind: "api-key",
1834
+ ...credential.key === void 0 ? {} : { key: credential.key },
1835
+ ...credential.env === void 0 ? {} : { env: { ...credential.env } }
1836
+ };
1837
+ return {
1838
+ kind: "grant",
1839
+ payload: credential
1840
+ };
1841
+ }
1373
1842
  /**
1374
- * Keys are the offered levels, values their wire spellings. A valueless key
1375
- * (`off:`) survives validation because schemastery passes nullable data
1376
- * through before any member schema runs `z.const(null)` only controls the
1377
- * error for non-null wrong values and what a configuration UI renders.
1378
- * Only resolution decides which levels may leave the value empty, so the
1379
- * diagnostic can name the route and model. The assertion narrows
1380
- * schemastery's `Dict`, which types every literal key as required; dict
1381
- * validation checks only present keys, so the runtime value is a partial record.
1843
+ * The credential service, or the failure that names what is missing. Reads
1844
+ * answer "nothing stored" without a service, because a composition with no
1845
+ * credential plane genuinely holds no credential; writes refuse, because a
1846
+ * login whose grant silently evaporated would report success and then fail
1847
+ * every request.
1848
+ * @param ctx - the plugin context.
1849
+ * @returns the live service.
1850
+ * @throws {LlmError} code `NO_CREDENTIAL_STORE` when none is mounted.
1382
1851
  */
1383
- const reasoningEfforts = z.dict(z.union([z.string(), z.const(null)]), z.union(THINKING_LEVELS));
1384
- /** The fields a `models` entry and a `modelOverrides` value share; only the id's home differs. */
1385
- const modelFields = {
1386
- name: z.string(),
1387
- contextWindow: z.number().step(1).min(1),
1388
- maxTokens: z.number().step(1).min(1),
1389
- input: z.array(z.union(MODALITIES)),
1390
- reasoningEfforts: z.union([z.const(false), reasoningEfforts]),
1391
- compat: compatProfile
1392
- };
1393
- const modelProfile = z.object({
1394
- id: z.string().required(),
1395
- ...modelFields
1396
- });
1397
- /** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */
1398
- const modelOverride = z.object(modelFields);
1399
- const profile = z.object({
1400
- apiKeyEnv: z.string().role("credential-ref"),
1401
- displayName: z.string(),
1402
- api: z.union(supportedProtocols()),
1403
- baseURL: z.string(),
1404
- models: z.array(modelProfile),
1405
- modelOverrides: z.dict(modelOverride),
1406
- compat: compatProfile,
1407
- defaultContextWindow: z.number().step(1).min(1).default(DEFAULT_CONTEXT_WINDOW),
1408
- defaultMaxTokens: z.number().step(1).min(1).default(DEFAULT_MAX_TOKENS),
1409
- defaultInput: z.array(z.union(MODALITIES)).default([...DEFAULT_INPUT]),
1410
- headers: z.dict(z.string()),
1411
- reasoning: z.union(THINKING_LEVELS),
1412
- thinkingBudgets,
1413
- cacheRetention: z.union([
1414
- "none",
1415
- "short",
1416
- "long"
1417
- ]),
1418
- transport: z.union([
1419
- "sse",
1420
- "websocket",
1421
- "websocket-cached",
1422
- "auto"
1423
- ]),
1424
- timeoutMs: z.natural(),
1425
- websocketConnectTimeoutMs: z.natural(),
1426
- streamIdleTimeoutMs: z.number().min(Number.MIN_VALUE).max(MAX_TIMER_DELAY_MS).default(DEFAULT_STREAM_IDLE_TIMEOUT_MS),
1427
- retryPolicy: RetryPolicySchema
1428
- });
1429
- /** Runtime schema for {@link Config}. */
1430
- const Config = z.object({ providers: z.dict(profile).default({}) });
1852
+ function writableStore(ctx) {
1853
+ const credentials = ctx.get("credentials");
1854
+ if (credentials === void 0) throw new LlmError("llm-pi-ai: this composition mounts no credentials service, so there is nowhere to store the credential a sign-in produces; mount one (nomix-credentials-local) to sign in", "NO_CREDENTIAL_STORE");
1855
+ return credentials;
1856
+ }
1431
1857
  /**
1432
- * Reject a section this adapter could not serve. Registered as the settings
1433
- * namespace's validator, so an unserviceable profile is refused where it is
1434
- * *written* `settings.mutate` answers `settings-rejected` with the offending
1435
- * route and model named instead of being stored and then quietly disabling
1436
- * every route in the namespace. It stays a validator rather than a schema
1437
- * transform because the schema is also the shape a configuration surface
1438
- * renders and the value an absent section resolves to; wrapping it would break
1439
- * both.
1440
- * @param config - the resolved section to check.
1441
- * @throws Error naming the route and model that cannot be served.
1858
+ * A pi-ai `CredentialStore` over the harness credential records.
1859
+ *
1860
+ * pi-ai runs OAuth refresh *inside* `modify()`, so this store's exclusion has
1861
+ * to cover a network round trip rather than a file rename which is why the
1862
+ * record write path takes a wait limit of its own rather than the short one a
1863
+ * local write would need.
1864
+ *
1865
+ * pi-ai asks this store about every provider in the collection, hand-declared
1866
+ * routes included, and a route key is an arbitrary settings dict key while a
1867
+ * record id is not. An id outside the record grammar can never have stored a
1868
+ * record, so reads answer "nothing stored" and a delete has nothing to remove;
1869
+ * only `modify` refuses it, because a write that cannot land must not report
1870
+ * that it did.
1871
+ * @param ctx - the plugin context carrying the optional `ctx.credentials`.
1872
+ * @returns the store to hand `createModels()`.
1442
1873
  */
1443
- function assertServiceable(config) {
1444
- resolveProfiles(config.providers);
1445
- }
1446
- /** Reject removed pre-release profile fields and name their replacements. */
1447
- function rejectRemovedFields(provider, source) {
1448
- const legacy = source;
1449
- if ("provider" in legacy) throw new Error(`llm-pi-ai: provider "${provider}" sets "provider", which moved to the providers dict key`);
1450
- if ("maxRetries" in legacy || "maxRetryDelayMs" in legacy) throw new Error(`llm-pi-ai: provider "${provider}" sets maxRetries or maxRetryDelayMs, which were removed; compose agent recovery with nomix-llm-retry`);
1874
+ function credentialStoreFrom(ctx) {
1875
+ return {
1876
+ async read(providerId) {
1877
+ const credentials = ctx.get("credentials");
1878
+ if (credentials === void 0) return void 0;
1879
+ if (!isCredentialKeySegment(providerId)) return void 0;
1880
+ return toPiCredential(await credentials.readRecord(recordKeyFor(providerId)));
1881
+ },
1882
+ async list() {
1883
+ const stored = await ctx.get("credentials")?.listRecords() ?? [];
1884
+ const mine = [];
1885
+ for (const entry of stored) {
1886
+ if (credentialKeyScope(entry.key) !== "llm-pi-ai") continue;
1887
+ mine.push({
1888
+ providerId: credentialKeyId(entry.key),
1889
+ type: entry.kind === "api-key" ? "api_key" : "oauth"
1890
+ });
1891
+ }
1892
+ return mine;
1893
+ },
1894
+ async modify(providerId, mutate) {
1895
+ if (!isCredentialKeySegment(providerId)) throw new LlmError(`llm-pi-ai: provider id "${providerId}" cannot address a stored credential record (a record id is a lowercase hyphenated identifier); authenticate this route through apiKeyEnv instead of a stored credential`, "UNSTORABLE_PROVIDER_ID");
1896
+ return toPiCredential(await writableStore(ctx).modifyRecord(recordKeyFor(providerId), async (current) => {
1897
+ const next = await mutate(toPiCredential(current));
1898
+ return next === void 0 ? void 0 : toRecord(next);
1899
+ }));
1900
+ },
1901
+ async delete(providerId) {
1902
+ if (!isCredentialKeySegment(providerId)) return;
1903
+ await writableStore(ctx).deleteRecord(recordKeyFor(providerId));
1904
+ }
1905
+ };
1451
1906
  }
1452
1907
  /**
1453
- * Validate profiles and return a detached route-keyed map suitable for
1454
- * per-request reads. This is the one explicit resolve step, so an omitted dict
1455
- * resolves to the empty (dormant) route set here rather than through a hidden
1456
- * fallback, and each route's models and pi-ai provider are materialized once.
1457
- * @param providers - configured provider profiles keyed by route.
1458
- * @returns validated profiles in configuration order.
1908
+ * A pi-ai `AuthContext` over the harness credential plane and the host
1909
+ * filesystem.
1910
+ *
1911
+ * `env()` answers from the credential seam first, so a value a deployment
1912
+ * stored through the harness is found by a provider's own ambient discovery
1913
+ * without this, that discovery reads only the process environment and a stored
1914
+ * `AWS_ACCESS_KEY_ID` is invisible to it. `fileExists()` answers about the host
1915
+ * process's own filesystem rather than the workspace `ctx.fs` seam, because the
1916
+ * paths it is asked about (`~/.aws/credentials`, application-default
1917
+ * credentials) are facts about where this process runs, not about the project
1918
+ * under edit.
1919
+ * @param ctx - the plugin context carrying the optional `ctx.credentials`.
1920
+ * @returns the auth context to hand `createModels()`.
1459
1921
  */
1460
- function resolveProfiles(providers) {
1461
- if (Array.isArray(providers)) throw new Error("llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles");
1462
- const entries = Object.entries(providers ?? {});
1463
- const resolved = /* @__PURE__ */ new Map();
1464
- for (const [provider, source] of entries) {
1465
- rejectRemovedFields(provider, source);
1466
- if (provider.length === 0) throw new Error("llm-pi-ai: provider names must be non-empty");
1467
- if (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider "${provider}" has an empty baseURL`);
1468
- if (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider "${provider}" has an empty displayName`);
1469
- const streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;
1470
- if (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider "${provider}" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);
1471
- const defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];
1472
- if (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider "${provider}" defaultInput must name at least one modality`);
1473
- const displayName = source.displayName ?? provider;
1474
- const catalog = resolveRouteModels({
1475
- provider,
1476
- ...source.api === void 0 ? {} : { api: source.api },
1477
- ...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },
1478
- ...source.models === void 0 ? {} : { models: source.models },
1479
- ...source.modelOverrides === void 0 ? {} : { modelOverrides: source.modelOverrides },
1480
- ...source.compat === void 0 ? {} : { compat: source.compat },
1481
- defaultInput,
1482
- defaultContextWindow: source.defaultContextWindow ?? 262144,
1483
- defaultMaxTokens: source.defaultMaxTokens ?? 32768
1484
- });
1485
- const { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;
1486
- resolved.set(provider, {
1487
- ...rest,
1488
- provider,
1489
- displayName,
1490
- ...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },
1491
- streamIdleTimeoutMs,
1492
- retryPolicy: resolveRetryPolicy(retryPolicy, `llm-pi-ai: provider "${provider}" retryPolicy`),
1493
- ...rest.headers === void 0 ? {} : { headers: { ...rest.headers } },
1494
- ...rest.thinkingBudgets === void 0 ? {} : { thinkingBudgets: { ...rest.thinkingBudgets } },
1495
- configuredMaxTokens: catalog.configuredMaxTokens,
1496
- piProvider: buildProvider({
1497
- provider,
1498
- displayName,
1499
- ...source.api === void 0 ? {} : { api: source.api },
1500
- ...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },
1501
- models: catalog.models,
1502
- namesCredential: apiKeyEnv !== void 0
1503
- })
1504
- });
1505
- }
1506
- return resolved;
1922
+ function authContextFrom(ctx) {
1923
+ return {
1924
+ async env(name) {
1925
+ if (isCredentialRefName(name)) {
1926
+ const hit = await ctx.get("credentials")?.resolve(credentialRef(name));
1927
+ if (hit !== void 0) return hit.value;
1928
+ }
1929
+ return launchEnvironmentOf(ctx).get(name)?.value;
1930
+ },
1931
+ async fileExists(path) {
1932
+ const expanded = path.startsWith("~/") || path === "~" ? resolve(homedir(), path.slice(1).replace(/^\//, "")) : path;
1933
+ try {
1934
+ await access(expanded);
1935
+ return true;
1936
+ } catch {
1937
+ return false;
1938
+ }
1939
+ }
1940
+ };
1507
1941
  }
1508
1942
  //#endregion
1509
1943
  //#region lib/types/discovery.js
@@ -1700,6 +2134,156 @@ async function discoverModels(request, storedApiKey) {
1700
2134
  return readListing(body);
1701
2135
  }
1702
2136
  //#endregion
2137
+ //#region lib/types/login.js
2138
+ /**
2139
+ * Authorization flows for the pi-ai providers that ship a login. This is the
2140
+ * whole of the translation between the harness's neutral notice/prompt
2141
+ * vocabulary and pi-ai's `AuthInteraction`; nothing above it knows which
2142
+ * library ran the conversation.
2143
+ *
2144
+ * @module nomix-llm-pi-ai/login
2145
+ */
2146
+ /**
2147
+ * The login methods one catalog provider offers.
2148
+ *
2149
+ * A method appears only when pi-ai can actually run it: `oauth` always carries
2150
+ * a `login`, while an api-key method has one only when the provider collects
2151
+ * its key interactively — which every installed one currently does, so a key is
2152
+ * typed into pi-ai's own prompt rather than into the settings form.
2153
+ * @param provider - the installed catalog provider, if pi-ai ships one.
2154
+ * @returns its methods, most preferred first; empty when it offers no login.
2155
+ */
2156
+ function loginMethods(provider) {
2157
+ const methods = [];
2158
+ const oauth = provider?.auth.oauth;
2159
+ if (oauth !== void 0) methods.push({
2160
+ id: "oauth",
2161
+ label: oauth.loginLabel ?? oauth.name
2162
+ });
2163
+ const apiKey = provider?.auth.apiKey;
2164
+ if (apiKey?.login !== void 0) methods.push({
2165
+ id: "api-key",
2166
+ label: apiKey.name
2167
+ });
2168
+ return methods;
2169
+ }
2170
+ /**
2171
+ * Restate one pi-ai login event in the seam's vocabulary.
2172
+ *
2173
+ * A device-code grant is the one event carrying two things the human needs at
2174
+ * once — where to go and what to type there — which is why the neutral notice
2175
+ * has a `code` beside its `url` rather than folding the code into the message.
2176
+ * @param event - what pi-ai reported.
2177
+ * @param session - the attempt to report it to.
2178
+ */
2179
+ function relay(event, session) {
2180
+ switch (event.type) {
2181
+ case "info": {
2182
+ const link = event.links?.[0];
2183
+ session.notify({
2184
+ message: event.message,
2185
+ ...link === void 0 ? {} : { url: link.url }
2186
+ });
2187
+ return;
2188
+ }
2189
+ case "auth_url":
2190
+ session.notify({
2191
+ message: event.instructions ?? "Open this page to continue signing in.",
2192
+ url: event.url
2193
+ });
2194
+ return;
2195
+ case "device_code":
2196
+ session.notify({
2197
+ message: "Enter this code on the verification page to finish signing in.",
2198
+ url: event.verificationUri,
2199
+ code: event.userCode
2200
+ });
2201
+ return;
2202
+ case "progress":
2203
+ session.notify({ message: event.message });
2204
+ return;
2205
+ default: session.notify({ message: "Signing in…" });
2206
+ }
2207
+ }
2208
+ /**
2209
+ * Restate one pi-ai prompt in the seam's vocabulary.
2210
+ *
2211
+ * `manual_code` becomes a plain text question because the difference pi-ai
2212
+ * draws — a code the human copies from a browser rather than a value they know
2213
+ * — changes nothing a surface renders. Its own `signal` is carried through, and
2214
+ * that is the part which matters: it is how a flow racing a typed code against
2215
+ * a browser callback withdraws the losing question.
2216
+ * @param prompt - what pi-ai asked.
2217
+ * @returns the neutral prompt to put to the human.
2218
+ */
2219
+ function restate(prompt) {
2220
+ const signal = prompt.signal === void 0 ? {} : { signal: prompt.signal };
2221
+ switch (prompt.type) {
2222
+ case "select": return {
2223
+ ...signal,
2224
+ kind: "select",
2225
+ message: prompt.message,
2226
+ options: prompt.options
2227
+ };
2228
+ case "secret": return {
2229
+ ...signal,
2230
+ kind: "secret",
2231
+ message: prompt.message,
2232
+ ...prompt.placeholder === void 0 ? {} : { placeholder: prompt.placeholder }
2233
+ };
2234
+ default: return {
2235
+ ...signal,
2236
+ kind: "text",
2237
+ message: prompt.message,
2238
+ ...prompt.placeholder === void 0 ? {} : { placeholder: prompt.placeholder }
2239
+ };
2240
+ }
2241
+ }
2242
+ /**
2243
+ * Register one authorization flow per installed provider that ships a login.
2244
+ *
2245
+ * Registration is unconditional on configuration: a provider has to be signed
2246
+ * into before a route for it is worth adding, so the flow exists from the
2247
+ * moment the plugin mounts rather than appearing once a profile does.
2248
+ * @param ctx - the plugin context carrying `ctx.authorization`.
2249
+ * @param auth - the injectables every collection here is built with.
2250
+ */
2251
+ function registerPiAiFlows(ctx, auth) {
2252
+ for (const providerId of catalogProviderIds()) {
2253
+ const provider = catalogProvider(providerId);
2254
+ const [first, ...rest] = loginMethods(provider);
2255
+ /* v8 ignore next 3 -- every id here names an installed provider and every
2256
+ installed provider ships a login, so nothing is skipped today; the guard
2257
+ is what keeps that from becoming a crash if either stops being true. */
2258
+ if (provider === void 0 || first === void 0) continue;
2259
+ /* v8 ignore next 7 -- every installed catalog id today is a lowercase
2260
+ hyphenated identifier; the guard keeps a future upstream id outside the
2261
+ record grammar (dotted or uppercase, as vendor ids elsewhere already
2262
+ are) from throwing in `recordKeyFor` and failing the whole mount. */
2263
+ if (!isCredentialKeySegment(providerId)) {
2264
+ ctx.logger.warn("llm-pi-ai: catalog provider \"%s\" cannot address a credential record; its sign-in is not offered", providerId);
2265
+ continue;
2266
+ }
2267
+ ctx.authorization.registerFlow({
2268
+ key: recordKeyFor(providerId),
2269
+ label: provider.name,
2270
+ methods: [first, ...rest],
2271
+ async run(session) {
2272
+ const models = createModels(auth);
2273
+ models.setProvider(provider);
2274
+ const type = session.method === "oauth" ? "oauth" : "api_key";
2275
+ await models.login(providerId, type, {
2276
+ signal: session.signal,
2277
+ notify: (event) => {
2278
+ relay(event, session);
2279
+ },
2280
+ prompt: (prompt) => session.prompt(restate(prompt))
2281
+ });
2282
+ }
2283
+ });
2284
+ }
2285
+ }
2286
+ //#endregion
1703
2287
  //#region lib/types/index.js
1704
2288
  /**
1705
2289
  * Generic pi-ai-backed LLM adapter plugin. One plugin instance owns a dict of
@@ -1773,15 +2357,10 @@ function registrationFacts(profiles) {
1773
2357
  })).sort((left, right) => left.provider.localeCompare(right.provider));
1774
2358
  }
1775
2359
  /**
1776
- * The configurable-provider directory: every installed catalog route this
1777
- * adapter can authenticate, plus every route the current profiles declare. A
1778
- * hand-declared route has no catalog entry, so without this union it would
1779
- * have no settings address and configuration surfaces could neither show nor
1780
- * edit it.
1781
- *
1782
- * The profile half is unconditional, which is what keeps a route already
1783
- * stored against a withheld provider editable and deletable rather than
1784
- * stranded in the settings document with nothing on the page to remove it.
2360
+ * The configurable-provider directory: every installed catalog route, plus
2361
+ * every route the current profiles declare. A hand-declared route has no
2362
+ * catalog entry, so without this union it would have no settings address and
2363
+ * configuration surfaces could neither show nor edit it.
1785
2364
  * @param profiles - the currently resolved provider profiles.
1786
2365
  * @returns the directory entries in catalog order, declared routes last.
1787
2366
  */
@@ -1797,7 +2376,7 @@ function directoryEntries(profiles) {
1797
2376
  declared: !catalog.has(provider)
1798
2377
  });
1799
2378
  };
1800
- for (const provider of catalog) if (catalogProviderTakesApiKey(provider)) declare(provider, provider);
2379
+ for (const provider of catalog) declare(provider, provider);
1801
2380
  for (const [provider, profile] of profiles) declare(provider, profile.displayName);
1802
2381
  return [...entries.values()];
1803
2382
  }
@@ -1834,14 +2413,22 @@ function apply(ctx, config) {
1834
2413
  if (hit !== void 0 && hit.length > 0) return assertUsableApiKey(hit, "llm-pi-ai", ref);
1835
2414
  throw new LlmError(`llm-pi-ai: no credential for provider route "${provider}"; its profile resolves ${ref}, which is not set — store ${ref} through the credentials service (the web Models page writes it) or export it, and remove apiKeyEnv only if this provider should authenticate from pi-ai's own environment discovery`, "MISSING_CREDENTIAL");
1836
2415
  };
2416
+ const auth = {
2417
+ credentials: credentialStoreFrom(ctx),
2418
+ authContext: authContextFrom(ctx)
2419
+ };
1837
2420
  const adapter = new PiAiAdapter({
1838
2421
  profiles,
1839
2422
  resolveApiKey,
2423
+ auth,
1840
2424
  resolveAttachments: () => ctx.get("attachments"),
1841
2425
  onReplayDegrade: ({ provider, model, reason }) => {
1842
2426
  ctx.logger.warn(`llm-pi-ai: unusable replay state on assistant history for route "${provider}/${model}"; sending that message as provider-neutral content (${reason})`);
1843
2427
  }
1844
2428
  });
2429
+ ctx.inject(["authorization"], (authorized) => {
2430
+ registerPiAiFlows(authorized, auth);
2431
+ });
1845
2432
  let directory;
1846
2433
  let directoryFacts;
1847
2434
  const ensureDirectory = () => {
@@ -1904,4 +2491,4 @@ function apply(ctx, config) {
1904
2491
  });
1905
2492
  }
1906
2493
  //#endregion
1907
- export { Config, PiAiAdapter, apply, inject, name, supportedProtocols };
2494
+ export { Config, PiAiAdapter, apply, inject, name, recordKeyFor, supportedProtocols };