@opengeni/api-router 3.0.1 → 3.1.2
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/dist/access-grant-rls.d.ts +8 -1
- package/dist/admission-trace.d.ts +8 -0
- package/dist/app.d.ts +50 -3
- package/dist/app.js +10 -1
- package/dist/artifact-catalog-cursor.d.ts +1 -0
- package/dist/attached-browser-viewer.d.ts +11 -0
- package/dist/auth/managed-auth-attempt-context.d.ts +2 -0
- package/dist/auth/managed-auth-rate-limits.d.ts +167 -0
- package/dist/auth/managed-auth-session-adapter.d.ts +9 -1
- package/dist/auth/managed-auth.d.ts +72 -5
- package/dist/auth/managed-sign-in-notifications.d.ts +4 -0
- package/dist/auth/new-signups-gate.d.ts +23 -0
- package/dist/auth/signup-funnel-metrics.d.ts +44 -0
- package/dist/azure-live.d.ts +28 -0
- package/dist/browser-action-fences.d.ts +13 -0
- package/dist/browser-controller-authority.d.ts +1 -61
- package/dist/browser-ephemeral.d.ts +5 -0
- package/dist/browser-lost-runtime-end.d.ts +24 -0
- package/dist/browser-state-authority.d.ts +1 -27
- package/dist/chunk-OGQDXVXY.js +18 -0
- package/dist/chunk-OGQDXVXY.js.map +1 -0
- package/dist/{chunk-AJ62T5QN.js → chunk-OT56OY4V.js} +80503 -39869
- package/dist/chunk-OT56OY4V.js.map +1 -0
- package/dist/claude-default-models.d.ts +19 -0
- package/dist/claude-subscription-core.d.ts +50 -0
- package/dist/claude-subscription-oauth.d.ts +36 -0
- package/dist/claude-subscription-profile.d.ts +9 -0
- package/dist/claude-subscription-usage.d.ts +6 -0
- package/dist/claude-workspace-connection.d.ts +15 -0
- package/dist/codemode.d.ts +40 -5
- package/dist/codex-realtime.d.ts +29 -3
- package/dist/codex-session-pointers.d.ts +19 -0
- package/dist/connection-ownership.d.ts +6 -3
- package/dist/controller-data-plane.d.ts +16 -0
- package/dist/credit-promotion-snapshot.d.ts +6 -0
- package/dist/editable-artifact-source-session.d.ts +3 -0
- package/dist/editable-artifact-websocket.d.ts +5 -3
- package/dist/fatal-process-boundary.d.ts +9 -1
- package/dist/github-access.d.ts +7 -1
- package/dist/github-browser-flow.d.ts +1 -1
- package/dist/http/acting-person.d.ts +36 -0
- package/dist/http/api-contract-compat.d.ts +19 -0
- package/dist/http/api-error.d.ts +50 -1
- package/dist/http/auth.d.ts +8 -1
- package/dist/http/cors.d.ts +12 -0
- package/dist/http/deprecation.d.ts +42 -0
- package/dist/http/keyed-admission.d.ts +12 -0
- package/dist/http/local-browser-boundary.d.ts +72 -0
- package/dist/http/metrics-listener.d.ts +22 -0
- package/dist/http/path-identifier.d.ts +17 -0
- package/dist/http/registered-route-label.d.ts +16 -0
- package/dist/http/rejection-telemetry.d.ts +34 -0
- package/dist/http/request-body.d.ts +27 -0
- package/dist/http/request-source.d.ts +41 -3
- package/dist/http/sse.d.ts +12 -1
- package/dist/http/unmatched-route.d.ts +18 -0
- package/dist/http/user-content.d.ts +36 -0
- package/dist/http/variable-sets-removed.d.ts +41 -0
- package/dist/http/websocket-upgrade-dispatch.d.ts +18 -0
- package/dist/index.js +1279 -108
- package/dist/index.js.map +1 -1
- package/dist/integration-connect-metrics.d.ts +35 -0
- package/dist/integration-endpoint-test.d.ts +20 -0
- package/dist/integrations/api-integrations.d.ts +2 -2
- package/dist/integrations/atlassian.d.ts +8 -3
- package/dist/integrations/fiken.d.ts +3 -1
- package/dist/integrations/github-lens-connect.d.ts +37 -66
- package/dist/integrations/google-drive.d.ts +2 -0
- package/dist/integrations/integration-commit-authority.d.ts +13 -0
- package/dist/integrations/marketplace-plugin.d.ts +43 -43
- package/dist/integrations/oauth-client.d.ts +171 -12
- package/dist/integrations/oauth-profiles.d.ts +42 -13
- package/dist/integrations/onepassword-vault-provider.d.ts +9 -0
- package/dist/integrations/slack-bot.d.ts +285 -7
- package/dist/integrations/slack-file-upload-flow.d.ts +62 -0
- package/dist/integrations/slack-interactions.d.ts +89 -10
- package/dist/integrations/slack-mrkdwn.d.ts +41 -0
- package/dist/integrations/slack-routing.d.ts +1 -1
- package/dist/integrations/slack-session-defaults.d.ts +58 -0
- package/dist/integrations/slack-task-file-upload.d.ts +36 -0
- package/dist/integrations/slack-tool-review.d.ts +5 -0
- package/dist/interaction-agent-access.d.ts +13 -8
- package/dist/interaction-agent-version.d.ts +21 -0
- package/dist/interaction-holder-heartbeat.d.ts +5 -0
- package/dist/interaction-metrics.d.ts +27 -2
- package/dist/interaction-route-stages.d.ts +25 -0
- package/dist/interaction-secrets-vault.d.ts +20 -0
- package/dist/interaction-secrets.d.ts +103 -0
- package/dist/mcp/action-catalog-types.d.ts +14 -0
- package/dist/mcp/action-catalog.gen.d.ts +2 -0
- package/dist/mcp/action-descriptions.d.ts +4 -0
- package/dist/mcp/action-schema-imports.gen.d.ts +1 -0
- package/dist/mcp/capability-account-readiness.d.ts +7 -0
- package/dist/mcp/child-read-evidence.d.ts +9 -0
- package/dist/mcp/company-profile-agent-admin.d.ts +12 -0
- package/dist/mcp/contract-input.d.ts +13 -0
- package/dist/mcp/documents.d.ts +2 -0
- package/dist/mcp/first-party-tool-permissions.d.ts +3 -606
- package/dist/mcp/notification-tools.d.ts +26 -0
- package/dist/mcp/orchestration-failure-diagnostic.d.ts +43 -0
- package/dist/mcp/scheduled-task-input.d.ts +1309 -0
- package/dist/mcp/scheduled-task-view.d.ts +217 -3
- package/dist/mcp/secret-tools.d.ts +14 -0
- package/dist/mcp/server.d.ts +108 -5
- package/dist/mcp/session-admin-access-tools.d.ts +33 -0
- package/dist/mcp/session-event-errors.d.ts +28 -0
- package/dist/mcp/session-event-view.d.ts +62 -0
- package/dist/mcp/session-view.d.ts +15 -0
- package/dist/mcp/session-wait.d.ts +18 -0
- package/dist/mcp/site-agent-clamp-tools.d.ts +38 -0
- package/dist/mcp/site-data-tools.d.ts +22 -0
- package/dist/mcp/site-publication-tools.d.ts +19 -0
- package/dist/mcp/site-sql-tools.d.ts +27 -0
- package/dist/mcp-oauth.d.ts +37 -4
- package/dist/model-calls/chat-completions.d.ts +87 -0
- package/dist/model-calls/pending-usage-settlements.d.ts +57 -0
- package/dist/model-calls/service.d.ts +36 -0
- package/dist/model-catalog.d.ts +9 -3
- package/dist/native-push-dispatch.d.ts +69 -0
- package/dist/observability.d.ts +3 -1
- package/dist/organization-mcp.d.ts +82 -0
- package/dist/prepared-mcp-actor.d.ts +77 -0
- package/dist/prepared-mcp-permissions.d.ts +8 -0
- package/dist/routes/analytics-consent.d.ts +26 -0
- package/dist/routes/api-integrations.d.ts +11 -0
- package/dist/routes/api-keys.d.ts +7 -7
- package/dist/routes/automations.d.ts +2 -0
- package/dist/routes/billing.d.ts +59 -0
- package/dist/routes/browser-sessions.d.ts +65 -2
- package/dist/routes/chat-completions.d.ts +11 -0
- package/dist/routes/claude-core-usage.d.ts +20 -0
- package/dist/routes/claude-subscription-accounts.d.ts +3 -0
- package/dist/routes/claude-subscription-oauth.d.ts +3 -0
- package/dist/routes/client-errors.d.ts +182 -0
- package/dist/routes/codex-core.d.ts +401 -0
- package/dist/routes/codex.d.ts +64 -2
- package/dist/routes/computer-sessions.d.ts +6 -1
- package/dist/routes/desktop-distribution.d.ts +32 -0
- package/dist/routes/github-browser-fonts.gen.d.ts +2 -0
- package/dist/routes/github-browser-pages.d.ts +27 -0
- package/dist/routes/inbox.d.ts +13 -0
- package/dist/routes/insights-response-cache.d.ts +10 -0
- package/dist/routes/insights-usage.d.ts +12 -0
- package/dist/routes/insights.d.ts +28 -0
- package/dist/routes/interaction-placement-message.d.ts +7 -0
- package/dist/routes/managed-sign-in-methods.d.ts +6 -0
- package/dist/routes/model-account-choice.d.ts +13 -0
- package/dist/routes/model-account-settings.d.ts +19 -0
- package/dist/routes/native-app-auth.d.ts +12 -0
- package/dist/routes/organization-integration-policy.d.ts +8 -0
- package/dist/routes/organization-integrations.d.ts +6 -0
- package/dist/routes/organization-mcp-connections.d.ts +3 -0
- package/dist/routes/organization-model-defaults.d.ts +9 -0
- package/dist/routes/organization-service-accounts.d.ts +3 -0
- package/dist/routes/personal-api-keys.d.ts +3 -0
- package/dist/routes/session-admin-access.d.ts +3 -0
- package/dist/routes/session-artifact-associations.d.ts +4 -0
- package/dist/routes/session-history-imports.d.ts +20 -0
- package/dist/routes/sessions.d.ts +38 -2
- package/dist/routes/site-data.d.ts +18 -0
- package/dist/routes/site-publishing.d.ts +5 -0
- package/dist/routes/site-runtime.d.ts +31 -0
- package/dist/routes/site-sql.d.ts +16 -0
- package/dist/routes/slack-bot-access.d.ts +3 -0
- package/dist/routes/subscription-account-pools.d.ts +21 -0
- package/dist/routes/subscription-core-http.d.ts +5 -0
- package/dist/routes/subscription-pool-access.d.ts +37 -0
- package/dist/routes/subscription-pool-core.d.ts +153 -0
- package/dist/routes/supergrok.d.ts +6 -6
- package/dist/routes/usage-allowances.d.ts +12 -0
- package/dist/routes/variable-sets-removed.d.ts +2 -0
- package/dist/routes/vault-providers.d.ts +34 -0
- package/dist/routes/vaults.d.ts +3 -0
- package/dist/routes/workspace-integrations.d.ts +35 -0
- package/dist/routes/workspace-model-providers.d.ts +4 -0
- package/dist/routes/workspaces.d.ts +11 -2
- package/dist/sandbox/agent-update.d.ts +64 -0
- package/dist/sandbox/auth-callout.d.ts +8 -0
- package/dist/sandbox/channel-a.d.ts +15 -1
- package/dist/sandbox/enrollment.d.ts +26 -4
- package/dist/sandbox/machine-audience.d.ts +29 -0
- package/dist/sandbox/machines.d.ts +15 -2
- package/dist/sandbox/metrics-ingestion.d.ts +6 -2
- package/dist/sandbox/screen-control.d.ts +85 -0
- package/dist/sandbox/viewer.d.ts +5 -1
- package/dist/sandbox-file-artifacts.d.ts +17 -1
- package/dist/scheduled-task-blockers.d.ts +39 -0
- package/dist/scheduled-task-deletion.d.ts +3 -4
- package/dist/scheduled-task-lifecycle.d.ts +14 -0
- package/dist/secret-answers.d.ts +40 -0
- package/dist/session-create-observability.d.ts +5 -0
- package/dist/session-event-view-36GO3IL7.js +528 -0
- package/dist/session-event-view-36GO3IL7.js.map +1 -0
- package/dist/signed-state-secret.d.ts +18 -0
- package/dist/site-agent-guard.d.ts +53 -0
- package/dist/site-data/operations.d.ts +103 -0
- package/dist/site-data/service.d.ts +203 -0
- package/dist/site-frame-guard.d.ts +32 -0
- package/dist/site-publishing/agent-data-tools.d.ts +84 -0
- package/dist/site-publishing/agent-model.d.ts +58 -0
- package/dist/site-publishing/agent-session.d.ts +16 -0
- package/dist/site-publishing/content-scanner.d.ts +31 -0
- package/dist/site-publishing/edge-sync.d.ts +48 -0
- package/dist/site-publishing/gateway-signature.d.ts +56 -0
- package/dist/site-publishing/limits.d.ts +63 -0
- package/dist/site-publishing/page-tool-authority.d.ts +30 -0
- package/dist/site-publishing/platform-usage.d.ts +113 -0
- package/dist/site-publishing/platform.d.ts +21 -0
- package/dist/site-publishing/readiness.d.ts +62 -0
- package/dist/site-publishing/runtime.d.ts +179 -0
- package/dist/site-publishing/service.d.ts +264 -0
- package/dist/site-publishing/session-events.d.ts +22 -0
- package/dist/site-publishing/session-views.d.ts +36 -0
- package/dist/site-publishing/viewer.d.ts +40 -0
- package/dist/site-session-origin.d.ts +31 -6
- package/dist/site-sql/format.d.ts +47 -0
- package/dist/site-sql/gateway.d.ts +50 -0
- package/dist/site-sql/service.d.ts +213 -0
- package/dist/temporal-schedule-sync.d.ts +26 -0
- package/dist/transcription/billing-refusal.d.ts +8 -0
- package/dist/transcription/normalize.d.ts +23 -0
- package/dist/transcription/providers/azure-mai.d.ts +12 -0
- package/dist/transcription/providers/azure-openai.d.ts +4 -0
- package/dist/transcription/providers/openai.d.ts +16 -0
- package/dist/transcription/providers/subscription-core.d.ts +39 -0
- package/dist/transcription/service.d.ts +10 -1
- package/dist/transcription/wav-duration.d.ts +8 -0
- package/dist/workspace-tool-gateway-attestations.d.ts +37 -0
- package/dist/workspace-tool-gateway-observability.d.ts +16 -0
- package/dist/workspace-tool-gateway-secrets.d.ts +27 -0
- package/dist/workspace-tool-gateway.d.ts +102 -6
- package/dist/workspace-tool-target-fence.d.ts +116 -0
- package/dist/workspace-tool-target.d.ts +225 -0
- package/dist/workspace-webhook-dispatch.d.ts +26 -0
- package/dist/xai-subscription-core.d.ts +60 -0
- package/package.json +25 -20
- package/src/access-grant-rls.ts +64 -14
- package/src/admission-trace.ts +14 -0
- package/src/app.ts +1684 -252
- package/src/artifact-catalog-cursor.ts +1 -0
- package/src/attached-browser-viewer.ts +26 -0
- package/src/auth/managed-auth-attempt-context.ts +9 -0
- package/src/auth/managed-auth-rate-limits.ts +252 -0
- package/src/auth/managed-auth-session-adapter.ts +64 -29
- package/src/auth/managed-auth.ts +303 -35
- package/src/auth/managed-email.ts +18 -1
- package/src/auth/managed-sign-in-notifications.ts +81 -0
- package/src/auth/new-signups-gate.ts +49 -0
- package/src/auth/organization-user-setup.ts +3 -3
- package/src/auth/signup-funnel-metrics.ts +164 -0
- package/src/azure-live.ts +103 -0
- package/src/browser-action-fences.ts +45 -0
- package/src/browser-controller-authority.ts +1 -186
- package/src/browser-ephemeral.ts +39 -0
- package/src/browser-lost-runtime-end.ts +71 -0
- package/src/browser-state-authority.ts +1 -236
- package/src/claude-default-models.ts +37 -0
- package/src/claude-subscription-core.ts +154 -0
- package/src/claude-subscription-oauth.ts +352 -0
- package/src/claude-subscription-profile.ts +73 -0
- package/src/claude-subscription-usage.ts +51 -0
- package/src/claude-workspace-connection.ts +82 -0
- package/src/codemode.ts +236 -39
- package/src/codex-realtime.ts +181 -53
- package/src/codex-session-pointers.ts +80 -0
- package/src/company-brain-okf.ts +1 -1
- package/src/connected-machine-computer-access.ts +2 -1
- package/src/connection-ownership.ts +19 -13
- package/src/controller-data-plane.ts +34 -0
- package/src/credit-promotion-snapshot.ts +36 -0
- package/src/editable-artifact-production.ts +10 -0
- package/src/editable-artifact-source-session.ts +123 -0
- package/src/editable-artifact-websocket.ts +16 -3
- package/src/fatal-process-boundary.ts +67 -3
- package/src/gateway-realtime.ts +12 -8
- package/src/github-access.ts +31 -5
- package/src/github-browser-flow.ts +1 -1
- package/src/http/acting-person.ts +105 -0
- package/src/http/api-contract-compat.ts +49 -0
- package/src/http/api-error.ts +210 -2
- package/src/http/auth.ts +68 -4
- package/src/http/cors.ts +37 -5
- package/src/http/deprecation.ts +118 -0
- package/src/http/keyed-admission.ts +29 -0
- package/src/http/local-browser-boundary.ts +343 -0
- package/src/http/metrics-listener.ts +57 -0
- package/src/http/path-identifier.ts +54 -0
- package/src/http/registered-route-label.ts +34 -0
- package/src/http/rejection-telemetry.ts +120 -0
- package/src/http/request-body.ts +127 -0
- package/src/http/request-source.ts +154 -13
- package/src/http/sse.ts +88 -28
- package/src/http/unmatched-route.ts +60 -0
- package/src/http/user-content.ts +158 -0
- package/src/http/variable-sets-removed.ts +122 -0
- package/src/http/websocket-upgrade-dispatch.ts +29 -0
- package/src/index.ts +107 -57
- package/src/integration-connect-metrics.ts +228 -0
- package/src/integration-endpoint-test.ts +291 -0
- package/src/integrations/api-integrations.ts +81 -7
- package/src/integrations/atlassian.ts +202 -83
- package/src/integrations/fiken.ts +66 -38
- package/src/integrations/github-app-connect.ts +64 -18
- package/src/integrations/github-lens-connect.ts +8 -29
- package/src/integrations/google-drive.ts +448 -152
- package/src/integrations/integration-commit-authority.ts +69 -0
- package/src/integrations/marketplace-plugin.ts +1 -1
- package/src/integrations/oauth-client.ts +733 -193
- package/src/integrations/oauth-profiles.ts +116 -45
- package/src/integrations/onepassword-vault-provider.ts +16 -0
- package/src/integrations/personal-github-repositories.ts +1 -1
- package/src/integrations/personal-github.ts +61 -35
- package/src/integrations/provider-oauth.ts +67 -85
- package/src/integrations/slack-app-home.ts +5 -5
- package/src/integrations/slack-bot.ts +893 -201
- package/src/integrations/slack-file-upload-flow.ts +147 -0
- package/src/integrations/slack-install.ts +7 -7
- package/src/integrations/slack-interactions.ts +1589 -299
- package/src/integrations/slack-mrkdwn.ts +193 -0
- package/src/integrations/slack-routing.ts +2 -2
- package/src/integrations/slack-session-defaults.ts +224 -0
- package/src/integrations/slack-task-file-upload.ts +323 -0
- package/src/integrations/slack-tool-review.ts +65 -0
- package/src/integrations/social-oauth.ts +90 -58
- package/src/interaction-agent-access.ts +40 -20
- package/src/interaction-agent-version.ts +85 -0
- package/src/interaction-holder-heartbeat.ts +24 -8
- package/src/interaction-metrics.ts +164 -2
- package/src/interaction-route-stages.ts +94 -0
- package/src/interaction-secrets-vault.ts +213 -0
- package/src/interaction-secrets.ts +426 -0
- package/src/mcp/action-catalog-types.ts +14 -0
- package/src/mcp/action-catalog.gen.ts +8014 -0
- package/src/mcp/action-descriptions.ts +299 -0
- package/src/mcp/action-schema-imports.gen.ts +304 -0
- package/src/mcp/capability-account-readiness.ts +17 -0
- package/src/mcp/child-read-evidence.ts +19 -0
- package/src/mcp/company-profile-agent-admin.ts +13 -0
- package/src/mcp/contract-input.ts +165 -0
- package/src/mcp/documents.ts +9 -2
- package/src/mcp/editable-artifacts.ts +29 -11
- package/src/mcp/files.ts +5 -1
- package/src/mcp/first-party-tool-permissions.ts +7 -285
- package/src/mcp/knowledge-entries.ts +108 -34
- package/src/mcp/notification-tools.ts +480 -0
- package/src/mcp/orchestration-failure-diagnostic.ts +43 -0
- package/src/mcp/scheduled-task-input.ts +89 -0
- package/src/mcp/scheduled-task-view.ts +63 -3
- package/src/mcp/secret-tools.ts +185 -0
- package/src/mcp/server.ts +2213 -1116
- package/src/mcp/session-admin-access-tools.ts +163 -0
- package/src/mcp/session-event-errors.ts +123 -0
- package/src/mcp/session-event-view.ts +395 -13
- package/src/mcp/session-view.ts +3 -0
- package/src/mcp/session-wait.ts +67 -7
- package/src/mcp/site-agent-clamp-tools.ts +140 -0
- package/src/mcp/site-data-tools.ts +339 -0
- package/src/mcp/site-publication-tools.ts +201 -0
- package/src/mcp/site-sql-tools.ts +427 -0
- package/src/mcp-oauth.ts +635 -45
- package/src/model-calls/chat-completions.ts +352 -0
- package/src/model-calls/pending-usage-settlements.ts +125 -0
- package/src/model-calls/service.ts +694 -0
- package/src/model-catalog.ts +68 -17
- package/src/native-push-dispatch.ts +457 -0
- package/src/observability.ts +15 -1
- package/src/organization-mcp.ts +485 -0
- package/src/prepared-mcp-actor.ts +154 -0
- package/src/prepared-mcp-permissions.ts +38 -0
- package/src/routes/analytics-consent.ts +123 -0
- package/src/routes/api-integrations.ts +268 -9
- package/src/routes/api-keys.ts +164 -25
- package/src/routes/artifact-catalog.ts +111 -0
- package/src/routes/automations.ts +163 -90
- package/src/routes/billing.ts +535 -59
- package/src/routes/browser-sessions.ts +966 -342
- package/src/routes/canonical-human-identities.ts +61 -0
- package/src/routes/capabilities.ts +112 -5
- package/src/routes/channels.ts +4 -3
- package/src/routes/chat-completions.ts +235 -0
- package/src/routes/claude-core-usage.ts +147 -0
- package/src/routes/claude-subscription-accounts.ts +233 -0
- package/src/routes/claude-subscription-oauth.ts +175 -0
- package/src/routes/client-errors.ts +394 -0
- package/src/routes/codex-core.ts +687 -0
- package/src/routes/codex.ts +1277 -1119
- package/src/routes/company-brain.ts +4 -0
- package/src/routes/computer-sessions.ts +319 -85
- package/src/routes/connect.ts +277 -175
- package/src/routes/connections.ts +690 -363
- package/src/routes/desktop-distribution.ts +217 -0
- package/src/routes/documents.ts +13 -7
- package/src/routes/editable-artifacts.ts +74 -4
- package/src/routes/enrollments.ts +110 -16
- package/src/routes/external-identity-links.ts +13 -12
- package/src/routes/files.ts +41 -16
- package/src/routes/github-browser-fonts.gen.ts +12 -0
- package/src/routes/github-browser-pages.ts +258 -0
- package/src/routes/github.ts +200 -75
- package/src/routes/inbox.ts +353 -0
- package/src/routes/insights-response-cache.ts +83 -0
- package/src/routes/insights-usage.ts +345 -0
- package/src/routes/insights.ts +103 -8
- package/src/routes/install.ts +51 -10
- package/src/routes/integration-facets.ts +70 -28
- package/src/routes/interaction-placement-message.ts +12 -0
- package/src/routes/knowledge.ts +136 -27
- package/src/routes/machines.ts +189 -135
- package/src/routes/managed-auth-session-sets.ts +43 -10
- package/src/routes/managed-onboarding.ts +39 -19
- package/src/routes/managed-sign-in-methods.ts +433 -0
- package/src/routes/memory-slack-publications.ts +3 -2
- package/src/routes/model-account-choice.ts +194 -0
- package/src/routes/model-account-settings.ts +235 -0
- package/src/routes/model-connection-access.ts +210 -48
- package/src/routes/native-app-auth.ts +296 -0
- package/src/routes/organization-integration-policy.ts +116 -0
- package/src/routes/organization-integrations.ts +326 -0
- package/src/routes/organization-mcp-connections.ts +183 -0
- package/src/routes/organization-memberships.ts +205 -19
- package/src/routes/organization-model-defaults.ts +110 -0
- package/src/routes/organization-model-providers.ts +74 -3
- package/src/routes/organization-service-accounts.ts +128 -0
- package/src/routes/organization-sessions.ts +21 -5
- package/src/routes/personal-api-keys.ts +184 -0
- package/src/routes/personal-github-git-broker.ts +2 -2
- package/src/routes/personal-github.ts +9 -4
- package/src/routes/plugins.ts +46 -7
- package/src/routes/pr-review-github.ts +105 -118
- package/src/routes/pr-review.ts +88 -82
- package/src/routes/preference-registry.ts +18 -0
- package/src/routes/rigs.ts +48 -13
- package/src/routes/scheduled-tasks.ts +347 -27
- package/src/routes/session-admin-access.ts +271 -0
- package/src/routes/session-artifact-associations.ts +164 -0
- package/src/routes/session-history-imports.ts +305 -0
- package/src/routes/sessions.ts +1682 -363
- package/src/routes/site-data.ts +340 -0
- package/src/routes/site-publishing.ts +584 -0
- package/src/routes/site-runtime.ts +1944 -0
- package/src/routes/site-sql.ts +263 -0
- package/src/routes/skill-content.ts +72 -7
- package/src/routes/skills.ts +5 -4
- package/src/routes/slack-bot-access.ts +108 -0
- package/src/routes/social.ts +27 -15
- package/src/routes/subscription-account-pools.ts +209 -0
- package/src/routes/subscription-core-http.ts +18 -0
- package/src/routes/subscription-pool-access.ts +180 -0
- package/src/routes/subscription-pool-core.ts +552 -0
- package/src/routes/supergrok.ts +174 -655
- package/src/routes/transcription-recordings.ts +71 -4
- package/src/routes/transcriptions.ts +26 -2
- package/src/routes/usage-allowances.ts +381 -0
- package/src/routes/variable-sets-removed.ts +19 -0
- package/src/routes/vault-providers.ts +782 -0
- package/src/routes/vaults.ts +421 -0
- package/src/routes/video-generation.ts +30 -12
- package/src/routes/workspace-artifacts.ts +165 -53
- package/src/routes/workspace-integrations.ts +576 -0
- package/src/routes/workspace-model-providers.ts +148 -0
- package/src/routes/workspace-state.ts +4 -0
- package/src/routes/workspaces.ts +625 -117
- package/src/sandbox/agent-update.ts +315 -0
- package/src/sandbox/auth-callout.ts +104 -21
- package/src/sandbox/channel-a.ts +165 -55
- package/src/sandbox/enrollment.ts +131 -22
- package/src/sandbox/machine-audience.ts +192 -0
- package/src/sandbox/machines.ts +75 -31
- package/src/sandbox/metrics-ingestion.ts +133 -2
- package/src/sandbox/rematerialize.ts +51 -21
- package/src/sandbox/screen-control.ts +289 -0
- package/src/sandbox/viewer.ts +33 -58
- package/src/sandbox-file-artifacts.ts +53 -27
- package/src/scheduled-task-blockers.ts +293 -0
- package/src/scheduled-task-deletion.ts +13 -3
- package/src/scheduled-task-lifecycle.ts +84 -0
- package/src/secret-answers.ts +119 -0
- package/src/session-create-observability.ts +46 -0
- package/src/session-realtime-context.ts +26 -4
- package/src/signed-state-secret.ts +58 -0
- package/src/site-agent-guard.ts +261 -0
- package/src/site-data/operations.ts +777 -0
- package/src/site-data/service.ts +1043 -0
- package/src/site-frame-guard.ts +107 -0
- package/src/site-publishing/agent-data-tools.ts +250 -0
- package/src/site-publishing/agent-model.ts +127 -0
- package/src/site-publishing/agent-session.ts +148 -0
- package/src/site-publishing/content-scanner.ts +93 -0
- package/src/site-publishing/edge-sync.ts +148 -0
- package/src/site-publishing/gateway-signature.ts +198 -0
- package/src/site-publishing/limits.ts +315 -0
- package/src/site-publishing/page-tool-authority.ts +111 -0
- package/src/site-publishing/platform-usage.ts +479 -0
- package/src/site-publishing/platform.ts +98 -0
- package/src/site-publishing/readiness.ts +330 -0
- package/src/site-publishing/runtime.ts +831 -0
- package/src/site-publishing/service.ts +1282 -0
- package/src/site-publishing/session-events.ts +262 -0
- package/src/site-publishing/session-views.ts +262 -0
- package/src/site-publishing/viewer.ts +75 -0
- package/src/site-session-origin.ts +91 -6
- package/src/site-sql/format.ts +134 -0
- package/src/site-sql/gateway.ts +168 -0
- package/src/site-sql/service.ts +1636 -0
- package/src/site-uploads.ts +27 -5
- package/src/temporal-schedule-sync.ts +74 -0
- package/src/transcription/billing-refusal.ts +14 -0
- package/src/transcription/normalize.ts +77 -0
- package/src/transcription/providers/azure-mai.ts +98 -0
- package/src/transcription/providers/azure-openai.ts +16 -7
- package/src/transcription/providers/codex-subscription.ts +190 -67
- package/src/transcription/providers/openai.ts +79 -5
- package/src/transcription/providers/subscription-core.ts +125 -0
- package/src/transcription/providers/xai-subscription.ts +81 -83
- package/src/transcription/segmenter.ts +7 -1
- package/src/transcription/service.ts +239 -10
- package/src/transcription/wav-duration.ts +39 -0
- package/src/workspace-deletion.ts +25 -1
- package/src/workspace-tool-gateway-attestations.ts +133 -0
- package/src/workspace-tool-gateway-observability.ts +64 -0
- package/src/workspace-tool-gateway-secrets.ts +104 -0
- package/src/workspace-tool-gateway.ts +921 -103
- package/src/workspace-tool-target-fence.ts +380 -0
- package/src/workspace-tool-target.ts +554 -0
- package/src/workspace-webhook-dispatch.ts +225 -0
- package/src/xai-realtime.ts +85 -81
- package/src/xai-subscription-core.ts +172 -0
- package/dist/browser-auth-broker.d.ts +0 -20
- package/dist/chunk-AJ62T5QN.js.map +0 -1
- package/dist/connection-authority-owner.d.ts +0 -59
- package/dist/routes/connection-authorities.d.ts +0 -3
- package/dist/routes/environments.d.ts +0 -5
- package/dist/routes/host-mcp-bindings.d.ts +0 -5
- package/dist/routes/host-mcp-resolvers.d.ts +0 -3
- package/dist/routes/packs.d.ts +0 -3
- package/dist/session-event-view-MU3HMNV3.js +0 -264
- package/dist/session-event-view-MU3HMNV3.js.map +0 -1
- package/dist/xai-subscription-auth.d.ts +0 -23
- package/src/browser-auth-broker.ts +0 -155
- package/src/connection-authority-owner.ts +0 -61
- package/src/routes/connection-authorities.ts +0 -139
- package/src/routes/environments.ts +0 -388
- package/src/routes/host-mcp-bindings.ts +0 -122
- package/src/routes/host-mcp-resolvers.ts +0 -41
- package/src/routes/packs.ts +0 -784
- package/src/xai-subscription-auth.ts +0 -139
package/src/routes/workspaces.ts
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
import { AZURE_LIVE_MODEL_ID } from "../azure-live";
|
|
2
|
+
import {
|
|
3
|
+
createRealtimeVoiceBilling,
|
|
4
|
+
deploymentRealtimeVoice,
|
|
5
|
+
realtimeVoiceOfferProblem,
|
|
6
|
+
} from "@opengeni/core";
|
|
7
|
+
import { withDirectModelProviders, workspaceModelCompactionPolicy } from "@opengeni/config";
|
|
8
|
+
import { listConnectionsMetadata } from "@opengeni/db";
|
|
9
|
+
import {
|
|
10
|
+
workspaceProviderApiKeyConnectionMetadataFromConnections,
|
|
11
|
+
listWorkspaceProviderCustomModelsByKind,
|
|
12
|
+
getOrganizationModelProviderCatalogForWorkspace,
|
|
13
|
+
type WorkspaceCustomModelProviderKind,
|
|
14
|
+
} from "@opengeni/db";
|
|
15
|
+
import { CLAUDE_CONNECTION_KINDS, type ClaudeConnectionCatalog } from "@opengeni/config";
|
|
1
16
|
import { SessionControlConflictError, WorkspacePauseTimerInputError } from "@opengeni/db";
|
|
2
17
|
import { updateWorkspaceSettingsWithToolDefaults } from "@opengeni/db/workspace-tool-defaults";
|
|
3
18
|
import { WorkspacePauseTimerRequest } from "@opengeni/contracts";
|
|
@@ -17,6 +32,7 @@ import {
|
|
|
17
32
|
DeleteWorkspaceGatewayCustomModelRequest,
|
|
18
33
|
DeleteWorkspaceOpenRouterCustomModelRequest,
|
|
19
34
|
UpdateWorkspaceModelPolicyRequest,
|
|
35
|
+
WorkspaceModelPolicyResponse,
|
|
20
36
|
UpdateWorkspaceRequest,
|
|
21
37
|
UpdateWorkspaceSettingsRequest,
|
|
22
38
|
WORKSPACE_CONTROL_ACTOR_MAX_BYTES,
|
|
@@ -25,6 +41,9 @@ import {
|
|
|
25
41
|
WorkspaceGatewayCustomModelsResponse,
|
|
26
42
|
WorkspaceOpenRouterCustomModel,
|
|
27
43
|
WorkspaceOpenRouterCustomModelsResponse,
|
|
44
|
+
WorkspaceOpperCustomModelsResponse,
|
|
45
|
+
CreateWorkspaceOpperCustomModelRequest,
|
|
46
|
+
DeleteWorkspaceOpperCustomModelRequest,
|
|
28
47
|
WorkspaceRealtimeModelCatalogResponse,
|
|
29
48
|
WorkspaceInferenceControlRequest,
|
|
30
49
|
Workspace,
|
|
@@ -36,13 +55,20 @@ import {
|
|
|
36
55
|
type WorkspaceMemberCandidate,
|
|
37
56
|
type WorkspaceMember as WorkspaceMemberValue,
|
|
38
57
|
} from "@opengeni/contracts";
|
|
58
|
+
import { loadWorkspaceCodexCatalogReadiness } from "@opengeni/core";
|
|
39
59
|
import {
|
|
40
60
|
allWorkspacePermissions,
|
|
61
|
+
getBillingBalance,
|
|
62
|
+
spendableCreditMicros,
|
|
41
63
|
createWorkspace,
|
|
42
64
|
ensureWorkspaceByExternalIdentity,
|
|
43
65
|
findWorkspaceByExternalIdentity,
|
|
44
66
|
getManagedUserProfilesByIds,
|
|
67
|
+
getWorkspace,
|
|
45
68
|
getWorkspaceModelPolicy,
|
|
69
|
+
getWorkspaceModelPolicyLayers,
|
|
70
|
+
getOrganizationModelDefaults,
|
|
71
|
+
deleteWorkspaceModelPolicy,
|
|
46
72
|
grantWorkspaceAccess,
|
|
47
73
|
listWorkspaceMembers,
|
|
48
74
|
listWorkspaceMemberManagementCandidates,
|
|
@@ -67,18 +93,21 @@ import {
|
|
|
67
93
|
updateWorkspace,
|
|
68
94
|
upsertWorkspaceMemberAsWorkspaceManager,
|
|
69
95
|
upsertWorkspaceModelPolicy,
|
|
70
|
-
|
|
96
|
+
readCodexCutoverDisposition,
|
|
97
|
+
listSubscriptionCoreCodexOperationCandidates,
|
|
71
98
|
workspaceControlRequestLockTimeoutMs,
|
|
72
|
-
workspaceXaiSubscriptionActive,
|
|
73
99
|
workspaceVercelAiGatewayConnectionActive,
|
|
74
|
-
workspaceOpenRouterConnectionActive,
|
|
75
|
-
organizationModelProviderConnectionActiveForWorkspace,
|
|
76
|
-
listOrganizationModelProviderCustomModelsForWorkspace,
|
|
77
100
|
WorkspaceGatewayCustomModelHistoryLimitError,
|
|
78
101
|
WorkspaceOpenRouterCustomModelHistoryLimitError,
|
|
79
102
|
WorkspaceExternalIdentityConflictError,
|
|
80
103
|
WorkspaceGatewayCustomModelLimitError,
|
|
81
104
|
WorkspaceOpenRouterCustomModelLimitError,
|
|
105
|
+
WorkspaceOpperCustomModelLimitError,
|
|
106
|
+
WorkspaceOpperCustomModelHistoryLimitError,
|
|
107
|
+
listWorkspaceProviderCustomModels,
|
|
108
|
+
createWorkspaceProviderCustomModel,
|
|
109
|
+
deleteWorkspaceProviderCustomModel,
|
|
110
|
+
replayWorkspaceProviderCustomModelCreate,
|
|
82
111
|
WorkspaceLimitExceededError,
|
|
83
112
|
} from "@opengeni/db";
|
|
84
113
|
import { boundWorkspaceControlHttpPage } from "@opengeni/events";
|
|
@@ -87,14 +116,26 @@ import { HTTPException } from "hono/http-exception";
|
|
|
87
116
|
import {
|
|
88
117
|
getManagedAuthRequestActorEpoch,
|
|
89
118
|
accountScopedApiKeyWorkspaceAuthority,
|
|
119
|
+
organizationWorkspaceInScope,
|
|
90
120
|
hasPermission,
|
|
91
121
|
requireAccessContext,
|
|
122
|
+
requireApiKeyDelegationContext,
|
|
123
|
+
requireExplicitPermissionDelegation,
|
|
124
|
+
isDeveloperSetupApiKeyContext,
|
|
92
125
|
listExternalActorWorkspaces,
|
|
93
126
|
addExternalWorkspaceMemberForRequest,
|
|
94
127
|
requireAccessGrant,
|
|
128
|
+
requireWorkspaceMemberManagementAuthority,
|
|
95
129
|
requireWorkspaceSettingsGrant,
|
|
96
130
|
requireFreshAccessGrant,
|
|
97
131
|
resolveWorkspaceCatalogSettings,
|
|
132
|
+
creditsDefaultSessionModel,
|
|
133
|
+
loadCoreRoutedXaiCatalogReadiness,
|
|
134
|
+
loadWorkspaceClaudeSubscriptionReadiness,
|
|
135
|
+
loadCoreRoutedClaudeCatalogReadiness,
|
|
136
|
+
withCoreRoutedXaiRestriction,
|
|
137
|
+
resolveDefaultSessionModelForSelections,
|
|
138
|
+
resolveWorkspaceModelSelection,
|
|
98
139
|
} from "@opengeni/core";
|
|
99
140
|
import { requireLimit } from "@opengeni/core";
|
|
100
141
|
import type { ApiRouteDeps } from "@opengeni/core";
|
|
@@ -107,7 +148,7 @@ import {
|
|
|
107
148
|
import { boundedLimit } from "../http/common";
|
|
108
149
|
import { ApiHttpError } from "../http/api-error";
|
|
109
150
|
import { browserSseDeliveryOptions, sseWorkspaceControlStream } from "../http/sse";
|
|
110
|
-
import {
|
|
151
|
+
import { projectWorkspaceModelCatalog } from "../model-catalog";
|
|
111
152
|
import { deleteWorkspaceForRequest } from "../workspace-deletion";
|
|
112
153
|
import {
|
|
113
154
|
AI_GATEWAY_REALTIME_MODELS,
|
|
@@ -120,10 +161,17 @@ import {
|
|
|
120
161
|
configuredModelInputIdentities,
|
|
121
162
|
configuredOpenRouterUpstreamModelIds,
|
|
122
163
|
configuredOpenRouterWorkspaceProductModelIds,
|
|
164
|
+
configuredOpperUpstreamModelIds,
|
|
165
|
+
configuredOpperWorkspaceProductModelIds,
|
|
166
|
+
WORKSPACE_OPPER_MODEL_ID_PREFIX,
|
|
123
167
|
WORKSPACE_GATEWAY_MODEL_ID_PREFIX,
|
|
124
168
|
WORKSPACE_OPENROUTER_MODEL_ID_PREFIX,
|
|
169
|
+
sandboxImageAllowlist,
|
|
125
170
|
type Settings,
|
|
126
171
|
} from "@opengeni/config";
|
|
172
|
+
import { AddExternalWorkspaceMemberRequest } from "@opengeni/contracts/external-identities";
|
|
173
|
+
import { parseRequestBody, parseRequestJson, readRequestJson } from "../http/request-body";
|
|
174
|
+
import { workspaceXaiOperationAvailable } from "../xai-subscription-core";
|
|
127
175
|
|
|
128
176
|
export function canonicalWorkspacePolicyModelIds(
|
|
129
177
|
settings: Settings,
|
|
@@ -193,6 +241,14 @@ export function workspaceMembersResponse(members: readonly WorkspaceMemberProjec
|
|
|
193
241
|
});
|
|
194
242
|
}
|
|
195
243
|
|
|
244
|
+
export function workspaceUpdateRequestsSettings(value: unknown): boolean {
|
|
245
|
+
return (
|
|
246
|
+
typeof value === "object" &&
|
|
247
|
+
value !== null &&
|
|
248
|
+
Object.prototype.hasOwnProperty.call(value, "settings")
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
196
252
|
export function workspaceUpdateRequestsAccountTransfer(value: unknown): boolean {
|
|
197
253
|
return (
|
|
198
254
|
typeof value === "object" &&
|
|
@@ -201,35 +257,90 @@ export function workspaceUpdateRequestsAccountTransfer(value: unknown): boolean
|
|
|
201
257
|
);
|
|
202
258
|
}
|
|
203
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Owning organization for `PUT /v1/workspaces/external`. An organization API
|
|
262
|
+
* key can only ever create workspaces in its own organization, so an omitted
|
|
263
|
+
* `accountId` resolves to that organization. Every other caller - notably a
|
|
264
|
+
* human who may belong to several organizations - must name it explicitly;
|
|
265
|
+
* guessing a default there could create the workspace in the wrong tenant.
|
|
266
|
+
*/
|
|
267
|
+
export function externalWorkspaceAccountId(
|
|
268
|
+
context: AccessContext,
|
|
269
|
+
requested: string | undefined,
|
|
270
|
+
): string {
|
|
271
|
+
if (requested !== undefined) return requested;
|
|
272
|
+
const organizationKey = accountScopedApiKeyWorkspaceAuthority(context);
|
|
273
|
+
if (organizationKey) return organizationKey.accountId;
|
|
274
|
+
throw new ApiHttpError(400, {
|
|
275
|
+
code: "validation_failed",
|
|
276
|
+
message:
|
|
277
|
+
"Invalid request body: accountId: required - pass the id of the organization that will own the workspace (only an organization API key may omit it).",
|
|
278
|
+
retryable: false,
|
|
279
|
+
details: {
|
|
280
|
+
code: "invalid_request_body",
|
|
281
|
+
issues: [{ path: "accountId", message: "Required" }],
|
|
282
|
+
omittedIssueCount: 0,
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Codex Live readiness: the legacy active subscription without a cutover
|
|
289
|
+
* row; on the shared core, any shared connection that could serve a
|
|
290
|
+
* realtime operation here; never ready during maintenance.
|
|
291
|
+
*/
|
|
292
|
+
async function workspaceCodexRealtimeReady(
|
|
293
|
+
routeDeps: ApiRouteDeps,
|
|
294
|
+
grant: { accountId: string; subjectId: string },
|
|
295
|
+
workspaceId: string,
|
|
296
|
+
): Promise<boolean> {
|
|
297
|
+
const disposition = await readCodexCutoverDisposition(routeDeps.db, grant.accountId, workspaceId);
|
|
298
|
+
if (disposition === "maintenance" || !routeDeps.settings.codexSubscriptionEnabled) return false;
|
|
299
|
+
const candidates = await listSubscriptionCoreCodexOperationCandidates(routeDeps.db, {
|
|
300
|
+
kind: "workspace",
|
|
301
|
+
accountId: grant.accountId,
|
|
302
|
+
workspaceId,
|
|
303
|
+
subjectId: grant.subjectId,
|
|
304
|
+
});
|
|
305
|
+
return candidates.length > 0;
|
|
306
|
+
}
|
|
307
|
+
|
|
204
308
|
export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
205
309
|
app.post("/v1/workspaces/:workspaceId/external-members", async (c) => {
|
|
310
|
+
// Validate at the HTTP boundary so a malformed body is a 400, not a raw
|
|
311
|
+
// schema error from the application layer.
|
|
312
|
+
const body = await readRequestJson(c);
|
|
313
|
+
parseRequestBody(AddExternalWorkspaceMemberRequest, body);
|
|
206
314
|
return c.json(
|
|
207
|
-
await addExternalWorkspaceMemberForRequest(
|
|
208
|
-
c,
|
|
209
|
-
deps,
|
|
210
|
-
c.req.param("workspaceId"),
|
|
211
|
-
await c.req.json(),
|
|
212
|
-
),
|
|
315
|
+
await addExternalWorkspaceMemberForRequest(c, deps, c.req.param("workspaceId"), body),
|
|
213
316
|
);
|
|
214
317
|
});
|
|
215
318
|
app.get("/v1/access/me", async (c) => {
|
|
216
319
|
return c.json(await requireAccessContext(c, deps));
|
|
217
320
|
});
|
|
218
321
|
|
|
322
|
+
app.get("/v1/workspaces/:workspaceId/access/grant", async (c) => {
|
|
323
|
+
// Inventory may be empty for an external actor. Resolve the selected
|
|
324
|
+
// workspace through the canonical membership/key-ceiling boundary.
|
|
325
|
+
const grant = await requireAccessGrant(c, deps, c.req.param("workspaceId"));
|
|
326
|
+
c.header("cache-control", "private, no-store");
|
|
327
|
+
return c.json(grant);
|
|
328
|
+
});
|
|
329
|
+
|
|
219
330
|
app.get("/v1/workspaces", async (c) => {
|
|
220
331
|
const context = await requireAccessContext(c, deps);
|
|
221
332
|
const externalWorkspaces = await listExternalActorWorkspaces(context, deps);
|
|
222
333
|
if (externalWorkspaces !== null)
|
|
223
334
|
return c.json(externalWorkspaces.map((workspace) => Workspace.parse(workspace)));
|
|
224
335
|
const accountScopedAuthority = accountScopedApiKeyWorkspaceAuthority(context);
|
|
225
|
-
if (
|
|
226
|
-
accountScopedAuthority
|
|
227
|
-
hasPermission(accountScopedAuthority.permissions, "workspace:read")
|
|
228
|
-
) {
|
|
336
|
+
if (accountScopedAuthority) {
|
|
337
|
+
if (!hasPermission(accountScopedAuthority.permissions, "workspace:read")) return c.json([]);
|
|
229
338
|
return c.json(
|
|
230
|
-
(await listSharedWorkspacesForAccount(deps.db, accountScopedAuthority.accountId))
|
|
231
|
-
(workspace) =>
|
|
232
|
-
|
|
339
|
+
(await listSharedWorkspacesForAccount(deps.db, accountScopedAuthority.accountId))
|
|
340
|
+
.filter((workspace) =>
|
|
341
|
+
organizationWorkspaceInScope(accountScopedAuthority.workspaceScope, workspace.id),
|
|
342
|
+
)
|
|
343
|
+
.map((workspace) => Workspace.parse(workspace)),
|
|
233
344
|
);
|
|
234
345
|
}
|
|
235
346
|
const readableWorkspaceIds = [
|
|
@@ -254,8 +365,10 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
254
365
|
|
|
255
366
|
app.put("/v1/workspaces/external", async (c) => {
|
|
256
367
|
const context = await requireAccessContext(c, deps);
|
|
257
|
-
const
|
|
258
|
-
|
|
368
|
+
const request = await parseRequestJson(c, EnsureWorkspaceRequest);
|
|
369
|
+
const accountId = externalWorkspaceAccountId(context, request.accountId);
|
|
370
|
+
const payload = { ...request, accountId };
|
|
371
|
+
requireAccountPermission(context, accountId, "workspace:create");
|
|
259
372
|
try {
|
|
260
373
|
const existing = await findWorkspaceByExternalIdentity(deps.db, {
|
|
261
374
|
accountId: payload.accountId,
|
|
@@ -266,6 +379,9 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
266
379
|
if (existing.accountId !== payload.accountId || existing.kind !== "shared") {
|
|
267
380
|
throw new WorkspaceExternalIdentityConflictError();
|
|
268
381
|
}
|
|
382
|
+
const authority = accountScopedApiKeyWorkspaceAuthority(context);
|
|
383
|
+
if (authority && !organizationWorkspaceInScope(authority.workspaceScope, existing.id))
|
|
384
|
+
throw new HTTPException(403, { message: "workspace is outside organization key scope" });
|
|
269
385
|
return c.json(
|
|
270
386
|
EnsureWorkspaceResponse.parse({
|
|
271
387
|
workspace: existing,
|
|
@@ -292,6 +408,13 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
292
408
|
maxWorkspacesPerAccount: workspaceLimit(deps),
|
|
293
409
|
});
|
|
294
410
|
const response = EnsureWorkspaceResponse.parse(result);
|
|
411
|
+
const authority = accountScopedApiKeyWorkspaceAuthority(context);
|
|
412
|
+
if (
|
|
413
|
+
!result.created &&
|
|
414
|
+
authority &&
|
|
415
|
+
!organizationWorkspaceInScope(authority.workspaceScope, result.workspace.id)
|
|
416
|
+
)
|
|
417
|
+
throw new HTTPException(403, { message: "workspace is outside organization key scope" });
|
|
295
418
|
return result.created ? c.json(response, 201) : c.json(response);
|
|
296
419
|
} catch (error) {
|
|
297
420
|
if (error instanceof WorkspaceExternalIdentityConflictError) {
|
|
@@ -308,7 +431,7 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
308
431
|
|
|
309
432
|
app.post("/v1/workspaces", async (c) => {
|
|
310
433
|
const context = await requireAccessContext(c, deps);
|
|
311
|
-
const payload =
|
|
434
|
+
const payload = await parseRequestJson(c, CreateWorkspaceRequest);
|
|
312
435
|
const accountId = payload.accountId ?? context.defaultAccountId;
|
|
313
436
|
if (!accountId) {
|
|
314
437
|
throw new HTTPException(409, {
|
|
@@ -335,14 +458,21 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
335
458
|
: {}),
|
|
336
459
|
maxWorkspacesPerAccount: workspaceLimit(deps),
|
|
337
460
|
});
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
461
|
+
// Setup keys already have canonical same-organization workspace access.
|
|
462
|
+
// Do not widen that ceiling with an all-permissions creator membership.
|
|
463
|
+
if (
|
|
464
|
+
!isDeveloperSetupApiKeyContext(context) &&
|
|
465
|
+
accountScopedApiKeyWorkspaceAuthority(context)?.permissionMode !== "explicit"
|
|
466
|
+
) {
|
|
467
|
+
await grantWorkspaceAccess(deps.db, {
|
|
468
|
+
accountId,
|
|
469
|
+
workspaceId: workspace.id,
|
|
470
|
+
subjectId: context.subjectId,
|
|
471
|
+
role: "owner",
|
|
472
|
+
permissions: allWorkspacePermissions,
|
|
473
|
+
...(context.subjectLabel ? { subjectLabel: context.subjectLabel } : {}),
|
|
474
|
+
});
|
|
475
|
+
}
|
|
346
476
|
return c.json(Workspace.parse(workspace), 201);
|
|
347
477
|
} catch (error) {
|
|
348
478
|
if (error instanceof WorkspaceLimitExceededError) {
|
|
@@ -361,7 +491,25 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
361
491
|
app.patch("/v1/workspaces/:workspaceId", async (c) => {
|
|
362
492
|
const workspaceId = c.req.param("workspaceId");
|
|
363
493
|
await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
|
|
364
|
-
const body = await c
|
|
494
|
+
const body = await readRequestJson(c);
|
|
495
|
+
if (workspaceUpdateRequestsSettings(body)) {
|
|
496
|
+
throw new ApiHttpError(400, {
|
|
497
|
+
code: "validation_failed",
|
|
498
|
+
message:
|
|
499
|
+
"Invalid request body: settings: workspace settings are not accepted here; send them to PATCH /v1/workspaces/:workspaceId/settings (SDK: updateWorkspaceSettings).",
|
|
500
|
+
retryable: false,
|
|
501
|
+
details: {
|
|
502
|
+
code: "invalid_request_body",
|
|
503
|
+
issues: [
|
|
504
|
+
{
|
|
505
|
+
path: "settings",
|
|
506
|
+
message: "Use PATCH /v1/workspaces/:workspaceId/settings",
|
|
507
|
+
},
|
|
508
|
+
],
|
|
509
|
+
omittedIssueCount: 0,
|
|
510
|
+
},
|
|
511
|
+
});
|
|
512
|
+
}
|
|
365
513
|
if (workspaceUpdateRequestsAccountTransfer(body)) {
|
|
366
514
|
throw new ApiHttpError(409, {
|
|
367
515
|
code: "conflict",
|
|
@@ -372,7 +520,7 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
372
520
|
details: { code: "workspace_transfer_unsupported" },
|
|
373
521
|
});
|
|
374
522
|
}
|
|
375
|
-
const payload = UpdateWorkspaceRequest
|
|
523
|
+
const payload = parseRequestBody(UpdateWorkspaceRequest, body);
|
|
376
524
|
const workspace = await updateWorkspace(deps.db, workspaceId, {
|
|
377
525
|
...(payload.name !== undefined ? { name: payload.name.trim() } : {}),
|
|
378
526
|
...(payload.slug !== undefined ? { slug: payload.slug?.trim() || null } : {}),
|
|
@@ -396,6 +544,13 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
396
544
|
message: "invalid workspace settings patch",
|
|
397
545
|
});
|
|
398
546
|
}
|
|
547
|
+
const requestedImage = parsed.data.defaultSandboxImage;
|
|
548
|
+
if (requestedImage && !sandboxImageAllowlist(deps.settings).includes(requestedImage)) {
|
|
549
|
+
throw new HTTPException(422, {
|
|
550
|
+
message:
|
|
551
|
+
"defaultSandboxImage must be one of the images in this deployment's OPENGENI_SANDBOX_IMAGE_ALLOWLIST",
|
|
552
|
+
});
|
|
553
|
+
}
|
|
399
554
|
// Request-scoped: bound the exclusive control-prefix wait so a busy
|
|
400
555
|
// workspace yields the retryable 503 instead of parking this request.
|
|
401
556
|
try {
|
|
@@ -427,77 +582,188 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
427
582
|
app.get("/v1/workspaces/:workspaceId/model-catalog", async (c) => {
|
|
428
583
|
const workspaceId = c.req.param("workspaceId");
|
|
429
584
|
const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:read");
|
|
585
|
+
const resolvedCatalog = await deps.resolveCatalogSettings();
|
|
586
|
+
const providerKinds: WorkspaceCustomModelProviderKind[] = [
|
|
587
|
+
"vercel_gateway",
|
|
588
|
+
"openrouter",
|
|
589
|
+
"opper",
|
|
590
|
+
...CLAUDE_CONNECTION_KINDS.filter(
|
|
591
|
+
(kind) =>
|
|
592
|
+
kind !== "claude_subscription" || resolvedCatalog.settings.claudeSubscriptionEnabled,
|
|
593
|
+
),
|
|
594
|
+
];
|
|
595
|
+
// Claude by its provider route: the shared core's projection (readiness
|
|
596
|
+
// and both Claude model restrictions) once it has cut over, else legacy.
|
|
597
|
+
const claudeCore = loadCoreRoutedClaudeCatalogReadiness(deps.db, resolvedCatalog.settings, {
|
|
598
|
+
accountId: grant.accountId,
|
|
599
|
+
workspaceId,
|
|
600
|
+
subjectId: grant.subjectId,
|
|
601
|
+
});
|
|
430
602
|
const [
|
|
431
|
-
|
|
432
|
-
resolvedCatalog,
|
|
603
|
+
currentConnectionModelRestrictions,
|
|
433
604
|
policy,
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
organizationOpenRouterConnectionActive,
|
|
442
|
-
organizationGatewayCustomModels,
|
|
443
|
-
organizationOpenRouterCustomModels,
|
|
605
|
+
codexCatalog,
|
|
606
|
+
xaiCatalog,
|
|
607
|
+
claudePool,
|
|
608
|
+
workspaceConnections,
|
|
609
|
+
workspaceCustomModels,
|
|
610
|
+
organizationProviders,
|
|
611
|
+
workspace,
|
|
444
612
|
] = await Promise.all([
|
|
445
|
-
|
|
446
|
-
|
|
613
|
+
claudeCore.then((core) =>
|
|
614
|
+
getWorkspaceConnectionModelRestrictions(
|
|
615
|
+
deps.db,
|
|
616
|
+
workspaceId,
|
|
617
|
+
grant.subjectId,
|
|
618
|
+
undefined,
|
|
619
|
+
core?.restrictions,
|
|
620
|
+
),
|
|
621
|
+
),
|
|
447
622
|
getWorkspaceModelPolicy(deps.db, workspaceId),
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
workspaceId,
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
}),
|
|
460
|
-
organizationModelProviderConnectionActiveForWorkspace(deps.db, {
|
|
461
|
-
accountId: grant.accountId,
|
|
462
|
-
workspaceId,
|
|
463
|
-
providerKind: "vercel_gateway",
|
|
464
|
-
}),
|
|
465
|
-
organizationModelProviderConnectionActiveForWorkspace(deps.db, {
|
|
623
|
+
// By the organization's Codex cutover row: legacy without one, the
|
|
624
|
+
// shared core for the caller when enabled, not ready while disabled.
|
|
625
|
+
loadWorkspaceCodexCatalogReadiness(
|
|
626
|
+
deps.db,
|
|
627
|
+
resolvedCatalog.settings,
|
|
628
|
+
{ accountId: grant.accountId, workspaceId, subjectId: grant.subjectId },
|
|
629
|
+
{ activeSettings: deps.settings },
|
|
630
|
+
),
|
|
631
|
+
// SuperGrok runs only on the shared core: its projection, or not
|
|
632
|
+
// ready on any other route.
|
|
633
|
+
loadCoreRoutedXaiCatalogReadiness(deps.db, deps.settings, {
|
|
466
634
|
accountId: grant.accountId,
|
|
467
635
|
workspaceId,
|
|
468
|
-
|
|
469
|
-
})
|
|
470
|
-
|
|
636
|
+
subjectId: grant.subjectId,
|
|
637
|
+
}).then(async (core) => ({
|
|
638
|
+
core,
|
|
639
|
+
active: core?.ready ?? false,
|
|
640
|
+
})),
|
|
641
|
+
// The route read above decides for both Claude readers (read once).
|
|
642
|
+
claudeCore.then(
|
|
643
|
+
async (core) =>
|
|
644
|
+
await loadWorkspaceClaudeSubscriptionReadiness(
|
|
645
|
+
deps.db,
|
|
646
|
+
resolvedCatalog.settings,
|
|
647
|
+
{ accountId: grant.accountId, workspaceId, subjectId: grant.subjectId },
|
|
648
|
+
core,
|
|
649
|
+
),
|
|
650
|
+
),
|
|
651
|
+
listConnectionsMetadata(deps.db, workspaceId, null),
|
|
652
|
+
listWorkspaceProviderCustomModelsByKind(deps.db, {
|
|
471
653
|
accountId: grant.accountId,
|
|
472
654
|
workspaceId,
|
|
473
|
-
|
|
655
|
+
providerKinds,
|
|
474
656
|
}),
|
|
475
|
-
|
|
657
|
+
getOrganizationModelProviderCatalogForWorkspace(deps.db, {
|
|
476
658
|
accountId: grant.accountId,
|
|
477
659
|
workspaceId,
|
|
478
|
-
|
|
660
|
+
providerKinds,
|
|
479
661
|
}),
|
|
662
|
+
getWorkspace(deps.db, workspaceId),
|
|
480
663
|
]);
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
664
|
+
const xaiSubscriptionActive = xaiCatalog.active;
|
|
665
|
+
const connectionModelRestrictions = xaiCatalog.core
|
|
666
|
+
? withCoreRoutedXaiRestriction(currentConnectionModelRestrictions, xaiCatalog.core)
|
|
667
|
+
: currentConnectionModelRestrictions;
|
|
668
|
+
const organizationDefaults = await getOrganizationModelDefaults(deps.db, grant.accountId);
|
|
669
|
+
const claudeConnections: ClaudeConnectionCatalog = {};
|
|
670
|
+
const workspaceClaudeConnections: ClaudeConnectionCatalog = {};
|
|
671
|
+
const workspaceConnectionActive = (kind: WorkspaceCustomModelProviderKind) =>
|
|
672
|
+
workspaceProviderApiKeyConnectionMetadataFromConnections(workspaceConnections, kind) !== null;
|
|
673
|
+
for (const kind of CLAUDE_CONNECTION_KINDS) {
|
|
674
|
+
if (kind === "claude_subscription" && !resolvedCatalog.settings.claudeSubscriptionEnabled)
|
|
675
|
+
continue;
|
|
676
|
+
claudeConnections[kind] = {
|
|
677
|
+
active:
|
|
678
|
+
kind === "claude_subscription"
|
|
679
|
+
? claudePool.organization
|
|
680
|
+
: organizationProviders[kind].active,
|
|
681
|
+
models: organizationProviders[kind].models,
|
|
682
|
+
};
|
|
683
|
+
workspaceClaudeConnections[kind] = {
|
|
684
|
+
active:
|
|
685
|
+
kind === "claude_subscription" ? claudePool.workspace : workspaceConnectionActive(kind),
|
|
686
|
+
models: workspaceCustomModels[kind],
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
const workspaceCatalogSettings = withDirectModelProviders(
|
|
690
|
+
resolvedCatalog.settings,
|
|
691
|
+
workspaceConnections,
|
|
500
692
|
);
|
|
693
|
+
const selections = resolveWorkspaceModelSelection({
|
|
694
|
+
claudeConnections,
|
|
695
|
+
workspaceClaudeConnections,
|
|
696
|
+
connectionModelRestrictions,
|
|
697
|
+
settings: workspaceCatalogSettings,
|
|
698
|
+
policy,
|
|
699
|
+
observations: codexCatalog.observations,
|
|
700
|
+
codexSubscriptionActive: codexCatalog.active,
|
|
701
|
+
xaiSubscriptionActive,
|
|
702
|
+
workspaceGatewayConnectionActive: workspaceConnectionActive("vercel_gateway"),
|
|
703
|
+
workspaceGatewayCustomModels: workspaceCustomModels.vercel_gateway,
|
|
704
|
+
workspaceOpenRouterConnectionActive: workspaceConnectionActive("openrouter"),
|
|
705
|
+
workspaceOpenRouterCustomModels: workspaceCustomModels.openrouter,
|
|
706
|
+
organizationGatewayConnectionActive: organizationProviders.vercel_gateway.active,
|
|
707
|
+
organizationOpenRouterConnectionActive: organizationProviders.openrouter.active,
|
|
708
|
+
organizationGatewayCustomModels: organizationProviders.vercel_gateway.models,
|
|
709
|
+
organizationOpenRouterCustomModels: organizationProviders.openrouter.models,
|
|
710
|
+
workspaceOpperConnectionActive: workspaceConnectionActive("opper"),
|
|
711
|
+
workspaceOpperCustomModels: workspaceCustomModels.opper,
|
|
712
|
+
organizationOpperConnectionActive: organizationProviders.opper.active,
|
|
713
|
+
organizationOpperCustomModels: organizationProviders.opper.models,
|
|
714
|
+
});
|
|
715
|
+
// The same precedence the server applies when a new chat, API create, or
|
|
716
|
+
// scheduled occurrence names no model; published so pickers show it.
|
|
717
|
+
const workspaceSettings = workspace?.settings ?? {};
|
|
718
|
+
const creditBalance =
|
|
719
|
+
deps.settings.billingMode === "stripe"
|
|
720
|
+
? await getBillingBalance(deps.db, grant.accountId)
|
|
721
|
+
: undefined;
|
|
722
|
+
const defaultSelection = await resolveDefaultSessionModelForSelections(deps.db, {
|
|
723
|
+
settings: workspaceCatalogSettings,
|
|
724
|
+
accountId: grant.accountId,
|
|
725
|
+
workspaceSettings,
|
|
726
|
+
selections,
|
|
727
|
+
organizationDefaults,
|
|
728
|
+
});
|
|
729
|
+
const catalog = projectWorkspaceModelCatalog(selections, {
|
|
730
|
+
defaultSelection,
|
|
731
|
+
creditsSelection: creditsDefaultSessionModel({
|
|
732
|
+
settings: workspaceCatalogSettings,
|
|
733
|
+
selections,
|
|
734
|
+
workspaceSettings,
|
|
735
|
+
organizationDefaults,
|
|
736
|
+
}),
|
|
737
|
+
});
|
|
738
|
+
for (const model of catalog.models) {
|
|
739
|
+
model.compactionPolicy = workspaceModelCompactionPolicy(
|
|
740
|
+
workspaceCatalogSettings,
|
|
741
|
+
{
|
|
742
|
+
id: model.id,
|
|
743
|
+
contextWindowTokens:
|
|
744
|
+
model.executionLimits?.contextWindowTokens ?? model.contextWindowTokens,
|
|
745
|
+
effectiveContextWindowTokens:
|
|
746
|
+
model.executionLimits?.effectiveContextWindowTokens ?? undefined,
|
|
747
|
+
autoCompactTokenLimit: model.executionLimits?.autoCompactTokenLimit ?? undefined,
|
|
748
|
+
},
|
|
749
|
+
workspaceSettings,
|
|
750
|
+
organizationDefaults,
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
if (creditBalance) {
|
|
754
|
+
for (const model of catalog.models) {
|
|
755
|
+
if (model.cost !== "credits") continue;
|
|
756
|
+
model.creditFunding = creditBalance.promotionalCredits?.some(
|
|
757
|
+
(credit) => credit.remainingMicros > 0 && credit.eligibleModelIds.includes(model.id),
|
|
758
|
+
)
|
|
759
|
+
? "promotional"
|
|
760
|
+
: spendableCreditMicros(creditBalance, model.id) > 0
|
|
761
|
+
? "general"
|
|
762
|
+
: "unavailable";
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
c.header("cache-control", "private, no-store");
|
|
766
|
+
return c.json(WorkspaceModelCatalogResponse.parse(catalog));
|
|
501
767
|
});
|
|
502
768
|
|
|
503
769
|
app.get("/v1/workspaces/:workspaceId/gateway-custom-models", async (c) => {
|
|
@@ -776,12 +1042,157 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
776
1042
|
return c.body(null, 204);
|
|
777
1043
|
});
|
|
778
1044
|
|
|
1045
|
+
app.get("/v1/workspaces/:workspaceId/opper-custom-models", async (c) => {
|
|
1046
|
+
const workspaceId = c.req.param("workspaceId");
|
|
1047
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:read");
|
|
1048
|
+
const models = await listWorkspaceProviderCustomModels(deps.db, {
|
|
1049
|
+
accountId: grant.accountId,
|
|
1050
|
+
workspaceId,
|
|
1051
|
+
providerKind: "opper",
|
|
1052
|
+
});
|
|
1053
|
+
c.header("cache-control", "private, no-store");
|
|
1054
|
+
return c.json(
|
|
1055
|
+
WorkspaceOpperCustomModelsResponse.parse({
|
|
1056
|
+
models: models.map(projectWorkspaceOpenRouterCustomModel),
|
|
1057
|
+
}),
|
|
1058
|
+
);
|
|
1059
|
+
});
|
|
1060
|
+
|
|
1061
|
+
app.post("/v1/workspaces/:workspaceId/opper-custom-models", async (c) => {
|
|
1062
|
+
const workspaceId = c.req.param("workspaceId");
|
|
1063
|
+
const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
|
|
1064
|
+
const parsed = CreateWorkspaceOpperCustomModelRequest.safeParse(
|
|
1065
|
+
await c.req.json().catch(() => null),
|
|
1066
|
+
);
|
|
1067
|
+
if (!parsed.success) {
|
|
1068
|
+
throw new HTTPException(422, { message: "invalid Opper custom model" });
|
|
1069
|
+
}
|
|
1070
|
+
const requestHash = workspaceCustomModelRequestHash({
|
|
1071
|
+
action: "create",
|
|
1072
|
+
upstreamModelId: parsed.data.upstreamModelId,
|
|
1073
|
+
label: parsed.data.label ?? null,
|
|
1074
|
+
});
|
|
1075
|
+
const replay = await replayWorkspaceProviderCustomModelCreate(deps.db, {
|
|
1076
|
+
accountId: grant.accountId,
|
|
1077
|
+
workspaceId,
|
|
1078
|
+
providerKind: "opper",
|
|
1079
|
+
operationId: parsed.data.operationId,
|
|
1080
|
+
requestHash,
|
|
1081
|
+
});
|
|
1082
|
+
if (replay.outcome === "conflict") {
|
|
1083
|
+
throw new HTTPException(409, {
|
|
1084
|
+
message: "Opper custom model operation conflicts with current state",
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
if (replay.outcome === "success") {
|
|
1088
|
+
return c.json(projectWorkspaceOpenRouterCustomModel(replay.model), 201);
|
|
1089
|
+
}
|
|
1090
|
+
const catalog = await deps.resolveCatalogSettings();
|
|
1091
|
+
if (configuredOpperUpstreamModelIds(catalog.settings).includes(parsed.data.upstreamModelId)) {
|
|
1092
|
+
throw new HTTPException(422, {
|
|
1093
|
+
message: "Opper model is already included in the deployment catalog",
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
const customProductId = `${WORKSPACE_OPPER_MODEL_ID_PREFIX}${parsed.data.upstreamModelId}`;
|
|
1097
|
+
const deploymentProductIds = new Set([
|
|
1098
|
+
...configuredModelInputIdentities(catalog.settings),
|
|
1099
|
+
...configuredOpperWorkspaceProductModelIds(catalog.settings),
|
|
1100
|
+
]);
|
|
1101
|
+
if (deploymentProductIds.has(customProductId)) {
|
|
1102
|
+
throw new HTTPException(422, {
|
|
1103
|
+
message: "Opper model product id conflicts with the deployment catalog",
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
try {
|
|
1107
|
+
const model = await createWorkspaceProviderCustomModel(deps.db, {
|
|
1108
|
+
accountId: grant.accountId,
|
|
1109
|
+
workspaceId,
|
|
1110
|
+
providerKind: "opper",
|
|
1111
|
+
upstreamModelId: parsed.data.upstreamModelId,
|
|
1112
|
+
label: parsed.data.label ?? null,
|
|
1113
|
+
operationId: parsed.data.operationId,
|
|
1114
|
+
requestHash,
|
|
1115
|
+
createdBySubjectId: grant.subjectId,
|
|
1116
|
+
});
|
|
1117
|
+
if (!model || model.retiredAt) {
|
|
1118
|
+
throw new HTTPException(409, {
|
|
1119
|
+
message: "Opper custom model operation conflicts with current state",
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1122
|
+
return c.json(projectWorkspaceOpenRouterCustomModel(model), 201);
|
|
1123
|
+
} catch (error) {
|
|
1124
|
+
if (
|
|
1125
|
+
error instanceof WorkspaceOpperCustomModelLimitError ||
|
|
1126
|
+
error instanceof WorkspaceOpperCustomModelHistoryLimitError
|
|
1127
|
+
) {
|
|
1128
|
+
throw new HTTPException(422, { message: error.message });
|
|
1129
|
+
}
|
|
1130
|
+
if (nestedPostgresSqlState(error) === "23505") {
|
|
1131
|
+
throw new HTTPException(422, {
|
|
1132
|
+
message: "Opper custom model already exists",
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
throw error;
|
|
1136
|
+
}
|
|
1137
|
+
});
|
|
1138
|
+
|
|
1139
|
+
app.delete("/v1/workspaces/:workspaceId/opper-custom-models/:customModelId", async (c) => {
|
|
1140
|
+
const workspaceId = c.req.param("workspaceId");
|
|
1141
|
+
const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
|
|
1142
|
+
const customModelId = c.req.param("customModelId");
|
|
1143
|
+
if (
|
|
1144
|
+
!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(
|
|
1145
|
+
customModelId,
|
|
1146
|
+
)
|
|
1147
|
+
) {
|
|
1148
|
+
throw new HTTPException(422, {
|
|
1149
|
+
message: "invalid Opper custom model id",
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
1152
|
+
const parsed = DeleteWorkspaceOpperCustomModelRequest.safeParse(
|
|
1153
|
+
await c.req.json().catch(() => null),
|
|
1154
|
+
);
|
|
1155
|
+
if (!parsed.success) {
|
|
1156
|
+
throw new HTTPException(422, {
|
|
1157
|
+
message: "invalid Opper custom model deletion",
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
const removed = await deleteWorkspaceProviderCustomModel(deps.db, {
|
|
1161
|
+
accountId: grant.accountId,
|
|
1162
|
+
workspaceId,
|
|
1163
|
+
providerKind: "opper",
|
|
1164
|
+
customModelId,
|
|
1165
|
+
expectedVersion: parsed.data.expectedVersion,
|
|
1166
|
+
operationId: parsed.data.operationId,
|
|
1167
|
+
requestHash: workspaceCustomModelRequestHash({
|
|
1168
|
+
action: "delete",
|
|
1169
|
+
customModelId,
|
|
1170
|
+
expectedVersion: parsed.data.expectedVersion,
|
|
1171
|
+
}),
|
|
1172
|
+
});
|
|
1173
|
+
if (removed.outcome === "not_found") {
|
|
1174
|
+
throw new HTTPException(404, {
|
|
1175
|
+
message: "Opper custom model not found",
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
if (removed.outcome === "conflict") {
|
|
1179
|
+
throw new HTTPException(409, {
|
|
1180
|
+
message: "Opper custom model changed; reload and retry",
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
return c.body(null, 204);
|
|
1184
|
+
});
|
|
1185
|
+
|
|
779
1186
|
app.get("/v1/workspaces/:workspaceId/realtime-model-catalog", async (c) => {
|
|
780
1187
|
const workspaceId = c.req.param("workspaceId");
|
|
781
1188
|
const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:read");
|
|
782
1189
|
const [codexConnected, supergrokConnected, workspaceGatewayConnected] = await Promise.all([
|
|
783
|
-
|
|
784
|
-
|
|
1190
|
+
workspaceCodexRealtimeReady(deps, grant, workspaceId),
|
|
1191
|
+
workspaceXaiOperationAvailable(deps.db, deps.settings, {
|
|
1192
|
+
accountId: grant.accountId,
|
|
1193
|
+
workspaceId,
|
|
1194
|
+
subjectId: grant.subjectId,
|
|
1195
|
+
}),
|
|
785
1196
|
workspaceVercelAiGatewayConnectionActive(deps.db, workspaceId),
|
|
786
1197
|
]);
|
|
787
1198
|
const availability = (
|
|
@@ -793,16 +1204,62 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
793
1204
|
: { available: false, unavailableReason: credentialReason };
|
|
794
1205
|
};
|
|
795
1206
|
const gatewayModels = Object.values(AI_GATEWAY_REALTIME_MODELS);
|
|
796
|
-
|
|
797
|
-
|
|
1207
|
+
// Deployment-funded voice is listed only when this deployment can offer
|
|
1208
|
+
// it (configured, and priced while credits are enforced). Hosted GPT Live
|
|
1209
|
+
// replaces the managed Gateway choices when configured.
|
|
1210
|
+
const managedCandidates = [
|
|
1211
|
+
{
|
|
1212
|
+
id: AZURE_LIVE_MODEL_ID,
|
|
1213
|
+
label: "GPT Live 1",
|
|
1214
|
+
description: "Realtime voice with session delegation",
|
|
1215
|
+
},
|
|
1216
|
+
...gatewayModels.map((model) => ({
|
|
798
1217
|
id: model.managedModelId,
|
|
799
1218
|
label: model.label,
|
|
800
|
-
provider: "OpenGeni" as const,
|
|
801
1219
|
description: model.description,
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
)
|
|
1220
|
+
})),
|
|
1221
|
+
]
|
|
1222
|
+
.filter((model) => {
|
|
1223
|
+
const voice = deploymentRealtimeVoice(deps.settings, model.id);
|
|
1224
|
+
return voice !== null && realtimeVoiceOfferProblem(deps.settings, voice) === null;
|
|
1225
|
+
})
|
|
1226
|
+
.filter((model, _index, offered) =>
|
|
1227
|
+
offered.some((candidate) => candidate.id === AZURE_LIVE_MODEL_ID)
|
|
1228
|
+
? model.id === AZURE_LIVE_MODEL_ID
|
|
1229
|
+
: true,
|
|
1230
|
+
);
|
|
1231
|
+
const realtimeVoiceBilling = createRealtimeVoiceBilling({
|
|
1232
|
+
db: deps.db,
|
|
1233
|
+
settings: deps.settings,
|
|
1234
|
+
});
|
|
1235
|
+
const [creditStanding, creditsDisabled] =
|
|
1236
|
+
managedCandidates.length > 0
|
|
1237
|
+
? await Promise.all([
|
|
1238
|
+
realtimeVoiceBilling.creditStanding(grant.accountId),
|
|
1239
|
+
realtimeVoiceBilling.creditsDisabled(workspaceId),
|
|
1240
|
+
])
|
|
1241
|
+
: (["none", false] as const);
|
|
1242
|
+
const hasCredits = creditStanding === "spendable";
|
|
1243
|
+
const models = [
|
|
1244
|
+
...managedCandidates.map((model, index) => ({
|
|
1245
|
+
...model,
|
|
1246
|
+
provider: "OpenGeni" as const,
|
|
1247
|
+
...(creditsDisabled
|
|
1248
|
+
? {
|
|
1249
|
+
available: false,
|
|
1250
|
+
unavailableReason: "Opengeni credits are turned off in this workspace",
|
|
1251
|
+
unavailableCode: "credits_disabled",
|
|
1252
|
+
}
|
|
1253
|
+
: hasCredits
|
|
1254
|
+
? { available: true, unavailableReason: null, unavailableCode: null }
|
|
1255
|
+
: {
|
|
1256
|
+
available: false,
|
|
1257
|
+
unavailableReason:
|
|
1258
|
+
creditStanding === "promotional_only"
|
|
1259
|
+
? "Promotional credits don't cover live voice. Add credits to use it."
|
|
1260
|
+
: "Add Opengeni credits to use live voice",
|
|
1261
|
+
unavailableCode: "insufficient_credits",
|
|
1262
|
+
}),
|
|
806
1263
|
recommended: index === 0,
|
|
807
1264
|
})),
|
|
808
1265
|
{
|
|
@@ -834,35 +1291,42 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
834
1291
|
return c.json(WorkspaceRealtimeModelCatalogResponse.parse({ models }));
|
|
835
1292
|
});
|
|
836
1293
|
|
|
1294
|
+
// The policy the workspace runs with and where it comes from: its own
|
|
1295
|
+
// saved policy, else its organization's default, else no restriction.
|
|
837
1296
|
app.get("/v1/workspaces/:workspaceId/model-policy", async (c) => {
|
|
838
1297
|
const workspaceId = c.req.param("workspaceId");
|
|
839
1298
|
await requireAccessGrant(c, deps, workspaceId, "workspace:read");
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
1299
|
+
return c.json(await workspaceModelPolicyResponse(deps, workspaceId));
|
|
1300
|
+
});
|
|
1301
|
+
|
|
1302
|
+
// Remove the workspace's own policy so it follows the organization default.
|
|
1303
|
+
app.delete("/v1/workspaces/:workspaceId/model-policy", async (c) => {
|
|
1304
|
+
const workspaceId = c.req.param("workspaceId");
|
|
1305
|
+
const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
|
|
1306
|
+
await deleteWorkspaceModelPolicy(deps.db, { accountId: grant.accountId, workspaceId });
|
|
1307
|
+
return c.json(await workspaceModelPolicyResponse(deps, workspaceId));
|
|
845
1308
|
});
|
|
846
1309
|
|
|
847
1310
|
// Full replace (PUT, not merge): null/omitted = unrestricted for that
|
|
848
|
-
// dimension; an empty array is a valid explicit total block.
|
|
1311
|
+
// dimension; an empty array is a valid explicit total block. The credit
|
|
1312
|
+
// switch is a workspace setting and never changes here. Settings access
|
|
849
1313
|
// admits workspace administrators and the verified Personal owner, without
|
|
850
1314
|
// widening membership or API-key delegation authority.
|
|
851
1315
|
app.put("/v1/workspaces/:workspaceId/model-policy", async (c) => {
|
|
852
1316
|
const workspaceId = c.req.param("workspaceId");
|
|
853
1317
|
const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
|
|
854
|
-
const payload =
|
|
1318
|
+
const payload = await parseRequestJson(c, UpdateWorkspaceModelPolicyRequest);
|
|
855
1319
|
const catalog = await resolveWorkspaceCatalogSettings(deps.db, deps.settings, {
|
|
856
1320
|
accountId: grant.accountId,
|
|
857
1321
|
workspaceId,
|
|
858
1322
|
});
|
|
859
|
-
|
|
1323
|
+
await upsertWorkspaceModelPolicy(deps.db, {
|
|
860
1324
|
accountId: grant.accountId,
|
|
861
1325
|
workspaceId,
|
|
862
1326
|
allowedProviders: payload.allowedProviders ?? null,
|
|
863
1327
|
allowedModels: canonicalWorkspacePolicyModelIds(catalog.settings, payload.allowedModels),
|
|
864
1328
|
});
|
|
865
|
-
return c.json(
|
|
1329
|
+
return c.json(await workspaceModelPolicyResponse(deps, workspaceId));
|
|
866
1330
|
});
|
|
867
1331
|
|
|
868
1332
|
app.post("/v1/workspaces/:workspaceId/pause-timer", async (c) => {
|
|
@@ -968,10 +1432,10 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
968
1432
|
|
|
969
1433
|
app.put("/v1/workspaces/:workspaceId/default-rig", async (c) => {
|
|
970
1434
|
const workspaceId = c.req.param("workspaceId");
|
|
971
|
-
await requireAccessGrant(c, deps, workspaceId, "rigs:manage");
|
|
972
|
-
const payload =
|
|
1435
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "rigs:manage");
|
|
1436
|
+
const payload = await parseRequestJson(c, SetWorkspaceDefaultRigRequest);
|
|
973
1437
|
if (payload.rigId) {
|
|
974
|
-
const rig = await getRig(deps.db,
|
|
1438
|
+
const rig = await getRig(deps.db, grant, payload.rigId);
|
|
975
1439
|
if (!rig) {
|
|
976
1440
|
throw new HTTPException(422, {
|
|
977
1441
|
message: `unknown rigId: ${payload.rigId}`,
|
|
@@ -996,14 +1460,19 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
996
1460
|
|
|
997
1461
|
app.get("/v1/workspaces/:workspaceId/members", async (c) => {
|
|
998
1462
|
const workspaceId = c.req.param("workspaceId");
|
|
999
|
-
await
|
|
1463
|
+
await requireWorkspaceMemberManagementAuthority(c, deps, workspaceId, "workspace:read");
|
|
1000
1464
|
const members = await listWorkspacePeople(deps, workspaceId);
|
|
1001
1465
|
return c.json(workspaceMembersResponse(members));
|
|
1002
1466
|
});
|
|
1003
1467
|
|
|
1004
1468
|
app.get("/v1/workspaces/:workspaceId/member-candidates", async (c) => {
|
|
1005
1469
|
const workspaceId = c.req.param("workspaceId");
|
|
1006
|
-
const grant = await
|
|
1470
|
+
const { grant } = await requireWorkspaceMemberManagementAuthority(
|
|
1471
|
+
c,
|
|
1472
|
+
deps,
|
|
1473
|
+
workspaceId,
|
|
1474
|
+
"members:manage",
|
|
1475
|
+
);
|
|
1007
1476
|
try {
|
|
1008
1477
|
return c.json(
|
|
1009
1478
|
ListWorkspaceMemberCandidatesResponse.parse({
|
|
@@ -1021,8 +1490,15 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
1021
1490
|
|
|
1022
1491
|
app.post("/v1/workspaces/:workspaceId/members", async (c) => {
|
|
1023
1492
|
const workspaceId = c.req.param("workspaceId");
|
|
1024
|
-
const grant = await
|
|
1025
|
-
|
|
1493
|
+
const { grant } = await requireWorkspaceMemberManagementAuthority(
|
|
1494
|
+
c,
|
|
1495
|
+
deps,
|
|
1496
|
+
workspaceId,
|
|
1497
|
+
"members:manage",
|
|
1498
|
+
);
|
|
1499
|
+
const payload = await parseRequestJson(c, AddWorkspaceMemberRequest);
|
|
1500
|
+
requireApiKeyDelegationContext(await requireAccessContext(c, deps), payload.permissions);
|
|
1501
|
+
requireExplicitPermissionDelegation(grant, payload.permissions);
|
|
1026
1502
|
let candidates: WorkspaceMemberCandidate[];
|
|
1027
1503
|
try {
|
|
1028
1504
|
candidates = await listWorkspaceMemberManagementCandidates(deps.db, {
|
|
@@ -1072,9 +1548,16 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
1072
1548
|
|
|
1073
1549
|
app.patch("/v1/workspaces/:workspaceId/members/:subjectId", async (c) => {
|
|
1074
1550
|
const workspaceId = c.req.param("workspaceId");
|
|
1075
|
-
const grant = await
|
|
1551
|
+
const { grant } = await requireWorkspaceMemberManagementAuthority(
|
|
1552
|
+
c,
|
|
1553
|
+
deps,
|
|
1554
|
+
workspaceId,
|
|
1555
|
+
"members:manage",
|
|
1556
|
+
);
|
|
1076
1557
|
const subjectId = decodeURIComponent(c.req.param("subjectId"));
|
|
1077
|
-
const payload =
|
|
1558
|
+
const payload = await parseRequestJson(c, UpdateWorkspaceMemberRequest);
|
|
1559
|
+
requireApiKeyDelegationContext(await requireAccessContext(c, deps), payload.permissions);
|
|
1560
|
+
requireExplicitPermissionDelegation(grant, payload.permissions);
|
|
1078
1561
|
const existing = await listWorkspacePeople(deps, workspaceId);
|
|
1079
1562
|
const current = existing.find((member) => member.subjectId === subjectId);
|
|
1080
1563
|
if (!current) {
|
|
@@ -1110,7 +1593,12 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
1110
1593
|
|
|
1111
1594
|
app.delete("/v1/workspaces/:workspaceId/members/:subjectId", async (c) => {
|
|
1112
1595
|
const workspaceId = c.req.param("workspaceId");
|
|
1113
|
-
const grant = await
|
|
1596
|
+
const { grant, organizationAdministrator } = await requireWorkspaceMemberManagementAuthority(
|
|
1597
|
+
c,
|
|
1598
|
+
deps,
|
|
1599
|
+
workspaceId,
|
|
1600
|
+
"members:manage",
|
|
1601
|
+
);
|
|
1114
1602
|
const subjectId = decodeURIComponent(c.req.param("subjectId"));
|
|
1115
1603
|
const members = await listWorkspaceMembers(deps.db, workspaceId);
|
|
1116
1604
|
// Never remove yourself, and never remove the last administering member.
|
|
@@ -1125,11 +1613,31 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
1125
1613
|
workspaceId,
|
|
1126
1614
|
actorSubjectId: grant.subjectId,
|
|
1127
1615
|
targetSubjectId: subjectId,
|
|
1616
|
+
// An organization owner/admin acting without their own workspace grant
|
|
1617
|
+
// proves that authority through the organization capability instead.
|
|
1618
|
+
...(organizationAdministrator
|
|
1619
|
+
? { requireOrganizationSharedWorkspaceAdministration: true }
|
|
1620
|
+
: {}),
|
|
1128
1621
|
});
|
|
1129
1622
|
return c.body(null, 204);
|
|
1130
1623
|
});
|
|
1131
1624
|
}
|
|
1132
1625
|
|
|
1626
|
+
async function workspaceModelPolicyResponse(
|
|
1627
|
+
deps: ApiRouteDeps,
|
|
1628
|
+
workspaceId: string,
|
|
1629
|
+
): Promise<WorkspaceModelPolicyResponse> {
|
|
1630
|
+
const layers = await getWorkspaceModelPolicyLayers(deps.db, workspaceId);
|
|
1631
|
+
const effective = layers.workspace ?? layers.organization;
|
|
1632
|
+
return WorkspaceModelPolicyResponse.parse({
|
|
1633
|
+
allowedProviders: effective?.allowedProviders ?? null,
|
|
1634
|
+
allowedModels: effective?.allowedModels ?? null,
|
|
1635
|
+
source: layers.workspace ? "workspace" : layers.organization ? "organization" : "none",
|
|
1636
|
+
organization: layers.organization,
|
|
1637
|
+
allowCreditModels: layers.allowCreditModels,
|
|
1638
|
+
});
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1133
1641
|
function workspaceLimit(deps: ApiRouteDeps): number | null {
|
|
1134
1642
|
if (deps.settings.usageLimitsMode !== "static" && deps.settings.usageLimitsMode !== "managed") {
|
|
1135
1643
|
return null;
|