@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.
- package/config/cloud.json +1 -1
- package/config/main.json +36 -2
- package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.d.ts +3 -0
- package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.js +1 -1
- package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.d.ts +2 -1
- package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.js +101 -32
- package/dist/api/ai-gateway/connect/DeviceCodeProtocol.d.ts +80 -0
- package/dist/api/ai-gateway/connect/DeviceCodeProtocol.js +3 -0
- package/dist/api/ai-gateway/connect/FileSessionImportAdapter.d.ts +38 -0
- package/dist/api/ai-gateway/connect/FileSessionImportAdapter.js +63 -0
- package/dist/api/ai-gateway/connect/LoopbackAuthorizationCallbackReceiver.d.ts +24 -0
- package/dist/api/ai-gateway/connect/LoopbackAuthorizationCallbackReceiver.js +136 -0
- package/dist/api/ai-gateway/connect/OAuthConnectAdapter.d.ts +2 -0
- package/dist/api/ai-gateway/connect/OAuthConnectAdapter.js +2 -1
- package/dist/api/ai-gateway/connect/OAuthIntegrationRegistry.d.ts +17 -13
- package/dist/api/ai-gateway/connect/OAuthIntegrationRegistry.js +52 -19
- package/dist/api/ai-gateway/connect/OpenAiSubscriptionSessionImportAdapter.d.ts +4 -28
- package/dist/api/ai-gateway/connect/OpenAiSubscriptionSessionImportAdapter.js +7 -58
- package/dist/api/ai-gateway/connect/ProviderAuthorizationProfiles.d.ts +4 -0
- package/dist/api/ai-gateway/connect/ProviderAuthorizationProfiles.js +116 -0
- package/dist/api/ai-gateway/connect/SessionImportProfiles.d.ts +10 -0
- package/dist/api/ai-gateway/connect/SessionImportProfiles.js +112 -0
- package/dist/api/ai-gateway/connect/index.d.ts +125 -23
- package/dist/api/ai-gateway/connect/index.js +1277 -260
- package/dist/api/ai-gateway/models/PodModelSelectionRepository.d.ts +4 -1
- package/dist/api/ai-gateway/models/PodModelSelectionRepository.js +154 -19
- package/dist/api/ai-gateway/providers/DeepSeekRuntimeAdapter.js +10 -6
- package/dist/api/ai-gateway/providers/ModelsDevCatalog.d.ts +7 -0
- package/dist/api/ai-gateway/providers/ModelsDevCatalog.js +25 -1
- package/dist/api/ai-gateway/providers/OfferingAuthorization.d.ts +24 -0
- package/dist/api/ai-gateway/providers/OfferingAuthorization.js +37 -0
- package/dist/api/ai-gateway/providers/OpenAiRuntimeAdapter.d.ts +1 -1
- package/dist/api/ai-gateway/providers/OpenAiRuntimeAdapter.js +5 -3
- package/dist/api/ai-gateway/providers/ProviderRegistry.d.ts +6 -3
- package/dist/api/ai-gateway/providers/ProviderRegistry.js +55 -16
- package/dist/api/ai-gateway/providers/ProviderRuntimeAdapter.d.ts +2 -0
- package/dist/api/ai-gateway/providers/ProviderRuntimeAdapter.js +37 -4
- package/dist/api/ai-gateway/providers/ProviderRuntimeRegistry.js +7 -0
- package/dist/api/ai-gateway/quota/SubscriptionQuotaAdapters.js +2 -1
- package/dist/api/ai-gateway/routing/ModelRouter.js +3 -1
- package/dist/api/container/common.js +30 -40
- package/dist/api/container/index.js +6 -2
- package/dist/api/container/routes.js +5 -22
- package/dist/api/handlers/AiClientConfigurationHandler.js +39 -1
- package/dist/api/handlers/AiGatewayManagementHandler.d.ts +3 -0
- package/dist/api/handlers/AiGatewayManagementHandler.js +173 -58
- package/dist/api/service/AiClientConfigurationService.d.ts +4 -15
- package/dist/api/service/AiClientConfigurationService.js +17 -64
- package/dist/cli/commands/start.js +2 -0
- package/dist/components/components.jsonld +1 -0
- package/dist/components/context.jsonld +80 -0
- package/dist/http/InternalPodDataHttpHandler.d.ts +3 -0
- package/dist/http/InternalPodDataHttpHandler.js +13 -2
- package/dist/http/InternalPodDataHttpHandler.jsonld +12 -0
- package/dist/identity/oidc/RememberedClientPromptFactory.d.ts +1 -1
- package/dist/identity/oidc/RememberedClientPromptFactory.js +5 -2
- package/dist/identity/oidc/RememberedConsentHandler.js +1 -1
- package/dist/identity/oidc/ScopedPickWebIdHandler.d.ts +1 -0
- package/dist/identity/oidc/ScopedPickWebIdHandler.js +26 -0
- package/dist/identity/oidc/ScopedPickWebIdHandler.jsonld +4 -0
- package/dist/identity/oidc/SessionBoundIdentityProviderFactory.d.ts +10 -0
- package/dist/identity/oidc/SessionBoundIdentityProviderFactory.js +21 -0
- package/dist/identity/oidc/SessionBoundIdentityProviderFactory.jsonld +172 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -2
- package/dist/runtime/component-parameter-keys.js +18 -2
- package/dist/storage/accessors/MixDataAccessor.js +6 -2
- package/dist/storage/rdf/PostgresRdfEngine.js +10 -2
- package/dist/storage/rdf/RdfContentTypes.js +4 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.d.ts +3 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.js +13 -16
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsList.js +1 -3
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.d.ts +2 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.js +2 -2
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.d.ts +4 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.js +127 -57
- package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.d.ts +6 -4
- package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.js +436 -83
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.d.ts +3 -2
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.js +212 -76
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.d.ts +6 -4
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.js +58 -41
- package/node_modules/@undefineds.co/ai-connections/dist/AiQuotaCard.d.ts +4 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiQuotaCard.js +63 -4
- package/node_modules/@undefineds.co/ai-connections/dist/ai-connections-client.d.ts +46 -6
- package/node_modules/@undefineds.co/ai-connections/dist/ai-connections-client.js +143 -14
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/base-adapter.d.ts +19 -3
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/base-adapter.js +45 -7
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/codex.d.ts +7 -1
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/codex.js +305 -40
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/index.cjs +383 -50
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/json-env-adapter.js +3 -2
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/pi.js +12 -3
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/transaction.d.ts +2 -0
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/transaction.js +39 -4
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/types.d.ts +8 -1
- package/node_modules/@undefineds.co/ai-connections/dist/client-visuals.d.ts +2 -0
- package/node_modules/@undefineds.co/ai-connections/dist/client-visuals.js +14 -0
- package/node_modules/@undefineds.co/ai-connections/dist/controller.d.ts +2 -2
- package/node_modules/@undefineds.co/ai-connections/dist/controller.js +216 -57
- package/node_modules/@undefineds.co/ai-connections/dist/index.d.ts +3 -1
- package/node_modules/@undefineds.co/ai-connections/dist/index.js +16 -2
- package/node_modules/@undefineds.co/ai-connections/dist/provider-visuals.js +6 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/execution/ldp-executor.js +27 -6
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/pod-database.js +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/select-query-builder.js +2 -2
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/sparql/builder/update-builder.js +12 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/builder.js +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/handlers/array.js +8 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/handlers/default.js +9 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/handlers/inline.js +3 -3
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/execution/ldp-executor.js +27 -6
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/pod-database.js +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/select-query-builder.js +2 -2
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/sparql/builder/update-builder.js +12 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/builder.js +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/handlers/array.js +8 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/handlers/default.js +9 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/handlers/inline.js +3 -3
- package/node_modules/@undefineds.co/extension-sdk/dist/web.d.ts +31 -0
- package/package.json +2 -2
- package/static/app/assets/{index-BikOyGPu.js → index-BCZVzMpj.js} +44 -44
- package/static/app/assets/inrupt-smoke.js +2 -2
- package/static/app/assets/main.css +1 -1
- package/static/app/assets/main.js +10 -10
- package/static/auth-callback/assets/{AiConfigContext-DrCH6ckh.js → AiConfigContext-DVkh8Kg2.js} +1 -1
- package/static/auth-callback/assets/{AiConfigPage-DVrlSSdA.js → AiConfigPage-HWVWpe-P.js} +1 -1
- package/static/auth-callback/assets/{DocumentProcessingPanel-_Md-v2R2.js → DocumentProcessingPanel-DDq-mH17.js} +1 -1
- package/static/auth-callback/assets/{IndexLifecyclePanel-BbWwe23H.js → IndexLifecyclePanel-Cx4cjrdP.js} +1 -1
- package/static/auth-callback/assets/{IndexSubjectPanel-upH9MjU-.js → IndexSubjectPanel-DzSw8M9j.js} +1 -1
- package/static/auth-callback/assets/{ModelAssignmentsPanel-CVGH4t4g.js → ModelAssignmentsPanel-BsRxGc2p.js} +1 -1
- package/static/auth-callback/assets/ModelsPage-DEe1lo6Q.js +10 -0
- package/static/auth-callback/assets/{NetworkPage-Dcbrb1fd.js → NetworkPage-DBiEh1Oz.js} +1 -1
- package/static/auth-callback/assets/{PaneListHeader-DrY-1wBq.js → PaneListHeader-lEEgjyN9.js} +1 -1
- package/static/auth-callback/assets/{SearchIndexingPanel-Dw25y53v.js → SearchIndexingPanel-CZCUUGt6.js} +1 -1
- package/static/auth-callback/assets/{StatusSubjectPanel-BHlz9rNF.js → StatusSubjectPanel-21qdueMr.js} +1 -1
- package/static/auth-callback/assets/{StatusWorkspace-BH7exQP5.js → StatusWorkspace-R8RKsqVz.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsPage-BYLKnM9f.js → SystemSettingsPage-BQ4e-4Wy.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsSubjectPanel-DT34LKku.js → SystemSettingsSubjectPanel-BopXD7SE.js} +1 -1
- package/static/auth-callback/assets/{activity-DdULRcSI.js → activity-DSfmTGfY.js} +1 -1
- package/static/auth-callback/assets/ai-connections-C03UWyPh.js +1 -0
- package/static/auth-callback/assets/{auth-callback-D7l2P25I.js → auth-callback-DleaitAS.js} +91 -91
- package/static/auth-callback/assets/auth-callback-vPSC2d2F.css +1 -0
- package/static/auth-callback/assets/{badge-j4zjFnmg.js → badge-B0aLu1sl.js} +1 -1
- package/static/auth-callback/assets/{download-DGXoks01.js → download-D_bFwdYJ.js} +1 -1
- package/static/auth-callback/assets/{external-link-CvbgXXaI.js → external-link-DRfjTaQu.js} +1 -1
- package/static/auth-callback/assets/{index-LRWvKJ2i.js → index-CG23cLYQ.js} +1 -1
- package/static/auth-callback/assets/{index-BOK3j1dz.js → index-CyV9ejwx.js} +1 -1
- package/static/auth-callback/assets/{index-browser-C1Qpe0g4.js → index-browser-D70paxIg.js} +1 -1
- package/static/auth-callback/assets/{key-round-CmgS5UdQ.js → key-round-BjV_mVYH.js} +1 -1
- package/static/auth-callback/assets/{rotate-ccw-c4CSG6Rq.js → rotate-ccw-CKoOAfse.js} +1 -1
- package/static/auth-callback/assets/{skeleton-ZPMTiRSM.js → skeleton-BZNjZaHx.js} +1 -1
- package/static/auth-callback/assets/{waypoints-xjyBflU5.js → waypoints-DoaJVzZv.js} +1 -1
- package/static/auth-callback/assets/{workspace-layout-B9nj6F5J.js → workspace-layout-CaP46_ZR.js} +1 -1
- package/static/auth-callback/auth-callback.html +2 -2
- package/static/dashboard/assets/{AiConfigContext-BWOOSYNr.js → AiConfigContext-BSrR27yD.js} +1 -1
- package/static/dashboard/assets/{AiConfigPage-CG2kQ9Wy.js → AiConfigPage-D65Z2LET.js} +1 -1
- package/static/dashboard/assets/{DocumentProcessingPanel-B4VXajfj.js → DocumentProcessingPanel-DyTe7Nei.js} +1 -1
- package/static/dashboard/assets/{IndexLifecyclePanel-CWCy0CC8.js → IndexLifecyclePanel-fK8ZGlrL.js} +1 -1
- package/static/dashboard/assets/{IndexSubjectPanel-CSgyQnG_.js → IndexSubjectPanel-CZPGor7v.js} +1 -1
- package/static/dashboard/assets/{ModelAssignmentsPanel-CdGIGidT.js → ModelAssignmentsPanel-CfYn5LMQ.js} +1 -1
- package/static/dashboard/assets/ModelsPage-djlJsghe.js +25 -0
- package/static/dashboard/assets/{NetworkPage-COia9NCH.js → NetworkPage-Coj6GnPl.js} +1 -1
- package/static/dashboard/assets/{PaneListHeader-SZWyr602.js → PaneListHeader-CUuFNSsZ.js} +1 -1
- package/static/dashboard/assets/{SearchIndexingPanel-D6PZtG6k.js → SearchIndexingPanel-CyJLioXS.js} +1 -1
- package/static/dashboard/assets/{StatusSubjectPanel-CxRD4kv0.js → StatusSubjectPanel-Cv26GSVC.js} +1 -1
- package/static/dashboard/assets/{StatusWorkspace-D3PfmY9-.js → StatusWorkspace-CDjFrsmB.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsPage-COg1MmMj.js → SystemSettingsPage-BuNOyNoa.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsSubjectPanel-BSVVB9Ol.js → SystemSettingsSubjectPanel-B2dasdez.js} +1 -1
- package/static/dashboard/assets/{activity-BJJx5cN-.js → activity-D1d2j_4Z.js} +1 -1
- package/static/dashboard/assets/ai-connections-C03UWyPh.js +1 -0
- package/static/dashboard/assets/{badge-elmrFSCj.js → badge-BeAAv6sp.js} +1 -1
- package/static/dashboard/assets/{dashboard-IvQrNmru.js → dashboard-BnGrUGv8.js} +68 -68
- package/static/dashboard/assets/dashboard-vPSC2d2F.css +1 -0
- package/static/dashboard/assets/{download-C3FH2KzG.js → download-DfFGiZRn.js} +1 -1
- package/static/dashboard/assets/{external-link-Bx7F0uKb.js → external-link-IsjU_LC9.js} +1 -1
- package/static/dashboard/assets/{index-liRoRIP1.js → index-BWQTucPe.js} +1 -1
- package/static/dashboard/assets/{index-M4-kWiGz.js → index-Dj75OjnW.js} +1 -1
- package/static/dashboard/assets/{key-round-CXg0bKAj.js → key-round-BJ_9wmQ_.js} +1 -1
- package/static/dashboard/assets/{rotate-ccw-yxJKOBrX.js → rotate-ccw-D3JGiFbR.js} +1 -1
- package/static/dashboard/assets/{skeleton-x9jNGrQT.js → skeleton-CC4nc-z-.js} +1 -1
- package/static/dashboard/assets/{waypoints-CTKeRsGp.js → waypoints-h7sqFqiG.js} +1 -1
- package/static/dashboard/assets/{workspace-layout--YkgkS38.js → workspace-layout-ZAPTOHhs.js} +1 -1
- package/static/dashboard/dashboard.html +2 -2
- package/static/settings/assets/{AiConfigContext-CelxXFcQ.js → AiConfigContext-lGkWpvKP.js} +1 -1
- package/static/settings/assets/{AiConfigPage-BaP-EovM.js → AiConfigPage-BbZWIBZq.js} +1 -1
- package/static/settings/assets/{DocumentProcessingPanel-DzLZluFv.js → DocumentProcessingPanel-DvYdjT-V.js} +1 -1
- package/static/settings/assets/{IndexLifecyclePanel-Bzj1-_oI.js → IndexLifecyclePanel-W5OGQZj7.js} +1 -1
- package/static/settings/assets/{IndexSubjectPanel-B263QLUh.js → IndexSubjectPanel-g_Aa5soq.js} +1 -1
- package/static/settings/assets/{ModelAssignmentsPanel-BAdT4UR0.js → ModelAssignmentsPanel-COlMBKXj.js} +1 -1
- package/static/settings/assets/ModelsPage-mApKi-aw.js +10 -0
- package/static/settings/assets/{NetworkPage-BK6a7l4g.js → NetworkPage-BDT05JUq.js} +1 -1
- package/static/settings/assets/{PaneListHeader-BAS2ICPq.js → PaneListHeader-CByhNpMG.js} +1 -1
- package/static/settings/assets/{SearchIndexingPanel-Cb_p-NgW.js → SearchIndexingPanel-BFAyzXls.js} +1 -1
- package/static/settings/assets/{StatusSubjectPanel-CcjqUua6.js → StatusSubjectPanel-Bz_XZ3VU.js} +1 -1
- package/static/settings/assets/{StatusWorkspace-7Ibty3_k.js → StatusWorkspace-CeVypHcW.js} +1 -1
- package/static/settings/assets/{SystemSettingsPage-DPSz4dg4.js → SystemSettingsPage-Dh7cQIfx.js} +1 -1
- package/static/settings/assets/{SystemSettingsSubjectPanel-Cb4HkKT5.js → SystemSettingsSubjectPanel-CSnpciO0.js} +1 -1
- package/static/settings/assets/{activity-Qhsr5Pxu.js → activity-DXz3EfFN.js} +1 -1
- package/static/settings/assets/ai-connections-C03UWyPh.js +1 -0
- package/static/settings/assets/{badge-B1vf2qCl.js → badge-1ZA144i4.js} +1 -1
- package/static/settings/assets/{download-CYNt0aZ-.js → download-CUHimlYa.js} +1 -1
- package/static/settings/assets/{external-link-ClKb39NT.js → external-link-BYHSVj2Z.js} +1 -1
- package/static/settings/assets/{index-y8ew3MLM.js → index-DKPDMdW5.js} +1 -1
- package/static/settings/assets/{index-browser-DJhvgpNI.js → index-browser-BaEFz0e0.js} +1 -1
- package/static/settings/assets/{index-BgiIDSch.js → index-viSgSvbO.js} +1 -1
- package/static/settings/assets/{key-round-5d-DrJz-.js → key-round-COByPOg8.js} +1 -1
- package/static/settings/assets/{rotate-ccw-CHZY7kS5.js → rotate-ccw-BC2EN6cE.js} +1 -1
- package/static/settings/assets/{settings-D5VRWyx6.js → settings-DLH9XUoT.js} +86 -86
- package/static/settings/assets/settings-vPSC2d2F.css +1 -0
- package/static/settings/assets/{skeleton-FNabNxNE.js → skeleton-B0-FOhKL.js} +1 -1
- package/static/settings/assets/{waypoints-BnL_8ljo.js → waypoints-DGMsvqWo.js} +1 -1
- package/static/settings/assets/{workspace-layout-D5q3F59S.js → workspace-layout-B0SVrJIu.js} +1 -1
- package/static/settings/settings.html +2 -2
- package/static/auth-callback/assets/ModelsPage-BpkVFKbf.js +0 -10
- package/static/auth-callback/assets/ai-connections-Bm52UO7Y.js +0 -1
- package/static/auth-callback/assets/auth-callback-01yz-UDU.css +0 -1
- package/static/dashboard/assets/ModelsPage-Chd5UK0D.js +0 -25
- package/static/dashboard/assets/ai-connections-Bm52UO7Y.js +0 -1
- package/static/dashboard/assets/dashboard-01yz-UDU.css +0 -1
- package/static/settings/assets/ModelsPage-C0NFa1zq.js +0 -10
- package/static/settings/assets/ai-connections-Bm52UO7Y.js +0 -1
- package/static/settings/assets/settings-01yz-UDU.css +0 -1
|
@@ -71,7 +71,7 @@ export function createAiConnectionsClient({ webId, podBaseUrl, authenticatedFetc
|
|
|
71
71
|
});
|
|
72
72
|
const payload = await readJson(response);
|
|
73
73
|
if (!response.ok) {
|
|
74
|
-
throw new
|
|
74
|
+
throw new AiConnectionsRequestError(normalizeAiConnectionsErrorMessage(payload, response.status, context), payload);
|
|
75
75
|
}
|
|
76
76
|
return payload;
|
|
77
77
|
};
|
|
@@ -83,6 +83,12 @@ export function createAiConnectionsClient({ webId, podBaseUrl, authenticatedFetc
|
|
|
83
83
|
const payload = await request(`${providerPath(provider)}${path}`, method, body, { provider });
|
|
84
84
|
return parseConnectAttempt(payload, provider);
|
|
85
85
|
};
|
|
86
|
+
const listGatewayModels = async () => {
|
|
87
|
+
const payload = await request('/v1/models', 'GET');
|
|
88
|
+
return Array.isArray(payload.data)
|
|
89
|
+
? payload.data.map(parseGatewayModel).filter(isDefined)
|
|
90
|
+
: [];
|
|
91
|
+
};
|
|
86
92
|
return {
|
|
87
93
|
webId,
|
|
88
94
|
apiBase,
|
|
@@ -93,12 +99,25 @@ export function createAiConnectionsClient({ webId, podBaseUrl, authenticatedFetc
|
|
|
93
99
|
const payload = await request('/api/ai/providers', 'GET');
|
|
94
100
|
return Array.isArray(payload.data) ? parseProviderSummaries(payload.data) : [];
|
|
95
101
|
},
|
|
96
|
-
async
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
102
|
+
async listAuthorizationMethods() {
|
|
103
|
+
const response = await authenticatedFetch(`${apiBase}/api/ai/connections/authorization-methods`, {
|
|
104
|
+
method: 'GET',
|
|
105
|
+
credentials: 'omit',
|
|
106
|
+
mode: 'cors',
|
|
107
|
+
headers: { accept: 'application/json' },
|
|
108
|
+
});
|
|
109
|
+
if (response.status === 404)
|
|
110
|
+
return [];
|
|
111
|
+
const payload = await readJson(response);
|
|
112
|
+
if (!response.ok) {
|
|
113
|
+
throw new Error(normalizeAiConnectionsErrorMessage(payload, response.status));
|
|
114
|
+
}
|
|
115
|
+
return isRecord(payload) && Array.isArray(payload.data)
|
|
116
|
+
? payload.data.map(parseAuthorizationMethodsSummary).filter(isDefined)
|
|
100
117
|
: [];
|
|
101
118
|
},
|
|
119
|
+
listModels: listGatewayModels,
|
|
120
|
+
listGatewayModels,
|
|
102
121
|
async listGatewayKeys() {
|
|
103
122
|
const payload = await request('/api/ai/gateway/keys', 'GET');
|
|
104
123
|
return Array.isArray(payload.data)
|
|
@@ -132,8 +151,12 @@ export function createAiConnectionsClient({ webId, podBaseUrl, authenticatedFetc
|
|
|
132
151
|
async deleteGatewayKey(keyId) {
|
|
133
152
|
await request(`/api/ai/gateway/keys/${encodeURIComponent(keyId)}`, 'DELETE');
|
|
134
153
|
},
|
|
135
|
-
async beginConnect(provider, mode) {
|
|
136
|
-
return await requestConnect(provider, '/connect/begin', 'POST', {
|
|
154
|
+
async beginConnect(provider, mode, options) {
|
|
155
|
+
return await requestConnect(provider, '/connect/begin', 'POST', compactObject({
|
|
156
|
+
mode,
|
|
157
|
+
offeringId: options?.offeringId,
|
|
158
|
+
authorizationMethodId: options?.authorizationMethodId,
|
|
159
|
+
}));
|
|
137
160
|
},
|
|
138
161
|
connectStatus(provider, attempt) {
|
|
139
162
|
if (!attempt.attemptId) {
|
|
@@ -143,6 +166,8 @@ export function createAiConnectionsClient({ webId, podBaseUrl, authenticatedFetc
|
|
|
143
166
|
state: attempt.state ?? '',
|
|
144
167
|
signature: attempt.signature ?? '',
|
|
145
168
|
});
|
|
169
|
+
if (attempt.mode)
|
|
170
|
+
query.set('mode', attempt.mode);
|
|
146
171
|
return requestConnect(provider, `/connect/status/${encodeURIComponent(attempt.attemptId)}?${query}`, 'GET');
|
|
147
172
|
},
|
|
148
173
|
completeApiKey(provider, attempt, apiKey, accountLabel, baseUrl) {
|
|
@@ -150,6 +175,7 @@ export function createAiConnectionsClient({ webId, podBaseUrl, authenticatedFetc
|
|
|
150
175
|
attemptId: attempt.attemptId,
|
|
151
176
|
state: attempt.state,
|
|
152
177
|
signature: attempt.signature,
|
|
178
|
+
offeringId: attempt.offeringId,
|
|
153
179
|
apiKey,
|
|
154
180
|
accountLabel,
|
|
155
181
|
baseUrl,
|
|
@@ -157,16 +183,29 @@ export function createAiConnectionsClient({ webId, podBaseUrl, authenticatedFetc
|
|
|
157
183
|
},
|
|
158
184
|
pollDevice(provider, attempt) {
|
|
159
185
|
return requestConnect(provider, '/connect/poll', 'POST', compactObject({
|
|
186
|
+
mode: attempt.mode,
|
|
160
187
|
attemptId: attempt.attemptId,
|
|
161
188
|
state: attempt.state,
|
|
162
189
|
signature: attempt.signature,
|
|
190
|
+
offeringId: attempt.offeringId,
|
|
163
191
|
}));
|
|
164
192
|
},
|
|
165
|
-
|
|
193
|
+
cancelConnect(provider, attempt) {
|
|
194
|
+
return requestConnect(provider, '/connect/cancel', 'POST', compactObject({
|
|
195
|
+
mode: attempt.mode,
|
|
196
|
+
attemptId: attempt.attemptId,
|
|
197
|
+
state: attempt.state,
|
|
198
|
+
signature: attempt.signature,
|
|
199
|
+
offeringId: attempt.offeringId,
|
|
200
|
+
}));
|
|
201
|
+
},
|
|
202
|
+
refreshOAuthCredential(provider, credentialId, refreshToken, expectedVersion, offeringId, mode) {
|
|
166
203
|
return requestConnect(provider, '/connect/refresh', 'POST', {
|
|
167
204
|
credentialId,
|
|
168
205
|
refreshToken,
|
|
169
206
|
expectedVersion,
|
|
207
|
+
...(offeringId ? { offeringId } : {}),
|
|
208
|
+
...(mode ? { mode } : {}),
|
|
170
209
|
});
|
|
171
210
|
},
|
|
172
211
|
async disconnect(provider, credentialId) {
|
|
@@ -217,7 +256,7 @@ export function createAiConnectionsClient({ webId, podBaseUrl, authenticatedFetc
|
|
|
217
256
|
return request(`${providerPath(provider)}/quota/refresh`, 'POST', compactObject(input), { provider });
|
|
218
257
|
},
|
|
219
258
|
async discoverModels(provider, input) {
|
|
220
|
-
const payload = await request(`${providerPath(provider)}/models/refresh`, 'POST', compactObject({ ...input }), { provider });
|
|
259
|
+
const payload = await request(`${providerPath(provider)}/models/refresh`, 'POST', compactObject({ ...input }), { provider, authMode: input?.authMode });
|
|
221
260
|
return parseModelDiscovery(payload, provider);
|
|
222
261
|
},
|
|
223
262
|
async saveProviderModel(provider, model) {
|
|
@@ -236,6 +275,15 @@ export function createAiConnectionsClient({ webId, podBaseUrl, authenticatedFetc
|
|
|
236
275
|
},
|
|
237
276
|
};
|
|
238
277
|
}
|
|
278
|
+
export class AiConnectionsRequestError extends Error {
|
|
279
|
+
constructor(message, payload) {
|
|
280
|
+
super(message);
|
|
281
|
+
this.name = 'AiConnectionsRequestError';
|
|
282
|
+
this.code = errorCodeFromPayload(payload);
|
|
283
|
+
this.providerStatus = isRecord(payload) && typeof payload.providerStatus === 'number'
|
|
284
|
+
? payload.providerStatus : undefined;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
239
287
|
export function normalizeAiConnectionsThrownError(error) {
|
|
240
288
|
if (error instanceof Error) {
|
|
241
289
|
return normalizeAiConnectionsErrorText(error.message);
|
|
@@ -259,7 +307,7 @@ export function normalizeAiConnectionsErrorMessage(payload, status, context = {}
|
|
|
259
307
|
const providerMessage = isRecord(payload) && typeof payload.providerMessage === 'string'
|
|
260
308
|
? payload.providerMessage.trim()
|
|
261
309
|
: undefined;
|
|
262
|
-
return withProviderMessage(modelDiscoveryErrorMessage(providerStatus), providerMessage);
|
|
310
|
+
return withProviderMessage(modelDiscoveryErrorMessage(providerStatus, context.authMode), providerMessage);
|
|
263
311
|
}
|
|
264
312
|
const coded = code ? messageForSafeErrorCode(code, context.provider) : undefined;
|
|
265
313
|
if (coded)
|
|
@@ -294,7 +342,13 @@ export function normalizeAiConnectionsErrorMessage(payload, status, context = {}
|
|
|
294
342
|
return 'AI Connection service is unavailable.';
|
|
295
343
|
return AI_CONNECTIONS_GENERIC_ERROR_MESSAGE;
|
|
296
344
|
}
|
|
345
|
+
const LOCAL_SESSION_REFRESH_FAILED_MESSAGE = '订阅登录态自动刷新失败,请稍后重试。';
|
|
346
|
+
const LOCAL_SESSION_REAUTH_REQUIRED_MESSAGE = '订阅登录态已失效,请在原客户端重新登录后重读,或使用设备码登录。';
|
|
347
|
+
const OAUTH_MODEL_AUTH_FAILED_MESSAGE = '订阅登录态不可用,请重读登录态或重新登录后再同步模型。';
|
|
297
348
|
const MODEL_DISCOVERY_SAFE_MESSAGES = new Set([
|
|
349
|
+
OAUTH_MODEL_AUTH_FAILED_MESSAGE,
|
|
350
|
+
LOCAL_SESSION_REFRESH_FAILED_MESSAGE,
|
|
351
|
+
LOCAL_SESSION_REAUTH_REQUIRED_MESSAGE,
|
|
298
352
|
'密钥不可用。请检查密钥是否填写正确,或换一个密钥后重试。',
|
|
299
353
|
'模型服务地址不正确。请检查服务地址后重试。',
|
|
300
354
|
'请求太频繁。请稍等一会儿再试。',
|
|
@@ -361,6 +415,17 @@ function messageForSafeErrorCode(code, provider) {
|
|
|
361
415
|
return '该服务地址指向 Xpod 不允许访问的网络,请改用公网 HTTPS 地址。';
|
|
362
416
|
case 'invalid_proxy_url':
|
|
363
417
|
return '代理地址必须是无账号密码的 HTTP 或 HTTPS 地址。';
|
|
418
|
+
case 'oauth_refresh_failed':
|
|
419
|
+
case 'oauth_refresh_unavailable':
|
|
420
|
+
case 'local_session_refresh_failed':
|
|
421
|
+
return LOCAL_SESSION_REFRESH_FAILED_MESSAGE;
|
|
422
|
+
case 'oauth_session_reauth_required':
|
|
423
|
+
case 'oauth_refresh_token_required':
|
|
424
|
+
case 'local_session_reauth_required':
|
|
425
|
+
case 'local_session_missing_refresh_token':
|
|
426
|
+
return LOCAL_SESSION_REAUTH_REQUIRED_MESSAGE;
|
|
427
|
+
case 'models_persistence_failed':
|
|
428
|
+
return '模型已获取,但保存到 Pod 失败。请重试同步模型。';
|
|
364
429
|
case 'quota_credential_not_found':
|
|
365
430
|
return '当前身份没有可用的额度凭证。';
|
|
366
431
|
case 'credential_secret_unavailable':
|
|
@@ -373,8 +438,10 @@ function messageForSafeErrorCode(code, provider) {
|
|
|
373
438
|
return undefined;
|
|
374
439
|
}
|
|
375
440
|
}
|
|
376
|
-
function modelDiscoveryErrorMessage(providerStatus) {
|
|
441
|
+
function modelDiscoveryErrorMessage(providerStatus, authMode) {
|
|
377
442
|
if (providerStatus === 401 || providerStatus === 403) {
|
|
443
|
+
if (authMode === 'deviceCodeOAuth')
|
|
444
|
+
return OAUTH_MODEL_AUTH_FAILED_MESSAGE;
|
|
378
445
|
return '密钥不可用。请检查密钥是否填写正确,或换一个密钥后重试。';
|
|
379
446
|
}
|
|
380
447
|
if (providerStatus === 404) {
|
|
@@ -450,6 +517,9 @@ function parseGatewayKeyRecord(value) {
|
|
|
450
517
|
}
|
|
451
518
|
return compactObject({
|
|
452
519
|
id: value.id,
|
|
520
|
+
kind: value.kind === 'client-credentials' ? value.kind : undefined,
|
|
521
|
+
credentialResource: stringValue(value.credentialResource),
|
|
522
|
+
fingerprint: stringValue(value.fingerprint),
|
|
453
523
|
owner: value.owner,
|
|
454
524
|
scopes: value.scopes,
|
|
455
525
|
createdAt: value.createdAt,
|
|
@@ -498,6 +568,7 @@ function parseGatewayModel(value) {
|
|
|
498
568
|
?? providerFromModelId(value.id);
|
|
499
569
|
if (!provider)
|
|
500
570
|
return undefined;
|
|
571
|
+
const imageInput = isRecord(value.capabilities) ? value.capabilities.imageInput : undefined;
|
|
501
572
|
return compactObject({
|
|
502
573
|
id: value.id,
|
|
503
574
|
provider,
|
|
@@ -509,7 +580,8 @@ function parseGatewayModel(value) {
|
|
|
509
580
|
? value.protocols.filter((protocol) => typeof protocol === 'string')
|
|
510
581
|
: undefined,
|
|
511
582
|
custom: value.custom === true ? true : undefined,
|
|
512
|
-
inputModalities: modalitiesFromWire(value.modalities, 'input')
|
|
583
|
+
inputModalities: modalitiesFromWire(value.modalities, 'input')
|
|
584
|
+
?? (imageInput === true ? ['text', 'image'] : imageInput === false ? ['text'] : undefined),
|
|
513
585
|
outputModalities: modalitiesFromWire(value.modalities, 'output'),
|
|
514
586
|
capabilities: modelCapabilitiesFromWire(value),
|
|
515
587
|
});
|
|
@@ -633,6 +705,7 @@ function parseProviderOffering(value) {
|
|
|
633
705
|
kind: stringValue(value.kind),
|
|
634
706
|
lifecycle: offeringLifecycleValue(value.lifecycle),
|
|
635
707
|
authModes,
|
|
708
|
+
authorizationMethods: arrayValue(value.authorizationMethods, parseAuthorizationMethod),
|
|
636
709
|
runtimeProviderIds: stringListValue(value.runtimeProviderIds),
|
|
637
710
|
productLabel: stringValue(value.productLabel),
|
|
638
711
|
credentialPrefixHints: stringListValue(value.credentialPrefixHints),
|
|
@@ -645,6 +718,53 @@ function parseProviderOffering(value) {
|
|
|
645
718
|
region: stringValue(value.region),
|
|
646
719
|
});
|
|
647
720
|
}
|
|
721
|
+
function parseAuthorizationMethodsSummary(value) {
|
|
722
|
+
if (!isRecord(value) || typeof value.offeringId !== 'string' || !value.offeringId)
|
|
723
|
+
return undefined;
|
|
724
|
+
const provider = providerValue(value.provider);
|
|
725
|
+
if (!provider)
|
|
726
|
+
return undefined;
|
|
727
|
+
const authorizationMethods = arrayValue(value.authorizationMethods, parseAuthorizationMethod);
|
|
728
|
+
return {
|
|
729
|
+
provider,
|
|
730
|
+
offeringId: value.offeringId,
|
|
731
|
+
...(Array.isArray(value.endpoints) ? { endpoints: arrayValue(value.endpoints, parseOfferingEndpoint) } : {}),
|
|
732
|
+
authorizationMethods,
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
function parseAuthorizationMethod(value) {
|
|
736
|
+
if (!isRecord(value) || typeof value.id !== 'string' || !value.id)
|
|
737
|
+
return undefined;
|
|
738
|
+
const authMode = offeringAuthModeValue(value.authMode);
|
|
739
|
+
const lifecycle = authorizationMethodLifecycleValue(value.lifecycle);
|
|
740
|
+
if (!authMode || !lifecycle)
|
|
741
|
+
return undefined;
|
|
742
|
+
const connectMode = isConnectMode(value.connectMode) ? value.connectMode : undefined;
|
|
743
|
+
return compactObject({
|
|
744
|
+
id: value.id,
|
|
745
|
+
authMode,
|
|
746
|
+
connectMode,
|
|
747
|
+
label: stringValue(value.label) ?? authorizationMethodFallbackLabel(value.id, authMode),
|
|
748
|
+
lifecycle,
|
|
749
|
+
reason: stringValue(value.reason),
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
function authorizationMethodLifecycleValue(value) {
|
|
753
|
+
return value === 'active' || value === 'unavailable' ? value : undefined;
|
|
754
|
+
}
|
|
755
|
+
function authorizationMethodFallbackLabel(id, authMode) {
|
|
756
|
+
if (id === 'device-code')
|
|
757
|
+
return '浏览器登录';
|
|
758
|
+
if (id === 'local-session-import')
|
|
759
|
+
return '已有登录态';
|
|
760
|
+
if (id === 'local-service')
|
|
761
|
+
return '本地服务';
|
|
762
|
+
if (id === 'api-key' || authMode === 'apiKey')
|
|
763
|
+
return 'API Key';
|
|
764
|
+
if (authMode === 'local')
|
|
765
|
+
return '本地服务';
|
|
766
|
+
return '浏览器登录';
|
|
767
|
+
}
|
|
648
768
|
function offeringLifecycleValue(value) {
|
|
649
769
|
return value === 'active' || value === 'legacy' || value === 'unavailable'
|
|
650
770
|
? value
|
|
@@ -769,7 +889,7 @@ function legacyCredentialFromSummary(value, provider) {
|
|
|
769
889
|
const authMode = legacyCredentialAuthMode(value.authMode);
|
|
770
890
|
return compactObject({
|
|
771
891
|
id: stringValue(value.credentialIri) ?? `${provider}:current`,
|
|
772
|
-
offeringId: legacyOfferingId(authMode),
|
|
892
|
+
offeringId: legacyOfferingId(provider, authMode),
|
|
773
893
|
authMode,
|
|
774
894
|
label: stringValue(value.accountLabel),
|
|
775
895
|
enabled: value.status === 'connected',
|
|
@@ -789,7 +909,9 @@ function legacyCredentialAuthMode(value) {
|
|
|
789
909
|
return 'deviceCode';
|
|
790
910
|
return 'apiKey';
|
|
791
911
|
}
|
|
792
|
-
function legacyOfferingId(authMode) {
|
|
912
|
+
function legacyOfferingId(provider, authMode) {
|
|
913
|
+
if (provider === 'kimi' && (authMode === 'deviceCode' || authMode === 'oauth'))
|
|
914
|
+
return 'subscription-key';
|
|
793
915
|
return authMode === 'deviceCode' || authMode === 'oauth'
|
|
794
916
|
? 'official-subscription'
|
|
795
917
|
: 'api-platform';
|
|
@@ -895,6 +1017,8 @@ function parseConnectAttempt(value, expectedProvider) {
|
|
|
895
1017
|
? value.apiKeyManagementSupported
|
|
896
1018
|
: undefined,
|
|
897
1019
|
credentialId: stringValue(value.credentialId),
|
|
1020
|
+
offeringId: stringValue(value.offeringId),
|
|
1021
|
+
authorizationMethodId: stringValue(value.authorizationMethodId),
|
|
898
1022
|
oauthCredential: parseOAuthCredential(value.oauthCredential),
|
|
899
1023
|
message: stringValue(value.message),
|
|
900
1024
|
});
|
|
@@ -916,6 +1040,10 @@ function parseOAuthCredential(value) {
|
|
|
916
1040
|
scope: stringValue(value.scope),
|
|
917
1041
|
idToken: stringValue(value.idToken),
|
|
918
1042
|
accountSubject: stringValue(value.accountSubject),
|
|
1043
|
+
accountId: stringValue(value.accountId),
|
|
1044
|
+
accountLabel: stringValue(value.accountLabel),
|
|
1045
|
+
offeringId: stringValue(value.offeringId),
|
|
1046
|
+
authorizationMethodId: stringValue(value.authorizationMethodId),
|
|
919
1047
|
expectedVersion: typeof value.expectedVersion === 'number' ? value.expectedVersion : undefined,
|
|
920
1048
|
});
|
|
921
1049
|
}
|
|
@@ -964,6 +1092,7 @@ function safeHttpUrl(value) {
|
|
|
964
1092
|
function isConnectMode(value) {
|
|
965
1093
|
return value === 'browserAssistedApiKey'
|
|
966
1094
|
|| value === 'deviceCodeOAuth'
|
|
1095
|
+
|| value === 'authorizationCodeOAuth'
|
|
967
1096
|
|| value === 'connectUnsupported';
|
|
968
1097
|
}
|
|
969
1098
|
function isConnectStatus(value) {
|
|
@@ -5,7 +5,21 @@ export declare class AiClientConfigError extends Error {
|
|
|
5
5
|
readonly code: 'model_catalog_empty' | 'model_catalog_invalid' | 'model_not_available';
|
|
6
6
|
constructor(code: 'model_catalog_empty' | 'model_catalog_invalid' | 'model_not_available', message?: string);
|
|
7
7
|
}
|
|
8
|
+
interface OwnershipState {
|
|
9
|
+
version: 1;
|
|
10
|
+
client: string;
|
|
11
|
+
webIdHash: string;
|
|
12
|
+
apiKeyFingerprint?: string;
|
|
13
|
+
projectionHashes?: Record<string, string>;
|
|
14
|
+
files: Array<{
|
|
15
|
+
path: string;
|
|
16
|
+
existed: boolean;
|
|
17
|
+
backupPath?: string;
|
|
18
|
+
}>;
|
|
19
|
+
}
|
|
8
20
|
export declare function hashWebId(webId: string): string;
|
|
21
|
+
declare function contentHash(value: string): string;
|
|
22
|
+
export declare const contentFingerprint: typeof contentHash;
|
|
9
23
|
export declare function normalizeV1Endpoint(endpoint: string): string;
|
|
10
24
|
export declare function normalizeMessagesEndpoint(endpoint: string): string;
|
|
11
25
|
export declare function parseJsonObject(content: string | undefined, label: string): Record<string, unknown>;
|
|
@@ -26,7 +40,7 @@ export declare function activeModelReferences(profile: AiConnectionsClientProfil
|
|
|
26
40
|
id: string;
|
|
27
41
|
name: string;
|
|
28
42
|
}>;
|
|
29
|
-
/**
|
|
43
|
+
/** Use supplied model metadata when available; file projection does not require discovery. */
|
|
30
44
|
export declare function normalizeClientProfile(profile: AiConnectionsClientProfile): AiConnectionsClientProfile;
|
|
31
45
|
export declare function stripLegacyXpodObject(value: Record<string, unknown>): void;
|
|
32
46
|
export declare abstract class BaseAiClientConfigAdapter implements AiClientConfigAdapter {
|
|
@@ -46,10 +60,12 @@ export declare abstract class BaseAiClientConfigAdapter implements AiClientConfi
|
|
|
46
60
|
protected abstract verifyProjection(profile: AiConnectionsClientProfile): Promise<ClientVerification>;
|
|
47
61
|
protected abstract restoreFile(filePath: string, current: string | undefined, original: string | undefined, originallyExisted: boolean): Promise<string | null>;
|
|
48
62
|
protected normalizeProfile(profile: AiConnectionsClientProfile): AiConnectionsClientProfile;
|
|
63
|
+
protected currentApiKeyFingerprint(_current: Map<string, string | undefined>): Promise<string | undefined>;
|
|
49
64
|
protected readOptional(filePath: string): Promise<string | undefined>;
|
|
50
65
|
private validateProfile;
|
|
51
|
-
|
|
52
|
-
|
|
66
|
+
protected readState(): Promise<OwnershipState | undefined>;
|
|
67
|
+
protected rejectSymlink(filePath: string): Promise<void>;
|
|
53
68
|
private exists;
|
|
54
69
|
private isExecutableOnPath;
|
|
55
70
|
}
|
|
71
|
+
export {};
|
|
@@ -13,6 +13,10 @@ export class AiClientConfigError extends Error {
|
|
|
13
13
|
export function hashWebId(webId) {
|
|
14
14
|
return crypto.createHash('sha256').update(webId.trim(), 'utf8').digest('hex');
|
|
15
15
|
}
|
|
16
|
+
function contentHash(value) {
|
|
17
|
+
return crypto.createHash('sha256').update(value, 'utf8').digest('hex');
|
|
18
|
+
}
|
|
19
|
+
export const contentFingerprint = contentHash;
|
|
16
20
|
export function normalizeV1Endpoint(endpoint) {
|
|
17
21
|
const normalized = endpoint.trim().replace(/\/+$/, '');
|
|
18
22
|
return normalized.endsWith('/v1') ? normalized : `${normalized}/v1`;
|
|
@@ -114,11 +118,11 @@ function normalizeActiveModels(models) {
|
|
|
114
118
|
}
|
|
115
119
|
return normalized;
|
|
116
120
|
}
|
|
117
|
-
/**
|
|
121
|
+
/** Use supplied model metadata when available; file projection does not require discovery. */
|
|
118
122
|
export function normalizeClientProfile(profile) {
|
|
119
123
|
return {
|
|
120
124
|
...profile,
|
|
121
|
-
model: resolveActiveModel(profile),
|
|
125
|
+
model: profile.activeModels?.length ? resolveActiveModel(profile) : profile.model?.trim() || undefined,
|
|
122
126
|
};
|
|
123
127
|
}
|
|
124
128
|
export function stripLegacyXpodObject(value) {
|
|
@@ -144,9 +148,23 @@ export class BaseAiClientConfigAdapter {
|
|
|
144
148
|
}
|
|
145
149
|
async inspect() {
|
|
146
150
|
const state = await this.readState();
|
|
151
|
+
let projectionMatches;
|
|
152
|
+
if (state?.projectionHashes) {
|
|
153
|
+
projectionMatches = true;
|
|
154
|
+
for (const filePath of this.configPaths) {
|
|
155
|
+
await this.rejectSymlink(filePath);
|
|
156
|
+
const content = await this.readOptional(filePath);
|
|
157
|
+
if (content === undefined || contentHash(content) !== state.projectionHashes[filePath]) {
|
|
158
|
+
projectionMatches = false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
147
162
|
return {
|
|
148
163
|
ownership: state ? 'owned' : 'unowned',
|
|
149
164
|
...(state ? { webIdHash: state.webIdHash } : {}),
|
|
165
|
+
...(projectionMatches === undefined ? {} : { projectionMatches }),
|
|
166
|
+
...(projectionMatches && /^[a-f0-9]{64}$/u.test(state?.apiKeyFingerprint ?? '')
|
|
167
|
+
? { apiKeyFingerprint: state.apiKeyFingerprint } : {}),
|
|
150
168
|
configPaths: [...this.configPaths],
|
|
151
169
|
};
|
|
152
170
|
}
|
|
@@ -163,8 +181,14 @@ export class BaseAiClientConfigAdapter {
|
|
|
163
181
|
contents.set(filePath, await this.readOptional(filePath));
|
|
164
182
|
}
|
|
165
183
|
const projected = await this.project(normalizedProfile, contents);
|
|
184
|
+
for (const filePath of projected.keys()) {
|
|
185
|
+
if (!contents.has(filePath)) {
|
|
186
|
+
await this.rejectSymlink(filePath);
|
|
187
|
+
contents.set(filePath, await this.readOptional(filePath));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
166
190
|
const timestamp = Date.now();
|
|
167
|
-
const files =
|
|
191
|
+
const files = [...projected.keys()].map((filePath) => {
|
|
168
192
|
const prior = currentState?.files.find((file) => file.path === filePath);
|
|
169
193
|
const existed = contents.get(filePath) !== undefined;
|
|
170
194
|
return prior ?? {
|
|
@@ -177,12 +201,14 @@ export class BaseAiClientConfigAdapter {
|
|
|
177
201
|
path: filePath,
|
|
178
202
|
content,
|
|
179
203
|
backupPath: files.find((file) => file.path === filePath)?.backupPath,
|
|
180
|
-
createBackup: !currentState && contents.get(filePath) !== undefined,
|
|
204
|
+
createBackup: !currentState?.files.some((file) => file.path === filePath) && contents.get(filePath) !== undefined,
|
|
181
205
|
}));
|
|
182
206
|
const state = {
|
|
183
207
|
version: 1,
|
|
184
208
|
client: this.client,
|
|
185
209
|
webIdHash: ownerHash,
|
|
210
|
+
apiKeyFingerprint: contentHash(profileApiKey(normalizedProfile)),
|
|
211
|
+
projectionHashes: Object.fromEntries([...projected].map(([filePath, content]) => [filePath, contentHash(content)])),
|
|
186
212
|
files,
|
|
187
213
|
};
|
|
188
214
|
writes.push({ path: this.statePath, content: stringifyJson(state) });
|
|
@@ -209,10 +235,19 @@ export class BaseAiClientConfigAdapter {
|
|
|
209
235
|
if (state.webIdHash !== hashWebId(webId)) {
|
|
210
236
|
throw new Error(`${this.client} AI Connection projection is owned by another WebID`);
|
|
211
237
|
}
|
|
212
|
-
const
|
|
238
|
+
const current = new Map();
|
|
213
239
|
for (const file of state.files) {
|
|
214
240
|
await this.rejectSymlink(file.path);
|
|
215
|
-
|
|
241
|
+
current.set(file.path, await this.readOptional(file.path));
|
|
242
|
+
}
|
|
243
|
+
const currentFingerprint = await this.currentApiKeyFingerprint(current);
|
|
244
|
+
if (state.apiKeyFingerprint &&
|
|
245
|
+
currentFingerprint &&
|
|
246
|
+
currentFingerprint !== state.apiKeyFingerprint) {
|
|
247
|
+
throw new Error(`${this.client} API key changed since projection was applied; refusing restore to avoid data loss`);
|
|
248
|
+
}
|
|
249
|
+
const writes = [];
|
|
250
|
+
for (const file of state.files) {
|
|
216
251
|
let original;
|
|
217
252
|
if (file.existed) {
|
|
218
253
|
if (!file.backupPath) {
|
|
@@ -226,7 +261,7 @@ export class BaseAiClientConfigAdapter {
|
|
|
226
261
|
}
|
|
227
262
|
writes.push({
|
|
228
263
|
path: file.path,
|
|
229
|
-
content: await this.restoreFile(file.path, current, original, file.existed),
|
|
264
|
+
content: await this.restoreFile(file.path, current.get(file.path), original, file.existed),
|
|
230
265
|
});
|
|
231
266
|
}
|
|
232
267
|
writes.push({ path: this.statePath, content: null });
|
|
@@ -235,6 +270,9 @@ export class BaseAiClientConfigAdapter {
|
|
|
235
270
|
normalizeProfile(profile) {
|
|
236
271
|
return normalizeClientProfile(profile);
|
|
237
272
|
}
|
|
273
|
+
async currentApiKeyFingerprint(_current) {
|
|
274
|
+
return undefined;
|
|
275
|
+
}
|
|
238
276
|
async readOptional(filePath) {
|
|
239
277
|
try {
|
|
240
278
|
return await fs.promises.readFile(filePath, 'utf8');
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { BaseAiClientConfigAdapter } from './base-adapter';
|
|
2
|
-
import type { AiConnectionsClientProfile, ClientVerification } from './types';
|
|
2
|
+
import type { AiClientConfigPlan, AiConnectionsClientProfile, ClientInspection, ClientVerification } from './types';
|
|
3
3
|
export interface CodexConfigAdapterOptions {
|
|
4
4
|
homeDir?: string;
|
|
5
5
|
}
|
|
6
6
|
export declare class CodexConfigAdapter extends BaseAiClientConfigAdapter {
|
|
7
7
|
private readonly configPath;
|
|
8
8
|
private readonly authPath;
|
|
9
|
+
private readonly catalogPath;
|
|
10
|
+
private readonly nativeModelsPath;
|
|
9
11
|
constructor(options?: CodexConfigAdapterOptions);
|
|
10
12
|
protected normalizeProfile(profile: AiConnectionsClientProfile): AiConnectionsClientProfile;
|
|
13
|
+
inspect(): Promise<ClientInspection>;
|
|
14
|
+
plan(profile: AiConnectionsClientProfile): Promise<AiClientConfigPlan>;
|
|
15
|
+
private ownsLegacyAuth;
|
|
11
16
|
protected project(profile: AiConnectionsClientProfile, current: Map<string, string | undefined>): Promise<Map<string, string>>;
|
|
12
17
|
protected verifyProjection(profile: AiConnectionsClientProfile): Promise<ClientVerification>;
|
|
13
18
|
protected restoreFile(filePath: string, current: string | undefined, original: string | undefined, originallyExisted: boolean): Promise<string | null>;
|
|
19
|
+
protected currentApiKeyFingerprint(current: Map<string, string | undefined>): Promise<string | undefined>;
|
|
14
20
|
private removeManagedBlock;
|
|
15
21
|
}
|