@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
|
@@ -4,8 +4,7 @@ import { Avatar, AvatarFallback, AvatarImage, Badge, Button, Input, Tooltip, Too
|
|
|
4
4
|
import { getProviderAvatar, getProviderAvatarBackground } from './provider-visuals.js';
|
|
5
5
|
import { Box, Brain, Check, Copy, ExternalLink, Globe, Image as ImageIcon, Info, Loader2, Pencil, Plus, RotateCw, Search, Trash2, } from 'lucide-react';
|
|
6
6
|
import { AiCredentialPoolSection, } from './AiCredentialPoolSection.js';
|
|
7
|
-
|
|
8
|
-
export function AiProviderCard({ definition, product, status, accountLabel, attempt, attemptOfferingId, apiKey, baseUrl = '', busy, disabled = false, error, quotas, models, verifyPending = false, onApiKeyChange, onBaseUrlChange, onBeginApiKey, onBeginOffering, onBeginBrowser, onSaveApiKey, onDisconnect, onCreateApiKeyCredential, onCreateLocalCredential, onUpdateCredential, onDeleteCredential, onTestCredential, onReorderCredentials, onRefreshQuota, onVerify, onAddModel, onEditModel, onDeleteModel, selectedModelIds, onModelSelectionChange, onDismissError, }) {
|
|
7
|
+
export function AiProviderCard({ definition, product, status, accountLabel, attempt, attemptOfferingId, apiKey, baseUrl = '', busy, disabled = false, error, quotas, models, verifyPending = false, onApiKeyChange, onBaseUrlChange, onBeginApiKey, onBeginOffering, onCancelConnect, onBeginBrowser, onSaveApiKey, onDisconnect, onCreateApiKeyCredential, onCreateLocalCredential, onUpdateCredential, onDeleteCredential, onTestCredential, onReorderCredentials, onRefreshQuota, onVerify, onAddModel, onEditModel, onDeleteModel, selectedModelIds, modelSelectionStatus, onModelSelectionChange, onDismissError, }) {
|
|
9
8
|
const isConfigured = status === 'configured';
|
|
10
9
|
const isConnected = status === 'connected';
|
|
11
10
|
const catalogError = models.length === 0 && error?.message && !error.offeringId
|
|
@@ -15,21 +14,20 @@ export function AiProviderCard({ definition, product, status, accountLabel, atte
|
|
|
15
14
|
const [copiedModelId, setCopiedModelId] = useState();
|
|
16
15
|
const [localSelectedModelIds, setLocalSelectedModelIds] = useState(selectedModelIds ?? []);
|
|
17
16
|
const effectiveSelectedModelIds = selectedModelIds ?? localSelectedModelIds;
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
label: offeringTitle(offering),
|
|
21
|
-
}]) ?? []), [product?.offerings]);
|
|
17
|
+
const catalog = useMemo(() => aggregateProviderModels(models), [models]);
|
|
18
|
+
const isModelSelected = (model) => model.selectionIds.some((id) => effectiveSelectedModelIds.includes(id));
|
|
22
19
|
const visibleModels = useMemo(() => {
|
|
23
20
|
const query = modelSearch.trim().toLocaleLowerCase();
|
|
24
21
|
if (!query)
|
|
25
|
-
return
|
|
26
|
-
return
|
|
27
|
-
}, [
|
|
22
|
+
return catalog;
|
|
23
|
+
return catalog.filter((model) => model.searchText.includes(query));
|
|
24
|
+
}, [catalog, modelSearch]);
|
|
28
25
|
const selectableVisibleModels = visibleModels.filter((model) => model.availability !== 'unavailable');
|
|
29
|
-
const selectedVisibleCount = selectableVisibleModels.filter(
|
|
26
|
+
const selectedVisibleCount = selectableVisibleModels.filter(isModelSelected).length;
|
|
30
27
|
const allVisibleSelected = selectableVisibleModels.length > 0 && selectedVisibleCount === selectableVisibleModels.length;
|
|
31
28
|
const someVisibleSelected = selectedVisibleCount > 0 && !allVisibleSelected;
|
|
32
|
-
const
|
|
29
|
+
const selectedModelCount = catalog.filter(isModelSelected).length;
|
|
30
|
+
const unavailableModelCount = catalog.filter((model) => model.availability === 'unavailable').length;
|
|
33
31
|
const copyModelId = async (modelId) => {
|
|
34
32
|
try {
|
|
35
33
|
await navigator.clipboard.writeText(modelId);
|
|
@@ -40,12 +38,15 @@ export function AiProviderCard({ definition, product, status, accountLabel, atte
|
|
|
40
38
|
setCopiedModelId(undefined);
|
|
41
39
|
}
|
|
42
40
|
};
|
|
43
|
-
const toggleModel = (
|
|
41
|
+
const toggleModel = (model) => {
|
|
44
42
|
const next = new Set(effectiveSelectedModelIds);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
const remove = isModelSelected(model);
|
|
44
|
+
for (const id of remove ? model.selectionIds : model.availableSelectionIds) {
|
|
45
|
+
if (remove)
|
|
46
|
+
next.delete(id);
|
|
47
|
+
else
|
|
48
|
+
next.add(id);
|
|
49
|
+
}
|
|
49
50
|
const nextModelIds = [...next];
|
|
50
51
|
if (selectedModelIds === undefined)
|
|
51
52
|
setLocalSelectedModelIds(nextModelIds);
|
|
@@ -54,34 +55,38 @@ export function AiProviderCard({ definition, product, status, accountLabel, atte
|
|
|
54
55
|
const toggleVisibleModels = () => {
|
|
55
56
|
const next = new Set(effectiveSelectedModelIds);
|
|
56
57
|
for (const model of selectableVisibleModels) {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
for (const id of allVisibleSelected ? model.selectionIds : model.availableSelectionIds) {
|
|
59
|
+
if (allVisibleSelected)
|
|
60
|
+
next.delete(id);
|
|
61
|
+
else
|
|
62
|
+
next.add(id);
|
|
63
|
+
}
|
|
62
64
|
}
|
|
63
65
|
const nextModelIds = [...next];
|
|
64
66
|
if (selectedModelIds === undefined)
|
|
65
67
|
setLocalSelectedModelIds(nextModelIds);
|
|
66
68
|
onModelSelectionChange?.(definition.id, nextModelIds);
|
|
67
69
|
};
|
|
68
|
-
return (_jsx(TooltipProvider, { children: _jsxs("div", { className: "space-y-8", children: [_jsxs("header", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsxs(Avatar, { className: "h-9 w-9 shrink-0 rounded-lg border border-border/50 bg-muted/50 shadow-sm", style: getProviderAvatarBackground(definition.id) ? { backgroundColor: getProviderAvatarBackground(definition.id) } : undefined, children: [_jsx(AvatarImage, { src: getProviderAvatar(definition.id), className: "object-cover" }), _jsx(AvatarFallback, { className: "rounded-lg bg-transparent text-sm font-bold uppercase text-muted-foreground", children: providerMark(definition.id) })] }), _jsxs("div", { className: "flex flex-col justify-center gap-0.5", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("h2", { className: "text-base font-semibold leading-none tracking-tight text-foreground", children: definition.name }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": "\u63D0\u4F9B\u5546\u8BF4\u660E", className: "cursor-help rounded-sm text-muted-foreground/50 focus:outline-none focus-visible:text-foreground", children: _jsx(Info, { "aria-hidden": "true", className: "h-3.5 w-3.5" }) }) }),
|
|
70
|
+
return (_jsx(TooltipProvider, { children: _jsxs("div", { className: "space-y-8", children: [_jsxs("header", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsxs(Avatar, { className: "h-9 w-9 shrink-0 rounded-lg border border-border/50 bg-muted/50 shadow-sm", style: getProviderAvatarBackground(definition.id) ? { backgroundColor: getProviderAvatarBackground(definition.id) } : undefined, children: [_jsx(AvatarImage, { src: getProviderAvatar(definition.id), className: "object-cover" }), _jsx(AvatarFallback, { className: "rounded-lg bg-transparent text-sm font-bold uppercase text-muted-foreground", children: providerMark(definition.id) })] }), _jsxs("div", { className: "flex flex-col justify-center gap-0.5", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("h2", { className: "text-base font-semibold leading-none tracking-tight text-foreground", children: definition.name }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": "\u63D0\u4F9B\u5546\u8BF4\u660E", className: "cursor-help rounded-sm text-muted-foreground/50 focus:outline-none focus-visible:text-foreground", children: _jsx(Info, { "aria-hidden": "true", className: "h-3.5 w-3.5" }) }) }), _jsxs(TooltipContent, { className: "max-w-xs space-y-2 text-xs", children: [_jsx("p", { children: definition.description }), _jsx("p", { children: "Provider \u51ED\u8BC1\u4FDD\u5B58\u5728\u5F53\u524D Pod\uFF0C\u7531 Pod \u6743\u9650\u4FDD\u62A4\u3002" })] })] })] }), _jsxs("a", { href: definition.homeUrl, target: "_blank", rel: "noreferrer", className: "flex items-center gap-0.5 text-[10px] leading-none text-muted-foreground transition-colors hover:text-primary", children: ["\u8BBF\u95EE\u5B98\u7F51 ", _jsx(ExternalLink, { "aria-hidden": "true", className: "h-2.5 w-2.5" })] })] })] }), _jsx(Badge, { variant: isConnected || isConfigured ? 'default' : 'secondary', children: connectionStatusLabel(status) })] }), _jsx(AiCredentialPoolSection, { definition: definition, product: product, status: status, accountLabel: accountLabel, attempt: attempt, attemptOfferingId: attemptOfferingId, apiKey: apiKey, baseUrl: baseUrl, busy: busy, disabled: disabled, error: error, suppressError: Boolean(catalogError), quotas: quotas, onApiKeyChange: onApiKeyChange, onBaseUrlChange: onBaseUrlChange, onBeginApiKey: onBeginApiKey, onBeginOffering: onBeginOffering, onCancelConnect: onCancelConnect, onBeginBrowser: onBeginBrowser, onSaveApiKey: onSaveApiKey, onDisconnect: onDisconnect, onCreateApiKeyCredential: product?.offerings.length ? onCreateApiKeyCredential : undefined, onCreateLocalCredential: product?.offerings.length ? onCreateLocalCredential : undefined, onUpdateCredential: onUpdateCredential, onDeleteCredential: onDeleteCredential, onTestCredential: onTestCredential, onReorderCredentials: onReorderCredentials, onRefreshQuota: onRefreshQuota, onDismissError: onDismissError }), _jsxs("section", { className: "space-y-4", children: [_jsxs("div", { "data-testid": "provider-models-header", className: "flex flex-col gap-3 border-b border-border/40 pb-4 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1", children: [_jsx(Box, { className: "h-4 w-4 shrink-0 text-primary" }), _jsx("h3", { className: "shrink-0 text-sm font-medium text-foreground/90", children: "\u53EF\u7528\u6A21\u578B" }), _jsxs("span", { className: "text-xs text-muted-foreground", children: ["\u5171 ", catalog.length, " \u00B7 \u5DF2\u52A0\u5165 ", selectedModelCount, " \u00B7 \u5DF2\u5931\u6548 ", unavailableModelCount] }), _jsxs("span", { role: "status", "aria-live": "polite", "aria-atomic": "true", className: cn('inline-flex items-center gap-1 text-xs', modelSelectionStatus === 'error' ? 'text-destructive' : 'text-muted-foreground'), children: [modelSelectionStatus === 'saving'
|
|
71
|
+
? _jsx(Loader2, { "aria-hidden": "true", className: "h-3 w-3 animate-spin motion-reduce:animate-none" })
|
|
72
|
+
: modelSelectionStatus === 'saved' ? _jsx(Check, { "aria-hidden": "true", className: "h-3 w-3" }) : null, modelSelectionStatus === 'saving' ? '保存中…'
|
|
73
|
+
: modelSelectionStatus === 'saved' ? '已保存'
|
|
74
|
+
: modelSelectionStatus === 'error' ? '保存失败,请重试' : '选择后自动保存'] })] }), _jsxs("div", { "data-testid": "provider-models-actions", className: "flex w-full flex-wrap items-center gap-2 sm:w-auto sm:flex-nowrap sm:justify-end", children: [(isConfigured || isConnected) && (onVerify || onAddModel) ? (_jsxs(_Fragment, { children: [onAddModel ? (_jsxs(Button, { variant: "outline", size: "sm", className: "h-8 gap-1.5 text-xs", disabled: disabled || busy, onClick: onAddModel, children: [_jsx(Plus, { "aria-hidden": "true", className: "h-3.5 w-3.5" }), "\u6DFB\u52A0\u6A21\u578B"] })) : null, onVerify && models.length > 0 ? (_jsxs(Button, { variant: "outline", size: "sm", className: "h-8 gap-1.5 text-xs", disabled: disabled || busy || verifyPending, onClick: onVerify, children: [verifyPending
|
|
69
75
|
? _jsx(Loader2, { "aria-hidden": "true", className: "h-3.5 w-3.5 animate-spin" })
|
|
70
76
|
: _jsx(RotateCw, { "aria-hidden": "true", className: "h-3.5 w-3.5" }), verifyPending ? '同步中...' : '刷新模型'] })) : onVerify ? (_jsxs(Button, { variant: "outline", size: "sm", className: "h-8 gap-1.5 text-xs", disabled: disabled || busy || verifyPending, onClick: onVerify, children: [verifyPending
|
|
71
77
|
? _jsx(Loader2, { "aria-hidden": "true", className: "h-3.5 w-3.5 animate-spin" })
|
|
72
78
|
: _jsx(RotateCw, { "aria-hidden": "true", className: "h-3.5 w-3.5" }), verifyPending ? '同步中...' : '同步模型'] })) : null] })) : null, _jsxs("div", { className: "relative w-full sm:w-auto", children: [_jsx(Search, { className: "absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { value: modelSearch, onChange: (event) => setModelSearch(event.target.value), placeholder: "\u641C\u7D22\u6A21\u578B...", className: "h-8 w-full bg-background pl-8 text-xs sm:w-[232px]", autoComplete: "off", "data-lpignore": "true", "data-1p-ignore": true })] })] })] }), models.length === 0 ? (_jsx("div", { className: "rounded-lg border border-dashed border-border/50 bg-muted/5 py-12 text-center text-sm text-muted-foreground", children: catalogError ? (_jsx("p", { className: "text-destructive", children: catalogError })) : ('暂无可用模型') })) : visibleModels.length === 0 ? (_jsx("div", { className: "rounded-lg border border-dashed border-border/50 bg-muted/5 py-12 text-center text-sm text-muted-foreground", children: "\u672A\u627E\u5230\u5339\u914D\u7684\u6A21\u578B" })) : (_jsxs("div", { className: "grid gap-2", children: [_jsx("div", { className: "flex items-center justify-between px-1 py-1", children: _jsxs("button", { type: "button", role: "checkbox", "aria-label": "\u5168\u9009\u5F53\u524D\u7ED3\u679C", "aria-checked": someVisibleSelected ? 'mixed' : allVisibleSelected, disabled: disabled || busy || selectableVisibleModels.length === 0, onClick: toggleVisibleModels, className: "flex items-center gap-2 text-xs text-muted-foreground disabled:opacity-50", children: [_jsx("span", { className: cn('flex h-4 w-4 items-center justify-center rounded border', allVisibleSelected || someVisibleSelected ? 'border-primary bg-primary text-primary-foreground' : 'border-border'), children: someVisibleSelected ? _jsx("span", { "aria-hidden": "true", children: "\u2212" }) : _jsx(Check, { "aria-hidden": "true", className: cn('h-3 w-3', !allVisibleSelected && 'invisible') }) }), "\u5168\u9009\u5F53\u524D\u7ED3\u679C"] }) }), visibleModels.map((model) => {
|
|
73
79
|
const selectionId = modelSelectionId(model);
|
|
74
|
-
const isSelected =
|
|
80
|
+
const isSelected = isModelSelected(model);
|
|
75
81
|
const isUnavailable = model.availability === 'unavailable';
|
|
76
82
|
const modelLabel = model.displayName ?? model.id;
|
|
77
|
-
const source = modelOfferingSource(model, offeringSources);
|
|
78
83
|
const iconTokens = [
|
|
79
84
|
...(model.inputModalities ?? []).filter((modality) => modality !== 'text'),
|
|
80
85
|
...(model.capabilities ?? []),
|
|
81
86
|
];
|
|
82
87
|
return (_jsxs("div", { className: cn('group flex items-center gap-3 rounded-lg border bg-card p-3 transition-all duration-200 hover:border-border/60 hover:bg-accent/30', isSelected ? 'border-primary/40 bg-primary/[0.03]' : 'border-border/40', isUnavailable && 'opacity-75'), children: [_jsx("button", { type: "button", role: "checkbox", "aria-checked": isSelected, "aria-label": `${isSelected ? '取消选择' : '选择'} ${modelLabel}`, className: cn('flex h-5 w-5 shrink-0 items-center justify-center rounded border transition-colors focus:outline-none focus-visible:border-ring', isSelected
|
|
83
88
|
? 'border-primary bg-primary text-primary-foreground'
|
|
84
|
-
: 'border-border text-transparent hover:border-primary/60'), disabled: disabled || busy || (isUnavailable && !isSelected), onClick: () => toggleModel(
|
|
89
|
+
: 'border-border text-transparent hover:border-primary/60'), disabled: disabled || busy || (isUnavailable && !isSelected), onClick: () => toggleModel(model), children: _jsx(Check, { "aria-hidden": "true", className: "h-3.5 w-3.5" }) }), _jsx("div", { className: "shrink-0 rounded bg-muted/50 p-2 text-muted-foreground transition-colors group-hover:text-primary", children: _jsx(Box, { className: "h-4 w-4" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "truncate text-sm font-medium text-foreground/90", children: modelLabel }), _jsx("div", { className: "flex items-center gap-1", children: iconTokens.map((token) => _jsx(CapabilityIcon, { type: token }, token)) }), model.custom ? _jsx(Badge, { variant: "outline", className: "shrink-0 text-[10px] font-normal", children: "\u624B\u5DE5" }) : null, isUnavailable ? (_jsx(Badge, { variant: "destructive", className: "shrink-0 text-[10px] font-normal", children: "\u5DF2\u5931\u6548" })) : null] }), model.displayName ? (_jsxs("div", { className: "mt-0.5 flex items-center gap-1.5", children: [_jsx("code", { className: "max-w-[300px] truncate font-mono text-[10px] text-muted-foreground opacity-70", children: model.id }), _jsx("button", { type: "button", onClick: () => void copyModelId(model.id), className: "rounded p-0.5 text-muted-foreground opacity-0 transition-opacity hover:bg-muted hover:text-foreground group-hover:opacity-100 group-focus-within:opacity-100 focus:opacity-100", "aria-label": `复制 ${model.displayName} ID`, title: "\u590D\u5236 ID", children: copiedModelId === model.id
|
|
85
90
|
? _jsx(Check, { "aria-hidden": "true", className: "h-3 w-3 text-primary" })
|
|
86
91
|
: _jsx(Copy, { "aria-hidden": "true", className: "h-3 w-3" }) })] })) : null] }), model.custom && (onEditModel || onDeleteModel) ? (_jsxs("div", { className: "flex shrink-0 items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 focus-within:opacity-100", children: [onEditModel ? (_jsx(Button, { variant: "ghost", size: "icon", className: "h-7 w-7", "aria-label": `编辑 ${model.displayName ?? model.id}`, onClick: () => onEditModel(model), children: _jsx(Pencil, { "aria-hidden": "true", className: "h-3.5 w-3.5 text-muted-foreground" }) })) : null, onDeleteModel ? (_jsx(Button, { variant: "ghost", size: "icon", className: "h-7 w-7", "aria-label": `删除 ${model.displayName ?? model.id}`, onClick: () => onDeleteModel(model), children: _jsx(Trash2, { "aria-hidden": "true", className: "h-3.5 w-3.5 text-muted-foreground" }) })) : null] })) : null] }, selectionId));
|
|
87
92
|
})] }))] })] }) }));
|
|
@@ -114,22 +119,34 @@ function modelSelectionId(model) {
|
|
|
114
119
|
return model.resourceId
|
|
115
120
|
?? (model.offeringId ? `${model.offeringId}:${model.id}` : model.id);
|
|
116
121
|
}
|
|
117
|
-
function
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
model.id
|
|
121
|
-
model
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
122
|
+
function aggregateProviderModels(models) {
|
|
123
|
+
const catalog = new Map();
|
|
124
|
+
for (const model of models) {
|
|
125
|
+
const key = `${model.provider}\0${model.id}`;
|
|
126
|
+
const selectionId = modelSelectionId(model);
|
|
127
|
+
const existing = catalog.get(key);
|
|
128
|
+
const searchText = [model.id, model.displayName].filter(Boolean).join('\n').toLocaleLowerCase();
|
|
129
|
+
if (!existing) {
|
|
130
|
+
catalog.set(key, {
|
|
131
|
+
...model,
|
|
132
|
+
selectionIds: [selectionId],
|
|
133
|
+
availableSelectionIds: model.availability === 'unavailable' ? [] : [selectionId],
|
|
134
|
+
searchText,
|
|
135
|
+
});
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (!existing.selectionIds.includes(selectionId))
|
|
139
|
+
existing.selectionIds.push(selectionId);
|
|
140
|
+
if (model.availability !== 'unavailable' && !existing.availableSelectionIds.includes(selectionId)) {
|
|
141
|
+
existing.availableSelectionIds.push(selectionId);
|
|
142
|
+
}
|
|
143
|
+
if (model.availability !== 'unavailable')
|
|
144
|
+
existing.availability = model.availability;
|
|
145
|
+
existing.capabilities = [...new Set([...(existing.capabilities ?? []), ...(model.capabilities ?? [])])];
|
|
146
|
+
existing.inputModalities = [...new Set([...(existing.inputModalities ?? []), ...(model.inputModalities ?? [])])];
|
|
147
|
+
existing.searchText += `\n${searchText}`;
|
|
148
|
+
}
|
|
149
|
+
return [...catalog.values()];
|
|
133
150
|
}
|
|
134
151
|
function connectionStatusLabel(status) {
|
|
135
152
|
switch (status) {
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import type { AiQuotaSnapshot } from './ai-connections-client';
|
|
2
|
-
export declare function AiQuotaCard({ providerName, offeringName, quota, busy, disabled, credentialLabel, error, onRefresh, }: {
|
|
2
|
+
export declare function AiQuotaCard({ providerName, offeringName, quota, busy, disabled, credentialLabel, multiple, compact, paused, error, onRefresh, }: {
|
|
3
3
|
providerName: string;
|
|
4
4
|
offeringName: string;
|
|
5
5
|
quota?: AiQuotaSnapshot;
|
|
6
6
|
busy: boolean;
|
|
7
7
|
disabled?: boolean;
|
|
8
8
|
credentialLabel?: string;
|
|
9
|
+
multiple?: boolean;
|
|
10
|
+
compact?: boolean;
|
|
11
|
+
paused?: boolean;
|
|
9
12
|
error?: string;
|
|
10
13
|
onRefresh: () => void;
|
|
11
14
|
}): import("react").JSX.Element;
|
|
@@ -1,8 +1,67 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { Button, Dialog, DialogContent, DialogTitle, DialogTrigger } from '@undefineds.co/shared-ui';
|
|
4
|
+
import { Info, Loader2, RefreshCcw, Wallet } from 'lucide-react';
|
|
5
|
+
export function AiQuotaCard({ providerName, offeringName, quota, busy, disabled = false, credentialLabel, multiple = false, compact = false, paused = false, error, onRefresh, }) {
|
|
6
|
+
if (compact) {
|
|
7
|
+
const available = !busy && !error && quota?.status === 'available';
|
|
8
|
+
return (_jsx("div", { className: `min-w-0 text-xs text-muted-foreground ${paused ? 'opacity-60' : ''}`, children: _jsxs("div", { className: "flex items-start gap-1", children: [_jsxs("div", { className: "min-w-0 flex-1 truncate py-1 [&>span+span]:ml-3", children: [paused ? _jsx("span", { children: "\u5DF2\u505C\u7528 \u00B7 \u4E0D\u53C2\u4E0E\u5168\u90E8\u5237\u65B0" }) : null, busy ? _jsx("span", { role: "status", children: "\u6B63\u5728\u67E5\u8BE2\u989D\u5EA6\u2026" })
|
|
9
|
+
: error ? _jsx("span", { role: "alert", title: error, className: "text-destructive", children: error })
|
|
10
|
+
: !quota ? _jsx("span", { children: credentialLabel ? '尚未检查' : `连接${offeringName}后可查询` })
|
|
11
|
+
: quota.status === 'unsupported' ? _jsx("span", { children: "\u5B98\u65B9\u989D\u5EA6\u63A5\u53E3\u4E0D\u652F\u6301" })
|
|
12
|
+
: quota.status === 'error' ? _jsx("span", { role: "alert", className: "text-destructive", children: "\u989D\u5EA6\u67E5\u8BE2\u5931\u8D25" })
|
|
13
|
+
: _jsx(QuotaSummary, { quota: quota }), available && quota.stale ? _jsx("span", { children: "\u6570\u636E\u53EF\u80FD\u5DF2\u8FC7\u671F" }) : null] }), _jsx(QuotaInfo, { quota: quota, label: credentialLabel ?? offeringName }), _jsx(Button, { className: "h-6 w-6 shrink-0 p-0", variant: "ghost", size: "sm", "aria-label": `刷新 ${providerName} ${offeringName}${credentialLabel ? ` ${credentialLabel}` : ''}额度`, disabled: busy || disabled, onClick: onRefresh, children: busy ? _jsx(Loader2, { "aria-hidden": "true", className: "h-3 w-3 animate-spin" }) : _jsx(RefreshCcw, { "aria-hidden": "true", className: "h-3 w-3" }) })] }) }));
|
|
14
|
+
}
|
|
15
|
+
return (_jsxs("div", { className: `${multiple ? 'space-y-1.5' : 'space-y-3'} border-t border-border/40 pt-3 ${paused ? 'opacity-60' : ''}`, children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [!multiple ? _jsx(Wallet, { className: "h-4 w-4 shrink-0 text-primary" }) : null, _jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "break-all text-sm font-medium text-foreground/90", children: multiple ? `凭证:${credentialLabel}` : '剩余额度' }), multiple && !busy && !error && quota?.status === 'available' ? (_jsx("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-xs text-muted-foreground", children: _jsx(QuotaSummary, { quota: quota }) })) : null] })] }), _jsxs(Button, { className: "shrink-0", variant: "ghost", size: "sm", "aria-label": `刷新 ${providerName} ${offeringName}${multiple ? ` ${credentialLabel}` : ''}额度`, disabled: busy || disabled, onClick: onRefresh, children: [busy
|
|
16
|
+
? _jsx(Loader2, { "aria-hidden": "true", className: "mr-2 h-3.5 w-3.5 animate-spin" })
|
|
17
|
+
: _jsx(RefreshCcw, { "aria-hidden": "true", className: "mr-2 h-3.5 w-3.5" }), busy ? '查询中' : '刷新'] })] }), credentialLabel && !multiple ? (_jsxs("p", { className: "text-xs text-muted-foreground", children: ["\u51ED\u8BC1\uFF1A", credentialLabel] })) : null, paused ? _jsx("p", { className: "text-xs text-muted-foreground", children: "\u5DF2\u505C\u7528 \u00B7 \u4E0D\u53C2\u4E0E\u5168\u90E8\u5237\u65B0" }) : null, busy ? (_jsx("p", { role: "status", className: "text-xs text-muted-foreground", children: "\u6B63\u5728\u67E5\u8BE2\u989D\u5EA6\u2026" })) : error ? (_jsx("p", { role: "alert", className: "text-sm text-destructive", children: error })) : !quota ? (_jsx("p", { className: "text-xs text-muted-foreground", children: credentialLabel ? '尚未检查' : `连接${offeringName}后可查询` })) : quota.status === 'unsupported' ? (_jsxs(_Fragment, { children: [_jsx("p", { className: "text-sm", children: "\u5B98\u65B9\u989D\u5EA6\u63A5\u53E3\u4E0D\u652F\u6301" }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["\u6765\u6E90\uFF1A", quota.source] })] })) : quota.status === 'error' ? (_jsx("p", { className: "text-sm text-destructive", children: "\u989D\u5EA6\u67E5\u8BE2\u5931\u8D25" })) : (multiple ? (_jsxs("details", { className: "text-xs text-muted-foreground", children: [_jsx("summary", { className: "cursor-pointer", "aria-label": `${credentialLabel}额度详情`, children: "\u8BE6\u60C5" }), _jsx("div", { className: "pt-3", children: _jsx(QuotaDetails, { quota: quota, hideBalance: true }) })] })) : _jsx(QuotaDetails, { quota: quota }))] }));
|
|
18
|
+
}
|
|
19
|
+
function QuotaInfo({ quota, label }) {
|
|
20
|
+
const [position, setPosition] = useState({ left: 16, top: 16, maxHeight: 400 });
|
|
21
|
+
const [open, setOpen] = useState(false);
|
|
22
|
+
const triggerRef = useRef(null);
|
|
23
|
+
const contentRef = useRef(null);
|
|
24
|
+
const outsideRef = useRef(false);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!open)
|
|
27
|
+
return;
|
|
28
|
+
// Capture also covers clicks on the page margin outside React's root.
|
|
29
|
+
const dismissOutside = (event) => {
|
|
30
|
+
if (!(event.target instanceof Node) || triggerRef.current?.contains(event.target) || contentRef.current?.contains(event.target))
|
|
31
|
+
return;
|
|
32
|
+
outsideRef.current = true;
|
|
33
|
+
setOpen(false);
|
|
34
|
+
};
|
|
35
|
+
const dismissMoved = (event) => {
|
|
36
|
+
if (event.type === 'scroll' && event.target instanceof Node && contentRef.current?.contains(event.target))
|
|
37
|
+
return;
|
|
38
|
+
outsideRef.current = true;
|
|
39
|
+
setOpen(false);
|
|
40
|
+
};
|
|
41
|
+
document.addEventListener('pointerdown', dismissOutside, true);
|
|
42
|
+
document.addEventListener('scroll', dismissMoved, true);
|
|
43
|
+
window.addEventListener('resize', dismissMoved);
|
|
44
|
+
return () => {
|
|
45
|
+
document.removeEventListener('pointerdown', dismissOutside, true);
|
|
46
|
+
document.removeEventListener('scroll', dismissMoved, true);
|
|
47
|
+
window.removeEventListener('resize', dismissMoved);
|
|
48
|
+
};
|
|
49
|
+
}, [open]);
|
|
50
|
+
return (_jsxs(Dialog, { modal: false, open: open, onOpenChange: (next) => { outsideRef.current = false; setOpen(next); }, children: [_jsx(DialogTrigger, { asChild: true, children: _jsx(Button, { ref: triggerRef, className: "h-6 w-6 shrink-0 p-0", variant: "ghost", size: "sm", "aria-label": `${label}额度详情`, disabled: !quota || quota.status === 'error', onClick: (event) => {
|
|
51
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
52
|
+
const width = Math.min(320, window.innerWidth - 32);
|
|
53
|
+
const left = Math.max(16, Math.min(rect.right - width, window.innerWidth - width - 16));
|
|
54
|
+
const top = Math.max(16, Math.min(rect.bottom + 8, window.innerHeight - 320));
|
|
55
|
+
setPosition({ left, top, maxHeight: window.innerHeight - top - 16 });
|
|
56
|
+
}, children: _jsx(Info, { "aria-hidden": "true", className: "h-3 w-3" }) }) }), _jsxs(DialogContent, { ref: contentRef, className: "w-[calc(100vw-2rem)] max-w-xs overflow-y-auto p-4", onEscapeKeyDown: () => triggerRef.current?.focus(), onCloseAutoFocus: (event) => { if (outsideRef.current)
|
|
57
|
+
event.preventDefault(); }, style: { ...position, transform: 'none', animation: 'none' }, "aria-describedby": undefined, children: [_jsx(DialogTitle, { className: "pr-8 text-sm", children: "\u989D\u5EA6\u8BE6\u60C5" }), quota?.status === 'available' ? _jsx(QuotaDetails, { quota: quota })
|
|
58
|
+
: quota ? _jsxs("p", { className: "break-words text-xs text-muted-foreground", children: ["\u6765\u6E90\uFF1A", quota.source] }) : null] })] }));
|
|
59
|
+
}
|
|
60
|
+
function QuotaSummary({ quota }) {
|
|
61
|
+
return (_jsxs(_Fragment, { children: [typeof quota.balance === 'number' ? _jsxs("span", { children: ["\u4F59\u989D\uFF1A", quota.balance] }) : null, quota.windows.map((window, index) => _jsxs("span", { children: [quotaWindowLabel(window.name), " \u00B7 ", remainingLabel(window)] }, index)), typeof quota.balance !== 'number' && quota.windows.length === 0 ? _jsx("span", { children: "\u670D\u52A1\u5546\u672A\u8FD4\u56DE\u989D\u5EA6\u6570\u636E" }) : null] }));
|
|
62
|
+
}
|
|
63
|
+
function QuotaDetails({ quota, hideBalance = false }) {
|
|
64
|
+
return (_jsxs("div", { className: "space-y-3 text-sm", children: [!hideBalance && typeof quota.balance === 'number' ? _jsxs("div", { children: ["\u4F59\u989D\uFF1A", quota.balance] }) : null, quota.windows.map((window, index) => (_jsxs("div", { className: "space-y-1.5", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "font-medium text-foreground", children: quotaWindowLabel(window.name) }), _jsx("span", { className: "text-muted-foreground", children: remainingLabel(window) })] }), remainingPercent(window) !== undefined ? (_jsx("div", { "aria-label": `${quotaWindowLabel(window.name)}剩余 ${String(remainingPercent(window))}%`, className: "h-1.5 overflow-hidden rounded-full bg-muted", role: "progressbar", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": remainingPercent(window), children: _jsx("div", { className: "h-full rounded-full bg-primary", style: { width: `${String(remainingPercent(window))}%` } }) })) : null, window.resetsAt ? _jsxs("p", { className: "text-xs text-muted-foreground", children: ["\u91CD\u7F6E\uFF1A", formatTimestamp(window.resetsAt)] }) : null] }, `${String(window.name)}-${index}`))), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["\u66F4\u65B0\uFF1A", formatTimestamp(quota.observedAt)] }), _jsxs("p", { className: "break-words text-xs text-muted-foreground", children: ["\u6765\u6E90\uFF1A", quota.source, quota.stale ? ' · 数据可能已过期' : ''] })] }));
|
|
6
65
|
}
|
|
7
66
|
function quotaWindowLabel(name) {
|
|
8
67
|
switch (name) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AiConnectionsModelSelection, AiConnectionsOAuthCredential } from '@undefineds.co/extension-sdk/web';
|
|
2
2
|
export declare const AI_CONNECTIONS_PROVIDERS: readonly ["openai", "anthropic", "kimi", "bailian", "deepseek", "zhipu", "ollama", "custom"];
|
|
3
3
|
export type AiConnectionsProvider = (typeof AI_CONNECTIONS_PROVIDERS)[number];
|
|
4
|
-
export type AiConnectionsMode = 'browserAssistedApiKey' | 'deviceCodeOAuth' | 'connectUnsupported';
|
|
4
|
+
export type AiConnectionsMode = 'browserAssistedApiKey' | 'deviceCodeOAuth' | 'authorizationCodeOAuth' | 'connectUnsupported';
|
|
5
5
|
export type AiConnectStatus = 'pending' | 'authorization_pending' | 'slow_down' | 'completed' | 'expired' | 'cancelled' | 'unsupported';
|
|
6
6
|
export interface AiConnectAttempt {
|
|
7
7
|
mode: AiConnectionsMode;
|
|
@@ -18,6 +18,8 @@ export interface AiConnectAttempt {
|
|
|
18
18
|
intervalSeconds?: number;
|
|
19
19
|
apiKeyManagementSupported?: boolean;
|
|
20
20
|
credentialId?: string;
|
|
21
|
+
offeringId?: string;
|
|
22
|
+
authorizationMethodId?: string;
|
|
21
23
|
oauthCredential?: AiConnectionsOAuthCredential;
|
|
22
24
|
message?: string;
|
|
23
25
|
}
|
|
@@ -53,6 +55,9 @@ export interface AiQuotaSnapshot {
|
|
|
53
55
|
}
|
|
54
56
|
export interface GatewayKeyRecord {
|
|
55
57
|
id: string;
|
|
58
|
+
kind?: 'client-credentials';
|
|
59
|
+
credentialResource?: string;
|
|
60
|
+
fingerprint?: string;
|
|
56
61
|
owner: string;
|
|
57
62
|
scopes: string[];
|
|
58
63
|
createdAt: string;
|
|
@@ -95,18 +100,40 @@ export interface CustomProviderModel {
|
|
|
95
100
|
capabilities?: string[];
|
|
96
101
|
}
|
|
97
102
|
export interface ProviderModelDiscovery {
|
|
103
|
+
/** False when some service scopes failed; retain their previous catalog. */
|
|
104
|
+
complete?: boolean;
|
|
98
105
|
provider: AiConnectionsProvider;
|
|
99
106
|
credential: string;
|
|
100
107
|
models: DiscoveredProviderModel[];
|
|
101
108
|
observedAt: string;
|
|
102
109
|
source: string;
|
|
103
110
|
}
|
|
111
|
+
export type AiProviderAuthorizationMethodId = 'device-code' | 'local-session-import' | 'api-key' | 'local-service' | string;
|
|
112
|
+
export interface AiProviderAuthorizationMethod {
|
|
113
|
+
id: AiProviderAuthorizationMethodId;
|
|
114
|
+
authMode: 'oauth' | 'deviceCode' | 'local' | 'apiKey';
|
|
115
|
+
connectMode?: AiConnectionsMode;
|
|
116
|
+
label: string;
|
|
117
|
+
lifecycle: 'active' | 'unavailable';
|
|
118
|
+
reason?: string;
|
|
119
|
+
}
|
|
120
|
+
export interface AiProviderAuthorizationMethodsSummary {
|
|
121
|
+
provider: AiConnectionsProvider;
|
|
122
|
+
offeringId: string;
|
|
123
|
+
endpoints?: AiProviderOffering['endpoints'];
|
|
124
|
+
authorizationMethods: AiProviderAuthorizationMethod[];
|
|
125
|
+
}
|
|
126
|
+
export interface AiConnectionBeginOptions {
|
|
127
|
+
offeringId?: string;
|
|
128
|
+
authorizationMethodId?: string;
|
|
129
|
+
}
|
|
104
130
|
export interface AiProviderOffering {
|
|
105
131
|
id: string;
|
|
106
132
|
label?: string;
|
|
107
133
|
kind?: 'oauth-subscription' | 'api-platform' | 'token-plan' | 'local';
|
|
108
134
|
lifecycle?: 'active' | 'legacy' | 'unavailable';
|
|
109
135
|
authModes?: Array<'oauth' | 'deviceCode' | 'apiKey' | 'local'>;
|
|
136
|
+
authorizationMethods?: AiProviderAuthorizationMethod[];
|
|
110
137
|
runtimeProviderIds?: string[];
|
|
111
138
|
productLabel?: string;
|
|
112
139
|
credentialPrefixHints?: string[];
|
|
@@ -196,10 +223,15 @@ export interface AiConnectionsClient {
|
|
|
196
223
|
readonly apiBase: string;
|
|
197
224
|
getServiceAccess(): Promise<unknown>;
|
|
198
225
|
listProviders(): Promise<AiProviderSummary[]>;
|
|
226
|
+
listAuthorizationMethods?(): Promise<AiProviderAuthorizationMethodsSummary[]>;
|
|
199
227
|
listModels(): Promise<AiGatewayModel[]>;
|
|
228
|
+
/** Active Gateway routing projection, independent of a host's Pod catalog. */
|
|
229
|
+
listGatewayModels?(): Promise<AiGatewayModel[]>;
|
|
200
230
|
listGatewayKeys(): Promise<GatewayKeyRecord[]>;
|
|
201
231
|
createGatewayKey(input: {
|
|
202
232
|
name: string;
|
|
233
|
+
apiKey?: string;
|
|
234
|
+
credentialResource?: string;
|
|
203
235
|
appliedClient?: string;
|
|
204
236
|
scopes?: string[];
|
|
205
237
|
expiresAt?: string;
|
|
@@ -209,14 +241,16 @@ export interface AiConnectionsClient {
|
|
|
209
241
|
enabled: boolean;
|
|
210
242
|
}): Promise<GatewayKeyRecord>;
|
|
211
243
|
deleteGatewayKey(keyId: string): Promise<void>;
|
|
212
|
-
beginConnect(provider: AiConnectionsProvider, mode: AiConnectionsMode): Promise<AiConnectAttempt>;
|
|
213
|
-
connectStatus(provider: AiConnectionsProvider, attempt: Pick<AiConnectAttempt, 'attemptId' | 'state' | 'signature'>): Promise<AiConnectAttempt>;
|
|
214
|
-
completeApiKey(provider: AiConnectionsProvider, attempt: Pick<AiConnectAttempt, 'attemptId' | 'state' | 'signature'
|
|
215
|
-
pollDevice(provider: AiConnectionsProvider, attempt: Pick<AiConnectAttempt, 'attemptId' | 'state' | 'signature'>): Promise<AiConnectAttempt>;
|
|
216
|
-
|
|
244
|
+
beginConnect(provider: AiConnectionsProvider, mode: AiConnectionsMode, options?: AiConnectionBeginOptions): Promise<AiConnectAttempt>;
|
|
245
|
+
connectStatus(provider: AiConnectionsProvider, attempt: Pick<AiConnectAttempt, 'attemptId' | 'state' | 'signature' | 'offeringId'> & Partial<Pick<AiConnectAttempt, 'mode'>>): Promise<AiConnectAttempt>;
|
|
246
|
+
completeApiKey(provider: AiConnectionsProvider, attempt: Pick<AiConnectAttempt, 'attemptId' | 'state' | 'signature' | 'offeringId'> & Partial<Pick<AiConnectAttempt, 'mode'>>, apiKey: string, accountLabel?: string, baseUrl?: string): Promise<AiConnectAttempt>;
|
|
247
|
+
pollDevice(provider: AiConnectionsProvider, attempt: Pick<AiConnectAttempt, 'attemptId' | 'state' | 'signature' | 'offeringId'> & Partial<Pick<AiConnectAttempt, 'mode'>>): Promise<AiConnectAttempt>;
|
|
248
|
+
cancelConnect?(provider: AiConnectionsProvider, attempt: Pick<AiConnectAttempt, 'attemptId' | 'state' | 'signature' | 'offeringId'> & Partial<Pick<AiConnectAttempt, 'mode'>>): Promise<AiConnectAttempt>;
|
|
249
|
+
refreshOAuthCredential(provider: AiConnectionsProvider, credentialId: string, refreshToken: string, expectedVersion: number, offeringId?: string, mode?: AiConnectionsMode): Promise<AiConnectAttempt>;
|
|
217
250
|
disconnect(provider: AiConnectionsProvider, credentialId?: string): Promise<AiConnectionsCredential | undefined>;
|
|
218
251
|
createApiKeyCredential(provider: AiConnectionsProvider, input: CreateApiKeyCredentialInput): Promise<AiProviderCredentialSummary>;
|
|
219
252
|
createLocalCredential(provider: AiConnectionsProvider, input: {
|
|
253
|
+
authorizationMethodId?: string;
|
|
220
254
|
offeringId?: string;
|
|
221
255
|
label?: string;
|
|
222
256
|
baseUrl?: string;
|
|
@@ -269,8 +303,14 @@ interface CreateAiConnectionsClientInput {
|
|
|
269
303
|
}
|
|
270
304
|
export declare function resolveAiConnectionsApiBase(podBaseUrl: string): string;
|
|
271
305
|
export declare function createAiConnectionsClient({ webId, podBaseUrl, authenticatedFetch, }: CreateAiConnectionsClientInput): AiConnectionsClient;
|
|
306
|
+
export declare class AiConnectionsRequestError extends Error {
|
|
307
|
+
readonly code?: string;
|
|
308
|
+
readonly providerStatus?: number;
|
|
309
|
+
constructor(message: string, payload: unknown);
|
|
310
|
+
}
|
|
272
311
|
export declare function normalizeAiConnectionsThrownError(error: unknown): string;
|
|
273
312
|
export declare function normalizeAiConnectionsErrorMessage(payload: unknown, status: number, context?: {
|
|
274
313
|
provider?: AiConnectionsProvider;
|
|
314
|
+
authMode?: 'apiKey' | 'deviceCodeOAuth' | 'local';
|
|
275
315
|
}): string;
|
|
276
316
|
export {};
|