@undefineds.co/xpod 0.4.3 → 0.4.5

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 (223) hide show
  1. package/config/cloud.json +1 -1
  2. package/config/main.json +36 -2
  3. package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.d.ts +3 -0
  4. package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.js +1 -1
  5. package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.d.ts +2 -1
  6. package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.js +101 -32
  7. package/dist/api/ai-gateway/connect/DeviceCodeProtocol.d.ts +80 -0
  8. package/dist/api/ai-gateway/connect/DeviceCodeProtocol.js +3 -0
  9. package/dist/api/ai-gateway/connect/FileSessionImportAdapter.d.ts +38 -0
  10. package/dist/api/ai-gateway/connect/FileSessionImportAdapter.js +63 -0
  11. package/dist/api/ai-gateway/connect/LoopbackAuthorizationCallbackReceiver.d.ts +24 -0
  12. package/dist/api/ai-gateway/connect/LoopbackAuthorizationCallbackReceiver.js +136 -0
  13. package/dist/api/ai-gateway/connect/OAuthConnectAdapter.d.ts +2 -0
  14. package/dist/api/ai-gateway/connect/OAuthConnectAdapter.js +2 -1
  15. package/dist/api/ai-gateway/connect/OAuthIntegrationRegistry.d.ts +17 -13
  16. package/dist/api/ai-gateway/connect/OAuthIntegrationRegistry.js +52 -19
  17. package/dist/api/ai-gateway/connect/OpenAiSubscriptionSessionImportAdapter.d.ts +4 -28
  18. package/dist/api/ai-gateway/connect/OpenAiSubscriptionSessionImportAdapter.js +7 -58
  19. package/dist/api/ai-gateway/connect/ProviderAuthorizationProfiles.d.ts +4 -0
  20. package/dist/api/ai-gateway/connect/ProviderAuthorizationProfiles.js +116 -0
  21. package/dist/api/ai-gateway/connect/SessionImportProfiles.d.ts +10 -0
  22. package/dist/api/ai-gateway/connect/SessionImportProfiles.js +112 -0
  23. package/dist/api/ai-gateway/connect/index.d.ts +125 -23
  24. package/dist/api/ai-gateway/connect/index.js +1277 -260
  25. package/dist/api/ai-gateway/models/PodModelSelectionRepository.d.ts +4 -1
  26. package/dist/api/ai-gateway/models/PodModelSelectionRepository.js +154 -19
  27. package/dist/api/ai-gateway/providers/DeepSeekRuntimeAdapter.js +10 -6
  28. package/dist/api/ai-gateway/providers/ModelsDevCatalog.d.ts +7 -0
  29. package/dist/api/ai-gateway/providers/ModelsDevCatalog.js +25 -1
  30. package/dist/api/ai-gateway/providers/OfferingAuthorization.d.ts +24 -0
  31. package/dist/api/ai-gateway/providers/OfferingAuthorization.js +37 -0
  32. package/dist/api/ai-gateway/providers/OpenAiRuntimeAdapter.d.ts +1 -1
  33. package/dist/api/ai-gateway/providers/OpenAiRuntimeAdapter.js +5 -3
  34. package/dist/api/ai-gateway/providers/ProviderRegistry.d.ts +6 -3
  35. package/dist/api/ai-gateway/providers/ProviderRegistry.js +55 -16
  36. package/dist/api/ai-gateway/providers/ProviderRuntimeAdapter.d.ts +2 -0
  37. package/dist/api/ai-gateway/providers/ProviderRuntimeAdapter.js +37 -4
  38. package/dist/api/ai-gateway/providers/ProviderRuntimeRegistry.js +7 -0
  39. package/dist/api/ai-gateway/quota/SubscriptionQuotaAdapters.js +2 -1
  40. package/dist/api/ai-gateway/routing/ModelRouter.js +3 -1
  41. package/dist/api/container/common.js +30 -40
  42. package/dist/api/container/index.js +6 -2
  43. package/dist/api/container/routes.js +5 -22
  44. package/dist/api/handlers/AiClientConfigurationHandler.js +39 -1
  45. package/dist/api/handlers/AiGatewayManagementHandler.d.ts +3 -0
  46. package/dist/api/handlers/AiGatewayManagementHandler.js +173 -58
  47. package/dist/api/service/AiClientConfigurationService.d.ts +4 -15
  48. package/dist/api/service/AiClientConfigurationService.js +17 -64
  49. package/dist/cli/commands/start.js +2 -0
  50. package/dist/components/components.jsonld +1 -0
  51. package/dist/components/context.jsonld +80 -0
  52. package/dist/http/InternalPodDataHttpHandler.d.ts +3 -0
  53. package/dist/http/InternalPodDataHttpHandler.js +13 -2
  54. package/dist/http/InternalPodDataHttpHandler.jsonld +12 -0
  55. package/dist/identity/oidc/RememberedClientPromptFactory.d.ts +1 -1
  56. package/dist/identity/oidc/RememberedClientPromptFactory.js +5 -2
  57. package/dist/identity/oidc/RememberedConsentHandler.js +1 -1
  58. package/dist/identity/oidc/ScopedPickWebIdHandler.d.ts +1 -0
  59. package/dist/identity/oidc/ScopedPickWebIdHandler.js +26 -0
  60. package/dist/identity/oidc/ScopedPickWebIdHandler.jsonld +4 -0
  61. package/dist/identity/oidc/SessionBoundIdentityProviderFactory.d.ts +10 -0
  62. package/dist/identity/oidc/SessionBoundIdentityProviderFactory.js +21 -0
  63. package/dist/identity/oidc/SessionBoundIdentityProviderFactory.jsonld +172 -0
  64. package/dist/index.d.ts +2 -1
  65. package/dist/index.js +4 -2
  66. package/dist/runtime/component-parameter-keys.js +18 -2
  67. package/dist/storage/accessors/MixDataAccessor.js +6 -2
  68. package/dist/storage/rdf/PostgresRdfEngine.js +10 -2
  69. package/dist/storage/rdf/RdfContentTypes.js +4 -0
  70. package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.d.ts +3 -0
  71. package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.js +13 -16
  72. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsList.js +1 -3
  73. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.d.ts +2 -1
  74. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.js +2 -2
  75. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.d.ts +4 -1
  76. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.js +127 -57
  77. package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.d.ts +6 -4
  78. package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.js +436 -83
  79. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.d.ts +3 -2
  80. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.js +212 -76
  81. package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.d.ts +6 -4
  82. package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.js +58 -41
  83. package/node_modules/@undefineds.co/ai-connections/dist/AiQuotaCard.d.ts +4 -1
  84. package/node_modules/@undefineds.co/ai-connections/dist/AiQuotaCard.js +63 -4
  85. package/node_modules/@undefineds.co/ai-connections/dist/ai-connections-client.d.ts +46 -6
  86. package/node_modules/@undefineds.co/ai-connections/dist/ai-connections-client.js +143 -14
  87. package/node_modules/@undefineds.co/ai-connections/dist/client-config/base-adapter.d.ts +19 -3
  88. package/node_modules/@undefineds.co/ai-connections/dist/client-config/base-adapter.js +45 -7
  89. package/node_modules/@undefineds.co/ai-connections/dist/client-config/codex.d.ts +7 -1
  90. package/node_modules/@undefineds.co/ai-connections/dist/client-config/codex.js +305 -40
  91. package/node_modules/@undefineds.co/ai-connections/dist/client-config/index.cjs +383 -50
  92. package/node_modules/@undefineds.co/ai-connections/dist/client-config/json-env-adapter.js +3 -2
  93. package/node_modules/@undefineds.co/ai-connections/dist/client-config/pi.js +12 -3
  94. package/node_modules/@undefineds.co/ai-connections/dist/client-config/transaction.d.ts +2 -0
  95. package/node_modules/@undefineds.co/ai-connections/dist/client-config/transaction.js +39 -4
  96. package/node_modules/@undefineds.co/ai-connections/dist/client-config/types.d.ts +8 -1
  97. package/node_modules/@undefineds.co/ai-connections/dist/client-visuals.d.ts +2 -0
  98. package/node_modules/@undefineds.co/ai-connections/dist/client-visuals.js +14 -0
  99. package/node_modules/@undefineds.co/ai-connections/dist/controller.d.ts +2 -2
  100. package/node_modules/@undefineds.co/ai-connections/dist/controller.js +216 -57
  101. package/node_modules/@undefineds.co/ai-connections/dist/index.d.ts +3 -1
  102. package/node_modules/@undefineds.co/ai-connections/dist/index.js +16 -2
  103. package/node_modules/@undefineds.co/ai-connections/dist/provider-visuals.js +6 -1
  104. package/node_modules/@undefineds.co/drizzle-solid/dist/core/execution/ldp-executor.js +27 -6
  105. package/node_modules/@undefineds.co/drizzle-solid/dist/core/pod-database.js +1 -1
  106. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/select-query-builder.js +2 -2
  107. package/node_modules/@undefineds.co/drizzle-solid/dist/core/sparql/builder/update-builder.js +12 -1
  108. package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/builder.js +1 -1
  109. package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/handlers/array.js +8 -0
  110. package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/handlers/default.js +9 -1
  111. package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/handlers/inline.js +3 -3
  112. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/execution/ldp-executor.js +27 -6
  113. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/pod-database.js +1 -1
  114. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/select-query-builder.js +2 -2
  115. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/sparql/builder/update-builder.js +12 -1
  116. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/builder.js +1 -1
  117. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/handlers/array.js +8 -0
  118. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/handlers/default.js +9 -1
  119. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/handlers/inline.js +3 -3
  120. package/node_modules/@undefineds.co/extension-sdk/dist/web.d.ts +31 -0
  121. package/package.json +2 -2
  122. package/static/app/assets/{index-BikOyGPu.js → index-BCZVzMpj.js} +44 -44
  123. package/static/app/assets/inrupt-smoke.js +2 -2
  124. package/static/app/assets/main.css +1 -1
  125. package/static/app/assets/main.js +10 -10
  126. package/static/auth-callback/assets/{AiConfigContext-DrCH6ckh.js → AiConfigContext-DVkh8Kg2.js} +1 -1
  127. package/static/auth-callback/assets/{AiConfigPage-DVrlSSdA.js → AiConfigPage-HWVWpe-P.js} +1 -1
  128. package/static/auth-callback/assets/{DocumentProcessingPanel-_Md-v2R2.js → DocumentProcessingPanel-DDq-mH17.js} +1 -1
  129. package/static/auth-callback/assets/{IndexLifecyclePanel-BbWwe23H.js → IndexLifecyclePanel-Cx4cjrdP.js} +1 -1
  130. package/static/auth-callback/assets/{IndexSubjectPanel-upH9MjU-.js → IndexSubjectPanel-DzSw8M9j.js} +1 -1
  131. package/static/auth-callback/assets/{ModelAssignmentsPanel-CVGH4t4g.js → ModelAssignmentsPanel-BsRxGc2p.js} +1 -1
  132. package/static/auth-callback/assets/ModelsPage-DEe1lo6Q.js +10 -0
  133. package/static/auth-callback/assets/{NetworkPage-Dcbrb1fd.js → NetworkPage-DBiEh1Oz.js} +1 -1
  134. package/static/auth-callback/assets/{PaneListHeader-DrY-1wBq.js → PaneListHeader-lEEgjyN9.js} +1 -1
  135. package/static/auth-callback/assets/{SearchIndexingPanel-Dw25y53v.js → SearchIndexingPanel-CZCUUGt6.js} +1 -1
  136. package/static/auth-callback/assets/{StatusSubjectPanel-BHlz9rNF.js → StatusSubjectPanel-21qdueMr.js} +1 -1
  137. package/static/auth-callback/assets/{StatusWorkspace-BH7exQP5.js → StatusWorkspace-R8RKsqVz.js} +1 -1
  138. package/static/auth-callback/assets/{SystemSettingsPage-BYLKnM9f.js → SystemSettingsPage-BQ4e-4Wy.js} +1 -1
  139. package/static/auth-callback/assets/{SystemSettingsSubjectPanel-DT34LKku.js → SystemSettingsSubjectPanel-BopXD7SE.js} +1 -1
  140. package/static/auth-callback/assets/{activity-DdULRcSI.js → activity-DSfmTGfY.js} +1 -1
  141. package/static/auth-callback/assets/ai-connections-C03UWyPh.js +1 -0
  142. package/static/auth-callback/assets/{auth-callback-D7l2P25I.js → auth-callback-DleaitAS.js} +91 -91
  143. package/static/auth-callback/assets/auth-callback-vPSC2d2F.css +1 -0
  144. package/static/auth-callback/assets/{badge-j4zjFnmg.js → badge-B0aLu1sl.js} +1 -1
  145. package/static/auth-callback/assets/{download-DGXoks01.js → download-D_bFwdYJ.js} +1 -1
  146. package/static/auth-callback/assets/{external-link-CvbgXXaI.js → external-link-DRfjTaQu.js} +1 -1
  147. package/static/auth-callback/assets/{index-LRWvKJ2i.js → index-CG23cLYQ.js} +1 -1
  148. package/static/auth-callback/assets/{index-BOK3j1dz.js → index-CyV9ejwx.js} +1 -1
  149. package/static/auth-callback/assets/{index-browser-C1Qpe0g4.js → index-browser-D70paxIg.js} +1 -1
  150. package/static/auth-callback/assets/{key-round-CmgS5UdQ.js → key-round-BjV_mVYH.js} +1 -1
  151. package/static/auth-callback/assets/{rotate-ccw-c4CSG6Rq.js → rotate-ccw-CKoOAfse.js} +1 -1
  152. package/static/auth-callback/assets/{skeleton-ZPMTiRSM.js → skeleton-BZNjZaHx.js} +1 -1
  153. package/static/auth-callback/assets/{waypoints-xjyBflU5.js → waypoints-DoaJVzZv.js} +1 -1
  154. package/static/auth-callback/assets/{workspace-layout-B9nj6F5J.js → workspace-layout-CaP46_ZR.js} +1 -1
  155. package/static/auth-callback/auth-callback.html +2 -2
  156. package/static/dashboard/assets/{AiConfigContext-BWOOSYNr.js → AiConfigContext-BSrR27yD.js} +1 -1
  157. package/static/dashboard/assets/{AiConfigPage-CG2kQ9Wy.js → AiConfigPage-D65Z2LET.js} +1 -1
  158. package/static/dashboard/assets/{DocumentProcessingPanel-B4VXajfj.js → DocumentProcessingPanel-DyTe7Nei.js} +1 -1
  159. package/static/dashboard/assets/{IndexLifecyclePanel-CWCy0CC8.js → IndexLifecyclePanel-fK8ZGlrL.js} +1 -1
  160. package/static/dashboard/assets/{IndexSubjectPanel-CSgyQnG_.js → IndexSubjectPanel-CZPGor7v.js} +1 -1
  161. package/static/dashboard/assets/{ModelAssignmentsPanel-CdGIGidT.js → ModelAssignmentsPanel-CfYn5LMQ.js} +1 -1
  162. package/static/dashboard/assets/ModelsPage-djlJsghe.js +25 -0
  163. package/static/dashboard/assets/{NetworkPage-COia9NCH.js → NetworkPage-Coj6GnPl.js} +1 -1
  164. package/static/dashboard/assets/{PaneListHeader-SZWyr602.js → PaneListHeader-CUuFNSsZ.js} +1 -1
  165. package/static/dashboard/assets/{SearchIndexingPanel-D6PZtG6k.js → SearchIndexingPanel-CyJLioXS.js} +1 -1
  166. package/static/dashboard/assets/{StatusSubjectPanel-CxRD4kv0.js → StatusSubjectPanel-Cv26GSVC.js} +1 -1
  167. package/static/dashboard/assets/{StatusWorkspace-D3PfmY9-.js → StatusWorkspace-CDjFrsmB.js} +1 -1
  168. package/static/dashboard/assets/{SystemSettingsPage-COg1MmMj.js → SystemSettingsPage-BuNOyNoa.js} +1 -1
  169. package/static/dashboard/assets/{SystemSettingsSubjectPanel-BSVVB9Ol.js → SystemSettingsSubjectPanel-B2dasdez.js} +1 -1
  170. package/static/dashboard/assets/{activity-BJJx5cN-.js → activity-D1d2j_4Z.js} +1 -1
  171. package/static/dashboard/assets/ai-connections-C03UWyPh.js +1 -0
  172. package/static/dashboard/assets/{badge-elmrFSCj.js → badge-BeAAv6sp.js} +1 -1
  173. package/static/dashboard/assets/{dashboard-IvQrNmru.js → dashboard-BnGrUGv8.js} +68 -68
  174. package/static/dashboard/assets/dashboard-vPSC2d2F.css +1 -0
  175. package/static/dashboard/assets/{download-C3FH2KzG.js → download-DfFGiZRn.js} +1 -1
  176. package/static/dashboard/assets/{external-link-Bx7F0uKb.js → external-link-IsjU_LC9.js} +1 -1
  177. package/static/dashboard/assets/{index-liRoRIP1.js → index-BWQTucPe.js} +1 -1
  178. package/static/dashboard/assets/{index-M4-kWiGz.js → index-Dj75OjnW.js} +1 -1
  179. package/static/dashboard/assets/{key-round-CXg0bKAj.js → key-round-BJ_9wmQ_.js} +1 -1
  180. package/static/dashboard/assets/{rotate-ccw-yxJKOBrX.js → rotate-ccw-D3JGiFbR.js} +1 -1
  181. package/static/dashboard/assets/{skeleton-x9jNGrQT.js → skeleton-CC4nc-z-.js} +1 -1
  182. package/static/dashboard/assets/{waypoints-CTKeRsGp.js → waypoints-h7sqFqiG.js} +1 -1
  183. package/static/dashboard/assets/{workspace-layout--YkgkS38.js → workspace-layout-ZAPTOHhs.js} +1 -1
  184. package/static/dashboard/dashboard.html +2 -2
  185. package/static/settings/assets/{AiConfigContext-CelxXFcQ.js → AiConfigContext-lGkWpvKP.js} +1 -1
  186. package/static/settings/assets/{AiConfigPage-BaP-EovM.js → AiConfigPage-BbZWIBZq.js} +1 -1
  187. package/static/settings/assets/{DocumentProcessingPanel-DzLZluFv.js → DocumentProcessingPanel-DvYdjT-V.js} +1 -1
  188. package/static/settings/assets/{IndexLifecyclePanel-Bzj1-_oI.js → IndexLifecyclePanel-W5OGQZj7.js} +1 -1
  189. package/static/settings/assets/{IndexSubjectPanel-B263QLUh.js → IndexSubjectPanel-g_Aa5soq.js} +1 -1
  190. package/static/settings/assets/{ModelAssignmentsPanel-BAdT4UR0.js → ModelAssignmentsPanel-COlMBKXj.js} +1 -1
  191. package/static/settings/assets/ModelsPage-mApKi-aw.js +10 -0
  192. package/static/settings/assets/{NetworkPage-BK6a7l4g.js → NetworkPage-BDT05JUq.js} +1 -1
  193. package/static/settings/assets/{PaneListHeader-BAS2ICPq.js → PaneListHeader-CByhNpMG.js} +1 -1
  194. package/static/settings/assets/{SearchIndexingPanel-Cb_p-NgW.js → SearchIndexingPanel-BFAyzXls.js} +1 -1
  195. package/static/settings/assets/{StatusSubjectPanel-CcjqUua6.js → StatusSubjectPanel-Bz_XZ3VU.js} +1 -1
  196. package/static/settings/assets/{StatusWorkspace-7Ibty3_k.js → StatusWorkspace-CeVypHcW.js} +1 -1
  197. package/static/settings/assets/{SystemSettingsPage-DPSz4dg4.js → SystemSettingsPage-Dh7cQIfx.js} +1 -1
  198. package/static/settings/assets/{SystemSettingsSubjectPanel-Cb4HkKT5.js → SystemSettingsSubjectPanel-CSnpciO0.js} +1 -1
  199. package/static/settings/assets/{activity-Qhsr5Pxu.js → activity-DXz3EfFN.js} +1 -1
  200. package/static/settings/assets/ai-connections-C03UWyPh.js +1 -0
  201. package/static/settings/assets/{badge-B1vf2qCl.js → badge-1ZA144i4.js} +1 -1
  202. package/static/settings/assets/{download-CYNt0aZ-.js → download-CUHimlYa.js} +1 -1
  203. package/static/settings/assets/{external-link-ClKb39NT.js → external-link-BYHSVj2Z.js} +1 -1
  204. package/static/settings/assets/{index-y8ew3MLM.js → index-DKPDMdW5.js} +1 -1
  205. package/static/settings/assets/{index-browser-DJhvgpNI.js → index-browser-BaEFz0e0.js} +1 -1
  206. package/static/settings/assets/{index-BgiIDSch.js → index-viSgSvbO.js} +1 -1
  207. package/static/settings/assets/{key-round-5d-DrJz-.js → key-round-COByPOg8.js} +1 -1
  208. package/static/settings/assets/{rotate-ccw-CHZY7kS5.js → rotate-ccw-BC2EN6cE.js} +1 -1
  209. package/static/settings/assets/{settings-D5VRWyx6.js → settings-DLH9XUoT.js} +86 -86
  210. package/static/settings/assets/settings-vPSC2d2F.css +1 -0
  211. package/static/settings/assets/{skeleton-FNabNxNE.js → skeleton-B0-FOhKL.js} +1 -1
  212. package/static/settings/assets/{waypoints-BnL_8ljo.js → waypoints-DGMsvqWo.js} +1 -1
  213. package/static/settings/assets/{workspace-layout-D5q3F59S.js → workspace-layout-B0SVrJIu.js} +1 -1
  214. package/static/settings/settings.html +2 -2
  215. package/static/auth-callback/assets/ModelsPage-BpkVFKbf.js +0 -10
  216. package/static/auth-callback/assets/ai-connections-Bm52UO7Y.js +0 -1
  217. package/static/auth-callback/assets/auth-callback-01yz-UDU.css +0 -1
  218. package/static/dashboard/assets/ModelsPage-Chd5UK0D.js +0 -25
  219. package/static/dashboard/assets/ai-connections-Bm52UO7Y.js +0 -1
  220. package/static/dashboard/assets/dashboard-01yz-UDU.css +0 -1
  221. package/static/settings/assets/ModelsPage-C0NFa1zq.js +0 -10
  222. package/static/settings/assets/ai-connections-Bm52UO7Y.js +0 -1
  223. package/static/settings/assets/settings-01yz-UDU.css +0 -1
@@ -2847,7 +2847,7 @@ class PostgresRdfEngine {
2847
2847
  }
2848
2848
  async scanNative(pattern, options, sourceScope) {
2849
2849
  const start = Date.now();
2850
- const resolved = await this.resolvePattern(pattern);
2850
+ const resolved = await this.resolvePattern(pattern, sourceScope);
2851
2851
  if (resolved.unresolved) {
2852
2852
  return {
2853
2853
  quads: [],
@@ -5703,7 +5703,7 @@ class PostgresRdfEngine {
5703
5703
  || filter.operator === '$datatype'
5704
5704
  || filter.operator === '$notDatatype';
5705
5705
  }
5706
- async resolvePattern(pattern) {
5706
+ async resolvePattern(pattern, explicitSourceScope) {
5707
5707
  const ids = {};
5708
5708
  const idSets = {};
5709
5709
  const excludedIdSets = {};
@@ -5716,6 +5716,14 @@ class PostgresRdfEngine {
5716
5716
  continue;
5717
5717
  }
5718
5718
  if ((0, types_1.isTerm)(value)) {
5719
+ // An access-scoped DefaultGraph represents the logical union of Pod
5720
+ // source documents. Their physical facts retain named graph IDs, so
5721
+ // constraining graph_id to the RDF default-graph term incorrectly
5722
+ // turns every normal SPARQL query into an empty result.
5723
+ const sourceScope = explicitSourceScope ?? pattern.sourceScope;
5724
+ if (key === 'graph' && value.termType === 'DefaultGraph' && sourceScopeHasFilters(sourceScope)) {
5725
+ continue;
5726
+ }
5719
5727
  const id = await this.requireDictionary().find(value);
5720
5728
  if (id === undefined) {
5721
5729
  return { ids, idSets, excludedIdSets, termFilters, unresolved: key };
@@ -10,6 +10,10 @@ exports.isRdfDocumentPath = isRdfDocumentPath;
10
10
  exports.isRdfDocument = isRdfDocument;
11
11
  exports.isSafeRdfDocumentContentType = isSafeRdfDocumentContentType;
12
12
  const CONTENT_TYPE_BY_EXTENSION = {
13
+ // Solid ACP access-control resources use the `.acr` suffix while their
14
+ // representation is Turtle. Treat them as line-addressable RDF so native
15
+ // prepared updates can safely persist universalAccess mutations.
16
+ '.acr': 'text/turtle',
13
17
  '.ttl': 'text/turtle',
14
18
  '.jsonld': 'application/ld+json',
15
19
  '.nt': 'application/n-triples',
@@ -1,8 +1,10 @@
1
+ import type { AiClientConfigurationModel } from '@undefineds.co/extension-sdk/web';
1
2
  export declare const AI_CONNECTIONS_CLIENTS: readonly ["codex", "claude-code", "pi", "codebuddy"];
2
3
  export type AiConnectionsClientId = (typeof AI_CONNECTIONS_CLIENTS)[number];
3
4
  export interface AiClientConfigurationStatus {
4
5
  status: 'notConfigured' | 'configured' | 'drifted' | 'unavailable' | 'unverifiable' | 'failedAndRestored';
5
6
  message?: string;
7
+ appliedKeyFingerprint?: string;
6
8
  }
7
9
  export interface AiClientConfigurationConfirmation {
8
10
  required: boolean;
@@ -25,6 +27,7 @@ export interface AiClientConfigurationBridge {
25
27
  plan(input: {
26
28
  client: AiConnectionsClientId;
27
29
  endpoint: string;
30
+ activeModels?: AiClientConfigurationModel[];
28
31
  }): Promise<AiClientConfigurationDryRun>;
29
32
  apply(input: {
30
33
  client: AiConnectionsClientId;
@@ -1,8 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useRef, useState } from 'react';
3
3
  import { Badge, Button, Input, } from '@undefineds.co/shared-ui';
4
- import { Bot, Code2, Copy, Pi, RotateCcw, SquareTerminal } from 'lucide-react';
4
+ import { Copy, RotateCcw, SquareTerminal } from 'lucide-react';
5
5
  import { normalizeAiConnectionsThrownError } from './ai-connections-client.js';
6
+ import { getClientAvatar } from './client-visuals.js';
6
7
  export const AI_CONNECTIONS_CLIENTS = ['codex', 'claude-code', 'pi', 'codebuddy'];
7
8
  export const AI_CLIENT_LABELS = {
8
9
  codex: 'Codex',
@@ -11,12 +12,11 @@ export const AI_CLIENT_LABELS = {
11
12
  codebuddy: 'CodeBuddy',
12
13
  };
13
14
  export function AiClientIcon({ client, className = 'h-4 w-4' }) {
14
- switch (client) {
15
- case 'claude-code': return _jsx(Bot, { className: className, "aria-hidden": "true" });
16
- case 'pi': return _jsx(Pi, { className: className, "aria-hidden": "true" });
17
- case 'codebuddy': return _jsx(Code2, { className: className, "aria-hidden": "true" });
18
- default: return _jsx(SquareTerminal, { className: className, "aria-hidden": "true" });
15
+ const avatar = getClientAvatar(client);
16
+ if (avatar) {
17
+ return _jsx("img", { src: avatar, alt: "", "aria-hidden": "true", className: `${className} shrink-0 rounded-[3px] object-cover` });
19
18
  }
19
+ return _jsx(SquareTerminal, { className: className, "aria-hidden": "true" });
20
20
  }
21
21
  export function AiClientConfigurationSection({ bridge, endpoint, client, createClientCredential, manualApiKey, autoApply = false, compact = false, onComplete, }) {
22
22
  const [status, setStatus] = useState({ status: 'notConfigured' });
@@ -71,12 +71,9 @@ export function AiClientConfigurationSection({ bridge, endpoint, client, createC
71
71
  } : {}),
72
72
  });
73
73
  applied = true;
74
- const nextStatus = await bridge.verify({ client, planId: plan.planId });
75
- setStatus(nextStatus);
74
+ setStatus({ status: 'configured' });
76
75
  setDryRun(undefined);
77
- if (nextStatus.status === 'configured') {
78
- onComplete?.();
79
- }
76
+ onComplete?.();
80
77
  }
81
78
  catch (error) {
82
79
  let recoveryMessage = errorMessage(error);
@@ -92,7 +89,7 @@ export function AiClientConfigurationSection({ bridge, endpoint, client, createC
92
89
  }
93
90
  }
94
91
  setStatus(failedAndRestoredError(error)
95
- ? { status: 'failedAndRestored', message: '配置验证失败,已自动恢复原配置。' }
92
+ ? { status: 'failedAndRestored', message: '配置写入失败,已自动恢复原配置。' }
96
93
  : { status: 'unavailable', message: recoveryMessage });
97
94
  }
98
95
  finally {
@@ -191,16 +188,16 @@ export function manualConfigurationText(client, endpoint, apiKey) {
191
188
  case 'codex':
192
189
  return [
193
190
  '# ~/.codex/config.toml',
191
+ '# 将 model_provider 放在第一个配置节之前;已有同名顶层字段时替换',
194
192
  'model_provider = "xpod"',
195
193
  '',
196
194
  '[model_providers.xpod]',
197
195
  'name = "Xpod AI Connection"',
198
196
  `base_url = ${JSON.stringify(v1Url)}`,
199
197
  'wire_api = "responses"',
200
- 'requires_openai_auth = true',
201
- '',
202
- '# ~/.codex/auth.json(合并到现有 JSON)',
203
- JSON.stringify({ OPENAI_API_KEY: secret }, null, 2),
198
+ 'requires_openai_auth = false',
199
+ `experimental_bearer_token = ${JSON.stringify(secret)}`,
200
+ '# 保留现有订阅登录,Xpod 单独使用此 provider 的 Key',
204
201
  ].join('\n');
205
202
  case 'claude-code':
206
203
  return [
@@ -18,9 +18,7 @@ export function AiConnectionsList({ controller }) {
18
18
  if (provider.id !== 'custom')
19
19
  return [...items, { ...provider }];
20
20
  const credentials = providerProducts.custom?.credentials ?? [];
21
- return [...items, ...(credentials.length > 0
22
- ? credentials.map((credential) => ({ ...provider, name: credential.label || provider.name, credentialId: credential.id }))
23
- : [{ ...provider }])];
21
+ return [...items, ...credentials.map((credential) => ({ ...provider, name: credential.label || provider.name, credentialId: credential.id }))];
24
22
  }, []);
25
23
  const providers = searchQuery
26
24
  ? providerItems.filter((provider) => providerDisplayName(provider, providerProducts).toLocaleLowerCase().includes(searchQuery))
@@ -1,4 +1,5 @@
1
1
  import { type AiConnectionsController } from './controller';
2
- export declare function AiConnectionsMain({ controller }: {
2
+ export declare function AiConnectionsMain({ controller, renderToaster }: {
3
3
  controller: AiConnectionsController;
4
+ renderToaster?: boolean;
4
5
  }): import("react").JSX.Element;
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { AI_CONNECTIONS_PINNED_SECTIONS, PROVIDERS, useProviderLoadError, useProviderProducts, useProviderSummaries, useSelectedCredentialId, useSelectedProvider, useSelectedSection, } from './controller.js';
3
3
  import { AiConnectionsPanel } from './AiConnectionsPanel.js';
4
4
  import { useEffect } from 'react';
5
- export function AiConnectionsMain({ controller }) {
5
+ export function AiConnectionsMain({ controller, renderToaster = true }) {
6
6
  const selectedSection = useSelectedSection(controller);
7
7
  const selectedProvider = useSelectedProvider(controller);
8
8
  const selectedCredentialId = useSelectedCredentialId(controller);
@@ -35,7 +35,7 @@ export function AiConnectionsMain({ controller }) {
35
35
  if (!controller.client) {
36
36
  return (_jsxs("section", { role: "alert", "aria-label": "AI Connections unavailable", children: [_jsx("h2", { children: "AI Connections \u5C1A\u672A\u5C31\u7EEA" }), _jsx("p", { children: "\u5BBF\u4E3B\u9700\u8981\u5148\u63D0\u4F9B\u5DF2\u767B\u5F55\u7684 WebID \u548C\u53EF\u7528\u7684 Pod\u3002" })] }));
37
37
  }
38
- return (_jsx("section", { role: "region", "aria-label": regionLabel, children: _jsx(AiConnectionsPanel, { client: controller.client, clientConfigurationBridge: controller.clientConfigurationBridge, selectedSection: selectedSection, selectedProvider: selectedProvider, selectedCredentialId: selectedCredentialId, openExternal: controller.openExternal, providerSummaries: providerSummaries, providerProducts: scopedProducts, providerLoadError: providerLoadError, onProviderStateChange: controller.setProviderState }) }));
38
+ return (_jsx("section", { role: "region", "aria-label": regionLabel, children: _jsx(AiConnectionsPanel, { client: controller.client, renderToaster: renderToaster, clientConfigurationBridge: controller.clientConfigurationBridge, selectedSection: selectedSection, selectedProvider: selectedProvider, selectedCredentialId: selectedCredentialId, openExternal: controller.openExternal, providerSummaries: providerSummaries, providerProducts: scopedProducts, providerLoadError: providerLoadError, providerLoading: !providerProducts[selectedProvider] && !providerLoadError, onProviderStateChange: controller.setProviderState }) }));
39
39
  }
40
40
  function scopedCustomOfferings(product, credential) {
41
41
  if (!credential)
@@ -3,6 +3,8 @@ import { type AiConnectionsWorkspaceSection, type ProviderProductState } from '.
3
3
  import type { AiClientConfigurationBridge } from './AiClientConfigurationSection';
4
4
  export interface AiConnectionsPanelProps {
5
5
  client: AiConnectionsClient;
6
+ /** Disable when the embedding application already renders shared-ui Toaster. */
7
+ renderToaster?: boolean;
6
8
  openExternal?: (url: string) => void | Promise<void>;
7
9
  clientConfigurationBridge?: AiClientConfigurationBridge;
8
10
  selectedSection?: AiConnectionsWorkspaceSection;
@@ -11,7 +13,8 @@ export interface AiConnectionsPanelProps {
11
13
  providerSummaries?: Partial<Record<AiConnectionsProvider, AiProviderConnectionSummary>>;
12
14
  providerProducts?: Partial<Record<AiConnectionsProvider, AiProviderSummary>>;
13
15
  providerLoadError?: string;
16
+ providerLoading?: boolean;
14
17
  onProviderStateChange?: (provider: AiConnectionsProvider, state: ProviderProductState) => void;
15
18
  onModelSelectionChange?: (provider: AiConnectionsProvider, modelIds: string[]) => void;
16
19
  }
17
- export declare function AiConnectionsPanel({ client, openExternal, clientConfigurationBridge, selectedSection, selectedProvider, selectedCredentialId, providerSummaries: providerSummariesInput, providerProducts, providerLoadError, onProviderStateChange, onModelSelectionChange, }: AiConnectionsPanelProps): import("react").JSX.Element;
20
+ export declare function AiConnectionsPanel({ client, renderToaster, openExternal, clientConfigurationBridge, selectedSection, selectedProvider, selectedCredentialId, providerSummaries: providerSummariesInput, providerProducts, providerLoadError, providerLoading, onProviderStateChange, onModelSelectionChange, }: AiConnectionsPanelProps): import("react").JSX.Element;
@@ -3,14 +3,18 @@ import { useCallback, useEffect, useRef, useState } from 'react';
3
3
  import { Toaster, toast, } from '@undefineds.co/shared-ui';
4
4
  import { normalizeAiConnectionsThrownError, } from './ai-connections-client.js';
5
5
  import { PROVIDERS, } from './controller.js';
6
+ import { offeringTitle } from './offering-label.js';
6
7
  import { AiProviderCard, } from './AiProviderCard.js';
7
8
  import { AiModelEditorDialog, } from './AiModelEditorDialog.js';
8
9
  import { AiGatewayKeysSection } from './AiGatewayKeysSection.js';
9
10
  const EMPTY_PROVIDER_SUMMARIES = {};
10
- export function AiConnectionsPanel({ client, openExternal = openExternalUrl, clientConfigurationBridge, selectedSection = 'provider', selectedProvider, selectedCredentialId, providerSummaries: providerSummariesInput = EMPTY_PROVIDER_SUMMARIES, providerProducts = {}, providerLoadError, onProviderStateChange, onModelSelectionChange, }) {
11
+ export function AiConnectionsPanel({ client, renderToaster = true, openExternal = openExternalUrl, clientConfigurationBridge, selectedSection = 'provider', selectedProvider, selectedCredentialId, providerSummaries: providerSummariesInput = EMPTY_PROVIDER_SUMMARIES, providerProducts = {}, providerLoadError, providerLoading = false, onProviderStateChange, onModelSelectionChange, }) {
11
12
  const [connectionStates, setConnectionStates] = useState({});
12
13
  const [models, setModels] = useState([]);
14
+ const [gatewayModels, setGatewayModels] = useState();
15
+ const [gatewayCatalogVersion, setGatewayCatalogVersion] = useState(0);
13
16
  const [selectedModelIds, setSelectedModelIds] = useState({});
17
+ const [modelSelectionStatus, setModelSelectionStatus] = useState({});
14
18
  const [attempts, setAttempts] = useState({});
15
19
  const [attemptOfferingIds, setAttemptOfferingIds] = useState({});
16
20
  const [apiKeyInputs, setApiKeyInputs] = useState({});
@@ -77,13 +81,23 @@ export function AiConnectionsPanel({ client, openExternal = openExternalUrl, cli
77
81
  pollingGeneration.current += 1;
78
82
  };
79
83
  }, [client]);
84
+ useEffect(() => {
85
+ let active = true;
86
+ setGatewayModels(undefined);
87
+ // Load the routing projection independently: the host's listModels may be a Pod catalog.
88
+ void client.listGatewayModels?.()
89
+ .then((availableModels) => { if (active)
90
+ setGatewayModels(availableModels); })
91
+ .catch(() => undefined);
92
+ return () => { active = false; };
93
+ }, [client, gatewayCatalogVersion]);
80
94
  const setBusy = (provider, value) => {
81
95
  setBusyProviders((current) => ({ ...current, [provider]: value }));
82
96
  };
83
- const setProviderError = (provider, value, offeringId) => {
97
+ const setProviderError = (provider, value, offeringId, authorization) => {
84
98
  setProviderErrors((current) => ({
85
99
  ...current,
86
- [provider]: value ? { message: value, offeringId } : undefined,
100
+ [provider]: value ? { message: value, offeringId, authorization } : undefined,
87
101
  }));
88
102
  };
89
103
  const openAttemptUrl = useCallback(async (attempt) => {
@@ -125,14 +139,14 @@ export function AiConnectionsPanel({ client, openExternal = openExternalUrl, cli
125
139
  }
126
140
  await beginConnectMode(definition.id, definition.browserMode);
127
141
  };
128
- const beginOfferingConnect = async (provider, offering, mode) => {
142
+ const beginOfferingConnect = async (provider, offering, mode, method) => {
129
143
  if (mode === 'browserAssistedApiKey') {
130
144
  await beginApiKey(provider);
131
145
  return;
132
146
  }
133
- await beginConnectMode(provider, mode, offering.id);
147
+ await beginConnectMode(provider, mode, offering.id, method?.id);
134
148
  };
135
- const beginConnectMode = async (provider, mode, offeringId) => {
149
+ const beginConnectMode = async (provider, mode, offeringId, authorizationMethodId) => {
136
150
  if (mode === 'connectUnsupported')
137
151
  return;
138
152
  setBusy(provider, true);
@@ -141,15 +155,18 @@ export function AiConnectionsPanel({ client, openExternal = openExternalUrl, cli
141
155
  const generation = pollingGeneration.current + 1;
142
156
  pollingGeneration.current = generation;
143
157
  try {
144
- const attempt = await client.beginConnect(provider, mode);
158
+ const attempt = await client.beginConnect(provider, mode, { offeringId, authorizationMethodId });
145
159
  setAttempts((current) => ({ ...current, [provider]: attempt }));
146
160
  if (!isPendingAttempt(attempt.status)) {
147
161
  const connected = attempt.status === 'completed';
148
- updateConnectionState(provider, connected ? 'connected' : 'failed');
162
+ if (connected)
163
+ await completeOAuthConnect(provider);
164
+ else
165
+ updateConnectionState(provider, 'failed');
149
166
  if (!connected) {
150
167
  setProviderError(provider, attempt.status === 'unsupported'
151
168
  ? '当前部署未启用账号授权'
152
- : attempt.message ?? connectFailureMessage(attempt.status), offeringId);
169
+ : attempt.message ?? connectFailureMessage(attempt.status), offeringId, { mode, authorizationMethodId });
153
170
  }
154
171
  setBusy(provider, false);
155
172
  return;
@@ -158,20 +175,47 @@ export function AiConnectionsPanel({ client, openExternal = openExternalUrl, cli
158
175
  await openAttemptUrl(attempt);
159
176
  void pollDeviceConnect(client, provider, attempt, generation, pollingGeneration, {
160
177
  onAttempt: (next) => setAttempts((current) => ({ ...current, [provider]: next })),
161
- onConnected: () => updateConnectionState(provider, 'connected'),
178
+ onConnected: () => completeOAuthConnect(provider),
162
179
  onFailed: (message) => {
163
180
  updateConnectionState(provider, 'failed');
164
- setProviderError(provider, message, offeringId);
181
+ setProviderError(provider, message, offeringId, { mode, authorizationMethodId });
165
182
  },
166
183
  onFinished: () => setBusy(provider, false),
167
184
  });
168
185
  }
169
186
  catch (error) {
170
187
  updateConnectionState(provider, 'failed');
171
- setProviderError(provider, errorMessage(error), offeringId);
188
+ setProviderError(provider, errorMessage(error), offeringId, { mode, authorizationMethodId });
172
189
  setBusy(provider, false);
173
190
  }
174
191
  };
192
+ const completeOAuthConnect = async (provider) => {
193
+ // Poll completion has already persisted the OAuth credential in the Pod.
194
+ updateConnectionState(provider, 'connected');
195
+ try {
196
+ const product = (await client.listProviders()).find((item) => item.id === provider);
197
+ if (product) {
198
+ setProviderProductOverrides((current) => ({ ...current, [provider]: product }));
199
+ }
200
+ }
201
+ catch (error) {
202
+ setProviderError(provider, `账号已连接,连接信息刷新失败:${errorMessage(error)}`);
203
+ }
204
+ };
205
+ const cancelConnect = async (provider, attempt) => {
206
+ pollingGeneration.current += 1;
207
+ setBusy(provider, false);
208
+ setAttempts((current) => ({ ...current, [provider]: undefined }));
209
+ setAttemptOfferingIds((current) => ({ ...current, [provider]: undefined }));
210
+ updateConnectionState(provider, 'failed');
211
+ try {
212
+ await client.cancelConnect?.(provider, attempt);
213
+ setProviderError(provider, '连接已取消');
214
+ }
215
+ catch (error) {
216
+ setProviderError(provider, errorMessage(error));
217
+ }
218
+ };
175
219
  const saveApiKey = async (definition) => {
176
220
  const apiKey = apiKeyInputs[definition.id]?.trim();
177
221
  const baseUrl = baseUrlInputs[definition.id]
@@ -241,15 +285,19 @@ export function AiConnectionsPanel({ client, openExternal = openExternalUrl, cli
241
285
  ? 'configured'
242
286
  : 'connected');
243
287
  };
244
- const syncProviderModels = async (provider, input, announceSuccess = false) => {
288
+ const syncProviderModels = async (provider, input, announceSuccess = false, failurePrefix = '') => {
245
289
  setVerifyingProviders((current) => ({ ...current, [provider]: true }));
246
290
  setProviderError(provider);
247
291
  try {
248
292
  const discovery = input
249
293
  ? await client.discoverModels(provider, input)
250
294
  : await client.discoverModels(provider);
295
+ setGatewayCatalogVersion((version) => version + 1);
251
296
  const selectedModels = effectiveProviderProducts[provider]?.selectedModels ?? [];
252
- const mergeScope = modelDiscoveryMergeScope(provider, input);
297
+ const mergeScope = {
298
+ ...modelDiscoveryMergeScope(provider, input),
299
+ ...(discovery.complete === false ? { markMissing: false } : {}),
300
+ };
253
301
  try {
254
302
  const persisted = await client.listModels();
255
303
  const persistedForProvider = persisted
@@ -277,7 +325,10 @@ export function AiConnectionsPanel({ client, openExternal = openExternalUrl, cli
277
325
  // The model catalog already reflects the discovery result; provider
278
326
  // summaries will refresh on the next host/provider reload.
279
327
  }
280
- if (announceSuccess) {
328
+ if (discovery.complete === false) {
329
+ setProviderError(provider, '部分连接同步失败,已保留原有模型目录,可稍后重试。', input?.offeringId);
330
+ }
331
+ else if (announceSuccess) {
281
332
  toast({
282
333
  variant: discovery.models.length > 0 ? 'success' : 'default',
283
334
  description: discovery.models.length > 0
@@ -289,7 +340,7 @@ export function AiConnectionsPanel({ client, openExternal = openExternalUrl, cli
289
340
  }
290
341
  catch (error) {
291
342
  const message = errorMessage(error);
292
- setProviderError(provider, message, input?.offeringId);
343
+ setProviderError(provider, `${failurePrefix}${message}`, input?.offeringId);
293
344
  return false;
294
345
  }
295
346
  finally {
@@ -324,24 +375,25 @@ export function AiConnectionsPanel({ client, openExternal = openExternalUrl, cli
324
375
  setBusy(provider, false);
325
376
  }
326
377
  };
327
- const createLocalCredential = async (provider, offering) => {
378
+ const createLocalCredential = async (provider, offering, method) => {
328
379
  setBusy(provider, true);
329
380
  setProviderError(provider);
330
381
  try {
331
- const isOpenAiSubscription = provider === 'openai' && offering.id === 'official-subscription';
382
+ const localService = offering.kind === 'local';
332
383
  const credential = await client.createLocalCredential(provider, {
333
384
  offeringId: offering.id,
334
- label: isOpenAiSubscription ? 'OpenAI Subscription' : 'Local Ollama',
335
- ...(isOpenAiSubscription ? {} : { baseUrl: offering.endpoints?.[0]?.baseUrl }),
385
+ authorizationMethodId: method?.id,
386
+ label: offering.label ?? offeringTitle(offering),
387
+ ...(localService ? { baseUrl: offering.endpoints?.[0]?.baseUrl } : {}),
336
388
  priority: 10,
337
389
  });
338
390
  mergeProviderCredential(provider, credential);
339
- toast({ description: isOpenAiSubscription ? '本机 OpenAI 登录已导入' : '本地 Ollama 已连接' });
391
+ toast({ description: `${offeringTitle(offering)} 已连接` });
340
392
  if (offering.modelDiscovery?.strategy !== 'unsupported') {
341
393
  await syncProviderModels(provider, {
342
394
  offeringId: credential.offeringId,
343
395
  credentialId: credential.id,
344
- });
396
+ }, false, localService ? '本地服务已连接,模型获取失败:' : '订阅已读取,模型获取失败:');
345
397
  }
346
398
  }
347
399
  catch (error) {
@@ -380,14 +432,25 @@ export function AiConnectionsPanel({ client, openExternal = openExternalUrl, cli
380
432
  }
381
433
  };
382
434
  const deleteProviderCredential = async (provider, credential) => {
435
+ // Legacy connection summaries use a synthetic id, not a Pod credential id.
436
+ if (credential.id === `${provider}:current` && credential.version === 0) {
437
+ if (effectiveProviderProducts[provider]?.credentials.some((item) => item.id !== credential.id)) {
438
+ setProviderError(provider, '请重新加载连接后再移除旧连接。', credential.offeringId);
439
+ return;
440
+ }
441
+ await disconnect(provider);
442
+ return;
443
+ }
383
444
  setBusy(provider, true);
384
445
  setProviderError(provider);
385
446
  try {
386
447
  await client.deleteProviderCredential(provider, credential.id);
448
+ const product = providerProductWithoutCredential(effectiveProviderProducts[provider], provider, credential.id);
387
449
  setProviderProductOverrides((current) => ({
388
450
  ...current,
389
- [provider]: providerProductWithoutCredential(effectiveProviderProducts[provider], provider, credential.id),
451
+ [provider]: product,
390
452
  }));
453
+ updateConnectionState(provider, connectionStateFromProduct(product));
391
454
  toast({ description: '凭证已删除' });
392
455
  }
393
456
  catch (error) {
@@ -460,34 +523,36 @@ export function AiConnectionsPanel({ client, openExternal = openExternalUrl, cli
460
523
  setBusy(provider, false);
461
524
  }
462
525
  };
526
+ const quotaRequests = useRef(new Set());
463
527
  const refreshQuota = async (provider, offering, credential) => {
464
- const setQuotaState = (patch) => {
465
- setQuotas((current) => ({
466
- ...current,
467
- [provider]: {
468
- ...current[provider],
469
- [offering.id]: {
470
- busy: false,
471
- ...current[provider]?.[offering.id],
472
- ...patch,
473
- },
474
- },
475
- }));
476
- };
477
- setQuotaState({ busy: true, error: undefined, credentialId: credential?.id });
478
- try {
479
- const quota = await client.quota(provider, true, {
480
- offeringId: offering.id,
481
- ...(credential ? {
482
- credentialId: credential.id,
483
- credentialIri: credential.id,
484
- } : {}),
485
- });
486
- setQuotaState({ quota, busy: false, error: undefined, credentialId: credential?.id });
487
- }
488
- catch (error) {
489
- setQuotaState({ busy: false, error: errorMessage(error), credentialId: credential?.id });
490
- }
528
+ const credentials = credential ? [credential] : (effectiveProviderProducts[provider]?.credentials ?? []).filter((item) => item.enabled && item.offeringId === offering.id);
529
+ await Promise.all(credentials.map(async (item) => {
530
+ const requestKey = `${provider}\0${item.id}`;
531
+ if (quotaRequests.current.has(requestKey))
532
+ return;
533
+ quotaRequests.current.add(requestKey);
534
+ const setQuotaState = (patch) => {
535
+ setQuotas((current) => ({
536
+ ...current,
537
+ [provider]: { ...current[provider], [item.id]: patch },
538
+ }));
539
+ };
540
+ setQuotaState({ busy: true, credentialId: item.id });
541
+ try {
542
+ const quota = await client.quota(provider, true, {
543
+ offeringId: offering.id,
544
+ credentialId: item.id,
545
+ credentialIri: item.id,
546
+ });
547
+ setQuotaState({ quota, busy: false, credentialId: item.id });
548
+ }
549
+ catch (error) {
550
+ setQuotaState({ busy: false, error: errorMessage(error), credentialId: item.id });
551
+ }
552
+ finally {
553
+ quotaRequests.current.delete(requestKey);
554
+ }
555
+ }));
491
556
  };
492
557
  const verifyProvider = async (provider) => {
493
558
  await syncProviderModels(provider, provider === 'custom' && selectedCredentialId
@@ -495,6 +560,7 @@ export function AiConnectionsPanel({ client, openExternal = openExternalUrl, cli
495
560
  : undefined, true);
496
561
  };
497
562
  const reloadModels = useCallback(async () => {
563
+ setGatewayCatalogVersion((version) => version + 1);
498
564
  try {
499
565
  setModels(await client.listModels());
500
566
  }
@@ -550,6 +616,7 @@ export function AiConnectionsPanel({ client, openExternal = openExternalUrl, cli
550
616
  const generation = (modelSelectionGeneration.current[provider] ?? 0) + 1;
551
617
  modelSelectionGeneration.current[provider] = generation;
552
618
  setSelectedModelIds((current) => ({ ...current, [provider]: ids }));
619
+ setModelSelectionStatus((current) => ({ ...current, [provider]: 'saving' }));
553
620
  void (async () => {
554
621
  try {
555
622
  const candidates = [
@@ -569,12 +636,15 @@ export function AiConnectionsPanel({ client, openExternal = openExternalUrl, cli
569
636
  await client.saveModelSelection?.(provider, selections);
570
637
  }
571
638
  if (modelSelectionGeneration.current[provider] === generation) {
639
+ setGatewayCatalogVersion((version) => version + 1);
640
+ setModelSelectionStatus((current) => ({ ...current, [provider]: 'saved' }));
572
641
  onModelSelectionChange?.(provider, ids);
573
642
  }
574
643
  }
575
644
  catch (error) {
576
645
  if (modelSelectionGeneration.current[provider] !== generation)
577
646
  return;
647
+ setModelSelectionStatus((current) => ({ ...current, [provider]: 'error' }));
578
648
  setSelectedModelIds((current) => ({ ...current, [provider]: previousIds }));
579
649
  onModelSelectionChange?.(provider, previousIds);
580
650
  toast({ variant: 'destructive', description: errorMessage(error) });
@@ -588,16 +658,16 @@ export function AiConnectionsPanel({ client, openExternal = openExternalUrl, cli
588
658
  const providerSelectedModelIds = selectedModelIds[definition.id]
589
659
  ?? providerProduct?.selectedModels.map(modelSelectionId)
590
660
  ?? [];
591
- return (_jsx(AiProviderCard, { definition: definition, product: providerProduct, status: resolvedConnectionState(connectionStates[definition.id], providerProduct), accountLabel: providerSummariesInput[definition.id]?.accountLabel, attempt: attempts[definition.id], attemptOfferingId: attemptOfferingIds[definition.id], apiKey: apiKeyInputs[definition.id] ?? '', baseUrl: baseUrlInputs[definition.id] ?? providerSummariesInput[definition.id]?.baseUrl ?? '', busy: Boolean(busyProviders[definition.id]), error: providerErrors[definition.id], quotas: quotas[definition.id], models: providerModels, selectedModelIds: providerSelectedModelIds, onApiKeyChange: (value) => setApiKeyInputs((current) => ({
661
+ return (_jsx(AiProviderCard, { definition: definition, product: providerProduct, status: resolvedConnectionState(connectionStates[definition.id], providerProduct), accountLabel: providerSummariesInput[definition.id]?.accountLabel, attempt: attempts[definition.id], attemptOfferingId: attemptOfferingIds[definition.id], apiKey: apiKeyInputs[definition.id] ?? '', baseUrl: baseUrlInputs[definition.id] ?? providerSummariesInput[definition.id]?.baseUrl ?? '', busy: Boolean(busyProviders[definition.id] || verifyingProviders[definition.id]), disabled: providerLoading, error: providerErrors[definition.id], quotas: quotas[definition.id], models: providerModels, selectedModelIds: providerSelectedModelIds, modelSelectionStatus: modelSelectionStatus[definition.id], onApiKeyChange: (value) => setApiKeyInputs((current) => ({
592
662
  ...current,
593
663
  [definition.id]: value,
594
664
  })), onBaseUrlChange: (value) => setBaseUrlInputs((current) => ({
595
665
  ...current,
596
666
  [definition.id]: value,
597
- })), onBeginApiKey: () => void beginApiKey(definition.id), onBeginOffering: (offering, mode) => void beginOfferingConnect(definition.id, offering, mode), onBeginBrowser: () => void beginBrowserConnect(definition), onSaveApiKey: () => void saveApiKey(definition), onDisconnect: (credential) => void disconnect(definition.id, credential?.id), onCreateApiKeyCredential: (offering, input) => createApiKeyCredential(definition.id, offering, input), onCreateLocalCredential: (offering) => createLocalCredential(definition.id, offering), onUpdateCredential: (credential, patch) => updateProviderCredential(definition.id, credential, patch), onDeleteCredential: (credential) => void deleteProviderCredential(definition.id, credential), onTestCredential: (credential) => void testProviderCredential(definition.id, credential), onReorderCredentials: (offering, credentials, fromIndex, toIndex) => void reorderProviderCredentials(definition.id, offering, credentials, fromIndex, toIndex), onRefreshQuota: (offering, credential) => void refreshQuota(definition.id, offering, credential), verifyPending: Boolean(verifyingProviders[definition.id]), onVerify: () => void verifyProvider(definition.id), onAddModel: () => openModelEditor(definition.id), onEditModel: (model) => openModelEditor(definition.id, model), onDeleteModel: (model) => void deleteProviderModel(definition.id, model), onModelSelectionChange: handleModelSelectionChange, onDismissError: () => setProviderError(definition.id) }, definition.id));
667
+ })), onBeginApiKey: () => void beginApiKey(definition.id), onBeginOffering: (offering, mode, method) => void beginOfferingConnect(definition.id, offering, mode, method), onCancelConnect: (attempt) => void cancelConnect(definition.id, attempt), onBeginBrowser: () => void beginBrowserConnect(definition), onSaveApiKey: () => void saveApiKey(definition), onDisconnect: (credential) => void disconnect(definition.id, credential?.id), onCreateApiKeyCredential: (offering, input) => createApiKeyCredential(definition.id, offering, input), onCreateLocalCredential: (offering, method) => createLocalCredential(definition.id, offering, method), onUpdateCredential: (credential, patch) => updateProviderCredential(definition.id, credential, patch), onDeleteCredential: (credential) => void deleteProviderCredential(definition.id, credential), onTestCredential: (credential) => void testProviderCredential(definition.id, credential), onReorderCredentials: (offering, credentials, fromIndex, toIndex) => void reorderProviderCredentials(definition.id, offering, credentials, fromIndex, toIndex), onRefreshQuota: (offering, credential) => void refreshQuota(definition.id, offering, credential), verifyPending: Boolean(verifyingProviders[definition.id]), onVerify: () => void verifyProvider(definition.id), onAddModel: () => openModelEditor(definition.id), onEditModel: (model) => openModelEditor(definition.id, model), onDeleteModel: (model) => void deleteProviderModel(definition.id, model), onModelSelectionChange: handleModelSelectionChange, onDismissError: () => setProviderError(definition.id) }, definition.id));
598
668
  })] }));
599
- const keyContent = (_jsx(AiGatewayKeysSection, { client: client, clientConfigurationBridge: clientConfigurationBridge }));
600
- return (_jsxs("div", { "data-testid": "ai-connections-panel", className: "mx-auto w-full max-w-5xl space-y-10 px-4 py-6 sm:px-8 sm:py-8", children: [_jsx(Toaster, {}), selectedSection === 'keys' ? keyContent : null, selectedSection === 'provider' ? providerContent : null, selectedSection === 'provider' && modelEditor ? (_jsx(AiModelEditorDialog, { open: true, providerName: PROVIDERS.find((definition) => definition.id === modelEditor.provider)?.name ?? modelEditor.provider, initialValue: modelEditor.model
669
+ const keyContent = (_jsx(AiGatewayKeysSection, { client: client, clientConfigurationBridge: clientConfigurationBridge, gatewayModels: gatewayModels }));
670
+ return (_jsxs("div", { "data-testid": "ai-connections-panel", className: "mx-auto w-full max-w-5xl space-y-10 px-4 py-6 sm:px-8 sm:py-8", children: [renderToaster ? _jsx(Toaster, {}) : null, selectedSection === 'keys' ? keyContent : null, selectedSection === 'provider' ? providerContent : null, selectedSection === 'provider' && modelEditor ? (_jsx(AiModelEditorDialog, { open: true, providerName: PROVIDERS.find((definition) => definition.id === modelEditor.provider)?.name ?? modelEditor.provider, initialValue: modelEditor.model
601
671
  ? {
602
672
  id: modelEditor.model.id,
603
673
  name: modelEditor.model.displayName ?? '',
@@ -635,11 +705,11 @@ async function pollDeviceConnect(client, provider, initial, generation, generati
635
705
  await delay(Math.max(1, attempt.intervalSeconds ?? 2) * 1000);
636
706
  if (generationRef.current !== generation)
637
707
  return;
638
- attempt = await client.pollDevice(provider, attempt);
708
+ attempt = { ...attempt, ...await client.pollDevice(provider, attempt) };
639
709
  callbacks.onAttempt(attempt);
640
710
  }
641
711
  if (attempt.status === 'completed') {
642
- callbacks.onConnected();
712
+ await callbacks.onConnected();
643
713
  }
644
714
  else if (generationRef.current === generation) {
645
715
  callbacks.onFailed(attempt.message || `连接${attempt.status === 'expired' ? '已过期' : '失败'}`);
@@ -741,7 +811,7 @@ function providerProductWithCredentialList(product, provider, offering, updatedC
741
811
  ? base.offerings
742
812
  : [...base.offerings, offering],
743
813
  credentials: sortCredentialsByPriority([
744
- ...base.credentials.filter((credential) => credential.offeringId !== offering.id || !updatedIds.has(credential.id)),
814
+ ...base.credentials.filter((credential) => !updatedIds.has(credential.id)),
745
815
  ...updatedCredentials,
746
816
  ]),
747
817
  };
@@ -1,9 +1,10 @@
1
- import type { AiConnectAttempt, AiConnectionsMode, AiProviderCredentialSummary, AiProviderOffering, AiProviderSummary, AiQuotaSnapshot } from './ai-connections-client';
1
+ import type { AiConnectAttempt, AiConnectionsMode, AiProviderAuthorizationMethod, AiProviderCredentialSummary, AiProviderOffering, AiProviderSummary, AiQuotaSnapshot } from './ai-connections-client';
2
2
  import type { AiProviderDefinition } from './controller';
3
3
  import type { ProviderConnectionState } from './AiProviderCard';
4
4
  export interface AiOfferingActionError {
5
5
  message: string;
6
6
  offeringId?: string;
7
+ authorization?: Pick<AiConnectAttempt, 'mode' | 'authorizationMethodId'>;
7
8
  }
8
9
  export interface AiOfferingQuotaState {
9
10
  quota?: AiQuotaSnapshot;
@@ -11,7 +12,7 @@ export interface AiOfferingQuotaState {
11
12
  error?: string;
12
13
  credentialId?: string;
13
14
  }
14
- export declare function AiCredentialPoolSection({ definition, product, status, accountLabel, attempt, attemptOfferingId, apiKey, baseUrl, busy, disabled, error, suppressError, quotas, onApiKeyChange, onBaseUrlChange, onBeginApiKey, onBeginOffering, onBeginBrowser, onSaveApiKey, onDisconnect, onCreateApiKeyCredential, onCreateLocalCredential, onUpdateCredential, onDeleteCredential, onTestCredential, onReorderCredentials, onRefreshQuota, onDismissError, }: {
15
+ export declare function AiCredentialPoolSection({ definition, product, status, accountLabel, attempt, attemptOfferingId, apiKey, baseUrl, busy, disabled, error, suppressError, quotas, onApiKeyChange, onBaseUrlChange, onBeginApiKey, onBeginOffering, onCancelConnect, onBeginBrowser, onSaveApiKey, onDisconnect, onCreateApiKeyCredential, onCreateLocalCredential, onUpdateCredential, onDeleteCredential, onTestCredential, onReorderCredentials, onRefreshQuota, onDismissError, }: {
15
16
  definition: AiProviderDefinition;
16
17
  product?: AiProviderSummary;
17
18
  status: ProviderConnectionState;
@@ -28,7 +29,8 @@ export declare function AiCredentialPoolSection({ definition, product, status, a
28
29
  onApiKeyChange: (value: string) => void;
29
30
  onBaseUrlChange?: (value: string) => void;
30
31
  onBeginApiKey: () => void;
31
- onBeginOffering?: (offering: AiProviderOffering, mode: AiConnectionsMode) => void;
32
+ onBeginOffering?: (offering: AiProviderOffering, mode: AiConnectionsMode, method?: AiProviderAuthorizationMethod) => void;
33
+ onCancelConnect?: (attempt: Pick<AiConnectAttempt, 'attemptId' | 'state' | 'signature' | 'offeringId'> & Partial<Pick<AiConnectAttempt, 'mode'>>) => void;
32
34
  onBeginBrowser: () => void;
33
35
  onSaveApiKey: () => void;
34
36
  onDisconnect: (credential?: AiProviderCredentialSummary) => void;
@@ -39,7 +41,7 @@ export declare function AiCredentialPoolSection({ definition, product, status, a
39
41
  proxyUrl?: string;
40
42
  priority: number;
41
43
  }) => Promise<void>;
42
- onCreateLocalCredential?: (offering: AiProviderOffering) => Promise<void>;
44
+ onCreateLocalCredential?: (offering: AiProviderOffering, method?: AiProviderAuthorizationMethod) => Promise<void>;
43
45
  onUpdateCredential?: (credential: AiProviderCredentialSummary, patch: {
44
46
  label?: string;
45
47
  enabled?: boolean;