@undefineds.co/xpod 0.4.11 → 0.4.12
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/components-ignore.json +5 -1
- package/config/notifications.json +68 -0
- package/config/xpod.base.json +9 -11
- package/dist/ai/service/AiCredentialSecret.d.ts +30 -0
- package/dist/ai/service/AiCredentialSecret.js +120 -0
- package/dist/ai/service/CredentialReaderImpl.d.ts +18 -0
- package/dist/ai/service/CredentialReaderImpl.js +81 -5
- package/dist/ai/service/CredentialReaderImpl.jsonld +42 -2
- package/dist/ai/service/EmbeddingModelPolicy.d.ts +79 -0
- package/dist/ai/service/EmbeddingModelPolicy.js +134 -0
- package/dist/ai/service/EmbeddingProviderError.js +6 -0
- package/dist/ai/service/EmbeddingServiceImpl.d.ts +13 -1
- package/dist/ai/service/EmbeddingServiceImpl.js +18 -5
- package/dist/ai/service/EmbeddingServiceImpl.jsonld +35 -0
- package/dist/ai/service/index.d.ts +2 -0
- package/dist/ai/service/index.js +2 -0
- package/dist/api/ai-gateway/connect/index.d.ts +20 -2
- package/dist/api/ai-gateway/connect/index.js +162 -16
- package/dist/api/ai-gateway/credentials/AiCredentialSecretDecoder.d.ts +12 -0
- package/dist/api/ai-gateway/credentials/AiCredentialSecretDecoder.js +30 -0
- package/dist/api/ai-gateway/errors.d.ts +1 -1
- package/dist/api/ai-gateway/models/GatewayEmbeddingModelCatalog.d.ts +11 -0
- package/dist/api/ai-gateway/models/GatewayEmbeddingModelCatalog.js +31 -0
- package/dist/api/ai-gateway/models/PodModelSelectionRepository.js +7 -3
- package/dist/api/ai-gateway/models/ProviderCustomModelsService.d.ts +18 -0
- package/dist/api/ai-gateway/models/ProviderCustomModelsService.js +23 -0
- package/dist/api/ai-gateway/models/ProviderModelDiscoveryAdapters.d.ts +3 -1
- package/dist/api/ai-gateway/models/ProviderModelDiscoveryAdapters.js +2 -45
- package/dist/api/ai-gateway/models/ProviderModelSelectionService.d.ts +10 -0
- package/dist/api/ai-gateway/models/ProviderModelSelectionService.js +57 -20
- package/dist/api/ai-gateway/models/ProviderModelType.d.ts +28 -0
- package/dist/api/ai-gateway/models/ProviderModelType.js +34 -0
- package/dist/api/ai-gateway/models/ProviderModelsAdapter.d.ts +10 -0
- package/dist/api/ai-gateway/models/ProviderModelsAdapter.js +3 -4
- package/dist/api/ai-gateway/models/index.d.ts +1 -0
- package/dist/api/ai-gateway/models/index.js +3 -1
- package/dist/api/ai-gateway/providers/CustomRuntimeAdapter.d.ts +7 -0
- package/dist/api/ai-gateway/providers/CustomRuntimeAdapter.js +9 -2
- package/dist/api/ai-gateway/providers/ModelsDevCatalog.d.ts +7 -1
- package/dist/api/ai-gateway/providers/ModelsDevCatalog.js +4 -10
- package/dist/api/ai-gateway/providers/ProviderRegistry.d.ts +107 -0
- package/dist/api/ai-gateway/providers/ProviderRegistry.js +244 -21
- package/dist/api/ai-gateway/providers/ProviderRuntimeRegistry.d.ts +5 -0
- package/dist/api/ai-gateway/providers/ProviderRuntimeRegistry.js +5 -1
- package/dist/api/ai-gateway/quota/SubscriptionQuotaAdapters.d.ts +12 -4
- package/dist/api/ai-gateway/quota/SubscriptionQuotaAdapters.js +11 -11
- package/dist/api/ai-gateway/routing/ModelRouter.d.ts +14 -0
- package/dist/api/ai-gateway/routing/ModelRouter.js +43 -4
- package/dist/api/ai-gateway/service-access/AiConnectionsServiceAccess.d.ts +9 -1
- package/dist/api/ai-gateway/service-access/AiConnectionsServiceAccess.js +3 -27
- package/dist/api/chatkit/pod-store.d.ts +31 -0
- package/dist/api/chatkit/pod-store.js +132 -8
- package/dist/api/container/common.js +24 -4
- package/dist/api/container/routes.js +17 -2
- package/dist/api/container/types.d.ts +3 -1
- package/dist/api/handlers/AdminHandler.d.ts +13 -0
- package/dist/api/handlers/AdminHandler.js +47 -18
- package/dist/api/handlers/AiConfigHandler.d.ts +6 -0
- package/dist/api/handlers/AiConfigHandler.js +28 -0
- package/dist/api/handlers/AiGatewayManagementHandler.js +36 -0
- package/dist/api/runs/RdfRunContextRetriever.d.ts +14 -0
- package/dist/api/runs/RdfRunContextRetriever.js +41 -5
- package/dist/api/runtime.js +2 -1
- package/dist/cli/commands/secret.d.ts +1 -0
- package/dist/cli/commands/secret.js +25 -7
- package/dist/components/components.jsonld +3 -1
- package/dist/components/context.jsonld +53 -1
- package/dist/http/SubgraphSparqlHttpHandler.d.ts +59 -2
- package/dist/http/SubgraphSparqlHttpHandler.js +145 -13
- package/dist/http/SubgraphSparqlHttpHandler.jsonld +37 -0
- package/dist/identity/drizzle/EdgeNodeRepository.d.ts +0 -12
- package/dist/identity/drizzle/EdgeNodeRepository.js +5 -13
- package/dist/index.d.ts +2 -1
- package/dist/index.js +7 -3
- package/dist/logging/log-file.d.ts +17 -0
- package/dist/logging/log-file.js +69 -0
- package/dist/main.js +2 -1
- package/dist/notifications/NotificationChannelSweeper.d.ts +50 -0
- package/dist/notifications/NotificationChannelSweeper.js +131 -0
- package/dist/notifications/NotificationChannelSweeper.jsonld +136 -0
- package/dist/notifications/ReclaimingWebSocket2023Storer.d.ts +25 -0
- package/dist/notifications/ReclaimingWebSocket2023Storer.js +56 -0
- package/dist/notifications/ReclaimingWebSocket2023Storer.jsonld +77 -0
- package/dist/notifications/index.d.ts +2 -0
- package/dist/notifications/index.js +2 -0
- package/dist/runtime/Proxy.d.ts +37 -0
- package/dist/runtime/Proxy.js +88 -16
- package/dist/runtime/bootstrap.js +2 -1
- package/dist/runtime/upgrade/BunNativeUpgradeRelay.d.ts +116 -0
- package/dist/runtime/upgrade/BunNativeUpgradeRelay.js +423 -0
- package/dist/runtime/upgrade/UpgradeHandshake.d.ts +63 -0
- package/dist/runtime/upgrade/UpgradeHandshake.js +199 -0
- package/dist/runtime/upgrade/WebSocketFrames.d.ts +67 -0
- package/dist/runtime/upgrade/WebSocketFrames.js +224 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiApiKeyPool.js +8 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiAuthorizationActions.d.ts +11 -2
- package/node_modules/@undefineds.co/ai-connections/dist/AiAuthorizationActions.js +27 -10
- package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.d.ts +7 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.js +13 -11
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectDialog.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsList.js +10 -6
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.d.ts +15 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.js +29 -3
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMainHeader.js +18 -3
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.d.ts +16 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.js +92 -20
- package/node_modules/@undefineds.co/ai-connections/dist/AiCopyButton.d.ts +35 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiCopyButton.js +45 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.js +71 -11
- package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialRow.js +9 -7
- package/node_modules/@undefineds.co/ai-connections/dist/AiEndpointList.d.ts +23 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiEndpointList.js +24 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.d.ts +13 -4
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.js +35 -38
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayModelsSection.d.ts +21 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayModelsSection.js +51 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiInfoTooltip.d.ts +15 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiInfoTooltip.js +16 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiModelCatalog.d.ts +175 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiModelCatalog.js +133 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiOfferingDetails.js +2 -2
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.js +13 -64
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderHeader.d.ts +21 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderHeader.js +12 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiRowAction.d.ts +15 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiRowAction.js +12 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiSortableCredentialList.js +2 -1
- package/node_modules/@undefineds.co/ai-connections/dist/ai-connections-client.d.ts +7 -0
- package/node_modules/@undefineds.co/ai-connections/dist/ai-connections-client.js +6 -0
- package/node_modules/@undefineds.co/ai-connections/dist/authorization-methods.d.ts +36 -5
- package/node_modules/@undefineds.co/ai-connections/dist/authorization-methods.js +52 -9
- package/node_modules/@undefineds.co/ai-connections/dist/client/normalize.js +30 -3
- package/node_modules/@undefineds.co/ai-connections/dist/client/types.d.ts +21 -1
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/base-adapter.d.ts +1 -3
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/base-adapter.js +3 -7
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/index.cjs +9 -7
- package/node_modules/@undefineds.co/ai-connections/dist/collection-runtime.d.ts +46 -0
- package/node_modules/@undefineds.co/ai-connections/dist/collection-runtime.js +231 -0
- package/node_modules/@undefineds.co/ai-connections/dist/collections.d.ts +119 -0
- package/node_modules/@undefineds.co/ai-connections/dist/collections.js +173 -0
- package/node_modules/@undefineds.co/ai-connections/dist/controller.d.ts +71 -5
- package/node_modules/@undefineds.co/ai-connections/dist/controller.js +285 -16
- package/node_modules/@undefineds.co/ai-connections/dist/credential-labels.d.ts +5 -0
- package/node_modules/@undefineds.co/ai-connections/dist/credential-labels.js +8 -3
- package/node_modules/@undefineds.co/ai-connections/dist/credential-storage.d.ts +59 -0
- package/node_modules/@undefineds.co/ai-connections/dist/credential-storage.js +131 -0
- package/node_modules/@undefineds.co/ai-connections/dist/endpoint-urls.d.ts +15 -0
- package/node_modules/@undefineds.co/ai-connections/dist/endpoint-urls.js +20 -0
- package/node_modules/@undefineds.co/ai-connections/dist/gateway-endpoints.d.ts +14 -0
- package/node_modules/@undefineds.co/ai-connections/dist/gateway-endpoints.js +20 -0
- package/node_modules/@undefineds.co/ai-connections/dist/index.d.ts +8 -0
- package/node_modules/@undefineds.co/ai-connections/dist/index.js +8 -0
- package/node_modules/@undefineds.co/ai-connections/dist/manifest.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/offering-endpoints.d.ts +14 -0
- package/node_modules/@undefineds.co/ai-connections/dist/offering-endpoints.js +17 -0
- package/node_modules/@undefineds.co/ai-connections/dist/provider-catalog.cjs +68 -1
- package/node_modules/@undefineds.co/ai-connections/dist/provider-catalog.d.ts +75 -1
- package/node_modules/@undefineds.co/ai-connections/dist/provider-catalog.js +119 -0
- package/node_modules/@undefineds.co/ai-connections/dist/provider-visuals.d.ts +5 -0
- package/node_modules/@undefineds.co/ai-connections/dist/provider-visuals.js +5 -0
- package/node_modules/@undefineds.co/ai-connections/dist/service-access.js +2 -27
- package/node_modules/@undefineds.co/ai-connections/package.json +1 -0
- package/node_modules/@undefineds.co/extension-sdk/dist/manifest.d.ts +1 -1
- package/node_modules/@undefineds.co/extension-sdk/dist/manifest.js +2 -0
- package/node_modules/@undefineds.co/extension-sdk/dist/web.d.ts +150 -0
- package/node_modules/@undefineds.co/extension-sdk/package.json +2 -1
- package/node_modules/@undefineds.co/models/README.md +1 -1
- package/node_modules/@undefineds.co/models/dist/ai-config/index.d.ts +3 -3
- package/node_modules/@undefineds.co/models/dist/ai-gateway.schema.d.ts +5 -0
- package/node_modules/@undefineds.co/models/dist/ai-gateway.schema.js +9 -0
- package/node_modules/@undefineds.co/models/dist/ai-runtime.repository.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/approval.repository.d.ts +2 -2
- package/node_modules/@undefineds.co/models/dist/audit.presentation.d.ts +2 -2
- package/node_modules/@undefineds.co/models/dist/capture.repository.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/chat-project.repository.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/chat.repository.d.ts +2 -2
- package/node_modules/@undefineds.co/models/dist/control-request.repository.d.ts +2 -2
- package/node_modules/@undefineds.co/models/dist/conversation-share.repository.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/credential.schema.d.ts +12 -0
- package/node_modules/@undefineds.co/models/dist/credential.schema.js +15 -1
- package/node_modules/@undefineds.co/models/dist/discovery/index.d.ts +2 -2
- package/node_modules/@undefineds.co/models/dist/discovery/providers.json +248 -7
- package/node_modules/@undefineds.co/models/dist/discovery/types.d.ts +31 -0
- package/node_modules/@undefineds.co/models/dist/extension/index.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/favorite/index.d.ts +2 -2
- package/node_modules/@undefineds.co/models/dist/fixtures/contracts-chat-contact.d.ts +5 -5
- package/node_modules/@undefineds.co/models/dist/import/index.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/index.d.ts +73 -73
- package/node_modules/@undefineds.co/models/dist/index.js +1 -1
- package/node_modules/@undefineds.co/models/dist/input-request.repository.d.ts +2 -2
- package/node_modules/@undefineds.co/models/dist/knowledge/index.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/message.repository.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/namespaces.js +5 -0
- package/node_modules/@undefineds.co/models/dist/pod-storage-descriptor.d.ts +4815 -26
- package/node_modules/@undefineds.co/models/dist/pod-storage-descriptor.js +482 -132
- package/node_modules/@undefineds.co/models/dist/schema.d.ts +4 -0
- package/node_modules/@undefineds.co/models/dist/session/index.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/settings/index.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/sidecar/persistence-mapping.d.ts +5 -5
- package/node_modules/@undefineds.co/models/dist/thread.repository.d.ts +2 -2
- package/node_modules/@undefineds.co/models/dist/types/message-block.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/vocab/_namespaces.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/vocab/index.d.ts +10 -10
- package/node_modules/@undefineds.co/models/dist/vocab/sidecar.vocab.d.ts +1 -0
- package/node_modules/@undefineds.co/models/dist/vocab/sidecar.vocab.js +1 -0
- package/node_modules/@undefineds.co/models/package.json +4 -2
- package/node_modules/@undefineds.co/pod-collections/README.md +71 -0
- package/node_modules/@undefineds.co/pod-collections/dist/diff.d.ts +85 -0
- package/node_modules/@undefineds.co/pod-collections/dist/diff.js +166 -0
- package/node_modules/@undefineds.co/pod-collections/dist/feed.d.ts +17 -0
- package/node_modules/@undefineds.co/pod-collections/dist/feed.js +27 -0
- package/node_modules/@undefineds.co/pod-collections/dist/index.cjs +1042 -0
- package/node_modules/@undefineds.co/pod-collections/dist/index.d.ts +37 -0
- package/node_modules/@undefineds.co/pod-collections/dist/index.js +89 -0
- package/node_modules/@undefineds.co/pod-collections/dist/layout.d.ts +75 -0
- package/node_modules/@undefineds.co/pod-collections/dist/layout.js +173 -0
- package/node_modules/@undefineds.co/pod-collections/dist/mapping.d.ts +78 -0
- package/node_modules/@undefineds.co/pod-collections/dist/mapping.js +287 -0
- package/node_modules/@undefineds.co/pod-collections/dist/mutations.d.ts +83 -0
- package/node_modules/@undefineds.co/pod-collections/dist/mutations.js +273 -0
- package/node_modules/@undefineds.co/pod-collections/dist/react.d.ts +21 -0
- package/node_modules/@undefineds.co/pod-collections/dist/react.js +22 -0
- package/node_modules/@undefineds.co/pod-collections/dist/read.d.ts +65 -0
- package/node_modules/@undefineds.co/pod-collections/dist/read.js +31 -0
- package/node_modules/@undefineds.co/pod-collections/dist/sync.d.ts +66 -0
- package/node_modules/@undefineds.co/pod-collections/dist/sync.js +260 -0
- package/node_modules/@undefineds.co/pod-collections/dist/types.d.ts +155 -0
- package/node_modules/@undefineds.co/pod-collections/dist/types.js +9 -0
- package/node_modules/@undefineds.co/pod-collections/package.json +42 -0
- package/package.json +15 -7
- package/static/app/assets/main.css +1 -1
- package/static/auth-callback/assets/AiConfigContext-DnQs1ZpW.js +1 -0
- package/static/auth-callback/assets/AiConfigPage-DOtvlxH0.js +1 -0
- package/static/auth-callback/assets/DocumentProcessingPanel-BS2voQgL.js +1 -0
- package/static/auth-callback/assets/IndexLifecyclePanel-Cvt0cJtN.js +1 -0
- package/static/auth-callback/assets/{IndexSubjectPanel-BbUqop4b.js → IndexSubjectPanel-Dhf01GqF.js} +1 -1
- package/static/auth-callback/assets/ModelAssignmentsPanel-BJutWaAF.js +1 -0
- package/static/auth-callback/assets/ModelsPage-BRS0sje3.js +11 -0
- package/static/auth-callback/assets/{NetworkPage-Vp2PrMxs.js → NetworkPage-B3qBfANA.js} +2 -2
- package/static/auth-callback/assets/{PaneListHeader-DY7baSFl.js → PaneListHeader-QQeJGTp4.js} +1 -1
- package/static/auth-callback/assets/SearchIndexingPanel-MyNUSEwT.js +1 -0
- package/static/auth-callback/assets/{StatusSubjectPanel-ArIS-TxT.js → StatusSubjectPanel-DQkEVsFs.js} +1 -1
- package/static/{settings/assets/StatusWorkspace-CoMFRXoV.js → auth-callback/assets/StatusWorkspace-Dkv63Uwk.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsPage-BDvT1NUz.js → SystemSettingsPage-TIsUfX5d.js} +1 -1
- package/static/{dashboard/assets/SystemSettingsSubjectPanel-WaE8mTQi.js → auth-callback/assets/SystemSettingsSubjectPanel-BJWEt2-7.js} +5 -5
- package/static/auth-callback/assets/XpodAiConnectionsPodStore-BJiXm-PF.js +3 -0
- package/static/auth-callback/assets/{activity-D1Dsfa_0.js → activity-5hNeNKnL.js} +1 -1
- package/static/auth-callback/assets/ai-connections-CryuHGKW.js +1 -0
- package/static/auth-callback/assets/{auth-callback-Cmf4hXVZ.js → auth-callback-CAFZ3R0B.js} +6 -6
- package/static/auth-callback/assets/auth-callback-rk080mvG.css +1 -0
- package/static/auth-callback/assets/{badge-CZsHq3Ih.js → badge-CAIPI0CB.js} +1 -1
- package/static/auth-callback/assets/collection-runtime-D9s7h9YA.js +1 -0
- package/static/auth-callback/assets/dialog-BjA109aX.js +1 -0
- package/static/auth-callback/assets/{download-DU9ntlHw.js → download-B3Up5W2G.js} +1 -1
- package/static/auth-callback/assets/{external-link-BfzaaZDx.js → external-link-BTXgSPzB.js} +1 -1
- package/static/auth-callback/assets/index-BppXlxcp.js +41 -0
- package/static/auth-callback/assets/index-CirW4CJf.js +1 -0
- package/static/auth-callback/assets/index-DlLYWOhw.js +4 -0
- package/static/auth-callback/assets/{index-browser-BNFqqC74.js → index-browser-DtU38ni3.js} +1 -1
- package/static/auth-callback/assets/{key-round-BwP3DBWo.js → key-round-CQCOrZ7x.js} +1 -1
- package/static/auth-callback/assets/layout-DB3pMyTl.js +1 -0
- package/static/auth-callback/assets/pod-collections-host-KnnGFZHL.js +8 -0
- package/static/auth-callback/assets/{rotate-ccw-VMwnmyab.js → rotate-ccw-C1zM2KtS.js} +1 -1
- package/static/auth-callback/assets/{skeleton-CoD55rBT.js → skeleton-Cqp7_M9-.js} +1 -1
- package/static/auth-callback/assets/{waypoints-DRo_1Ca7.js → waypoints-Bj6gAUSQ.js} +1 -1
- package/static/auth-callback/assets/{workspace-layout--mcXl3My.js → workspace-layout-DK8mDzrY.js} +1 -1
- package/static/auth-callback/auth-callback.html +2 -2
- package/static/dashboard/assets/AiConfigContext-BsE7MqX8.js +1 -0
- package/static/dashboard/assets/AiConfigPage-DvM-lRXa.js +1 -0
- package/static/dashboard/assets/DocumentProcessingPanel-BPfdlfuf.js +1 -0
- package/static/dashboard/assets/IndexLifecyclePanel--m0AGxvh.js +1 -0
- package/static/dashboard/assets/{IndexSubjectPanel-B2cXwl8X.js → IndexSubjectPanel-Bb7m1k3d.js} +1 -1
- package/static/dashboard/assets/ModelAssignmentsPanel-BLi_zbMa.js +1 -0
- package/static/dashboard/assets/ModelsPage-CxdpgnfR.js +11 -0
- package/static/dashboard/assets/{NetworkPage-DV2V0qWO.js → NetworkPage-BAIPw-D_.js} +2 -2
- package/static/dashboard/assets/{PaneListHeader-D0c1yCFH.js → PaneListHeader-BBCMei0r.js} +1 -1
- package/static/dashboard/assets/SearchIndexingPanel-Ck4Y-xjR.js +1 -0
- package/static/dashboard/assets/{StatusSubjectPanel-oPSECj7i.js → StatusSubjectPanel-D1KWfAXE.js} +1 -1
- package/static/dashboard/assets/{StatusWorkspace-PdovQPKa.js → StatusWorkspace-JbA5gzXx.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsPage-CtNDklkx.js → SystemSettingsPage-BbwQWsSR.js} +1 -1
- package/static/{settings/assets/SystemSettingsSubjectPanel-DExjDo_v.js → dashboard/assets/SystemSettingsSubjectPanel-N117nMt5.js} +5 -5
- package/static/dashboard/assets/XpodAiConnectionsPodStore-CdDOb4SV.js +18 -0
- package/static/dashboard/assets/{activity-B9ylSoyr.js → activity-DX1I96o_.js} +1 -1
- package/static/dashboard/assets/ai-connections-DwCRqOQa.js +1 -0
- package/static/dashboard/assets/{badge-BNbFbpIb.js → badge-k2vhtDqH.js} +1 -1
- package/static/dashboard/assets/collection-runtime-BFQ8teQJ.js +1 -0
- package/static/dashboard/assets/{dashboard-CD-FFVRD.js → dashboard-DWZ-fmCT.js} +4 -4
- package/static/dashboard/assets/dashboard-rk080mvG.css +1 -0
- package/static/dashboard/assets/dialog-1CCw-iHT.js +1 -0
- package/static/dashboard/assets/{download-nOP38LtW.js → download-C6-SNY1q.js} +1 -1
- package/static/dashboard/assets/{external-link-Bh2ewN9E.js → external-link-BgPcZ_j2.js} +1 -1
- package/static/dashboard/assets/index-6LcIUIYO.js +1 -0
- package/static/dashboard/assets/index-D7A8U6Pt.js +41 -0
- package/static/dashboard/assets/index-UD6QOE7H.js +4 -0
- package/static/dashboard/assets/{key-round-bGmguBLv.js → key-round-BOd7Jo0Q.js} +1 -1
- package/static/dashboard/assets/layout-DB3pMyTl.js +1 -0
- package/static/dashboard/assets/pod-collections-host-KnnGFZHL.js +8 -0
- package/static/dashboard/assets/{rotate-ccw-D2x__ODW.js → rotate-ccw-CCgJqsvx.js} +1 -1
- package/static/dashboard/assets/{skeleton-VOqft8WS.js → skeleton-Bc7abAn5.js} +1 -1
- package/static/dashboard/assets/{waypoints-fgRqm4oH.js → waypoints-s-opmJxx.js} +1 -1
- package/static/dashboard/assets/{workspace-layout-DV4dgeHX.js → workspace-layout-DqIQeTBV.js} +1 -1
- package/static/dashboard/dashboard.html +2 -2
- package/static/settings/assets/AiConfigContext-BB9KZySa.js +1 -0
- package/static/settings/assets/AiConfigPage-DGSXUkLs.js +1 -0
- package/static/settings/assets/DocumentProcessingPanel-Da2Re6Rg.js +1 -0
- package/static/settings/assets/IndexLifecyclePanel-BSZuIzgr.js +1 -0
- package/static/settings/assets/{IndexSubjectPanel-BgbI9c-a.js → IndexSubjectPanel-CFd0ay-r.js} +1 -1
- package/static/settings/assets/ModelAssignmentsPanel-CSAryvWJ.js +1 -0
- package/static/settings/assets/ModelsPage-BQwCwLHU.js +11 -0
- package/static/settings/assets/{NetworkPage-C8OA9Mtp.js → NetworkPage-BKymvsQc.js} +2 -2
- package/static/settings/assets/{PaneListHeader-COvlPJWj.js → PaneListHeader-Bjh3hRdQ.js} +1 -1
- package/static/settings/assets/SearchIndexingPanel-MjKL5QLU.js +1 -0
- package/static/settings/assets/{StatusSubjectPanel-BuLml7qn.js → StatusSubjectPanel-Bvl6K4mx.js} +1 -1
- package/static/settings/assets/StatusWorkspace-B0NzrP--.js +1 -0
- package/static/settings/assets/{SystemSettingsPage-DlzmaWV-.js → SystemSettingsPage-D2z6Z4FE.js} +1 -1
- package/static/{auth-callback/assets/SystemSettingsSubjectPanel-CDqRuC4t.js → settings/assets/SystemSettingsSubjectPanel-4sxma4X4.js} +5 -5
- package/static/settings/assets/XpodAiConnectionsPodStore-BkNQ8fZx.js +3 -0
- package/static/settings/assets/{activity-TLerXgMs.js → activity-CgJJGpjx.js} +1 -1
- package/static/settings/assets/ai-connections-CryuHGKW.js +1 -0
- package/static/settings/assets/{badge-Bcs8iWrH.js → badge-C4NypVyT.js} +1 -1
- package/static/settings/assets/collection-runtime-CTLCDxAi.js +1 -0
- package/static/settings/assets/dialog-Csq0vWUi.js +1 -0
- package/static/settings/assets/{download-Ct3QmHPt.js → download-DaLJJ-Wp.js} +1 -1
- package/static/settings/assets/{external-link-C8KiHbss.js → external-link--w_iW5Au.js} +1 -1
- package/static/settings/assets/index-B0mQa59b.js +4 -0
- package/static/settings/assets/index-BukHiu4y.js +1 -0
- package/static/settings/assets/index-COmVnZi2.js +41 -0
- package/static/settings/assets/{index-browser-CazX1pc2.js → index-browser-BGpvHwD0.js} +1 -1
- package/static/settings/assets/{key-round-B19YD1GA.js → key-round-Bk4YRjBu.js} +1 -1
- package/static/settings/assets/layout-DB3pMyTl.js +1 -0
- package/static/settings/assets/pod-collections-host-KnnGFZHL.js +8 -0
- package/static/settings/assets/{rotate-ccw-AQm2kMgU.js → rotate-ccw-TCabbqsr.js} +1 -1
- package/static/settings/assets/{settings-C-VBtt9r.js → settings-CJWpdbNC.js} +5 -5
- package/static/settings/assets/settings-rk080mvG.css +1 -0
- package/static/settings/assets/{skeleton-DyZ1OBYf.js → skeleton-JDHYVe7t.js} +1 -1
- package/static/settings/assets/{waypoints-CC3wq-SU.js → waypoints-DDvEl-MU.js} +1 -1
- package/static/settings/assets/{workspace-layout-BxXNKgf9.js → workspace-layout-DV5QU30U.js} +1 -1
- package/static/settings/settings.html +2 -2
- package/static/auth-callback/assets/AiConfigContext-DqWRSm7n.js +0 -1
- package/static/auth-callback/assets/AiConfigPage-C5YYyvzl.js +0 -1
- package/static/auth-callback/assets/DocumentProcessingPanel-DZCiacBz.js +0 -1
- package/static/auth-callback/assets/IndexLifecyclePanel-CCLeOljB.js +0 -1
- package/static/auth-callback/assets/ModelAssignmentsPanel-jUUTDKuh.js +0 -1
- package/static/auth-callback/assets/ModelsPage-B08zdtff.js +0 -10
- package/static/auth-callback/assets/SearchIndexingPanel-D4YRg1-8.js +0 -1
- package/static/auth-callback/assets/StatusWorkspace-Cp5LQ9Yx.js +0 -1
- package/static/auth-callback/assets/ai-connections-CHNTKemd.js +0 -1
- package/static/auth-callback/assets/auth-callback-DWMMiFjh.css +0 -1
- package/static/auth-callback/assets/index-DSNnLUbU.js +0 -4
- package/static/auth-callback/assets/index-FHhHoKgp.js +0 -41
- package/static/dashboard/assets/AiConfigContext-BpPDKSzI.js +0 -1
- package/static/dashboard/assets/AiConfigPage-wsqEZDIX.js +0 -1
- package/static/dashboard/assets/DocumentProcessingPanel-CDSy3juc.js +0 -1
- package/static/dashboard/assets/IndexLifecyclePanel-CVd6vQCX.js +0 -1
- package/static/dashboard/assets/ModelAssignmentsPanel-BeBZhnQd.js +0 -1
- package/static/dashboard/assets/ModelsPage-B6McSCJw.js +0 -25
- package/static/dashboard/assets/SearchIndexingPanel-CGs0OZ12.js +0 -1
- package/static/dashboard/assets/ai-connections-CHNTKemd.js +0 -1
- package/static/dashboard/assets/dashboard-DWMMiFjh.css +0 -1
- package/static/dashboard/assets/index-PgS-Bt7X.js +0 -41
- package/static/dashboard/assets/index-QN2QgEwr.js +0 -4
- package/static/settings/assets/AiConfigContext-zKQYdfai.js +0 -1
- package/static/settings/assets/AiConfigPage-Bs1EE3Ei.js +0 -1
- package/static/settings/assets/DocumentProcessingPanel-CSFfdOXS.js +0 -1
- package/static/settings/assets/IndexLifecyclePanel-BR9Su49B.js +0 -1
- package/static/settings/assets/ModelAssignmentsPanel-C0BE7nbk.js +0 -1
- package/static/settings/assets/ModelsPage-CU-YQ8_7.js +0 -10
- package/static/settings/assets/SearchIndexingPanel-Bdd46mIV.js +0 -1
- package/static/settings/assets/ai-connections-CHNTKemd.js +0 -1
- package/static/settings/assets/index-1Q2cRjZd.js +0 -41
- package/static/settings/assets/index-DBO_Vq0P.js +0 -4
- package/static/settings/assets/settings-DWMMiFjh.css +0 -1
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { Badge, Button, Input, } from '@undefineds.co/shared-ui';
|
|
4
|
-
import {
|
|
4
|
+
import { RotateCcw, SquareTerminal } from 'lucide-react';
|
|
5
5
|
import { normalizeAiConnectionsThrownError } from './ai-connections-client.js';
|
|
6
6
|
import { getClientAvatar } from './client-visuals.js';
|
|
7
|
+
import { normalizeMessagesEndpoint, normalizeV1Endpoint } from './endpoint-urls.js';
|
|
8
|
+
import { AiCopyButton } from './AiCopyButton.js';
|
|
7
9
|
export const AI_CONNECTIONS_CLIENTS = ['codex', 'claude-code', 'pi', 'codebuddy'];
|
|
8
10
|
export const AI_CLIENT_LABELS = {
|
|
9
11
|
codex: 'Codex',
|
|
@@ -23,12 +25,10 @@ export function AiClientConfigurationSection({ bridge, endpoint, client, createC
|
|
|
23
25
|
const [dryRun, setDryRun] = useState();
|
|
24
26
|
const [confirmationValue, setConfirmationValue] = useState('');
|
|
25
27
|
const [busy, setBusy] = useState(false);
|
|
26
|
-
const [copiedManualConfig, setCopiedManualConfig] = useState(false);
|
|
27
28
|
const autoApplyStarted = useRef(false);
|
|
28
29
|
useEffect(() => {
|
|
29
30
|
setDryRun(undefined);
|
|
30
31
|
setConfirmationValue('');
|
|
31
|
-
setCopiedManualConfig(false);
|
|
32
32
|
if (!bridge) {
|
|
33
33
|
setStatus({ status: 'unavailable' });
|
|
34
34
|
return;
|
|
@@ -149,13 +149,10 @@ export function AiClientConfigurationSection({ bridge, endpoint, client, createC
|
|
|
149
149
|
const confirmationSatisfied = !confirmation?.required || confirmationValue === confirmation.token;
|
|
150
150
|
const clientLabel = AI_CLIENT_LABELS[client];
|
|
151
151
|
const manual = !bridge;
|
|
152
|
-
const
|
|
153
|
-
await navigator.clipboard?.writeText(manualConfigurationText(client, endpoint, manualApiKey));
|
|
154
|
-
setCopiedManualConfig(true);
|
|
155
|
-
};
|
|
152
|
+
const manualConfig = manualConfigurationText(client, endpoint, manualApiKey);
|
|
156
153
|
return (_jsxs("div", { className: compact ? '' : 'overflow-hidden rounded-md border border-border/60', children: [!compact ? _jsxs("div", { className: "flex flex-wrap items-center gap-2 px-3 py-2", children: [_jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground", children: _jsx(AiClientIcon, { client: client }) }), _jsxs("div", { className: "min-w-[10rem] flex-1", children: [_jsx("div", { className: "text-sm font-medium", children: clientLabel }), !manual ? _jsx("div", { className: "mt-0.5 text-xs text-muted-foreground", children: status.message ?? (status.status === 'configured'
|
|
157
154
|
? `${clientLabel} 正在使用 Xpod。`
|
|
158
|
-
: '可自动写入本机配置。') }) : null] }), !manual ? _jsx(Badge, { variant: "secondary", children: statusLabel(status.status) }) : null, manual ? (
|
|
155
|
+
: '可自动写入本机配置。') }) : null] }), !manual ? _jsx(Badge, { variant: "secondary", children: statusLabel(status.status) }) : null, manual ? (_jsx(AiCopyButton, { value: manualConfig, label: `${clientLabel} 配置`, variant: "ghost", size: "icon", iconClassName: "h-4 w-4" })) : (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Button, { variant: "outline", size: "sm", "aria-label": `配置 ${clientLabel}`, disabled: busy, onClick: () => void plan(), children: "\u914D\u7F6E" }), _jsx(Button, { variant: "ghost", size: "icon", "aria-label": `恢复 ${clientLabel} 配置`, disabled: status.status === 'notConfigured' || busy, onClick: () => void restore(), children: _jsx(RotateCcw, { className: "h-4 w-4" }) })] }))] }) : null, compact && busy ? (_jsxs("div", { className: "py-1 text-xs text-muted-foreground", children: ["\u6B63\u5728\u5E94\u7528 ", clientLabel, " \u914D\u7F6E\u2026"] })) : null, compact && !busy && status.message ? (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 py-1 text-xs text-destructive", children: [_jsx("span", { children: status.message }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => void plan(), children: "\u91CD\u8BD5\u5E94\u7528\u914D\u7F6E" })] })) : null, dryRun ? (_jsxs("div", { className: "space-y-3 border-t border-border/60 bg-muted/20 px-4 py-3", children: [_jsx("div", { className: "text-xs font-medium", children: "\u5C06\u6267\u884C\u4EE5\u4E0B\u66F4\u6539" }), dryRun.changes.map((change) => (_jsxs("div", { className: "text-xs text-muted-foreground", children: [_jsx("span", { className: "font-mono", children: change.target }), ' · ', changeActionLabel(change.action), change.backup ? ' · 创建备份' : ''] }, `${change.target}:${change.action}`))), confirmation?.required ? (_jsxs("div", { className: "space-y-2", children: [confirmation.message ? _jsx("div", { className: "text-xs text-muted-foreground", children: confirmation.message }) : null, _jsxs("div", { className: "text-xs text-muted-foreground", children: ["\u786E\u8BA4\u7801\uFF1A", _jsx("code", { className: "font-mono text-foreground", children: confirmation.token })] }), _jsx(Input, { "aria-label": `输入确认码以应用 ${clientLabel} 配置`, value: confirmationValue, onChange: (event) => setConfirmationValue(event.target.value) })] })) : null, _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { size: "sm", "aria-label": confirmation?.required
|
|
159
156
|
? `确认并应用 ${clientLabel} 配置`
|
|
160
157
|
: `应用 ${clientLabel} 配置`, disabled: !createClientCredential || busy || !confirmationSatisfied, onClick: () => void apply(), children: confirmation?.required ? '确认并应用' : '应用配置' }), _jsx(Button, { variant: "ghost", size: "sm", disabled: busy, onClick: () => {
|
|
161
158
|
setDryRun(undefined);
|
|
@@ -179,11 +176,16 @@ function statusLabel(status) {
|
|
|
179
176
|
default: return '未配置';
|
|
180
177
|
}
|
|
181
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* The OpenAI-compatible base a client is pointed at, derived from the Xpod URL.
|
|
181
|
+
* The rule itself is shared with the client-config adapters, so what a copied
|
|
182
|
+
* config claims and what the adapters write cannot drift apart.
|
|
183
|
+
*/
|
|
184
|
+
export const openAiCompatibleBaseUrl = normalizeV1Endpoint;
|
|
182
185
|
export function manualConfigurationText(client, endpoint, apiKey) {
|
|
183
186
|
const secret = apiKey ?? '<粘贴 Xpod API Key>';
|
|
184
|
-
const
|
|
185
|
-
const
|
|
186
|
-
const messagesUrl = baseUrl.replace(/\/v1$/, '');
|
|
187
|
+
const v1Url = normalizeV1Endpoint(endpoint);
|
|
188
|
+
const messagesUrl = normalizeMessagesEndpoint(endpoint);
|
|
187
189
|
switch (client) {
|
|
188
190
|
case 'codex':
|
|
189
191
|
return [
|
|
@@ -33,7 +33,7 @@ export function AiConnectDialog({ controller, definition, offerings, apiOffering
|
|
|
33
33
|
const authorizationError = error?.offeringId === offering.id ? error.authorization : undefined;
|
|
34
34
|
const attemptedMethod = methods.find((method) => method.id === (authorizationError?.authorizationMethodId ?? offeringAttempt?.authorizationMethodId))
|
|
35
35
|
?? activeMethods.find(isOAuthMethod);
|
|
36
|
-
const attemptedMode = authorizationError?.mode ?? offeringAttempt?.mode ?? (attemptedMethod ? connectModeForMethod(attemptedMethod) : modeForOffering(offering
|
|
36
|
+
const attemptedMode = authorizationError?.mode ?? offeringAttempt?.mode ?? (attemptedMethod ? connectModeForMethod(attemptedMethod) : modeForOffering(offering));
|
|
37
37
|
const offeringError = error?.offeringId === offering.id ? error.message : undefined;
|
|
38
38
|
if (offering.lifecycle === 'unavailable' && activeMethods.length === 0) {
|
|
39
39
|
return _jsxs("fieldset", { "data-create-offering": offering.id, className: "space-y-2 border-t border-border/50 pt-3 first:border-t-0 first:pt-0", children: [_jsx("legend", { className: "px-1 text-sm font-medium", children: offeringTitle(offering) }), _jsx("p", { className: "text-xs text-muted-foreground", children: offering.kind === 'oauth-subscription'
|
|
@@ -2,9 +2,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useContext, useRef } from 'react';
|
|
3
3
|
import { Avatar, AvatarFallback, AvatarImage, cn } from '@undefineds.co/shared-ui';
|
|
4
4
|
import { WorkspaceLayoutContext } from '@undefineds.co/extension-sdk/react';
|
|
5
|
-
import { getProviderAvatar, getProviderAvatarBackground } from './provider-visuals.js';
|
|
6
|
-
import { AI_CONNECTIONS_PINNED_SECTIONS, PROVIDERS, useProviderLoadError, useProviderProducts, useProviderSearch, useProviderStates, useSelectedCredentialId, useSelectedProvider, useSelectedSection, } from './controller.js';
|
|
5
|
+
import { XPOD_AVATAR, getProviderAvatar, getProviderAvatarBackground } from './provider-visuals.js';
|
|
6
|
+
import { AI_CONNECTIONS_PINNED_SECTIONS, PROVIDERS, useAvailableProviders, useProviderLoadError, useProviderProducts, useProviderSearch, useProviderStates, useSelectedCredentialId, useSelectedProvider, useSelectedSection, } from './controller.js';
|
|
7
7
|
export function AiConnectionsList({ controller }) {
|
|
8
|
+
const availableProviders = useAvailableProviders(controller);
|
|
8
9
|
const workspace = useContext(WorkspaceLayoutContext);
|
|
9
10
|
const selectedSection = useSelectedSection(controller);
|
|
10
11
|
const selectedProvider = useSelectedProvider(controller);
|
|
@@ -13,7 +14,10 @@ export function AiConnectionsList({ controller }) {
|
|
|
13
14
|
const providerStates = useProviderStates(controller);
|
|
14
15
|
const providerProducts = useProviderProducts(controller);
|
|
15
16
|
const providerLoadError = useProviderLoadError(controller);
|
|
16
|
-
const
|
|
17
|
+
const visibleProviders = availableProviders
|
|
18
|
+
? PROVIDERS.filter((provider) => availableProviders.includes(provider.id))
|
|
19
|
+
: PROVIDERS;
|
|
20
|
+
const providerItems = visibleProviders.reduce((items, provider) => {
|
|
17
21
|
if (provider.id !== 'custom')
|
|
18
22
|
return [...items, { ...provider }];
|
|
19
23
|
const credentials = providerProducts.custom?.credentials ?? [];
|
|
@@ -86,11 +90,11 @@ function moveSelection(items, requestedIndex, controller, optionRefs) {
|
|
|
86
90
|
}
|
|
87
91
|
/**
|
|
88
92
|
* The pinned section is an issued-credential surface, i.e. another provider from
|
|
89
|
-
* the client's point of view, so it
|
|
90
|
-
*
|
|
93
|
+
* the client's point of view, so it carries the Xpod provider mark and falls
|
|
94
|
+
* back to its initials only while that mark is unavailable.
|
|
91
95
|
*/
|
|
92
96
|
function PinnedMark({ section: _section }) {
|
|
93
|
-
return (
|
|
97
|
+
return (_jsxs(Avatar, { className: "h-9 w-9 shrink-0 rounded-md border border-border/20", children: [_jsx(AvatarImage, { src: XPOD_AVATAR, className: "object-cover" }), _jsx(AvatarFallback, { className: "rounded-md bg-muted text-[10px] font-bold uppercase text-muted-foreground", children: "XP" })] }));
|
|
94
98
|
}
|
|
95
99
|
function ProviderStateIndicator({ state, statusId, }) {
|
|
96
100
|
const active = state === 'configured' || state === 'connected';
|
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
import { type AiConnectionsController } from './controller';
|
|
2
|
+
/**
|
|
3
|
+
* The page's live credentials table.
|
|
4
|
+
*
|
|
5
|
+
* `useCredentialRows` subscribes to the controller's snapshot of the collection:
|
|
6
|
+
* the rows it returns already include optimistic writes, so a create/update/
|
|
7
|
+
* delete shows before the Pod has confirmed it, and the projection diff keeps
|
|
8
|
+
* unchanged rows identical. Both the table and the layer that reads it are
|
|
9
|
+
* loaded lazily, so this hook is a plain `useSyncExternalStore` over whatever the
|
|
10
|
+
* controller has - which is nothing until the collection's first read lands.
|
|
11
|
+
*
|
|
12
|
+
* Until then - while the layer is still loading, after a failed first read, or
|
|
13
|
+
* when the host offers no collection at all - `credentialRows` stays undefined
|
|
14
|
+
* and the page keeps rendering what the store reported, so a table that cannot
|
|
15
|
+
* load is never shown as an empty table.
|
|
16
|
+
*/
|
|
2
17
|
export declare function AiConnectionsMain({ controller, renderToaster }: {
|
|
3
18
|
controller: AiConnectionsController;
|
|
4
19
|
renderToaster?: boolean;
|
|
@@ -1,14 +1,35 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { AI_CONNECTIONS_PINNED_SECTIONS, PROVIDERS, useProviderLoadError, useProviderProducts, useProviderSummaries, useSelectedCredentialId, useSelectedProvider, useSelectedSection, } from './controller.js';
|
|
2
|
+
import { AI_CONNECTIONS_PINNED_SECTIONS, PROVIDERS, useLiveRevision, useProviderLoadError, useProviderProducts, useProviderSummaries, useSelectedCredentialId, useSelectedProvider, useSelectedSection, } from './controller.js';
|
|
3
|
+
import { useCredentialRows } from './collections.js';
|
|
3
4
|
import { AiConnectionsPanel } from './AiConnectionsPanel.js';
|
|
4
5
|
import { useEffect } from 'react';
|
|
6
|
+
/**
|
|
7
|
+
* The page's live credentials table.
|
|
8
|
+
*
|
|
9
|
+
* `useCredentialRows` subscribes to the controller's snapshot of the collection:
|
|
10
|
+
* the rows it returns already include optimistic writes, so a create/update/
|
|
11
|
+
* delete shows before the Pod has confirmed it, and the projection diff keeps
|
|
12
|
+
* unchanged rows identical. Both the table and the layer that reads it are
|
|
13
|
+
* loaded lazily, so this hook is a plain `useSyncExternalStore` over whatever the
|
|
14
|
+
* controller has - which is nothing until the collection's first read lands.
|
|
15
|
+
*
|
|
16
|
+
* Until then - while the layer is still loading, after a failed first read, or
|
|
17
|
+
* when the host offers no collection at all - `credentialRows` stays undefined
|
|
18
|
+
* and the page keeps rendering what the store reported, so a table that cannot
|
|
19
|
+
* load is never shown as an empty table.
|
|
20
|
+
*/
|
|
5
21
|
export function AiConnectionsMain({ controller, renderToaster = true }) {
|
|
22
|
+
const liveCredentialRows = useCredentialRows(controller);
|
|
23
|
+
return (_jsx(AiConnectionsMainBody, { controller: controller, renderToaster: renderToaster, liveCredentialRows: liveCredentialRows }));
|
|
24
|
+
}
|
|
25
|
+
function AiConnectionsMainBody({ controller, renderToaster, liveCredentialRows, }) {
|
|
6
26
|
const selectedSection = useSelectedSection(controller);
|
|
7
27
|
const selectedProvider = useSelectedProvider(controller);
|
|
8
28
|
const selectedCredentialId = useSelectedCredentialId(controller);
|
|
9
29
|
const providerSummaries = useProviderSummaries(controller);
|
|
10
30
|
const providerProducts = useProviderProducts(controller);
|
|
11
31
|
const providerLoadError = useProviderLoadError(controller);
|
|
32
|
+
const liveRevision = useLiveRevision(controller);
|
|
12
33
|
const provider = PROVIDERS.find((item) => item.id === selectedProvider);
|
|
13
34
|
const selectedCredential = selectedProvider === 'custom'
|
|
14
35
|
? providerProducts.custom?.credentials.find((credential) => credential.id === selectedCredentialId)
|
|
@@ -28,15 +49,20 @@ export function AiConnectionsMain({ controller, renderToaster = true }) {
|
|
|
28
49
|
},
|
|
29
50
|
}
|
|
30
51
|
: providerProducts;
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
// The open page holds the live subscriptions for the tables it renders, and
|
|
54
|
+
// releases them when it goes away. Re-entrant, so StrictMode is harmless.
|
|
55
|
+
return controller.watchPageTables();
|
|
56
|
+
}, [controller]);
|
|
31
57
|
useEffect(() => {
|
|
32
58
|
if (controller.client)
|
|
33
59
|
void controller.loadProviders();
|
|
34
60
|
return () => controller.cancelProviderLoads();
|
|
35
|
-
}, [controller]);
|
|
61
|
+
}, [controller, liveRevision]);
|
|
36
62
|
if (!controller.client) {
|
|
37
63
|
return (_jsxs("section", { role: "alert", "aria-label": "AI Connections unavailable", children: [_jsx("h2", { children: "AI Connections \u5C1A\u672A\u5C31\u7EEA" }), _jsx("p", { children: "\u5BBF\u4E3B\u9700\u8981\u5148\u63D0\u4F9B\u5DF2\u767B\u5F55\u7684 WebID \u548C\u53EF\u7528\u7684 Pod\u3002" })] }));
|
|
38
64
|
}
|
|
39
|
-
return (_jsx("section", { role: "region", "aria-label": regionLabel, children: _jsx(AiConnectionsPanel, { client: controller.client, renderToaster: renderToaster, clientConfigurationBridge: controller.clientConfigurationBridge, selectedSection: selectedSection, selectedProvider: selectedProvider, selectedCredentialId: selectedCredentialId, openExternal: controller.openExternal, providerSummaries: providerSummaries, providerProducts: scopedProducts, providerLoadError: providerLoadError, providerLoading: !providerProducts[selectedProvider] && !providerLoadError, onProviderStateChange: controller.setProviderState }) }));
|
|
65
|
+
return (_jsx("section", { role: "region", "aria-label": regionLabel, children: _jsx(AiConnectionsPanel, { client: controller.client, renderToaster: renderToaster, clientConfigurationBridge: controller.clientConfigurationBridge, selectedSection: selectedSection, selectedProvider: selectedProvider, selectedCredentialId: selectedCredentialId, openExternal: controller.openExternal, providerSummaries: providerSummaries, providerProducts: scopedProducts, providerLoadError: providerLoadError, providerLoading: !providerProducts[selectedProvider] && !providerLoadError, onProviderStateChange: controller.setProviderState, liveRevision: liveRevision, liveCredentialRows: liveCredentialRows }) }));
|
|
40
66
|
}
|
|
41
67
|
function scopedCustomOfferings(product, credential) {
|
|
42
68
|
if (!credential)
|
|
@@ -1,13 +1,28 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { AI_CONNECTIONS_PINNED_SECTIONS, PROVIDERS, useProviderProducts, useSelectedProvider, useSelectedSection, } from './controller.js';
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { AI_CONNECTIONS_PINNED_SECTIONS, PROVIDERS, useLiveUpdates, useProviderProducts, useSelectedProvider, useSelectedSection, } from './controller.js';
|
|
3
|
+
/** One short line per state; the title carries the explanation. */
|
|
4
|
+
const LIVE_UPDATE_AFFORDANCE = {
|
|
5
|
+
live: {
|
|
6
|
+
label: '实时',
|
|
7
|
+
title: '实时更新已开启:Pod 中的改动会立即反映到本页。',
|
|
8
|
+
dotClass: 'bg-emerald-500',
|
|
9
|
+
},
|
|
10
|
+
unavailable: {
|
|
11
|
+
label: '实时不可用',
|
|
12
|
+
title: '实时更新当前不可用;本页仍会正常读取与操作。',
|
|
13
|
+
dotClass: 'bg-muted-foreground/60',
|
|
14
|
+
},
|
|
15
|
+
};
|
|
3
16
|
export function AiConnectionsMainHeader({ controller, }) {
|
|
4
17
|
const selectedSection = useSelectedSection(controller);
|
|
5
18
|
const selectedProvider = useSelectedProvider(controller);
|
|
6
19
|
const providerProducts = useProviderProducts(controller);
|
|
20
|
+
const liveUpdates = useLiveUpdates(controller);
|
|
7
21
|
const provider = PROVIDERS.find((candidate) => candidate.id === selectedProvider);
|
|
8
22
|
const title = AI_CONNECTIONS_PINNED_SECTIONS.find((item) => item.id === selectedSection)?.title
|
|
9
23
|
?? providerProducts[selectedProvider]?.name
|
|
10
24
|
?? provider?.name
|
|
11
25
|
?? selectedProvider;
|
|
12
|
-
|
|
26
|
+
const liveAffordance = liveUpdates === 'idle' ? undefined : LIVE_UPDATE_AFFORDANCE[liveUpdates];
|
|
27
|
+
return (_jsxs("div", { className: "flex h-full min-w-0 items-center gap-2 px-4", children: [_jsx("h1", { className: "truncate text-sm font-medium text-foreground", children: title }), liveAffordance && (_jsxs("span", { "data-live-updates": liveUpdates, title: liveAffordance.title, "aria-label": liveAffordance.title, className: "ml-auto inline-flex shrink-0 items-center gap-1 text-[10px] font-medium text-muted-foreground", children: [_jsx("span", { "aria-hidden": "true", className: `h-1.5 w-1.5 rounded-full ${liveAffordance.dotClass}` }), liveAffordance.label] }))] }));
|
|
13
28
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type AiConnectionsClient, type AiConnectionsProvider, type AiProviderConnectionSummary, type AiProviderSummary } from './ai-connections-client';
|
|
2
2
|
import { type AiConnectionsWorkspaceSection, type ProviderProductState } from './controller';
|
|
3
3
|
import type { AiClientConfigurationBridge } from './AiClientConfigurationSection';
|
|
4
|
+
import { type CredentialRow } from './collections';
|
|
4
5
|
export interface AiConnectionsPanelProps {
|
|
5
6
|
client: AiConnectionsClient;
|
|
6
7
|
/** Disable when the embedding application already renders shared-ui Toaster. */
|
|
@@ -16,5 +17,19 @@ export interface AiConnectionsPanelProps {
|
|
|
16
17
|
providerLoading?: boolean;
|
|
17
18
|
onProviderStateChange?: (provider: AiConnectionsProvider, state: ProviderProductState) => void;
|
|
18
19
|
onModelSelectionChange?: (provider: AiConnectionsProvider, modelIds: string[]) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Advances when a watched Pod table document changed; the page re-reads the
|
|
22
|
+
* tables it renders through its existing loaders.
|
|
23
|
+
*/
|
|
24
|
+
liveRevision?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Live rows of the credentials table, when the host exposes a collection.
|
|
27
|
+
*
|
|
28
|
+
* Present, every credential list the page renders is rebuilt from these rows
|
|
29
|
+
* (including optimistic writes) instead of from the summary the store read, so
|
|
30
|
+
* one table has one owner. The store's summaries stay the enrichment source
|
|
31
|
+
* for the attributes the descriptor cannot project.
|
|
32
|
+
*/
|
|
33
|
+
liveCredentialRows?: readonly CredentialRow[];
|
|
19
34
|
}
|
|
20
|
-
export declare function AiConnectionsPanel({ client, renderToaster, openExternal, clientConfigurationBridge, selectedSection, selectedProvider, selectedCredentialId, providerSummaries: providerSummariesInput, providerProducts, providerLoadError, providerLoading, onProviderStateChange, onModelSelectionChange, }: AiConnectionsPanelProps): import("react").JSX.Element;
|
|
35
|
+
export declare function AiConnectionsPanel({ client, renderToaster, openExternal, clientConfigurationBridge, selectedSection, selectedProvider, selectedCredentialId, providerSummaries: providerSummariesInput, providerProducts, providerLoadError, providerLoading, onProviderStateChange, onModelSelectionChange, liveRevision, liveCredentialRows, }: AiConnectionsPanelProps): import("react").JSX.Element;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { Toaster, toast, } from '@undefineds.co/shared-ui';
|
|
4
4
|
import { normalizeAiConnectionsThrownError, } from './ai-connections-client.js';
|
|
5
5
|
import { PROVIDERS, } from './controller.js';
|
|
@@ -7,8 +7,10 @@ import { offeringTitle } from './offering-label.js';
|
|
|
7
7
|
import { AiProviderCard, } from './AiProviderCard.js';
|
|
8
8
|
import { AiModelEditorDialog, } from './AiModelEditorDialog.js';
|
|
9
9
|
import { AiGatewayKeysSection } from './AiGatewayKeysSection.js';
|
|
10
|
+
import { credentialCarriers, withLiveCredentials } from './collections.js';
|
|
11
|
+
import { modelCatalogId, withCatalogModelId } from './AiModelCatalog.js';
|
|
10
12
|
const EMPTY_PROVIDER_SUMMARIES = {};
|
|
11
|
-
export function AiConnectionsPanel({ client, renderToaster = true, openExternal = openExternalUrl, clientConfigurationBridge, selectedSection = 'provider', selectedProvider, selectedCredentialId, providerSummaries: providerSummariesInput = EMPTY_PROVIDER_SUMMARIES, providerProducts = {}, providerLoadError, providerLoading = false, onProviderStateChange, onModelSelectionChange, }) {
|
|
13
|
+
export function AiConnectionsPanel({ client, renderToaster = true, openExternal = openExternalUrl, clientConfigurationBridge, selectedSection = 'provider', selectedProvider, selectedCredentialId, providerSummaries: providerSummariesInput = EMPTY_PROVIDER_SUMMARIES, providerProducts = {}, providerLoadError, providerLoading = false, onProviderStateChange, onModelSelectionChange, liveRevision = 0, liveCredentialRows, }) {
|
|
12
14
|
const [connectionStates, setConnectionStates] = useState({});
|
|
13
15
|
const [models, setModels] = useState([]);
|
|
14
16
|
const [gatewayModels, setGatewayModels] = useState();
|
|
@@ -29,10 +31,17 @@ export function AiConnectionsPanel({ client, renderToaster = true, openExternal
|
|
|
29
31
|
const [providerProductOverrides, setProviderProductOverrides] = useState({});
|
|
30
32
|
const pollingGeneration = useRef(0);
|
|
31
33
|
const modelSelectionGeneration = useRef({});
|
|
32
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Credentials come from the live rows whenever the host has a collection for
|
|
36
|
+
* that table; the store's own list is only the enrichment carrier, and an
|
|
37
|
+
* override produced by a mutation is a projection of those same rows, never an
|
|
38
|
+
* independent read. Everything else about a product (offerings, models,
|
|
39
|
+
* status) still comes from the merged products.
|
|
40
|
+
*/
|
|
41
|
+
const effectiveProviderProducts = withLiveCredentials({
|
|
33
42
|
...providerProducts,
|
|
34
43
|
...providerProductOverrides,
|
|
35
|
-
};
|
|
44
|
+
}, credentialCarriers(providerProducts, providerProductOverrides), liveCredentialRows);
|
|
36
45
|
const updateConnectionState = useCallback((provider, state) => {
|
|
37
46
|
setConnectionStates((current) => ({ ...current, [provider]: state }));
|
|
38
47
|
onProviderStateChange?.(provider, productStateFromConnection(state));
|
|
@@ -80,7 +89,7 @@ export function AiConnectionsPanel({ client, renderToaster = true, openExternal
|
|
|
80
89
|
active = false;
|
|
81
90
|
pollingGeneration.current += 1;
|
|
82
91
|
};
|
|
83
|
-
}, [client]);
|
|
92
|
+
}, [client, liveRevision]);
|
|
84
93
|
useEffect(() => {
|
|
85
94
|
let active = true;
|
|
86
95
|
setGatewayModels(undefined);
|
|
@@ -130,14 +139,15 @@ export function AiConnectionsPanel({ client, renderToaster = true, openExternal
|
|
|
130
139
|
setBusy(provider, false);
|
|
131
140
|
}
|
|
132
141
|
};
|
|
142
|
+
/**
|
|
143
|
+
* The provider-level browser entry the legacy connect path still calls.
|
|
144
|
+
*
|
|
145
|
+
* Which ways in exist is offering data, so a definition can no longer name a
|
|
146
|
+
* mode; the only mode left at this level is the API-key flow, which is what
|
|
147
|
+
* this handler starts.
|
|
148
|
+
*/
|
|
133
149
|
const beginBrowserConnect = async (definition) => {
|
|
134
|
-
|
|
135
|
-
return;
|
|
136
|
-
if (definition.browserMode === 'browserAssistedApiKey') {
|
|
137
|
-
await beginApiKey(definition.id);
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
await beginConnectMode(definition.id, definition.browserMode);
|
|
150
|
+
await beginApiKey(definition.id);
|
|
141
151
|
};
|
|
142
152
|
const beginOfferingConnect = async (provider, offering, mode, method) => {
|
|
143
153
|
if (mode === 'browserAssistedApiKey') {
|
|
@@ -651,10 +661,39 @@ export function AiConnectionsPanel({ client, renderToaster = true, openExternal
|
|
|
651
661
|
}
|
|
652
662
|
})();
|
|
653
663
|
}, [client, effectiveProviderProducts, modelSelectionGeneration, models, onModelSelectionChange, selectedCredentialId, selectedModelIds]);
|
|
664
|
+
/** Selection ids a provider currently has, however they were last reported. */
|
|
665
|
+
const selectionIdsFor = useCallback((provider) => (selectedModelIds[provider]
|
|
666
|
+
?? effectiveProviderProducts[provider]?.selectedModels.map(modelSelectionId)
|
|
667
|
+
?? []), [selectedModelIds, effectiveProviderProducts]);
|
|
668
|
+
/**
|
|
669
|
+
* The key a gateway row is selected under.
|
|
670
|
+
*
|
|
671
|
+
* The projection names a model by its id; the Pod stores the selection as the
|
|
672
|
+
* model's resource URI. Selecting by the bare id would therefore compare
|
|
673
|
+
* unequal against everything already stored and resolve to a resource the
|
|
674
|
+
* write cannot find, so the row's own id is used whenever the account has one.
|
|
675
|
+
*/
|
|
676
|
+
const gatewaySelectionId = useCallback((model) => {
|
|
677
|
+
const stored = models.find((candidate) => candidate.provider === model.provider
|
|
678
|
+
&& modelCatalogId(candidate) === modelCatalogId(model));
|
|
679
|
+
return stored ? modelSelectionId(stored) : modelSelectionId(model);
|
|
680
|
+
}, [models]);
|
|
681
|
+
/** The gateway list switches the same selection the provider pages switch. */
|
|
682
|
+
const gatewayModelSelection = useMemo(() => ({
|
|
683
|
+
isSelected: (model) => selectionIdsFor(model.provider).includes(gatewaySelectionId(model)),
|
|
684
|
+
toggle: (model) => {
|
|
685
|
+
const current = selectionIdsFor(model.provider);
|
|
686
|
+
const selectionId = gatewaySelectionId(model);
|
|
687
|
+
void handleModelSelectionChange(model.provider, current.includes(selectionId)
|
|
688
|
+
? current.filter((id) => id !== selectionId)
|
|
689
|
+
: [...current, selectionId]);
|
|
690
|
+
},
|
|
691
|
+
disabled: providerLoading,
|
|
692
|
+
}), [gatewaySelectionId, handleModelSelectionChange, providerLoading, selectionIdsFor]);
|
|
654
693
|
const providerContent = (_jsxs("section", { children: [providerLoadError ? (_jsxs("p", { className: "mb-4 rounded-md border border-destructive/30 px-3 py-2 text-sm text-destructive", children: ["Provider \u72B6\u6001\u8BFB\u53D6\u5931\u8D25\uFF1A", providerLoadError] })) : null, PROVIDERS.filter((definition) => definition.id === (selectedProvider ?? 'openai')).map((definition) => {
|
|
655
694
|
const providerProduct = effectiveProviderProducts[definition.id];
|
|
656
695
|
const providerModels = mergeProviderModelCatalog(models.filter((model) => model.provider === definition.id
|
|
657
|
-
&& (definition.id !== 'custom' || !selectedCredentialId || model.credentialId === selectedCredentialId)), providerProduct?.selectedModels ?? []);
|
|
696
|
+
&& (definition.id !== 'custom' || !selectedCredentialId || model.credentialId === selectedCredentialId)), providerProduct?.selectedModels ?? [], gatewayModels ?? []);
|
|
658
697
|
const providerSelectedModelIds = selectedModelIds[definition.id]
|
|
659
698
|
?? providerProduct?.selectedModels.map(modelSelectionId)
|
|
660
699
|
?? [];
|
|
@@ -666,7 +705,7 @@ export function AiConnectionsPanel({ client, renderToaster = true, openExternal
|
|
|
666
705
|
[definition.id]: value,
|
|
667
706
|
})), onBeginApiKey: () => void beginApiKey(definition.id), onBeginOffering: (offering, mode, method) => void beginOfferingConnect(definition.id, offering, mode, method), onCancelConnect: (attempt) => void cancelConnect(definition.id, attempt), onBeginBrowser: () => void beginBrowserConnect(definition), onSaveApiKey: () => void saveApiKey(definition), onDisconnect: (credential) => void disconnect(definition.id, credential?.id), onCreateApiKeyCredential: (offering, input) => createApiKeyCredential(definition.id, offering, input), onCreateLocalCredential: (offering, method) => createLocalCredential(definition.id, offering, method), onUpdateCredential: (credential, patch) => updateProviderCredential(definition.id, credential, patch), onDeleteCredential: (credential) => void deleteProviderCredential(definition.id, credential), onTestCredential: (credential) => void testProviderCredential(definition.id, credential), onReorderCredentials: (offering, credentials, fromIndex, toIndex) => void reorderProviderCredentials(definition.id, offering, credentials, fromIndex, toIndex), onRefreshQuota: (offering, credential) => void refreshQuota(definition.id, offering, credential), verifyPending: Boolean(verifyingProviders[definition.id]), onVerify: () => void verifyProvider(definition.id), onAddModel: () => openModelEditor(definition.id), onEditModel: (model) => openModelEditor(definition.id, model), onDeleteModel: (model) => void deleteProviderModel(definition.id, model), onModelSelectionChange: handleModelSelectionChange, onDismissError: () => setProviderError(definition.id) }, definition.id));
|
|
668
707
|
})] }));
|
|
669
|
-
const keyContent = (_jsx(AiGatewayKeysSection, { client: client, clientConfigurationBridge: clientConfigurationBridge, gatewayModels: gatewayModels }));
|
|
708
|
+
const keyContent = (_jsx(AiGatewayKeysSection, { client: client, clientConfigurationBridge: clientConfigurationBridge, gatewayModels: gatewayModels, modelSelection: gatewayModelSelection, liveRevision: liveRevision }));
|
|
670
709
|
return (_jsxs("div", { "data-testid": "ai-connections-panel", className: "mx-auto w-full max-w-5xl space-y-10 px-4 py-6 sm:px-8 sm:py-8", children: [renderToaster ? _jsx(Toaster, {}) : null, selectedSection === 'keys' ? keyContent : null, selectedSection === 'provider' ? providerContent : null, selectedSection === 'provider' && modelEditor ? (_jsx(AiModelEditorDialog, { open: true, providerName: PROVIDERS.find((definition) => definition.id === modelEditor.provider)?.name ?? modelEditor.provider, initialValue: modelEditor.model
|
|
671
710
|
? {
|
|
672
711
|
id: modelEditor.model.id,
|
|
@@ -836,6 +875,9 @@ function delay(milliseconds) {
|
|
|
836
875
|
return new Promise((resolve) => window.setTimeout(resolve, milliseconds));
|
|
837
876
|
}
|
|
838
877
|
function errorMessage(error) {
|
|
878
|
+
if (error instanceof TypeError && /failed to fetch|fetch failed|networkerror|load failed/i.test(error.message)) {
|
|
879
|
+
return '暂时无法连接 Xpod,请在连接恢复后确认操作结果,再重试。';
|
|
880
|
+
}
|
|
839
881
|
const message = normalizeAiConnectionsThrownError(error);
|
|
840
882
|
return message === 'AI Connection request failed. Please try again.'
|
|
841
883
|
? '请求未完成。请确认 Xpod 正在运行且登录仍有效,然后重试。'
|
|
@@ -936,22 +978,52 @@ function markMissingSelectedModelsUnavailable(current, provider, selectedModels,
|
|
|
936
978
|
}
|
|
937
979
|
return merged;
|
|
938
980
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
981
|
+
/**
|
|
982
|
+
* Fold the discovered catalog and the Pod's pinned selections into one list.
|
|
983
|
+
*
|
|
984
|
+
* Entries are folded onto the model id they name first (`withCatalogModelId`),
|
|
985
|
+
* so a pinned selection which only carries its stored resource reference lands
|
|
986
|
+
* on the catalog row it belongs to instead of being listed a second time. The
|
|
987
|
+
* two rows still keep their own resource ids: the card collects every
|
|
988
|
+
* `selectionId` it sees, so unpicking the model releases all of them.
|
|
989
|
+
*
|
|
990
|
+
* `projection` carries the capability evidence. Capabilities are not Pod data -
|
|
991
|
+
* a row records what was discovered and nothing more - so they are derived from
|
|
992
|
+
* the model id against the provider catalog, and the Gateway projection is that
|
|
993
|
+
* derivation for the models it publishes.
|
|
994
|
+
*/
|
|
995
|
+
function mergeProviderModelCatalog(catalog, selectedModels, projection = []) {
|
|
996
|
+
const evidence = new Map();
|
|
997
|
+
for (const model of projection) {
|
|
998
|
+
evidence.set(`${model.provider}\0${modelCatalogId(model)}`, model);
|
|
999
|
+
}
|
|
1000
|
+
const withEvidence = (model) => {
|
|
1001
|
+
const source = evidence.get(`${model.provider}\0${modelCatalogId(model)}`);
|
|
1002
|
+
const capabilities = [...new Set([...(model.capabilities ?? []), ...(source?.capabilities ?? [])])];
|
|
1003
|
+
const inputModalities = model.inputModalities ?? source?.inputModalities;
|
|
1004
|
+
if (capabilities.length === 0 && !inputModalities)
|
|
1005
|
+
return model;
|
|
1006
|
+
return compactModel({
|
|
1007
|
+
...model,
|
|
1008
|
+
...(capabilities.length > 0 ? { capabilities } : {}),
|
|
1009
|
+
...(inputModalities ? { inputModalities } : {}),
|
|
1010
|
+
});
|
|
1011
|
+
};
|
|
1012
|
+
const merged = catalog.map((model) => withEvidence(withCatalogModelId(model)));
|
|
1013
|
+
for (const selectedModel of selectedModels.map(withCatalogModelId)) {
|
|
942
1014
|
const index = merged.findIndex((model) => modelSelectionId(model) === modelSelectionId(selectedModel));
|
|
943
1015
|
if (index === -1) {
|
|
944
|
-
merged.push(selectedModel);
|
|
1016
|
+
merged.push(withEvidence(selectedModel));
|
|
945
1017
|
continue;
|
|
946
1018
|
}
|
|
947
|
-
merged[index] = compactModel({
|
|
1019
|
+
merged[index] = withEvidence(compactModel({
|
|
948
1020
|
...merged[index],
|
|
949
1021
|
...selectedModel,
|
|
950
1022
|
displayName: merged[index].displayName ?? selectedModel.displayName,
|
|
951
1023
|
availability: merged[index].availability === 'unavailable'
|
|
952
1024
|
? 'unavailable'
|
|
953
1025
|
: selectedModel.availability,
|
|
954
|
-
});
|
|
1026
|
+
}));
|
|
955
1027
|
}
|
|
956
1028
|
return merged;
|
|
957
1029
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ComponentProps } from 'react';
|
|
2
|
+
import { Button } from '@undefineds.co/shared-ui';
|
|
3
|
+
/**
|
|
4
|
+
* One clipboard affordance for the whole applet: the copied flag, its reset
|
|
5
|
+
* timer, and the "no clipboard access" failure all live here instead of being
|
|
6
|
+
* re-implemented by every caller that hands a value to the user.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useCopyToClipboard(resetMs?: number): {
|
|
9
|
+
copied: boolean;
|
|
10
|
+
copy: (value: string) => Promise<void>;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Copy button carrying the applet's established affordance: a `复制 <what>`
|
|
14
|
+
* accessible name, the visible label swapping to `已复制`, and a check glyph in
|
|
15
|
+
* place of the copy glyph for the length of the feedback window.
|
|
16
|
+
*/
|
|
17
|
+
export declare function AiCopyButton({ value, label, text, title, variant, size, disabled, className, iconClassName, copiedIconClassName, onError, }: {
|
|
18
|
+
/**
|
|
19
|
+
* Text to copy. A function is resolved when the button is pressed, for
|
|
20
|
+
* secrets that only exist for the length of one flow.
|
|
21
|
+
*/
|
|
22
|
+
value: string | (() => string);
|
|
23
|
+
/** What is copied; the accessible name becomes `复制 ${label}`. */
|
|
24
|
+
label: string;
|
|
25
|
+
/** Visible label. Omit for an icon-only button. */
|
|
26
|
+
text?: string;
|
|
27
|
+
title?: string;
|
|
28
|
+
variant?: ComponentProps<typeof Button>['variant'];
|
|
29
|
+
size?: ComponentProps<typeof Button>['size'];
|
|
30
|
+
disabled?: boolean;
|
|
31
|
+
className?: string;
|
|
32
|
+
iconClassName?: string;
|
|
33
|
+
copiedIconClassName?: string;
|
|
34
|
+
onError?: (cause: unknown) => void;
|
|
35
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { Button, cn } from '@undefineds.co/shared-ui';
|
|
4
|
+
import { Check, Copy } from 'lucide-react';
|
|
5
|
+
const CLIPBOARD_UNAVAILABLE = '当前浏览器无法访问剪贴板,请允许剪贴板访问后重试。';
|
|
6
|
+
/**
|
|
7
|
+
* One clipboard affordance for the whole applet: the copied flag, its reset
|
|
8
|
+
* timer, and the "no clipboard access" failure all live here instead of being
|
|
9
|
+
* re-implemented by every caller that hands a value to the user.
|
|
10
|
+
*/
|
|
11
|
+
export function useCopyToClipboard(resetMs = 1500) {
|
|
12
|
+
const [copied, setCopied] = useState(false);
|
|
13
|
+
const timer = useRef(undefined);
|
|
14
|
+
useEffect(() => () => clearTimeout(timer.current), []);
|
|
15
|
+
const copy = useCallback(async (value) => {
|
|
16
|
+
if (!navigator.clipboard?.writeText)
|
|
17
|
+
throw new Error(CLIPBOARD_UNAVAILABLE);
|
|
18
|
+
await navigator.clipboard.writeText(value);
|
|
19
|
+
setCopied(true);
|
|
20
|
+
clearTimeout(timer.current);
|
|
21
|
+
timer.current = setTimeout(() => setCopied(false), resetMs);
|
|
22
|
+
}, [resetMs]);
|
|
23
|
+
return { copied, copy };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Copy button carrying the applet's established affordance: a `复制 <what>`
|
|
27
|
+
* accessible name, the visible label swapping to `已复制`, and a check glyph in
|
|
28
|
+
* place of the copy glyph for the length of the feedback window.
|
|
29
|
+
*/
|
|
30
|
+
export function AiCopyButton({ value, label, text, title, variant = 'outline', size = 'sm', disabled = false, className, iconClassName = 'h-3.5 w-3.5', copiedIconClassName, onError, }) {
|
|
31
|
+
const { copied, copy } = useCopyToClipboard();
|
|
32
|
+
const iconOnly = text === undefined;
|
|
33
|
+
const Icon = copied ? Check : Copy;
|
|
34
|
+
const handleClick = () => {
|
|
35
|
+
void (async () => {
|
|
36
|
+
try {
|
|
37
|
+
await copy(typeof value === 'function' ? value() : value);
|
|
38
|
+
}
|
|
39
|
+
catch (cause) {
|
|
40
|
+
onError?.(cause);
|
|
41
|
+
}
|
|
42
|
+
})();
|
|
43
|
+
};
|
|
44
|
+
return (_jsxs(Button, { type: "button", variant: variant, size: size, disabled: disabled, className: className, "aria-label": `复制 ${label}`, title: title ?? `复制 ${label}`, onClick: handleClick, children: [_jsx(Icon, { "aria-hidden": "true", className: cn(iconClassName, copied && copiedIconClassName) }), _jsx("span", { className: iconOnly ? 'sr-only' : 'ml-1.5', children: copied ? '已复制' : text ?? '复制' })] }));
|
|
45
|
+
}
|