@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/site-uploads.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { WorkspaceArtifactSourceBundle, type AccessGrant } from "@opengeni/contracts";
|
|
2
2
|
import type { ApiRouteDeps, ObjectStorageDependency } from "@opengeni/core";
|
|
3
|
+
import { retryWhileMissing } from "@opengeni/storage";
|
|
3
4
|
import {
|
|
4
5
|
createWorkspaceArtifactUpload,
|
|
5
6
|
getWorkspaceArtifactUpload,
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
prepareWorkspaceArtifactContent,
|
|
11
12
|
type PreparedWorkspaceArtifactContent,
|
|
12
13
|
} from "./workspace-artifact-content";
|
|
14
|
+
import { userContentSignedGetUrlOptions } from "./http/user-content";
|
|
13
15
|
type Storage = NonNullable<ObjectStorageDependency>;
|
|
14
16
|
export const MAX_SITE_SOURCE_BYTES = 64 * 1024 * 1024;
|
|
15
17
|
|
|
@@ -19,10 +21,15 @@ export async function validateSiteSource(storage: Storage, key: string, sizeByte
|
|
|
19
21
|
"Editable source JSON must be at most 64 MiB. Exclude dependencies and build output; HTML has a separate storage limit.",
|
|
20
22
|
);
|
|
21
23
|
}
|
|
22
|
-
const content = await storage.getObjectBytes(key);
|
|
24
|
+
const content = await retryWhileMissing(() => storage.getObjectBytes(key));
|
|
25
|
+
if (!content) {
|
|
26
|
+
throw new WorkspaceArtifactOperationError(
|
|
27
|
+
"Site source is not available yet. Retry publication with the same upload.",
|
|
28
|
+
);
|
|
29
|
+
}
|
|
23
30
|
try {
|
|
24
31
|
WorkspaceArtifactSourceBundle.parse(
|
|
25
|
-
JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(content
|
|
32
|
+
JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(content.bytes)),
|
|
26
33
|
);
|
|
27
34
|
} catch {
|
|
28
35
|
throw new WorkspaceArtifactOperationError(
|
|
@@ -129,13 +136,22 @@ async function freeze(
|
|
|
129
136
|
}
|
|
130
137
|
decoder.decode();
|
|
131
138
|
}
|
|
132
|
-
await storage.putObjectStreamIfAbsent({
|
|
139
|
+
const created = await storage.putObjectStreamIfAbsent({
|
|
133
140
|
key: to,
|
|
134
141
|
contentType,
|
|
135
142
|
byteSize: head.ContentLength,
|
|
136
143
|
chunks: chunks(),
|
|
137
144
|
});
|
|
138
|
-
|
|
145
|
+
// A successful conditional PUT is the receipt. A following visibility miss
|
|
146
|
+
// cannot invalidate it. Only a conflict needs the existing winner's metadata.
|
|
147
|
+
if (created) return head.ContentLength;
|
|
148
|
+
const stored = await retryWhileMissing(() => storage.headObject!(to));
|
|
149
|
+
if (!stored || stored.ContentLength === undefined) {
|
|
150
|
+
throw new WorkspaceArtifactOperationError(
|
|
151
|
+
"Frozen Site upload is unavailable. Retry publication with the same upload.",
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
return stored.ContentLength;
|
|
139
155
|
}
|
|
140
156
|
type Input = Partial<Parameters<typeof prepareWorkspaceArtifactContent>[2]> & { uploadId?: string };
|
|
141
157
|
export async function prepareWorkspaceArtifactPublication(
|
|
@@ -190,7 +206,13 @@ export async function workspaceArtifactDownloads(
|
|
|
190
206
|
audience: "sandbox" | "public",
|
|
191
207
|
) {
|
|
192
208
|
const [html, source] = await Promise.all([
|
|
193
|
-
|
|
209
|
+
// Site HTML runs publisher scripts; opened directly from storage it would
|
|
210
|
+
// render outside the console's opaque-origin frame, so it downloads.
|
|
211
|
+
storage.createGetUrl({
|
|
212
|
+
key: ref.contentKey,
|
|
213
|
+
audience,
|
|
214
|
+
...userContentSignedGetUrlOptions("text/html", "site.html"),
|
|
215
|
+
}),
|
|
194
216
|
ref.sourceKey ? storage.createGetUrl({ key: ref.sourceKey, audience }) : null,
|
|
195
217
|
]);
|
|
196
218
|
return {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { ScheduledTask } from "@opengeni/contracts";
|
|
2
|
+
import { getScheduledTaskIncludingDeleted, type Database } from "@opengeni/db";
|
|
3
|
+
import { sql } from "drizzle-orm";
|
|
4
|
+
|
|
5
|
+
const LOCK_TIMEOUT = "5s";
|
|
6
|
+
const WRITE_TIMEOUT_MS = 5_000;
|
|
7
|
+
|
|
8
|
+
type TemporalScheduleSyncDependencies = {
|
|
9
|
+
db: Database;
|
|
10
|
+
withDeadline<T>(deadline: number, work: () => Promise<T>): Promise<T>;
|
|
11
|
+
upsert(task: ScheduledTask): Promise<void>;
|
|
12
|
+
/** Idempotent: an absent Temporal schedule is already removed. */
|
|
13
|
+
remove(temporalScheduleId: string): Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Serialize external writes across API replicas, independently of task edits.
|
|
18
|
+
* A queued sync rereads the newest committed row after acquiring this lock;
|
|
19
|
+
* input snapshots never become desired state. Cleanup uses the same key, so
|
|
20
|
+
* an in-flight upsert finishes before its tombstone's external deletion.
|
|
21
|
+
* Failure compensation commits before releasing the lock, so a queued writer
|
|
22
|
+
* cannot read the row being restored and then publish that failed edit.
|
|
23
|
+
*
|
|
24
|
+
* Deadlines bound both lock admission and network occupancy. A thrown network
|
|
25
|
+
* error retains its unknown-outcome semantics; this is not durable recovery
|
|
26
|
+
* for a process crash or a lost Temporal acknowledgement.
|
|
27
|
+
*/
|
|
28
|
+
export function createTemporalScheduleSynchronizer(deps: TemporalScheduleSyncDependencies) {
|
|
29
|
+
const write = async <T>(
|
|
30
|
+
temporalScheduleId: string,
|
|
31
|
+
work: (tx: Database) => Promise<T>,
|
|
32
|
+
): Promise<T> =>
|
|
33
|
+
deps.db.transaction(async (tx) => {
|
|
34
|
+
await tx.execute(sql`select set_config('lock_timeout', ${LOCK_TIMEOUT}, true)`);
|
|
35
|
+
await tx.execute(sql`select pg_advisory_xact_lock(
|
|
36
|
+
hashtextextended(${`scheduled-task-temporal:${temporalScheduleId}`}, 0)
|
|
37
|
+
)`);
|
|
38
|
+
return await work(tx);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
async sync(
|
|
43
|
+
task: Pick<ScheduledTask, "id" | "workspaceId" | "temporalScheduleId">,
|
|
44
|
+
onFailure?: (tx: Database, error: unknown) => Promise<Error>,
|
|
45
|
+
) {
|
|
46
|
+
const result = await write(task.temporalScheduleId, async (tx) => {
|
|
47
|
+
try {
|
|
48
|
+
await deps.withDeadline(Date.now() + WRITE_TIMEOUT_MS, async () => {
|
|
49
|
+
const current = await getScheduledTaskIncludingDeleted(tx, task.workspaceId, task.id);
|
|
50
|
+
if (current && current.temporalScheduleId !== task.temporalScheduleId)
|
|
51
|
+
throw new Error("Scheduled task Temporal identity changed");
|
|
52
|
+
if (!current || current.deletedAt !== null || current.schedule.type === "manual") {
|
|
53
|
+
await deps.remove(task.temporalScheduleId);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const { deletedAt: _deletedAt, ...latest } = current;
|
|
57
|
+
await deps.upsert(latest);
|
|
58
|
+
});
|
|
59
|
+
return { ok: true as const };
|
|
60
|
+
} catch (error) {
|
|
61
|
+
return { ok: false as const, error: onFailure ? await onFailure(tx, error) : error };
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
// Throw after commit: throwing inside the transaction would also undo a
|
|
65
|
+
// successful compensation. A failed commit cannot claim that receipt.
|
|
66
|
+
if (!result.ok) throw result.error;
|
|
67
|
+
},
|
|
68
|
+
async remove(temporalScheduleId: string) {
|
|
69
|
+
await write(temporalScheduleId, async () =>
|
|
70
|
+
deps.withDeadline(Date.now() + WRITE_TIMEOUT_MS, () => deps.remove(temporalScheduleId)),
|
|
71
|
+
);
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TranscriptionBillingRefusedError } from "@opengeni/core";
|
|
2
|
+
import type { Context } from "hono";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Same body shape as session admission refusals (`code` + `message`, plus
|
|
6
|
+
* allowance `scope`/`resetsAt`), so SDK/React clients classify it as a
|
|
7
|
+
* definitive credit/allowance refusal rather than a retryable failure.
|
|
8
|
+
*/
|
|
9
|
+
export function transcriptionBillingRefusal(
|
|
10
|
+
c: Context,
|
|
11
|
+
error: TranscriptionBillingRefusedError,
|
|
12
|
+
): Response {
|
|
13
|
+
return c.json({ code: error.code, message: error.message, ...error.details }, error.status);
|
|
14
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { TranscriptionServiceError } from "@opengeni/core";
|
|
2
|
+
import { createFfmpegTranscriptionSegmenter, TranscriptionSegmenterError } from "./segmenter";
|
|
3
|
+
import { wavDurationSeconds } from "./wav-duration";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Decode one uploaded recording to 16 kHz mono PCM WAV with a hard decode
|
|
7
|
+
* ceiling, and measure its duration from the bytes the server produced.
|
|
8
|
+
*/
|
|
9
|
+
export type TranscriptionAudioNormalizer = (input: {
|
|
10
|
+
audio: Uint8Array;
|
|
11
|
+
mimeType: string;
|
|
12
|
+
/** Longest accepted recording; anything longer is refused, never truncated. */
|
|
13
|
+
maxDurationSeconds: number;
|
|
14
|
+
signal?: AbortSignal | undefined;
|
|
15
|
+
}) => Promise<{ bytes: Uint8Array; durationSeconds: number }>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* ffmpeg decodes at most `maxDurationSeconds + 1` seconds (`-t`), so a long or
|
|
19
|
+
* hostile upload costs bounded CPU and disk. Output that reaches that ceiling
|
|
20
|
+
* was longer than the limit and is refused as `too_large` before any provider
|
|
21
|
+
* call, so the transcript the user receives is never silently cut short.
|
|
22
|
+
*/
|
|
23
|
+
export function createFfmpegAudioNormalizer(input: {
|
|
24
|
+
ffmpegPath: string;
|
|
25
|
+
}): TranscriptionAudioNormalizer {
|
|
26
|
+
const segmenter = createFfmpegTranscriptionSegmenter({ ffmpegPath: input.ffmpegPath });
|
|
27
|
+
return async ({ audio, mimeType, maxDurationSeconds, signal }) => {
|
|
28
|
+
if (!Number.isFinite(maxDurationSeconds) || maxDurationSeconds <= 0) {
|
|
29
|
+
throw new TranscriptionServiceError({
|
|
30
|
+
code: "unavailable",
|
|
31
|
+
message: "Voice input duration limit is not configured.",
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
const decodeSeconds = Math.ceil(maxDurationSeconds) + 1;
|
|
35
|
+
// One segment strictly longer than the decode ceiling: never a second file.
|
|
36
|
+
const segmentSeconds = decodeSeconds + 1;
|
|
37
|
+
let normalized: Uint8Array | undefined;
|
|
38
|
+
try {
|
|
39
|
+
for await (const segment of segmenter.segment({
|
|
40
|
+
sourceMimeType: mimeType,
|
|
41
|
+
chunks: (async function* () {
|
|
42
|
+
yield audio;
|
|
43
|
+
})(),
|
|
44
|
+
providerSegmentSeconds: segmentSeconds,
|
|
45
|
+
totalDurationMilliseconds: segmentSeconds * 1_000,
|
|
46
|
+
maxDecodeSeconds: decodeSeconds,
|
|
47
|
+
...(signal ? { signal } : {}),
|
|
48
|
+
})) {
|
|
49
|
+
if (normalized) {
|
|
50
|
+
throw new TranscriptionServiceError({ code: "too_large", message: "Audio is too long." });
|
|
51
|
+
}
|
|
52
|
+
normalized = segment.bytes;
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (error instanceof TranscriptionSegmenterError) {
|
|
56
|
+
throw new TranscriptionServiceError({
|
|
57
|
+
code: error.code === "unknown" ? "invalid_audio" : error.code,
|
|
58
|
+
message: "Audio could not be prepared for transcription.",
|
|
59
|
+
retryable: error.retryable,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
const durationSeconds = normalized ? wavDurationSeconds(normalized) : null;
|
|
65
|
+
if (!normalized || durationSeconds === null || !(durationSeconds > 0)) {
|
|
66
|
+
throw new TranscriptionServiceError({
|
|
67
|
+
code: "invalid_audio",
|
|
68
|
+
message: "Audio could not be decoded.",
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// Reaching the decode ceiling (within one 20 ms frame) means the source ran past it.
|
|
72
|
+
if (durationSeconds > decodeSeconds - 0.02) {
|
|
73
|
+
throw new TranscriptionServiceError({ code: "too_large", message: "Audio is too long." });
|
|
74
|
+
}
|
|
75
|
+
return { bytes: normalized, durationSeconds };
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { VoiceInputPricing } from "@opengeni/config";
|
|
2
|
+
import type { TranscriptionProvider } from "@opengeni/core";
|
|
3
|
+
import { createFfmpegAudioNormalizer } from "../normalize";
|
|
4
|
+
import { fetchError, responseError } from "./openai";
|
|
5
|
+
|
|
6
|
+
/** Azure Speech file transcription; credentials and model selection stay server-side. */
|
|
7
|
+
export function createMaiTranscriptionProvider(input: {
|
|
8
|
+
endpoint: string;
|
|
9
|
+
apiKey: string;
|
|
10
|
+
apiVersion: string;
|
|
11
|
+
model: string;
|
|
12
|
+
pricing?: VoiceInputPricing | null;
|
|
13
|
+
ffmpegPath: string;
|
|
14
|
+
fetch?: typeof fetch;
|
|
15
|
+
}): TranscriptionProvider {
|
|
16
|
+
const fetchImpl = input.fetch ?? fetch;
|
|
17
|
+
const normalize = createFfmpegAudioNormalizer({ ffmpegPath: input.ffmpegPath });
|
|
18
|
+
return {
|
|
19
|
+
id: "azure-mai",
|
|
20
|
+
supportsServerDeadline: true,
|
|
21
|
+
deploymentFunded: { model: input.model, pricing: input.pricing ?? null },
|
|
22
|
+
available: () => Boolean(input.apiKey),
|
|
23
|
+
async transcribe({ audio, mimeType, filename, requestId, signal }) {
|
|
24
|
+
let bytes = audio;
|
|
25
|
+
let contentType = mimeType;
|
|
26
|
+
let name = filename;
|
|
27
|
+
// Resumable segments and credit-billed one-shot uploads already arrive
|
|
28
|
+
// as server-normalized WAV. Anything else (credit billing off) gets the
|
|
29
|
+
// same bounded decoder before entering Speech's file API.
|
|
30
|
+
if (!["audio/wav", "audio/x-wav", "audio/mpeg", "audio/flac"].includes(mimeType)) {
|
|
31
|
+
const normalized = await normalize({
|
|
32
|
+
audio,
|
|
33
|
+
mimeType,
|
|
34
|
+
maxDurationSeconds: 600,
|
|
35
|
+
...(signal ? { signal } : {}),
|
|
36
|
+
});
|
|
37
|
+
bytes = normalized.bytes;
|
|
38
|
+
contentType = "audio/wav";
|
|
39
|
+
name = "audio.wav";
|
|
40
|
+
}
|
|
41
|
+
const form = new FormData();
|
|
42
|
+
form.append("audio", new Blob([Uint8Array.from(bytes).buffer], { type: contentType }), name);
|
|
43
|
+
form.append(
|
|
44
|
+
"definition",
|
|
45
|
+
JSON.stringify({ enhancedMode: { enabled: true, model: input.model } }),
|
|
46
|
+
);
|
|
47
|
+
let response: Response;
|
|
48
|
+
try {
|
|
49
|
+
response = await fetchImpl(
|
|
50
|
+
`${input.endpoint.replace(/\/+$/, "")}/speechtotext/transcriptions:transcribe?api-version=${encodeURIComponent(input.apiVersion)}`,
|
|
51
|
+
{
|
|
52
|
+
method: "POST",
|
|
53
|
+
headers: {
|
|
54
|
+
"Ocp-Apim-Subscription-Key": input.apiKey,
|
|
55
|
+
"x-opengeni-request-id": requestId,
|
|
56
|
+
},
|
|
57
|
+
body: form,
|
|
58
|
+
...(signal ? { signal } : {}),
|
|
59
|
+
},
|
|
60
|
+
);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
throw fetchError(error);
|
|
63
|
+
}
|
|
64
|
+
if (!response.ok) throw responseError(response.status);
|
|
65
|
+
const body = await response.json().catch(() => null);
|
|
66
|
+
if (
|
|
67
|
+
!body ||
|
|
68
|
+
!Array.isArray(body.combinedPhrases) ||
|
|
69
|
+
!body.combinedPhrases.every(
|
|
70
|
+
(phrase: unknown) =>
|
|
71
|
+
typeof phrase === "object" &&
|
|
72
|
+
phrase !== null &&
|
|
73
|
+
"text" in phrase &&
|
|
74
|
+
typeof phrase.text === "string",
|
|
75
|
+
)
|
|
76
|
+
) {
|
|
77
|
+
throw responseError(502);
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
usage:
|
|
81
|
+
typeof body.durationMilliseconds === "number" &&
|
|
82
|
+
Number.isFinite(body.durationMilliseconds) &&
|
|
83
|
+
body.durationMilliseconds >= 0
|
|
84
|
+
? { kind: "duration" as const, seconds: body.durationMilliseconds / 1000 }
|
|
85
|
+
: null,
|
|
86
|
+
text: body.combinedPhrases.map((phrase: { text: string }) => phrase.text).join("\n"),
|
|
87
|
+
languages: [
|
|
88
|
+
...new Set<string>(
|
|
89
|
+
(Array.isArray(body.phrases) ? body.phrases : []).flatMap(
|
|
90
|
+
(phrase: { locale?: unknown }) =>
|
|
91
|
+
typeof phrase?.locale === "string" && phrase.locale ? [phrase.locale] : [],
|
|
92
|
+
),
|
|
93
|
+
),
|
|
94
|
+
],
|
|
95
|
+
};
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { voiceInputModelReportsDurationOnly, type VoiceInputPricing } from "@opengeni/config";
|
|
1
2
|
import type { TranscriptionProvider } from "@opengeni/core";
|
|
2
|
-
import { fetchError, responseError } from "./openai";
|
|
3
|
+
import { fetchError, parseTranscriptionResponseBody, responseError } from "./openai";
|
|
3
4
|
|
|
4
5
|
export function createAzureOpenAiTranscriptionProvider(input: {
|
|
5
6
|
endpoint: string;
|
|
@@ -7,17 +8,27 @@ export function createAzureOpenAiTranscriptionProvider(input: {
|
|
|
7
8
|
apiVersion: string;
|
|
8
9
|
apiKey: string | null;
|
|
9
10
|
adToken: string | null;
|
|
11
|
+
/** Underlying model of the deployment; defaults to the deployment name. */
|
|
12
|
+
model?: string;
|
|
13
|
+
pricing?: VoiceInputPricing | null;
|
|
10
14
|
fetch?: typeof fetch;
|
|
11
15
|
}): TranscriptionProvider {
|
|
12
16
|
const fetchImpl = input.fetch ?? fetch;
|
|
13
|
-
const
|
|
17
|
+
const model = input.model ?? input.deployment;
|
|
18
|
+
const endpoint = input.endpoint.replace(/\/+$/, "");
|
|
19
|
+
const url = `${endpoint}/openai/deployments/${encodeURIComponent(input.deployment)}/audio/transcriptions?api-version=${encodeURIComponent(input.apiVersion)}`;
|
|
14
20
|
return {
|
|
15
21
|
id: "azure-openai",
|
|
16
22
|
supportsServerDeadline: true,
|
|
23
|
+
deploymentFunded: { model, pricing: input.pricing ?? null },
|
|
17
24
|
available: () => Boolean(input.apiKey || input.adToken),
|
|
18
25
|
async transcribe({ audio, mimeType, filename, requestId, signal }) {
|
|
19
26
|
const form = new FormData();
|
|
20
27
|
form.append("file", new Blob([Uint8Array.from(audio).buffer], { type: mimeType }), filename);
|
|
28
|
+
// Whisper reports its billed audio duration only in verbose_json.
|
|
29
|
+
if (voiceInputModelReportsDurationOnly(model)) {
|
|
30
|
+
form.append("response_format", "verbose_json");
|
|
31
|
+
}
|
|
21
32
|
const headers: Record<string, string> = input.apiKey
|
|
22
33
|
? { "api-key": input.apiKey, "x-opengeni-request-id": requestId }
|
|
23
34
|
: { Authorization: `Bearer ${input.adToken}`, "x-opengeni-request-id": requestId };
|
|
@@ -34,13 +45,11 @@ export function createAzureOpenAiTranscriptionProvider(input: {
|
|
|
34
45
|
}
|
|
35
46
|
if (!response.ok) throw responseError(response.status);
|
|
36
47
|
const body = await response.json().catch(() => null);
|
|
37
|
-
|
|
48
|
+
const parsed = parseTranscriptionResponseBody(body);
|
|
49
|
+
if (!parsed) {
|
|
38
50
|
throw responseError(502);
|
|
39
51
|
}
|
|
40
|
-
return
|
|
41
|
-
text: body.text,
|
|
42
|
-
languages: typeof body.language === "string" && body.language ? [body.language] : [],
|
|
43
|
-
};
|
|
52
|
+
return parsed;
|
|
44
53
|
},
|
|
45
54
|
};
|
|
46
55
|
}
|
|
@@ -1,20 +1,151 @@
|
|
|
1
1
|
import { CODEX_CLIENT_VERSION, CODEX_ORIGINATOR } from "@opengeni/codex/constants";
|
|
2
|
+
import type { CodexFetch } from "@opengeni/codex";
|
|
2
3
|
import type { Settings } from "@opengeni/config";
|
|
3
4
|
import {
|
|
4
5
|
type TranscriptionAvailabilityContext,
|
|
5
6
|
type TranscriptionProvider,
|
|
6
7
|
TranscriptionServiceError,
|
|
7
8
|
} from "@opengeni/core";
|
|
8
|
-
import {
|
|
9
|
-
|
|
9
|
+
import {
|
|
10
|
+
acquireSubscriptionCoreCodexOperationLease,
|
|
11
|
+
buildSubscriptionCoreCodexConnectionTokenResolver,
|
|
12
|
+
buildSubscriptionCoreCodexOperationFetch,
|
|
13
|
+
getWorkspace,
|
|
14
|
+
listSubscriptionCoreCodexOperationCandidates,
|
|
15
|
+
readCodexCutoverDisposition,
|
|
16
|
+
releaseSubscriptionCoreCodexOperationLease,
|
|
17
|
+
renewSubscriptionCoreCodexOperationLease,
|
|
18
|
+
type Database,
|
|
19
|
+
type SubscriptionCoreCodexOperationLeaseRef,
|
|
20
|
+
type SubscriptionCoreCodexOperationScope,
|
|
21
|
+
} from "@opengeni/db";
|
|
22
|
+
import { fetchError } from "./openai";
|
|
23
|
+
import {
|
|
24
|
+
coreTranscriptionResult,
|
|
25
|
+
coreTranscriptionUnavailable,
|
|
26
|
+
withoutFallback,
|
|
27
|
+
} from "./subscription-core";
|
|
10
28
|
|
|
11
29
|
const TRANSCRIBE_URL = "https://chatgpt.com/backend-api/transcribe";
|
|
12
30
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Codex transcription on the shared subscription core (M3 PR 2c, EP-N01..N04):
|
|
33
|
+
* a sessionless operation for the authenticated caller in an explicit
|
|
34
|
+
* account/workspace context, on a shared organization- or workspace-scoped
|
|
35
|
+
* connection only, under its own operation lease and the per-connection
|
|
36
|
+
* refresh lock. It never reads the legacy active pointer.
|
|
37
|
+
*/
|
|
38
|
+
async function transcribeOnCore(
|
|
39
|
+
input: { settings: Settings; db: Database; fetch: typeof fetch },
|
|
40
|
+
request: {
|
|
41
|
+
accountId: string;
|
|
42
|
+
workspaceId: string;
|
|
43
|
+
subjectId: string;
|
|
44
|
+
requestId: string;
|
|
45
|
+
send: (
|
|
46
|
+
accessToken: string,
|
|
47
|
+
accountId: string | null,
|
|
48
|
+
fetchImpl: CodexFetch,
|
|
49
|
+
) => Promise<Response>;
|
|
50
|
+
},
|
|
51
|
+
): Promise<{ text: string; languages: string[] }> {
|
|
52
|
+
const scope: SubscriptionCoreCodexOperationScope = {
|
|
53
|
+
kind: "workspace",
|
|
54
|
+
accountId: request.accountId,
|
|
55
|
+
workspaceId: request.workspaceId,
|
|
56
|
+
subjectId: request.subjectId,
|
|
57
|
+
};
|
|
58
|
+
const candidates = await listSubscriptionCoreCodexOperationCandidates(input.db, scope);
|
|
59
|
+
const operationId = crypto.randomUUID();
|
|
60
|
+
const attemptId = crypto.randomUUID();
|
|
61
|
+
for (const candidate of candidates) {
|
|
62
|
+
const ref: SubscriptionCoreCodexOperationLeaseRef = {
|
|
63
|
+
operationId,
|
|
64
|
+
attemptId,
|
|
65
|
+
operationKind: "transcription",
|
|
66
|
+
connectionId: candidate.connectionId,
|
|
67
|
+
holderId: `transcription:${request.requestId}`.slice(0, 256),
|
|
68
|
+
generation: 1,
|
|
69
|
+
};
|
|
70
|
+
const lease = await acquireSubscriptionCoreCodexOperationLease(input.db, scope, ref);
|
|
71
|
+
if (lease.kind !== "acquired") continue;
|
|
72
|
+
try {
|
|
73
|
+
const resolver = buildSubscriptionCoreCodexConnectionTokenResolver(
|
|
74
|
+
input.db,
|
|
75
|
+
input.settings,
|
|
76
|
+
scope,
|
|
77
|
+
candidate.connectionId,
|
|
78
|
+
ref,
|
|
79
|
+
);
|
|
80
|
+
const requestFetch = buildSubscriptionCoreCodexOperationFetch(
|
|
81
|
+
input.db,
|
|
82
|
+
scope,
|
|
83
|
+
ref,
|
|
84
|
+
candidate.connectionId,
|
|
85
|
+
input.fetch,
|
|
86
|
+
{ requestId: `transcription:${request.requestId}` },
|
|
87
|
+
);
|
|
88
|
+
const dispatch = async (force: boolean): Promise<Response> => {
|
|
89
|
+
const token = force ? await resolver.refresh() : await resolver.getToken();
|
|
90
|
+
// Pre-dispatch fence: the exact operation lease must still be live.
|
|
91
|
+
if (!(await renewSubscriptionCoreCodexOperationLease(input.db, scope, ref))) {
|
|
92
|
+
throw coreTranscriptionUnavailable();
|
|
93
|
+
}
|
|
94
|
+
return await request.send(token.accessToken, token.chatgptAccountId, requestFetch);
|
|
95
|
+
};
|
|
96
|
+
let response: Response;
|
|
97
|
+
try {
|
|
98
|
+
response = await dispatch(false);
|
|
99
|
+
if (response.status === 401) {
|
|
100
|
+
await response.arrayBuffer();
|
|
101
|
+
response = await dispatch(true);
|
|
102
|
+
}
|
|
103
|
+
} catch (error) {
|
|
104
|
+
if (error instanceof TranscriptionServiceError) throw error;
|
|
105
|
+
// A provider transport failure keeps its classification but is never
|
|
106
|
+
// replayed through another provider.
|
|
107
|
+
throw withoutFallback(fetchError(error));
|
|
108
|
+
}
|
|
109
|
+
// Keep operation custody through parsing, not just response headers.
|
|
110
|
+
return await coreTranscriptionResult(response);
|
|
111
|
+
} finally {
|
|
112
|
+
await releaseSubscriptionCoreCodexOperationLease(input.db, scope, ref).catch(() => false);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
throw coreTranscriptionUnavailable();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function sendTranscription(
|
|
119
|
+
fetchImpl: CodexFetch,
|
|
120
|
+
input: {
|
|
121
|
+
accessToken: string;
|
|
122
|
+
chatgptAccountId: string | null;
|
|
123
|
+
audio: Uint8Array;
|
|
124
|
+
mimeType: string;
|
|
125
|
+
filename: string;
|
|
126
|
+
requestId: string;
|
|
127
|
+
signal?: AbortSignal | undefined;
|
|
128
|
+
},
|
|
129
|
+
): Promise<Response> {
|
|
130
|
+
const form = new FormData();
|
|
131
|
+
form.append(
|
|
132
|
+
"file",
|
|
133
|
+
new Blob([Uint8Array.from(input.audio).buffer], { type: input.mimeType }),
|
|
134
|
+
input.filename,
|
|
16
135
|
);
|
|
17
|
-
return
|
|
136
|
+
return await fetchImpl(TRANSCRIBE_URL, {
|
|
137
|
+
method: "POST",
|
|
138
|
+
headers: {
|
|
139
|
+
Authorization: `Bearer ${input.accessToken}`,
|
|
140
|
+
...(input.chatgptAccountId ? { "ChatGPT-Account-ID": input.chatgptAccountId } : {}),
|
|
141
|
+
originator: CODEX_ORIGINATOR,
|
|
142
|
+
"User-Agent": `${CODEX_ORIGINATOR}/${CODEX_CLIENT_VERSION}`,
|
|
143
|
+
version: CODEX_CLIENT_VERSION,
|
|
144
|
+
"x-opengeni-request-id": input.requestId,
|
|
145
|
+
},
|
|
146
|
+
body: form,
|
|
147
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
148
|
+
});
|
|
18
149
|
}
|
|
19
150
|
|
|
20
151
|
export function createCodexSubscriptionTranscriptionProvider(input: {
|
|
@@ -32,74 +163,66 @@ export function createCodexSubscriptionTranscriptionProvider(input: {
|
|
|
32
163
|
// passes workspaceId so we only claim Codex when a subscription is
|
|
33
164
|
// attached; otherwise OpenAI/Azure remain eligible.
|
|
34
165
|
if (!context?.workspaceId) return true;
|
|
35
|
-
|
|
166
|
+
const accountId =
|
|
167
|
+
(context as { accountId?: string }).accountId ??
|
|
168
|
+
(await getWorkspace(input.db, context.workspaceId))?.accountId;
|
|
169
|
+
// An unresolvable account fails closed rather than guessing a path.
|
|
170
|
+
if (!accountId) return false;
|
|
171
|
+
const disposition = await readCodexCutoverDisposition(
|
|
172
|
+
input.db,
|
|
173
|
+
accountId,
|
|
174
|
+
context.workspaceId,
|
|
175
|
+
);
|
|
176
|
+
// A disabled cutover row is maintenance: unavailable, no legacy read.
|
|
177
|
+
if (disposition === "maintenance") return false;
|
|
178
|
+
if (disposition === "core") {
|
|
179
|
+
const candidates = await listSubscriptionCoreCodexOperationCandidates(input.db, {
|
|
180
|
+
kind: "workspace",
|
|
181
|
+
accountId,
|
|
182
|
+
workspaceId: context.workspaceId,
|
|
183
|
+
subjectId: context.subjectId ?? "service:subscription-core",
|
|
184
|
+
});
|
|
185
|
+
return candidates.length > 0;
|
|
186
|
+
}
|
|
187
|
+
return false;
|
|
36
188
|
});
|
|
37
189
|
return {
|
|
38
190
|
id: "codex-subscription",
|
|
39
191
|
supportsServerDeadline: true,
|
|
40
192
|
experimental: true,
|
|
41
193
|
available: probe,
|
|
42
|
-
async transcribe({
|
|
43
|
-
|
|
44
|
-
|
|
194
|
+
async transcribe({
|
|
195
|
+
audio,
|
|
196
|
+
mimeType,
|
|
197
|
+
filename,
|
|
198
|
+
workspaceId,
|
|
199
|
+
accountId: organizationId,
|
|
200
|
+
subjectId,
|
|
201
|
+
requestId,
|
|
202
|
+
signal,
|
|
203
|
+
}) {
|
|
204
|
+
const disposition = await readCodexCutoverDisposition(input.db, organizationId, workspaceId);
|
|
205
|
+
if (disposition === "maintenance") throw coreTranscriptionUnavailable();
|
|
206
|
+
|
|
207
|
+
return await transcribeOnCore(
|
|
208
|
+
{ settings: input.settings, db: input.db, fetch: fetchImpl },
|
|
209
|
+
{
|
|
210
|
+
accountId: organizationId,
|
|
211
|
+
workspaceId,
|
|
212
|
+
subjectId,
|
|
213
|
+
requestId,
|
|
214
|
+
send: async (accessToken, chatgptAccountId, requestFetch) =>
|
|
215
|
+
await sendTranscription(requestFetch, {
|
|
216
|
+
accessToken,
|
|
217
|
+
chatgptAccountId,
|
|
218
|
+
audio,
|
|
219
|
+
mimeType,
|
|
220
|
+
filename,
|
|
221
|
+
requestId,
|
|
222
|
+
signal,
|
|
223
|
+
}),
|
|
224
|
+
},
|
|
45
225
|
);
|
|
46
|
-
if (!account) {
|
|
47
|
-
throw new TranscriptionServiceError({
|
|
48
|
-
fallbackSafe: true,
|
|
49
|
-
code: "unavailable",
|
|
50
|
-
message: "Transcription is unavailable.",
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
const resolver = buildCodexTokenResolver(input.db, input.settings, workspaceId, account.id);
|
|
54
|
-
let token: Awaited<ReturnType<typeof resolver.getToken>>;
|
|
55
|
-
try {
|
|
56
|
-
token = await resolver.getToken();
|
|
57
|
-
} catch {
|
|
58
|
-
throw new TranscriptionServiceError({
|
|
59
|
-
fallbackSafe: true,
|
|
60
|
-
code: "unavailable",
|
|
61
|
-
message: "Transcription is unavailable.",
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
const request = async (accessToken: string, accountId: string | null) => {
|
|
65
|
-
const form = new FormData();
|
|
66
|
-
form.append(
|
|
67
|
-
"file",
|
|
68
|
-
new Blob([Uint8Array.from(audio).buffer], { type: mimeType }),
|
|
69
|
-
filename,
|
|
70
|
-
);
|
|
71
|
-
return await fetchImpl(TRANSCRIBE_URL, {
|
|
72
|
-
method: "POST",
|
|
73
|
-
headers: {
|
|
74
|
-
Authorization: `Bearer ${accessToken}`,
|
|
75
|
-
...(accountId ? { "ChatGPT-Account-ID": accountId } : {}),
|
|
76
|
-
originator: CODEX_ORIGINATOR,
|
|
77
|
-
"User-Agent": `${CODEX_ORIGINATOR}/${CODEX_CLIENT_VERSION}`,
|
|
78
|
-
version: CODEX_CLIENT_VERSION,
|
|
79
|
-
// Observability only; the upstream API is not treated as idempotent.
|
|
80
|
-
"x-opengeni-request-id": requestId,
|
|
81
|
-
},
|
|
82
|
-
body: form,
|
|
83
|
-
...(signal ? { signal } : {}),
|
|
84
|
-
});
|
|
85
|
-
};
|
|
86
|
-
let response: Response;
|
|
87
|
-
try {
|
|
88
|
-
response = await request(token.accessToken, token.chatgptAccountId);
|
|
89
|
-
if (response.status === 401) {
|
|
90
|
-
token = await resolver.refresh();
|
|
91
|
-
response = await request(token.accessToken, token.chatgptAccountId);
|
|
92
|
-
}
|
|
93
|
-
} catch (error) {
|
|
94
|
-
throw fetchError(error);
|
|
95
|
-
}
|
|
96
|
-
if (!response.ok) throw responseError(response.status);
|
|
97
|
-
const body = await response.json().catch(() => null);
|
|
98
|
-
if (!body || typeof body.text !== "string") throw responseError(502);
|
|
99
|
-
return {
|
|
100
|
-
text: body.text,
|
|
101
|
-
languages: typeof body.language === "string" && body.language ? [body.language] : [],
|
|
102
|
-
};
|
|
103
226
|
},
|
|
104
227
|
};
|
|
105
228
|
}
|