@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
@@ -1,7 +1,7 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as os from 'node:os';
3
3
  import * as path from 'node:path';
4
- import { BaseAiClientConfigAdapter, looksLikePreviousXpodValue, normalizeV1Endpoint, parseJsonObject, profileApiKey, stringifyJson, } from './base-adapter.js';
4
+ import { BaseAiClientConfigAdapter, AiClientConfigError, looksLikePreviousXpodValue, contentFingerprint, normalizeV1Endpoint, parseJsonObject, profileApiKey, stringifyJson, } from './base-adapter.js';
5
5
  const START = '# >>> xpod-ai-connections managed';
6
6
  const END = '# <<< xpod-ai-connections managed';
7
7
  export class CodexConfigAdapter extends BaseAiClientConfigAdapter {
@@ -9,50 +9,137 @@ export class CodexConfigAdapter extends BaseAiClientConfigAdapter {
9
9
  const codexHome = path.join(options.homeDir ?? os.homedir(), '.codex');
10
10
  const configPath = path.join(codexHome, 'config.toml');
11
11
  const authPath = path.join(codexHome, 'auth.json');
12
- super('codex', 'codex', [configPath, authPath], codexHome);
12
+ super('codex', 'codex', [configPath], codexHome);
13
13
  this.configPath = configPath;
14
14
  this.authPath = authPath;
15
+ this.catalogPath = path.join(codexHome, 'xpod-model-catalog.json');
16
+ this.nativeModelsPath = path.join(codexHome, 'models_cache.json');
15
17
  }
16
18
  normalizeProfile(profile) {
17
- if (!profile.model?.trim() && (!profile.activeModels || profile.activeModels.length === 0)) {
18
- return { ...profile, model: undefined };
19
+ // Refreshing the menu must not select a different model on the user's behalf.
20
+ return profile.model?.trim() ? super.normalizeProfile(profile) : { ...profile, model: undefined };
21
+ }
22
+ async inspect() {
23
+ const inspection = await super.inspect();
24
+ const state = await this.readState();
25
+ if (!state?.files.some((file) => file.path === this.catalogPath))
26
+ return inspection;
27
+ await this.rejectSymlink(this.catalogPath);
28
+ const catalog = await this.readOptional(this.catalogPath);
29
+ if (catalog !== undefined && contentFingerprint(catalog) === state.projectionHashes?.[this.catalogPath]) {
30
+ return { ...inspection, configPaths: [...inspection.configPaths, this.catalogPath] };
31
+ }
32
+ const withoutFingerprint = { ...inspection };
33
+ delete withoutFingerprint.apiKeyFingerprint;
34
+ return { ...withoutFingerprint, projectionMatches: false, configPaths: [...inspection.configPaths, this.catalogPath] };
35
+ }
36
+ async plan(profile) {
37
+ const plan = await super.plan(profile);
38
+ const state = await this.readState();
39
+ const legacyAuth = state?.files.find((file) => file.path === this.authPath);
40
+ if (!legacyAuth)
41
+ return plan;
42
+ await this.rejectSymlink(this.authPath);
43
+ const current = await this.readOptional(this.authPath);
44
+ if (!this.ownsLegacyAuth(current, state?.apiKeyFingerprint))
45
+ return plan;
46
+ let original;
47
+ if (legacyAuth.existed) {
48
+ if (!legacyAuth.backupPath)
49
+ throw new Error('Missing Codex auth.json backup metadata');
50
+ await this.rejectSymlink(legacyAuth.backupPath);
51
+ original = await this.readOptional(legacyAuth.backupPath);
52
+ if (original === undefined)
53
+ throw new Error('Missing Codex auth.json backup; refusing to guess login state');
19
54
  }
20
- return super.normalizeProfile(profile);
55
+ // Migrate auth in the same transaction without keeping it in the new ownership state.
56
+ plan.writes.splice(plan.writes.length - 1, 0, {
57
+ path: this.authPath,
58
+ content: restoreLegacyAuth(current, original, legacyAuth.existed),
59
+ expectedContentHash: contentFingerprint(current),
60
+ });
61
+ return plan;
62
+ }
63
+ ownsLegacyAuth(current, fingerprint) {
64
+ if (!fingerprint || current === undefined)
65
+ return false;
66
+ const auth = parseJsonObject(current, 'Codex auth.json');
67
+ return typeof auth.OPENAI_API_KEY === 'string' && contentFingerprint(auth.OPENAI_API_KEY) === fingerprint;
21
68
  }
22
69
  async project(profile, current) {
23
- const config = stripRootLevelModelKeys(this.removeManagedBlock(current.get(this.configPath) ?? '')).trimEnd();
70
+ const baseContent = current.get(this.configPath) ?? '';
71
+ let nativeModels = [];
72
+ if (profile.activeModels?.length) {
73
+ const nativeCatalog = await this.readOptional(this.nativeModelsPath);
74
+ if (nativeCatalog !== undefined)
75
+ nativeModels = readCatalogModels(nativeCatalog, 'Codex native model cache');
76
+ }
77
+ let catalog = codexModelCatalog(profile.activeModels, nativeModels);
78
+ const state = await this.readState();
79
+ const ownsCatalog = state?.files.some((file) => file.path === this.catalogPath);
80
+ if (catalog !== undefined || ownsCatalog) {
81
+ await this.rejectSymlink(this.catalogPath);
82
+ const existingCatalog = await this.readOptional(this.catalogPath);
83
+ current.set(this.catalogPath, existingCatalog);
84
+ catalog ?? (catalog = existingCatalog);
85
+ if (catalog === undefined)
86
+ throw new Error('Codex model catalog is missing; refresh with the current Gateway models');
87
+ }
88
+ const unmanagedConfig = this.removeManagedBlock(baseContent);
89
+ if (hasUnmanagedModelProviderTable(unmanagedConfig)) {
90
+ throw new Error('Codex config.toml already defines [model_providers.xpod] outside managed block');
91
+ }
92
+ const config = stripRootLevelModelKeys(unmanagedConfig).trim();
24
93
  const model = profile.model?.trim();
25
- const block = [
94
+ const rootBlock = [
26
95
  START,
27
96
  'model_provider = "xpod"',
28
- ...(model ? [`model = ${JSON.stringify(model)}`] : []),
97
+ ...(model ? [`model = ${JSON.stringify(model)}`] : rootLevelLines(baseContent, 'model')),
98
+ ...(catalog !== undefined ? [`model_catalog_json = ${JSON.stringify(this.catalogPath)}`] : rootLevelLines(baseContent, 'model_catalog_json')),
99
+ END,
100
+ ].join('\n');
101
+ const providerBlock = [
102
+ START,
29
103
  '',
30
104
  '[model_providers.xpod]',
31
105
  'name = "Xpod AI Connection"',
32
106
  `base_url = ${JSON.stringify(normalizeV1Endpoint(profile.endpoint))}`,
33
107
  'wire_api = "responses"',
34
- 'requires_openai_auth = true',
108
+ 'requires_openai_auth = false',
109
+ `experimental_bearer_token = ${JSON.stringify(profileApiKey(profile))}`,
35
110
  END,
36
111
  '',
37
112
  ].join('\n');
38
- const auth = parseJsonObject(current.get(this.authPath), 'Codex auth.json');
39
- auth.OPENAI_API_KEY = profileApiKey(profile);
40
- return new Map([
41
- [this.configPath, `${config}${config ? '\n\n' : ''}${block}`],
42
- [this.authPath, stringifyJson(auth)],
43
- ]);
113
+ const projected = new Map([[this.configPath, `${rootBlock}\n\n${config}${config ? '\n\n' : ''}${providerBlock}`]]);
114
+ if (catalog !== undefined)
115
+ projected.set(this.catalogPath, catalog);
116
+ return projected;
44
117
  }
45
118
  async verifyProjection(profile) {
46
119
  try {
47
120
  const config = await fs.promises.readFile(this.configPath, 'utf8');
48
- const auth = parseJsonObject(await fs.promises.readFile(this.authPath, 'utf8'), 'Codex auth.json');
49
121
  const modelMatches = profile.model
50
- ? config.includes(`model = ${JSON.stringify(profile.model)}`)
51
- : !hasRootLevelKey(config, 'model');
52
- const ok = config.includes('model_provider = "xpod"') &&
53
- modelMatches &&
54
- config.includes(`base_url = ${JSON.stringify(normalizeV1Endpoint(profile.endpoint))}`) &&
55
- auth.OPENAI_API_KEY === profileApiKey(profile);
122
+ ? rootLevelLines(config, 'model').some((line) => line.trim() === `model = ${JSON.stringify(profile.model)}`)
123
+ : true;
124
+ const provider = tableLines(config, 'model_providers.xpod');
125
+ const state = await this.readState();
126
+ const ownsCatalog = state?.files.some((file) => file.path === this.catalogPath);
127
+ let catalogMatches = true;
128
+ if (profile.activeModels !== undefined || ownsCatalog) {
129
+ const catalog = await fs.promises.readFile(this.catalogPath, 'utf8');
130
+ // Validate the applied snapshot, not a cache Codex may have refreshed since planning.
131
+ const expectedCatalog = codexModelCatalog(profile.activeModels, readCatalogModels(catalog, 'Codex model catalog'));
132
+ catalogMatches = rootLevelLines(config, 'model_catalog_json')
133
+ .includes(`model_catalog_json = ${JSON.stringify(this.catalogPath)}`) &&
134
+ contentFingerprint(catalog) === state?.projectionHashes?.[this.catalogPath] &&
135
+ (expectedCatalog === undefined || catalog === expectedCatalog);
136
+ }
137
+ const ok = rootLevelLines(config, 'model_provider').some((line) => line.trim() === 'model_provider = "xpod"') &&
138
+ modelMatches && catalogMatches &&
139
+ provider.includes(`base_url = ${JSON.stringify(normalizeV1Endpoint(profile.endpoint))}`) &&
140
+ provider.includes('wire_api = "responses"') &&
141
+ provider.includes('requires_openai_auth = false') &&
142
+ provider.includes(`experimental_bearer_token = ${JSON.stringify(profileApiKey(profile))}`);
56
143
  return ok ? { ok: true } : { ok: false, reason: 'Codex projection differs from the requested connection' };
57
144
  }
58
145
  catch (error) {
@@ -60,17 +147,18 @@ export class CodexConfigAdapter extends BaseAiClientConfigAdapter {
60
147
  }
61
148
  }
62
149
  async restoreFile(filePath, current, original, originallyExisted) {
63
- if (filePath === this.authPath) {
64
- const restored = parseJsonObject(current, 'Codex auth.json');
65
- const before = parseJsonObject(original, 'Codex original auth.json');
66
- if (Object.prototype.hasOwnProperty.call(before, 'OPENAI_API_KEY') &&
67
- !looksLikePreviousXpodValue(before.OPENAI_API_KEY)) {
68
- restored.OPENAI_API_KEY = before.OPENAI_API_KEY;
150
+ if (filePath === this.catalogPath) {
151
+ const state = await this.readState();
152
+ if (current === undefined || contentFingerprint(current) !== state?.projectionHashes?.[this.catalogPath]) {
153
+ throw new Error('Codex model catalog changed since projection was applied; refusing restore to avoid data loss');
69
154
  }
70
- else {
71
- delete restored.OPENAI_API_KEY;
72
- }
73
- return !originallyExisted && Object.keys(restored).length === 0 ? null : stringifyJson(restored);
155
+ return originallyExisted ? original : null;
156
+ }
157
+ if (filePath === this.authPath) {
158
+ const state = await this.readState();
159
+ if (!this.ownsLegacyAuth(current, state?.apiKeyFingerprint))
160
+ return current ?? null;
161
+ return restoreLegacyAuth(current, original, originallyExisted);
74
162
  }
75
163
  let restored = this.removeManagedBlock(current ?? '').trim();
76
164
  const hasCurrentProvider = hasRootLevelKey(restored, 'model_provider');
@@ -86,17 +174,51 @@ export class CodexConfigAdapter extends BaseAiClientConfigAdapter {
86
174
  restored = insertRootLevelLines(restored, originalRoot);
87
175
  }
88
176
  }
177
+ if (!hasRootLevelKey(restored, 'model_catalog_json') && !originalHasXpodProjection) {
178
+ const originalCatalog = rootLevelLines(originalContent, 'model_catalog_json');
179
+ if (originalCatalog.length > 0)
180
+ restored = insertRootLevelLines(restored, originalCatalog);
181
+ }
89
182
  return !originallyExisted && !restored ? null : `${restored}${restored ? '\n' : ''}`;
90
183
  }
184
+ async currentApiKeyFingerprint(current) {
185
+ const token = tableLines(current.get(this.configPath) ?? '', 'model_providers.xpod')
186
+ .find((line) => /^experimental_bearer_token\s*=/u.test(line));
187
+ if (token) {
188
+ const value = JSON.parse(token.slice(token.indexOf('=') + 1).trim());
189
+ return typeof value === 'string' ? contentFingerprint(value) : undefined;
190
+ }
191
+ // Old ownership records may still manage the global auth file until migration.
192
+ if (current.has(this.authPath)) {
193
+ const auth = parseJsonObject(current.get(this.authPath), 'Codex auth.json');
194
+ return typeof auth.OPENAI_API_KEY === 'string' ? contentFingerprint(auth.OPENAI_API_KEY) : undefined;
195
+ }
196
+ return undefined;
197
+ }
91
198
  removeManagedBlock(content) {
92
- const start = content.indexOf(START);
93
- if (start < 0)
94
- return content;
95
- const end = content.indexOf(END, start);
96
- if (end < 0)
97
- throw new Error('Codex xpod managed block is incomplete');
98
- return `${content.slice(0, start)}${content.slice(end + END.length)}`;
199
+ let start = content.indexOf(START);
200
+ while (start >= 0) {
201
+ const end = content.indexOf(END, start);
202
+ if (end < 0)
203
+ throw new Error('Codex xpod managed block is incomplete');
204
+ content = `${content.slice(0, start)}${content.slice(end + END.length)}`;
205
+ start = content.indexOf(START);
206
+ }
207
+ return content;
208
+ }
209
+ }
210
+ function tableLines(content, table) {
211
+ const lines = [];
212
+ let selected = false;
213
+ for (const line of content.split('\n')) {
214
+ if (isTomlTableHeader(line)) {
215
+ selected = line.trim() === `[${table}]`;
216
+ }
217
+ else if (selected) {
218
+ lines.push(line.trim());
219
+ }
99
220
  }
221
+ return lines;
100
222
  }
101
223
  /**
102
224
  * Remove only the root-level keys owned by the Codex projection. A TOML key
@@ -149,10 +271,153 @@ function insertRootLevelLines(content, lines) {
149
271
  function isTomlTableHeader(line) {
150
272
  return /^\s*\[\[?[^\]]+\]\]?\s*(?:#.*)?$/u.test(line);
151
273
  }
274
+ function hasUnmanagedModelProviderTable(content) {
275
+ for (const line of content.split('\n')) {
276
+ if (!isTomlTableHeader(line) || /^\s*\[\[/.test(line)) {
277
+ continue;
278
+ }
279
+ if (normalizeTomlTableName(line) === 'model_providers.xpod') {
280
+ return true;
281
+ }
282
+ }
283
+ return false;
284
+ }
285
+ function normalizeTomlTableName(line) {
286
+ const match = /^\s*\[\s*([^\]]+)\s*\]\s*(?:#.*)?$/u.exec(line);
287
+ if (!match)
288
+ return undefined;
289
+ const rawName = match[1].trim();
290
+ const segments = parseTomlTableSegments(rawName);
291
+ return segments.length === 1 ? undefined : normalizeTomlDottedKey(rawName);
292
+ }
293
+ function normalizeTomlDottedKey(content) {
294
+ const parts = parseTomlTableSegments(content);
295
+ return parts.map((part) => removeTomlQuotes(part)).join('.');
296
+ }
297
+ function parseTomlTableSegments(input) {
298
+ const parts = [];
299
+ let current = '';
300
+ let quote = null;
301
+ for (let i = 0; i < input.length; i++) {
302
+ const char = input[i];
303
+ if (quote) {
304
+ if (char === quote) {
305
+ quote = null;
306
+ continue;
307
+ }
308
+ current += char;
309
+ continue;
310
+ }
311
+ if (char === '"' || char === "'") {
312
+ quote = char;
313
+ continue;
314
+ }
315
+ if (char === '.') {
316
+ parts.push(current.trim());
317
+ current = '';
318
+ continue;
319
+ }
320
+ current += char;
321
+ }
322
+ parts.push(current.trim());
323
+ return parts.map((part) => part.trim()).filter((part) => part.length > 0);
324
+ }
325
+ function removeTomlQuotes(value) {
326
+ if (value.length === 0)
327
+ return value;
328
+ const first = value[0];
329
+ const last = value[value.length - 1];
330
+ if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
331
+ return value.slice(1, -1);
332
+ }
333
+ return value;
334
+ }
152
335
  function isRootModelKey(line) {
153
336
  return rootModelKey(line) !== undefined;
154
337
  }
155
338
  function rootModelKey(line) {
156
- const match = /^\s*(model_provider|model)\s*=/.exec(line);
339
+ const match = /^\s*(model_provider|model|model_catalog_json)\s*=/.exec(line);
157
340
  return match?.[1];
158
341
  }
342
+ /** Revert only the two fields the old adapter owned; preserve refreshed OAuth state. */
343
+ function restoreLegacyAuth(current, original, originallyExisted) {
344
+ const restored = parseJsonObject(current, 'Codex auth.json');
345
+ const before = parseJsonObject(original, 'Codex original auth.json');
346
+ if (restored.auth_mode === 'apikey') {
347
+ if (Object.prototype.hasOwnProperty.call(before, 'auth_mode')) {
348
+ restored.auth_mode = before.auth_mode;
349
+ }
350
+ else {
351
+ delete restored.auth_mode;
352
+ }
353
+ }
354
+ if (Object.prototype.hasOwnProperty.call(before, 'OPENAI_API_KEY') &&
355
+ !looksLikePreviousXpodValue(before.OPENAI_API_KEY)) {
356
+ restored.OPENAI_API_KEY = before.OPENAI_API_KEY;
357
+ }
358
+ else {
359
+ delete restored.OPENAI_API_KEY;
360
+ }
361
+ return !originallyExisted && Object.keys(restored).length === 0 ? null : stringifyJson(restored);
362
+ }
363
+ /** Gateway ids are already routable; provider labels must not rewrite their slugs. */
364
+ function codexModelCatalog(models, nativeModels = []) {
365
+ if (models === undefined)
366
+ return undefined;
367
+ const available = models.filter((model) => model.availability === undefined || model.availability === 'available');
368
+ if (available.length === 0)
369
+ throw new AiClientConfigError('model_catalog_empty');
370
+ const seen = new Set();
371
+ return stringifyJson({ models: available.map((model, index) => {
372
+ const id = model.id.trim();
373
+ if (!id || seen.has(id))
374
+ throw new Error('Codex model catalog requires unique, non-empty Gateway model ids');
375
+ seen.add(id);
376
+ const native = nativeModels.find((entry) => entry.slug === id);
377
+ const nativeModalities = Array.isArray(native?.input_modalities) ? native.input_modalities : ['text'];
378
+ const declaredModalities = model.inputModalities?.filter((value) => value === 'text' || value === 'image');
379
+ const modalities = declaredModalities?.filter((value) => !native || nativeModalities.includes(value)) ?? nativeModalities;
380
+ const contextWindow = Number.isSafeInteger(model.contextWindow) && model.contextWindow > 0 ? model.contextWindow : undefined;
381
+ const reasoning = codexReasoningLevels(model);
382
+ return {
383
+ slug: id,
384
+ description: 'Xpod Gateway model',
385
+ supported_reasoning_levels: reasoning.levels,
386
+ ...(reasoning.defaultLevel ? { default_reasoning_level: reasoning.defaultLevel } : {}),
387
+ shell_type: 'shell_command',
388
+ support_verbosity: false,
389
+ supports_parallel_tool_calls: false,
390
+ truncation_policy: { mode: 'tokens', limit: 10000 },
391
+ experimental_supported_tools: [],
392
+ base_instructions: 'You are a coding assistant.',
393
+ ...native,
394
+ display_name: model.displayName?.trim() || native?.display_name || id,
395
+ visibility: 'list',
396
+ supported_in_api: true,
397
+ priority: index,
398
+ input_modalities: modalities.length ? [...new Set(modalities)] : ['text'],
399
+ ...(contextWindow !== undefined ? { context_window: contextWindow } : {}),
400
+ ...(contextWindow !== undefined && typeof native?.max_context_window === 'number'
401
+ ? { max_context_window: Math.min(contextWindow, native.max_context_window) } : {}),
402
+ };
403
+ }) });
404
+ }
405
+ function codexReasoningLevels(model) {
406
+ if (model.provider !== 'deepseek' || !model.capabilities?.includes('reasoning'))
407
+ return { levels: [] };
408
+ return {
409
+ levels: [
410
+ { effort: 'low', description: 'DeepSeek low reasoning depth' },
411
+ { effort: 'high', description: 'DeepSeek standard reasoning depth' },
412
+ { effort: 'max', description: 'DeepSeek maximum reasoning depth' },
413
+ ],
414
+ defaultLevel: 'high',
415
+ };
416
+ }
417
+ function readCatalogModels(content, label) {
418
+ const catalog = parseJsonObject(content, label);
419
+ if (!Array.isArray(catalog.models) || catalog.models.some((model) => !model || typeof model !== 'object' || Array.isArray(model) || typeof model.slug !== 'string')) {
420
+ throw new Error(`${label} must contain a models array with string slugs`);
421
+ }
422
+ return catalog.models;
423
+ }