@averyyy/pi-coding-agent 0.82.1-piclient.9 → 0.84.1-piclient.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (353) hide show
  1. package/CHANGELOG.md +272 -0
  2. package/README.md +6 -1
  3. package/dist/cli/args.d.ts +2 -0
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +27 -1
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/auth-check.d.ts +19 -0
  8. package/dist/cli/auth-check.d.ts.map +1 -0
  9. package/dist/cli/auth-check.js +50 -0
  10. package/dist/cli/auth-check.js.map +1 -0
  11. package/dist/cli/auth-command.d.ts +24 -0
  12. package/dist/cli/auth-command.d.ts.map +1 -0
  13. package/dist/cli/auth-command.js +102 -0
  14. package/dist/cli/auth-command.js.map +1 -0
  15. package/dist/cli/config-selector.d.ts.map +1 -1
  16. package/dist/cli/config-selector.js +2 -2
  17. package/dist/cli/config-selector.js.map +1 -1
  18. package/dist/cli/credential-print.d.ts +13 -0
  19. package/dist/cli/credential-print.d.ts.map +1 -0
  20. package/dist/cli/credential-print.js +76 -0
  21. package/dist/cli/credential-print.js.map +1 -0
  22. package/dist/cli/experimental/auth.d.ts +16 -0
  23. package/dist/cli/experimental/auth.d.ts.map +1 -0
  24. package/dist/cli/experimental/auth.js +13 -0
  25. package/dist/cli/experimental/auth.js.map +1 -0
  26. package/dist/cli/experimental/cli.d.ts +6 -0
  27. package/dist/cli/experimental/cli.d.ts.map +1 -0
  28. package/dist/cli/experimental/cli.js +5 -0
  29. package/dist/cli/experimental/cli.js.map +1 -0
  30. package/dist/cli/experimental/command-options.d.ts +17 -0
  31. package/dist/cli/experimental/command-options.d.ts.map +1 -0
  32. package/dist/cli/experimental/command-options.js +35 -0
  33. package/dist/cli/experimental/command-options.js.map +1 -0
  34. package/dist/cli/experimental/command.d.ts +63 -0
  35. package/dist/cli/experimental/command.d.ts.map +1 -0
  36. package/dist/cli/experimental/command.js +130 -0
  37. package/dist/cli/experimental/command.js.map +1 -0
  38. package/dist/cli/experimental/commands/client.d.ts +13 -0
  39. package/dist/cli/experimental/commands/client.d.ts.map +1 -0
  40. package/dist/cli/experimental/commands/client.js +25 -0
  41. package/dist/cli/experimental/commands/client.js.map +1 -0
  42. package/dist/cli/experimental/commands/pi.d.ts +15 -0
  43. package/dist/cli/experimental/commands/pi.d.ts.map +1 -0
  44. package/dist/cli/experimental/commands/pi.js +28 -0
  45. package/dist/cli/experimental/commands/pi.js.map +1 -0
  46. package/dist/cli/experimental/commands/server.d.ts +13 -0
  47. package/dist/cli/experimental/commands/server.d.ts.map +1 -0
  48. package/dist/cli/experimental/commands/server.js +25 -0
  49. package/dist/cli/experimental/commands/server.js.map +1 -0
  50. package/dist/cli/experimental/transport-address.d.ts +10 -0
  51. package/dist/cli/experimental/transport-address.d.ts.map +1 -0
  52. package/dist/cli/experimental/transport-address.js +38 -0
  53. package/dist/cli/experimental/transport-address.js.map +1 -0
  54. package/dist/cli/list-models.d.ts +1 -1
  55. package/dist/cli/list-models.d.ts.map +1 -1
  56. package/dist/cli/list-models.js +2 -2
  57. package/dist/cli/list-models.js.map +1 -1
  58. package/dist/cli/startup-ui.d.ts +1 -1
  59. package/dist/cli/startup-ui.d.ts.map +1 -1
  60. package/dist/cli/startup-ui.js +2 -2
  61. package/dist/cli/startup-ui.js.map +1 -1
  62. package/dist/cli.d.ts.map +1 -1
  63. package/dist/cli.js +1 -0
  64. package/dist/cli.js.map +1 -1
  65. package/dist/client/index.d.ts +3 -0
  66. package/dist/client/index.d.ts.map +1 -0
  67. package/dist/client/index.js +3 -0
  68. package/dist/client/index.js.map +1 -0
  69. package/dist/client/remote-session.d.ts +53 -0
  70. package/dist/client/remote-session.d.ts.map +1 -0
  71. package/dist/client/remote-session.js +340 -0
  72. package/dist/client/remote-session.js.map +1 -0
  73. package/dist/client/transcript.d.ts +12 -0
  74. package/dist/client/transcript.d.ts.map +1 -0
  75. package/dist/client/transcript.js +98 -0
  76. package/dist/client/transcript.js.map +1 -0
  77. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  78. package/dist/core/agent-session-runtime.js +3 -0
  79. package/dist/core/agent-session-runtime.js.map +1 -1
  80. package/dist/core/agent-session-services.d.ts +1 -0
  81. package/dist/core/agent-session-services.d.ts.map +1 -1
  82. package/dist/core/agent-session-services.js +1 -0
  83. package/dist/core/agent-session-services.js.map +1 -1
  84. package/dist/core/agent-session.d.ts +3 -12
  85. package/dist/core/agent-session.d.ts.map +1 -1
  86. package/dist/core/agent-session.js +74 -65
  87. package/dist/core/agent-session.js.map +1 -1
  88. package/dist/core/auth-storage.d.ts +25 -9
  89. package/dist/core/auth-storage.d.ts.map +1 -1
  90. package/dist/core/auth-storage.js +237 -39
  91. package/dist/core/auth-storage.js.map +1 -1
  92. package/dist/core/extensions/index.d.ts +1 -1
  93. package/dist/core/extensions/index.d.ts.map +1 -1
  94. package/dist/core/extensions/index.js.map +1 -1
  95. package/dist/core/extensions/loader.d.ts.map +1 -1
  96. package/dist/core/extensions/loader.js +43 -20
  97. package/dist/core/extensions/loader.js.map +1 -1
  98. package/dist/core/extensions/runner.d.ts +3 -1
  99. package/dist/core/extensions/runner.d.ts.map +1 -1
  100. package/dist/core/extensions/runner.js +10 -0
  101. package/dist/core/extensions/runner.js.map +1 -1
  102. package/dist/core/extensions/types.d.ts +33 -3
  103. package/dist/core/extensions/types.d.ts.map +1 -1
  104. package/dist/core/extensions/types.js.map +1 -1
  105. package/dist/core/footer-data-provider.d.ts +10 -0
  106. package/dist/core/footer-data-provider.d.ts.map +1 -1
  107. package/dist/core/footer-data-provider.js +1 -1
  108. package/dist/core/footer-data-provider.js.map +1 -1
  109. package/dist/core/http-dispatcher.d.ts.map +1 -1
  110. package/dist/core/http-dispatcher.js +5 -0
  111. package/dist/core/http-dispatcher.js.map +1 -1
  112. package/dist/core/keybindings.d.ts +44 -4
  113. package/dist/core/keybindings.d.ts.map +1 -1
  114. package/dist/core/model-config.d.ts +29 -5
  115. package/dist/core/model-config.d.ts.map +1 -1
  116. package/dist/core/model-config.js +4 -0
  117. package/dist/core/model-config.js.map +1 -1
  118. package/dist/core/model-registry.d.ts +5 -3
  119. package/dist/core/model-registry.d.ts.map +1 -1
  120. package/dist/core/model-registry.js +13 -10
  121. package/dist/core/model-registry.js.map +1 -1
  122. package/dist/core/model-resolver.d.ts +4 -3
  123. package/dist/core/model-resolver.d.ts.map +1 -1
  124. package/dist/core/model-resolver.js +42 -10
  125. package/dist/core/model-resolver.js.map +1 -1
  126. package/dist/core/model-runtime.d.ts +32 -13
  127. package/dist/core/model-runtime.d.ts.map +1 -1
  128. package/dist/core/model-runtime.js +233 -73
  129. package/dist/core/model-runtime.js.map +1 -1
  130. package/dist/core/models-store.d.ts +12 -7
  131. package/dist/core/models-store.d.ts.map +1 -1
  132. package/dist/core/models-store.js +83 -14
  133. package/dist/core/models-store.js.map +1 -1
  134. package/dist/core/package-manager.d.ts +4 -1
  135. package/dist/core/package-manager.d.ts.map +1 -1
  136. package/dist/core/package-manager.js +76 -42
  137. package/dist/core/package-manager.js.map +1 -1
  138. package/dist/core/pi-manifest.d.ts +8 -0
  139. package/dist/core/pi-manifest.d.ts.map +1 -0
  140. package/dist/core/pi-manifest.js +25 -0
  141. package/dist/core/pi-manifest.js.map +1 -0
  142. package/dist/core/pi-server-client.d.ts +2 -2
  143. package/dist/core/pi-server-client.d.ts.map +1 -1
  144. package/dist/core/pi-server-client.js +2 -0
  145. package/dist/core/pi-server-client.js.map +1 -1
  146. package/dist/core/provider-composer.d.ts +4 -1
  147. package/dist/core/provider-composer.d.ts.map +1 -1
  148. package/dist/core/provider-composer.js +36 -15
  149. package/dist/core/provider-composer.js.map +1 -1
  150. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  151. package/dist/core/remote-catalog-provider.js +73 -67
  152. package/dist/core/remote-catalog-provider.js.map +1 -1
  153. package/dist/core/resource-loader.d.ts +15 -0
  154. package/dist/core/resource-loader.d.ts.map +1 -1
  155. package/dist/core/resource-loader.js +64 -10
  156. package/dist/core/resource-loader.js.map +1 -1
  157. package/dist/core/runtime-credentials.d.ts +5 -5
  158. package/dist/core/runtime-credentials.d.ts.map +1 -1
  159. package/dist/core/runtime-credentials.js +11 -8
  160. package/dist/core/runtime-credentials.js.map +1 -1
  161. package/dist/core/session-manager.d.ts.map +1 -1
  162. package/dist/core/session-manager.js +3 -1
  163. package/dist/core/session-manager.js.map +1 -1
  164. package/dist/core/settings-manager.d.ts +12 -0
  165. package/dist/core/settings-manager.d.ts.map +1 -1
  166. package/dist/core/settings-manager.js +40 -16
  167. package/dist/core/settings-manager.js.map +1 -1
  168. package/dist/core/tools/bash.d.ts +4 -0
  169. package/dist/core/tools/bash.d.ts.map +1 -1
  170. package/dist/core/tools/bash.js +6 -4
  171. package/dist/core/tools/bash.js.map +1 -1
  172. package/dist/core/tools/edit.d.ts +4 -0
  173. package/dist/core/tools/edit.d.ts.map +1 -1
  174. package/dist/core/tools/edit.js +11 -7
  175. package/dist/core/tools/edit.js.map +1 -1
  176. package/dist/core/tools/find.d.ts +7 -0
  177. package/dist/core/tools/find.d.ts.map +1 -1
  178. package/dist/core/tools/find.js +16 -19
  179. package/dist/core/tools/find.js.map +1 -1
  180. package/dist/core/tools/grep.d.ts +4 -0
  181. package/dist/core/tools/grep.d.ts.map +1 -1
  182. package/dist/core/tools/grep.js +5 -1
  183. package/dist/core/tools/grep.js.map +1 -1
  184. package/dist/core/tools/ls.d.ts +4 -0
  185. package/dist/core/tools/ls.d.ts.map +1 -1
  186. package/dist/core/tools/ls.js +5 -1
  187. package/dist/core/tools/ls.js.map +1 -1
  188. package/dist/core/tools/read.d.ts +4 -0
  189. package/dist/core/tools/read.d.ts.map +1 -1
  190. package/dist/core/tools/read.js +7 -3
  191. package/dist/core/tools/read.js.map +1 -1
  192. package/dist/core/tools/render-utils.d.ts.map +1 -1
  193. package/dist/core/tools/render-utils.js +6 -3
  194. package/dist/core/tools/render-utils.js.map +1 -1
  195. package/dist/core/tools/write.d.ts +4 -0
  196. package/dist/core/tools/write.d.ts.map +1 -1
  197. package/dist/core/tools/write.js +6 -2
  198. package/dist/core/tools/write.js.map +1 -1
  199. package/dist/extensions/llama/index.d.ts.map +1 -1
  200. package/dist/extensions/llama/index.js +11 -2
  201. package/dist/extensions/llama/index.js.map +1 -1
  202. package/dist/extensions/llama/provider.d.ts.map +1 -1
  203. package/dist/extensions/llama/provider.js +22 -8
  204. package/dist/extensions/llama/provider.js.map +1 -1
  205. package/dist/index.d.ts +4 -4
  206. package/dist/index.d.ts.map +1 -1
  207. package/dist/index.js +1 -1
  208. package/dist/index.js.map +1 -1
  209. package/dist/main.d.ts.map +1 -1
  210. package/dist/main.js +94 -6
  211. package/dist/main.js.map +1 -1
  212. package/dist/modes/index.d.ts +1 -0
  213. package/dist/modes/index.d.ts.map +1 -1
  214. package/dist/modes/index.js.map +1 -1
  215. package/dist/modes/interactive/components/assistant-message.d.ts +5 -2
  216. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  217. package/dist/modes/interactive/components/assistant-message.js +13 -4
  218. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  219. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  220. package/dist/modes/interactive/components/custom-editor.js +7 -0
  221. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  222. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  223. package/dist/modes/interactive/components/footer.js +2 -2
  224. package/dist/modes/interactive/components/footer.js.map +1 -1
  225. package/dist/modes/interactive/components/markdown-transform.d.ts +3 -0
  226. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -0
  227. package/dist/modes/interactive/components/markdown-transform.js +19 -0
  228. package/dist/modes/interactive/components/markdown-transform.js.map +1 -0
  229. package/dist/modes/interactive/components/mermaid.d.ts +11 -0
  230. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
  231. package/dist/modes/interactive/components/mermaid.js +75 -0
  232. package/dist/modes/interactive/components/mermaid.js.map +1 -0
  233. package/dist/modes/interactive/components/model-selector.d.ts +1 -1
  234. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  235. package/dist/modes/interactive/components/model-selector.js +20 -5
  236. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  237. package/dist/modes/interactive/components/scoped-models-selector.d.ts +4 -0
  238. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  239. package/dist/modes/interactive/components/scoped-models-selector.js +26 -0
  240. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  241. package/dist/modes/interactive/components/settings-selector.d.ts +8 -2
  242. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  243. package/dist/modes/interactive/components/settings-selector.js +30 -0
  244. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  245. package/dist/modes/interactive/components/user-message.d.ts +3 -1
  246. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  247. package/dist/modes/interactive/components/user-message.js +9 -2
  248. package/dist/modes/interactive/components/user-message.js.map +1 -1
  249. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  250. package/dist/modes/interactive/external-editor.js +7 -5
  251. package/dist/modes/interactive/external-editor.js.map +1 -1
  252. package/dist/modes/interactive/interactive-mode.d.ts +36 -2
  253. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  254. package/dist/modes/interactive/interactive-mode.js +481 -150
  255. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  256. package/dist/modes/interactive/theme/dark.json +1 -0
  257. package/dist/modes/interactive/theme/light.json +1 -0
  258. package/dist/modes/interactive/theme/theme-controller.d.ts +3 -0
  259. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  260. package/dist/modes/interactive/theme/theme-controller.js +10 -1
  261. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  262. package/dist/modes/interactive/theme/theme-schema.json +5 -1
  263. package/dist/modes/interactive/theme/theme.d.ts +2 -2
  264. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  265. package/dist/modes/interactive/theme/theme.js +24 -6
  266. package/dist/modes/interactive/theme/theme.js.map +1 -1
  267. package/dist/modes/json-event.d.ts +28 -0
  268. package/dist/modes/json-event.d.ts.map +1 -0
  269. package/dist/modes/json-event.js +12 -0
  270. package/dist/modes/json-event.js.map +1 -0
  271. package/dist/modes/print-mode.d.ts.map +1 -1
  272. package/dist/modes/print-mode.js +12 -2
  273. package/dist/modes/print-mode.js.map +1 -1
  274. package/dist/modes/rpc/rpc-client.d.ts +5 -4
  275. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  276. package/dist/modes/rpc/rpc-client.js.map +1 -1
  277. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  278. package/dist/modes/rpc/rpc-mode.js +17 -3
  279. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  280. package/dist/package-manager-cli.d.ts.map +1 -1
  281. package/dist/package-manager-cli.js +11 -9
  282. package/dist/package-manager-cli.js.map +1 -1
  283. package/dist/rpc-entry.d.ts.map +1 -1
  284. package/dist/rpc-entry.js +1 -0
  285. package/dist/rpc-entry.js.map +1 -1
  286. package/dist/server/create-harness.d.ts +26 -0
  287. package/dist/server/create-harness.d.ts.map +1 -0
  288. package/dist/server/create-harness.js +104 -0
  289. package/dist/server/create-harness.js.map +1 -0
  290. package/dist/utils/abort.d.ts +5 -0
  291. package/dist/utils/abort.d.ts.map +1 -0
  292. package/dist/utils/abort.js +48 -0
  293. package/dist/utils/abort.js.map +1 -0
  294. package/dist/utils/clipboard.d.ts +1 -1
  295. package/dist/utils/clipboard.d.ts.map +1 -1
  296. package/dist/utils/clipboard.js +22 -2
  297. package/dist/utils/clipboard.js.map +1 -1
  298. package/dist/utils/management-http.d.ts +23 -0
  299. package/dist/utils/management-http.d.ts.map +1 -0
  300. package/dist/utils/management-http.js +50 -0
  301. package/dist/utils/management-http.js.map +1 -0
  302. package/dist/utils/paths.d.ts +3 -0
  303. package/dist/utils/paths.d.ts.map +1 -1
  304. package/dist/utils/paths.js +23 -1
  305. package/dist/utils/paths.js.map +1 -1
  306. package/dist/utils/tool-result-images.d.ts +19 -0
  307. package/dist/utils/tool-result-images.d.ts.map +1 -0
  308. package/dist/utils/tool-result-images.js +45 -0
  309. package/dist/utils/tool-result-images.js.map +1 -0
  310. package/dist/utils/tools-manager.d.ts.map +1 -1
  311. package/dist/utils/tools-manager.js +4 -6
  312. package/dist/utils/tools-manager.js.map +1 -1
  313. package/dist/utils/version-check.d.ts +4 -0
  314. package/dist/utils/version-check.d.ts.map +1 -1
  315. package/dist/utils/version-check.js +20 -2
  316. package/dist/utils/version-check.js.map +1 -1
  317. package/docs/compaction.md +2 -2
  318. package/docs/custom-provider.md +16 -8
  319. package/docs/extensions.md +33 -6
  320. package/docs/json.md +19 -14
  321. package/docs/keybindings.md +46 -14
  322. package/docs/models.md +24 -3
  323. package/docs/providers.md +10 -1
  324. package/docs/quickstart.md +2 -0
  325. package/docs/rpc.md +13 -11
  326. package/docs/sdk.md +21 -2
  327. package/docs/security.md +1 -1
  328. package/docs/session-format.md +2 -0
  329. package/docs/settings.md +4 -1
  330. package/docs/themes.md +5 -3
  331. package/docs/usage.md +7 -0
  332. package/examples/extensions/custom-compaction.ts +1 -16
  333. package/examples/extensions/custom-provider-anthropic/index.ts +10 -3
  334. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  335. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  336. package/examples/extensions/custom-provider-gitlab-duo/index.ts +2 -1
  337. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  338. package/examples/extensions/doom-overlay/wad-finder.ts +7 -3
  339. package/examples/extensions/gondolin/package-lock.json +2 -2
  340. package/examples/extensions/gondolin/package.json +1 -1
  341. package/examples/extensions/handoff.ts +2 -11
  342. package/examples/extensions/qna.ts +3 -7
  343. package/examples/extensions/sandbox/package-lock.json +2 -2
  344. package/examples/extensions/sandbox/package.json +1 -1
  345. package/examples/extensions/summarize.ts +7 -18
  346. package/examples/extensions/with-deps/package-lock.json +2 -2
  347. package/examples/extensions/with-deps/package.json +1 -1
  348. package/examples/rpc-extension-ui.ts +11 -2
  349. package/examples/sdk/02-custom-model.ts +1 -2
  350. package/examples/sdk/09-api-keys-and-oauth.ts +1 -1
  351. package/examples/sdk/12-full-control.ts +3 -1
  352. package/examples/sdk/README.md +1 -1
  353. package/package.json +14 -7
@@ -2,12 +2,26 @@ import { dirname, join } from "node:path";
2
2
  import { createModels, lazyStream, ModelsError, } from "@earendil-works/pi-ai";
3
3
  import * as builtinProviderCatalog from "@earendil-works/pi-ai/providers/all";
4
4
  import { getAgentDir } from "../config.js";
5
+ import { operationSignal, raceWithAbortSignal } from "../utils/abort.js";
5
6
  import { AuthStorage as DefaultAuthStorage } from "./auth-storage.js";
6
7
  import { ModelConfig } from "./model-config.js";
7
8
  import { FileModelsStore, InMemoryCodingAgentModelsStore } from "./models-store.js";
8
9
  import { composeModelProvider, configuredRequestAuthStatus, resolveCompatibilityRequestConfig, resolveConfiguredModelHeaders, validateExtensionProvider, } from "./provider-composer.js";
9
10
  import { withRemoteCatalog } from "./remote-catalog-provider.js";
10
11
  import { RuntimeCredentials } from "./runtime-credentials.js";
12
+ /** Credentials changed successfully, but the local model/auth snapshot could not be synchronized. */
13
+ export class CredentialSynchronizationError extends Error {
14
+ providerId;
15
+ operation;
16
+ credential;
17
+ constructor(providerId, operation, credential, options) {
18
+ super(`Credential ${operation} committed for ${providerId}, but local synchronization failed`, options);
19
+ this.name = "CredentialSynchronizationError";
20
+ this.providerId = providerId;
21
+ this.operation = operation;
22
+ this.credential = credential;
23
+ }
24
+ }
11
25
  function mergeHeaders(base, override) {
12
26
  if (!base && !override)
13
27
  return undefined;
@@ -41,8 +55,11 @@ export class ModelRuntime {
41
55
  storedProviders: new Set(),
42
56
  auth: new Map(),
43
57
  };
44
- availabilityRefresh;
58
+ availabilityRefreshSeq = 0;
59
+ availabilityErrorSeq = 0;
60
+ providerAvailabilitySeq = new Map();
45
61
  availabilityError;
62
+ credentialOperations = new Map();
46
63
  constructor(credentials, config, modelsPath, modelsStore, providers, modelNetworkEnabled) {
47
64
  this.credentials = credentials;
48
65
  this.config = config;
@@ -72,12 +89,17 @@ export class ModelRuntime {
72
89
  runtime.configureRadiusProviders();
73
90
  runtime.rebuildProviders();
74
91
  const refreshFromNetwork = runtime.modelNetworkEnabled && options.allowModelNetwork === true;
75
- const controller = refreshFromNetwork ? new AbortController() : undefined;
76
- const timeout = controller
77
- ? setTimeout(() => controller.abort(), options.modelRefreshTimeoutMs ?? 15_000)
78
- : undefined;
92
+ const controller = refreshFromNetwork && options.modelRefreshTimeoutMs !== undefined ? new AbortController() : undefined;
93
+ const timeout = controller ? setTimeout(() => controller.abort(), options.modelRefreshTimeoutMs) : undefined;
94
+ const signal = controller
95
+ ? options.signal
96
+ ? AbortSignal.any([options.signal, controller.signal])
97
+ : controller.signal
98
+ : options.signal;
79
99
  try {
80
- await runtime.refresh({ allowNetwork: refreshFromNetwork, signal: controller?.signal });
100
+ if (options.refreshOnCreate !== false) {
101
+ await runtime.refresh({ allowNetwork: refreshFromNetwork, signal });
102
+ }
81
103
  }
82
104
  finally {
83
105
  if (timeout)
@@ -149,16 +171,18 @@ export class ModelRuntime {
149
171
  available: all.filter((model) => this.snapshot.configuredProviders.has(model.provider)),
150
172
  };
151
173
  }
152
- async runAvailabilityRefresh() {
174
+ async runAvailabilityRefresh(seq, errorSeq, signal) {
153
175
  const providers = this.models.getProviders();
154
176
  const [available, checks, credentials] = await Promise.all([
155
- this.models.getAvailable(),
177
+ this.models.getAvailable(undefined, { signal }),
156
178
  Promise.all(providers.map(async (provider) => [
157
179
  provider.id,
158
- await this.models.checkAuth(provider.id),
180
+ await this.models.checkAuth(provider.id, { signal }),
159
181
  ])),
160
- this.credentials.list(),
182
+ this.credentials.list({ signal }),
161
183
  ]);
184
+ if (seq !== this.availabilityRefreshSeq)
185
+ return;
162
186
  const auth = new Map(checks);
163
187
  const configuredProviders = new Set(checks
164
188
  .filter((entry) => entry[1] !== undefined)
@@ -170,28 +194,76 @@ export class ModelRuntime {
170
194
  storedProviders: new Set(credentials.map((entry) => entry.providerId)),
171
195
  auth,
172
196
  };
173
- this.availabilityError = undefined;
197
+ if (errorSeq === this.availabilityErrorSeq)
198
+ this.availabilityError = undefined;
174
199
  }
175
- queueAvailabilityRefresh(after) {
176
- const refresh = (after ?? Promise.resolve()).catch(() => { }).then(() => this.runAvailabilityRefresh());
177
- const recorded = refresh.catch((error) => {
178
- this.availabilityError = error instanceof Error ? error.message : String(error);
200
+ queueAvailabilityRefresh(signal) {
201
+ const seq = ++this.availabilityRefreshSeq;
202
+ for (const [providerId, providerSeq] of this.providerAvailabilitySeq) {
203
+ this.providerAvailabilitySeq.set(providerId, providerSeq + 1);
204
+ }
205
+ const errorSeq = ++this.availabilityErrorSeq;
206
+ const effectiveSignal = operationSignal(signal);
207
+ return this.runAvailabilityRefresh(seq, errorSeq, effectiveSignal).catch((error) => {
208
+ if (errorSeq === this.availabilityErrorSeq && !effectiveSignal.aborted) {
209
+ this.availabilityError = error instanceof Error ? error.message : String(error);
210
+ }
179
211
  throw error;
180
212
  });
181
- const tracked = recorded.finally(() => {
182
- if (this.availabilityRefresh === tracked)
183
- this.availabilityRefresh = undefined;
184
- });
185
- this.availabilityRefresh = tracked;
186
- return tracked;
187
- }
188
- /** Coalesce concurrent readers onto the pending refresh. */
189
- refreshAvailability() {
190
- return this.availabilityRefresh ?? this.queueAvailabilityRefresh(undefined);
191
213
  }
192
- /** Mutations must not observe an in-flight refresh started before them. */
193
- forceRefreshAvailability() {
194
- return this.queueAvailabilityRefresh(this.availabilityRefresh);
214
+ async refreshProviderAvailability(providerId, signal) {
215
+ // Invalidate any full availability pass that started before this credential change.
216
+ ++this.availabilityRefreshSeq;
217
+ const providerSeq = (this.providerAvailabilitySeq.get(providerId) ?? 0) + 1;
218
+ this.providerAvailabilitySeq.set(providerId, providerSeq);
219
+ const errorSeq = ++this.availabilityErrorSeq;
220
+ try {
221
+ const [available, auth, credential] = await Promise.all([
222
+ this.models.getAvailable(providerId, { signal }),
223
+ this.models.checkAuth(providerId, { signal }),
224
+ this.credentials.read(providerId, { signal }),
225
+ ]);
226
+ signal.throwIfAborted();
227
+ if (this.providerAvailabilitySeq.get(providerId) !== providerSeq)
228
+ return;
229
+ const configuredProviders = new Set(this.snapshot.configuredProviders);
230
+ const storedProviders = new Set(this.snapshot.storedProviders);
231
+ const authByProvider = new Map(this.snapshot.auth);
232
+ if (auth) {
233
+ configuredProviders.add(providerId);
234
+ authByProvider.set(providerId, auth);
235
+ }
236
+ else {
237
+ configuredProviders.delete(providerId);
238
+ authByProvider.delete(providerId);
239
+ }
240
+ if (credential)
241
+ storedProviders.add(providerId);
242
+ else
243
+ storedProviders.delete(providerId);
244
+ const all = [...this.models.getModels()];
245
+ const availableById = new Map([...this.snapshot.available.filter((model) => model.provider !== providerId), ...available].map((model) => [
246
+ `${model.provider}\0${model.id}`,
247
+ model,
248
+ ]));
249
+ this.snapshot = {
250
+ all,
251
+ available: all.flatMap((model) => availableById.get(`${model.provider}\0${model.id}`) ?? []),
252
+ configuredProviders,
253
+ storedProviders,
254
+ auth: authByProvider,
255
+ };
256
+ if (errorSeq === this.availabilityErrorSeq)
257
+ this.availabilityError = undefined;
258
+ }
259
+ catch (error) {
260
+ if (this.providerAvailabilitySeq.get(providerId) === providerSeq &&
261
+ errorSeq === this.availabilityErrorSeq &&
262
+ !signal.aborted) {
263
+ this.availabilityError = error instanceof Error ? error.message : String(error);
264
+ }
265
+ throw error;
266
+ }
195
267
  }
196
268
  getProviders() {
197
269
  return this.models.getProviders();
@@ -205,24 +277,26 @@ export class ModelRuntime {
205
277
  getModel(providerId, modelId) {
206
278
  return this.models.getModel(providerId, modelId);
207
279
  }
208
- async checkAuth(providerId) {
209
- return this.models.checkAuth(providerId);
280
+ async checkAuth(providerId, options) {
281
+ return this.models.checkAuth(providerId, options);
210
282
  }
211
- async getAvailable(providerId) {
283
+ async getAvailable(providerId, options) {
212
284
  if (providerId) {
213
- if (this.availabilityRefresh) {
214
- await this.availabilityRefresh;
215
- return this.snapshot.available.filter((model) => model.provider === providerId);
216
- }
285
+ const errorSeq = ++this.availabilityErrorSeq;
217
286
  try {
218
- return await this.models.getAvailable(providerId);
287
+ const available = await this.models.getAvailable(providerId, options);
288
+ if (errorSeq === this.availabilityErrorSeq)
289
+ this.availabilityError = undefined;
290
+ return available;
219
291
  }
220
292
  catch (error) {
221
- this.availabilityError = error instanceof Error ? error.message : String(error);
293
+ if (errorSeq === this.availabilityErrorSeq && !options?.signal?.aborted) {
294
+ this.availabilityError = error instanceof Error ? error.message : String(error);
295
+ }
222
296
  throw error;
223
297
  }
224
298
  }
225
- await this.refreshAvailability();
299
+ await this.queueAvailabilityRefresh(options?.signal);
226
300
  return this.snapshot.available;
227
301
  }
228
302
  getAvailableSnapshot() {
@@ -256,6 +330,9 @@ export class ModelRuntime {
256
330
  isUsingOAuth(providerId) {
257
331
  return this.snapshot.auth.get(providerId)?.type === "oauth";
258
332
  }
333
+ isUsingSubscription(providerId) {
334
+ return this.isUsingOAuth(providerId) && this.models.getProvider(providerId)?.auth.oauth?.isSubscription === true;
335
+ }
259
336
  hasConfiguredAuth(providerId) {
260
337
  return this.snapshot.configuredProviders.has(providerId);
261
338
  }
@@ -274,26 +351,62 @@ export class ModelRuntime {
274
351
  },
275
352
  };
276
353
  }
277
- async setRuntimeApiKey(providerId, apiKey, refreshOptions = {}) {
278
- this.credentials.setRuntimeApiKey(providerId, apiKey);
279
- const auth = new Map(this.snapshot.auth).set(providerId, { type: "api_key", source: "runtime API key" });
280
- const configuredProviders = new Set(this.snapshot.configuredProviders).add(providerId);
281
- const storedProviders = new Set(this.snapshot.storedProviders).add(providerId);
282
- this.snapshot = {
283
- ...this.snapshot,
284
- auth,
285
- configuredProviders,
286
- storedProviders,
287
- available: this.snapshot.all.filter((model) => configuredProviders.has(model.provider)),
288
- };
289
- await this.refresh(refreshOptions);
354
+ enqueueCredentialOperation(providerId, signal, task) {
355
+ const previous = this.credentialOperations.get(providerId) ?? Promise.resolve();
356
+ let markStarted;
357
+ const started = new Promise((resolve) => {
358
+ markStarted = resolve;
359
+ });
360
+ const operation = (async () => {
361
+ await previous.catch(() => { });
362
+ signal.throwIfAborted();
363
+ markStarted?.();
364
+ return task();
365
+ })();
366
+ const tail = operation.catch(() => { });
367
+ this.credentialOperations.set(providerId, tail);
368
+ void tail.then(() => {
369
+ if (this.credentialOperations.get(providerId) === tail)
370
+ this.credentialOperations.delete(providerId);
371
+ });
372
+ return raceWithAbortSignal(started, signal).then(() => operation);
290
373
  }
291
- async removeRuntimeApiKey(providerId) {
292
- this.credentials.removeRuntimeApiKey(providerId);
293
- await this.refresh({ allowNetwork: this.modelNetworkEnabled });
374
+ async synchronizeCredentialState(providerId, operation, credential, signal) {
375
+ try {
376
+ signal.throwIfAborted();
377
+ this.recomposeProvider(providerId);
378
+ const compositionError = this.compositionErrors.get(providerId);
379
+ if (compositionError)
380
+ throw new Error(compositionError);
381
+ const result = await this.models.refresh({ allowNetwork: false, providers: [providerId], signal });
382
+ if (result.aborted)
383
+ signal.throwIfAborted();
384
+ const refreshError = result.errors.get(providerId);
385
+ if (refreshError)
386
+ throw refreshError;
387
+ this.updateModelSnapshot();
388
+ await this.refreshProviderAvailability(providerId, signal);
389
+ }
390
+ catch (cause) {
391
+ throw new CredentialSynchronizationError(providerId, operation, credential, { cause });
392
+ }
294
393
  }
295
- listCredentials() {
296
- return this.credentials.list();
394
+ setRuntimeApiKey(providerId, apiKey, options = {}) {
395
+ const signal = operationSignal(options.signal);
396
+ return this.enqueueCredentialOperation(providerId, signal, async () => {
397
+ this.credentials.setRuntimeApiKey(providerId, apiKey);
398
+ await this.synchronizeCredentialState(providerId, "setRuntimeApiKey", { type: "api_key", key: apiKey }, signal);
399
+ });
400
+ }
401
+ removeRuntimeApiKey(providerId, options = {}) {
402
+ const signal = operationSignal(options.signal);
403
+ return this.enqueueCredentialOperation(providerId, signal, async () => {
404
+ this.credentials.removeRuntimeApiKey(providerId);
405
+ await this.synchronizeCredentialState(providerId, "removeRuntimeApiKey", undefined, signal);
406
+ });
407
+ }
408
+ listCredentials(options) {
409
+ return this.credentials.list(options);
297
410
  }
298
411
  getProviderAuthStatus(providerId) {
299
412
  if (this.credentials.hasRuntimeApiKey(providerId))
@@ -310,10 +423,15 @@ export class ModelRuntime {
310
423
  const provider = this.models.getProvider(model.provider);
311
424
  if (!provider)
312
425
  throw new ModelsError("provider", `Unknown provider: ${model.provider}`);
313
- const resolution = await this.getAuth(model, { apiKey: options?.apiKey, env: options?.env });
426
+ const resolution = await this.getAuth(model, {
427
+ apiKey: options?.apiKey,
428
+ env: options?.env,
429
+ signal: options?.signal,
430
+ });
314
431
  if (!resolution)
315
432
  throw new ModelsError("auth", `Provider is not configured: ${model.provider}`);
316
- const { transformHeaders, ...providerOptions } = options ?? {};
433
+ const { transformHeaders, ...rawProviderOptions } = options ?? {};
434
+ const providerOptions = rawProviderOptions;
317
435
  let headers = mergeHeaders(resolution.auth.headers, providerOptions.headers);
318
436
  if (transformHeaders)
319
437
  headers = await transformHeaders(headers ?? {});
@@ -349,21 +467,48 @@ export class ModelRuntime {
349
467
  completeSimple(model, context, options) {
350
468
  return this.streamSimple(model, context, options).result();
351
469
  }
352
- async login(providerId, type, interaction) {
353
- const credential = await this.models.login(providerId, type, interaction);
354
- await this.refresh({ allowNetwork: this.modelNetworkEnabled });
355
- return credential;
470
+ async fetchDeferred(model, handle, options) {
471
+ return lazyStream(model, async () => {
472
+ const prepared = await this.prepareRequest(model, options);
473
+ if (!prepared.provider.fetchDeferred) {
474
+ throw new ModelsError("provider", `Provider ${model.provider} does not support deferred responses`);
475
+ }
476
+ return prepared.provider.fetchDeferred(prepared.model, handle, prepared.options);
477
+ }).result();
356
478
  }
357
- async logout(providerId) {
358
- await this.models.logout(providerId);
359
- // Reset credential-dependent compatibility projections before the unconfigured provider is skipped by refresh.
360
- this.recomposeProvider(providerId);
361
- await this.refresh({ allowNetwork: this.modelNetworkEnabled });
479
+ async cancelDeferred(model, handle, options) {
480
+ const prepared = await this.prepareRequest(model, options);
481
+ if (!prepared.provider.cancelDeferred) {
482
+ throw new ModelsError("provider", `Provider ${model.provider} does not support deferred responses`);
483
+ }
484
+ await prepared.provider.cancelDeferred(prepared.model, handle, prepared.options);
485
+ }
486
+ login(providerId, type, interaction) {
487
+ const signal = operationSignal(interaction.signal);
488
+ return this.enqueueCredentialOperation(providerId, signal, async () => {
489
+ const credential = await this.models.login(providerId, type, { ...interaction, signal });
490
+ await this.synchronizeCredentialState(providerId, "login", credential, signal);
491
+ return credential;
492
+ });
493
+ }
494
+ logout(providerId, options = {}) {
495
+ const signal = operationSignal(options.signal);
496
+ return this.enqueueCredentialOperation(providerId, signal, async () => {
497
+ await this.models.logout(providerId, { signal });
498
+ await this.synchronizeCredentialState(providerId, "logout", undefined, signal);
499
+ });
362
500
  }
363
501
  async refresh(options = {}) {
364
502
  this.config = await ModelConfig.load(this.modelsPath);
365
503
  this.configureRadiusProviders();
366
- this.rebuildProviders();
504
+ if (options.providers) {
505
+ for (const providerId of new Set(options.providers))
506
+ this.recomposeProvider(providerId);
507
+ this.updateModelSnapshot();
508
+ }
509
+ else {
510
+ this.rebuildProviders();
511
+ }
367
512
  const refreshOptions = {
368
513
  ...options,
369
514
  allowNetwork: options.allowNetwork ?? this.modelNetworkEnabled,
@@ -374,14 +519,29 @@ export class ModelRuntime {
374
519
  aborted: refreshOptions.signal?.aborted ?? false,
375
520
  errors: new Map(),
376
521
  };
522
+ const errors = new Map(result.errors);
377
523
  this.updateModelSnapshot();
378
- try {
379
- await this.forceRefreshAvailability();
524
+ if (options.providers) {
525
+ await Promise.all([...new Set(options.providers)].map(async (providerId) => {
526
+ try {
527
+ await this.refreshProviderAvailability(providerId, operationSignal(options.signal));
528
+ }
529
+ catch (error) {
530
+ if (!options.signal?.aborted) {
531
+ errors.set(providerId, error instanceof Error ? error : new Error(String(error)));
532
+ }
533
+ }
534
+ }));
380
535
  }
381
- catch {
382
- // Availability errors are recorded by forceRefreshAvailability; refreshed models remain usable.
536
+ else {
537
+ try {
538
+ await this.queueAvailabilityRefresh(options.signal);
539
+ }
540
+ catch {
541
+ // Availability errors are recorded by the latest pass; refreshed models remain usable.
542
+ }
383
543
  }
384
- return result;
544
+ return { aborted: result.aborted || (options.signal?.aborted ?? false), errors };
385
545
  }
386
546
  registerNativeProvider(provider) {
387
547
  if (!provider.id.trim())