@opengeni/api-router 0.30.1 → 1.0.0
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 +3 -0
- package/dist/admission-trace.d.ts +8 -0
- package/dist/api-websocket.d.ts +18 -0
- package/dist/app.d.ts +50 -2
- package/dist/app.js +12 -1
- package/dist/artifact-catalog-cursor.d.ts +27 -0
- package/dist/auth/managed-auth-attempt-context.d.ts +10 -0
- package/dist/auth/managed-auth-rate-limits.d.ts +167 -0
- package/dist/auth/managed-auth-session-adapter.d.ts +6 -0
- package/dist/auth/managed-auth.d.ts +102 -3
- package/dist/auth/managed-email.d.ts +29 -0
- package/dist/auth/managed-sign-in-notifications.d.ts +4 -0
- package/dist/auth/new-signups-gate.d.ts +23 -0
- package/dist/auth/organization-user-setup.d.ts +80 -0
- package/dist/auth/signup-funnel-metrics.d.ts +44 -0
- package/dist/browser-controller-authority.d.ts +1 -61
- package/dist/browser-ephemeral.d.ts +5 -0
- package/dist/browser-state-authority.d.ts +1 -27
- package/dist/chunk-6TZ5LG3O.js +123948 -0
- package/dist/chunk-6TZ5LG3O.js.map +1 -0
- package/dist/chunk-OGQDXVXY.js +18 -0
- package/dist/chunk-OGQDXVXY.js.map +1 -0
- package/dist/claude-subscription-account-conflicts.d.ts +1 -0
- package/dist/claude-subscription-account-usage.d.ts +39 -0
- package/dist/claude-subscription-oauth.d.ts +25 -0
- package/dist/claude-subscription-profile.d.ts +9 -0
- package/dist/claude-subscription-usage.d.ts +44 -0
- package/dist/claude-workspace-connection.d.ts +15 -0
- package/dist/codemode.d.ts +32 -1
- package/dist/company-brain-okf.d.ts +24 -0
- package/dist/connected-machine-computer-access.d.ts +11 -0
- package/dist/connection-ownership.d.ts +54 -0
- package/dist/controller-data-plane.d.ts +32 -0
- package/dist/editable-artifact-office-import.d.ts +7 -4
- package/dist/editable-artifact-source-session.d.ts +3 -0
- package/dist/editable-artifact-websocket.d.ts +10 -18
- package/dist/editable-artifact-workspace-files.d.ts +1 -1
- package/dist/fatal-process-boundary.d.ts +25 -0
- package/dist/github-access.d.ts +31 -2
- package/dist/http/acting-person.d.ts +24 -0
- package/dist/http/api-contract-compat.d.ts +19 -0
- package/dist/http/api-error.d.ts +27 -1
- package/dist/http/cors.d.ts +17 -0
- package/dist/http/deprecation.d.ts +42 -0
- package/dist/http/interaction-control-error.d.ts +13 -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/request-body.d.ts +27 -0
- package/dist/http/request-source.d.ts +52 -0
- package/dist/http/sse.d.ts +17 -6
- package/dist/http/unmatched-route.d.ts +18 -0
- package/dist/http/user-content.d.ts +36 -0
- package/dist/http/websocket-upgrade-dispatch.d.ts +18 -0
- package/dist/index.d.ts +10 -3
- package/dist/index.js +1129 -166
- package/dist/index.js.map +1 -1
- package/dist/integration-endpoint-test.d.ts +20 -0
- package/dist/integrations/api-integrations.d.ts +2 -2
- package/dist/integrations/atlassian.d.ts +29 -3
- package/dist/integrations/connect-authority.d.ts +1 -0
- package/dist/integrations/connect-callback-return.d.ts +6 -0
- package/dist/integrations/fiken.d.ts +16 -2
- package/dist/integrations/github-app-connect.d.ts +47 -0
- package/dist/integrations/github-installation-proof.d.ts +3 -0
- package/dist/integrations/github-lens-connect.d.ts +116 -0
- package/dist/integrations/github-skill-source.d.ts +1 -5
- package/dist/integrations/google-drive.d.ts +25 -0
- package/dist/integrations/integration-commit-authority.d.ts +13 -0
- package/dist/integrations/marketplace-plugin.d.ts +2691 -0
- package/dist/integrations/oauth-client.d.ts +178 -18
- package/dist/integrations/oauth-profiles.d.ts +222 -0
- package/dist/integrations/oauth-return-path.d.ts +1 -0
- package/dist/integrations/personal-github-repositories.d.ts +84 -0
- package/dist/integrations/personal-github.d.ts +42 -0
- package/dist/integrations/pr-review-provider.d.ts +22 -0
- package/dist/integrations/provider-oauth.d.ts +19 -1
- package/dist/integrations/slack-app-home.d.ts +24 -0
- package/dist/integrations/slack-bot.d.ts +367 -12
- package/dist/integrations/slack-file-upload-flow.d.ts +62 -0
- package/dist/integrations/slack-install.d.ts +20 -0
- package/dist/integrations/slack-interactions.d.ts +113 -10
- package/dist/integrations/slack-mrkdwn.d.ts +41 -0
- package/dist/integrations/slack-routing.d.ts +120 -0
- package/dist/integrations/slack-session-defaults.d.ts +58 -0
- package/dist/integrations/slack-task-file-upload.d.ts +36 -0
- package/dist/integrations/social-oauth.d.ts +7 -0
- package/dist/interaction-agent-access.d.ts +15 -0
- package/dist/interaction-frame-proxy.d.ts +68 -0
- package/dist/interaction-metrics.d.ts +2 -0
- package/dist/mcp/action-catalog-types.d.ts +9 -0
- package/dist/mcp/action-catalog.gen.d.ts +2 -0
- package/dist/mcp/capability-account-readiness.d.ts +7 -0
- package/dist/mcp/child-read-evidence.d.ts +9 -0
- package/dist/mcp/command-read.d.ts +24 -0
- package/dist/mcp/company-profile-agent-admin.d.ts +44 -0
- package/dist/mcp/contract-input.d.ts +11 -0
- package/dist/mcp/documents.d.ts +7 -5
- package/dist/mcp/files.d.ts +2 -2
- package/dist/mcp/first-party-tool-permissions.d.ts +650 -0
- package/dist/mcp/knowledge-entries.d.ts +5 -0
- package/dist/mcp/orchestration-failure-diagnostic.d.ts +43 -0
- package/dist/mcp/receipts.d.ts +9 -0
- package/dist/mcp/request-abort.d.ts +19 -0
- package/dist/mcp/scheduled-task-input.d.ts +1189 -0
- package/dist/mcp/scheduled-task-view.d.ts +22 -4
- package/dist/mcp/server.d.ts +255 -3
- package/dist/mcp/session-event-view.d.ts +94 -0
- package/dist/mcp/session-view.d.ts +66 -2
- package/dist/mcp/session-wait.d.ts +174 -0
- package/dist/mcp-oauth.d.ts +52 -0
- package/dist/model-catalog.d.ts +11 -31
- package/dist/observability.d.ts +3 -1
- package/dist/organization-mcp.d.ts +52 -0
- package/dist/organization-recovery-notifications.d.ts +41 -0
- package/dist/routes/analytics-consent.d.ts +26 -0
- package/dist/routes/api-integrations.d.ts +25 -0
- package/dist/routes/api-keys.d.ts +17 -0
- package/dist/routes/artifact-catalog.d.ts +6 -0
- package/dist/routes/automations.d.ts +19 -0
- package/dist/routes/billing.d.ts +49 -0
- package/dist/routes/browser-sessions.d.ts +71 -3
- 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 +146 -0
- package/dist/routes/codex.d.ts +76 -2
- package/dist/routes/company-brain.d.ts +3 -0
- package/dist/routes/company-profile.d.ts +2 -1
- package/dist/routes/computer-sessions.d.ts +14 -0
- package/dist/routes/connect.d.ts +5 -0
- package/dist/routes/editable-artifacts.d.ts +2 -0
- package/dist/routes/external-identity-links.d.ts +6 -0
- package/dist/routes/feedback.d.ts +3 -0
- package/dist/routes/files.d.ts +4 -0
- package/dist/routes/github-browser-pages.d.ts +12 -0
- package/dist/routes/github.d.ts +2 -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 +30 -1
- package/dist/routes/knowledge.d.ts +3 -0
- package/dist/routes/managed-auth-session-sets.d.ts +26 -0
- package/dist/routes/managed-onboarding.d.ts +29 -0
- package/dist/routes/managed-sign-in-methods.d.ts +6 -0
- package/dist/routes/model-connection-access.d.ts +3 -0
- package/dist/routes/organization-integration-policy.d.ts +3 -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-providers.d.ts +3 -0
- package/dist/routes/organization-recovery.d.ts +19 -0
- package/dist/routes/organization-service-accounts.d.ts +3 -0
- package/dist/routes/organization-sessions.d.ts +26 -0
- package/dist/routes/personal-github-git-broker.d.ts +29 -0
- package/dist/routes/personal-github.d.ts +3 -0
- package/dist/routes/pr-review-github.d.ts +3 -0
- package/dist/routes/pr-review.d.ts +3 -0
- package/dist/routes/session-artifact-associations.d.ts +4 -0
- package/dist/routes/session-history-imports.d.ts +9 -0
- package/dist/routes/sessions.d.ts +44 -6
- package/dist/routes/skill-content.d.ts +4 -0
- package/dist/routes/skill-install-authority.d.ts +6 -0
- package/dist/routes/subscription-account-pools.d.ts +34 -0
- package/dist/routes/subscription-pool-access.d.ts +16 -0
- package/dist/routes/supergrok.d.ts +6 -1
- package/dist/routes/usage-allowances.d.ts +12 -0
- package/dist/routes/user-resource-authorities.d.ts +3 -0
- package/dist/routes/workspace-artifacts.d.ts +2 -1
- package/dist/routes/workspace-capture.d.ts +10 -2
- package/dist/routes/workspace-integrations.d.ts +35 -0
- package/dist/routes/workspace-learning.d.ts +3 -0
- package/dist/routes/workspace-model-providers.d.ts +4 -0
- package/dist/routes/workspaces.d.ts +29 -0
- package/dist/sandbox/auth-callout.d.ts +8 -0
- package/dist/sandbox/channel-a.d.ts +19 -1
- package/dist/sandbox/connection-authority.d.ts +3 -0
- package/dist/sandbox/enrollment.d.ts +9 -1
- package/dist/sandbox/machines.d.ts +5 -2
- package/dist/sandbox/metrics-ingestion.d.ts +28 -20
- package/dist/sandbox/rematerialize.d.ts +2 -0
- package/dist/sandbox/session-attach-variable-sets.d.ts +30 -0
- package/dist/sandbox/viewer.d.ts +26 -1
- package/dist/sandbox-file-artifacts.d.ts +50 -0
- package/dist/scheduled-task-deletion.d.ts +13 -0
- package/dist/session-create-observability.d.ts +5 -0
- package/dist/session-event-view-MPS2OZD3.js +292 -0
- package/dist/session-event-view-MPS2OZD3.js.map +1 -0
- package/dist/site-session-origin.d.ts +13 -0
- package/dist/site-uploads.d.ts +41 -0
- package/dist/slack-reaction-files.d.ts +1 -1
- package/dist/temporal-schedule-cleanup.d.ts +1 -0
- package/dist/temporal-schedule-sync.d.ts +26 -0
- package/dist/transcription/providers/xai-subscription.d.ts +1 -0
- package/dist/transcription/service.d.ts +2 -1
- package/dist/work-discovery-observability.d.ts +33 -0
- package/dist/workspace-artifact-content.d.ts +28 -0
- package/dist/workspace-artifact-provenance.d.ts +7 -0
- package/dist/workspace-delete-observability.d.ts +10 -0
- package/dist/workspace-deletion.d.ts +6 -0
- package/dist/workspace-state-projection.d.ts +3 -5
- package/dist/workspace-tool-gateway-observability.d.ts +17 -0
- package/dist/workspace-tool-gateway.d.ts +123 -0
- package/dist/workspace-webhook-dispatch.d.ts +26 -0
- package/package.json +23 -19
- package/src/access-grant-rls.ts +75 -0
- package/src/admission-trace.ts +14 -0
- package/src/api-websocket.ts +23 -0
- package/src/app.ts +1974 -256
- package/src/artifact-catalog-cursor.ts +60 -0
- package/src/auth/managed-auth-attempt-context.ts +70 -0
- package/src/auth/managed-auth-rate-limits.ts +252 -0
- package/src/auth/managed-auth-session-adapter.ts +222 -0
- package/src/auth/managed-auth.ts +536 -60
- package/src/auth/managed-email.ts +174 -0
- 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 +307 -0
- package/src/auth/signup-funnel-metrics.ts +164 -0
- package/src/browser-controller-authority.ts +1 -186
- package/src/browser-ephemeral.ts +39 -0
- package/src/browser-state-authority.ts +1 -236
- package/src/claude-subscription-account-conflicts.ts +12 -0
- package/src/claude-subscription-account-usage.ts +48 -0
- package/src/claude-subscription-oauth.ts +362 -0
- package/src/claude-subscription-profile.ts +73 -0
- package/src/claude-subscription-usage.ts +97 -0
- package/src/claude-workspace-connection.ts +82 -0
- package/src/codemode.ts +194 -30
- package/src/codex-realtime.ts +8 -2
- package/src/company-brain-okf.ts +340 -0
- package/src/connected-machine-computer-access.ts +33 -0
- package/src/connection-ownership.ts +199 -0
- package/src/controller-data-plane.ts +81 -0
- package/src/editable-artifact-native-kernel.ts +26 -15
- package/src/editable-artifact-office-import.ts +77 -9
- package/src/editable-artifact-production.ts +23 -7
- package/src/editable-artifact-source-session.ts +123 -0
- package/src/editable-artifact-websocket.ts +27 -21
- package/src/editable-artifact-workspace-files.ts +31 -6
- package/src/fatal-process-boundary.ts +246 -0
- package/src/gateway-realtime.ts +1 -1
- package/src/github-access.ts +147 -5
- package/src/http/acting-person.ts +71 -0
- package/src/http/api-contract-compat.ts +49 -0
- package/src/http/api-error.ts +115 -1
- package/src/http/auth.ts +48 -0
- package/src/http/cors.ts +67 -0
- package/src/http/deprecation.ts +118 -0
- package/src/http/interaction-control-error.ts +164 -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/request-body.ts +127 -0
- package/src/http/request-source.ts +178 -0
- package/src/http/sse.ts +486 -132
- package/src/http/unmatched-route.ts +60 -0
- package/src/http/user-content.ts +158 -0
- package/src/http/websocket-upgrade-dispatch.ts +29 -0
- package/src/index.ts +157 -52
- package/src/integration-endpoint-test.ts +291 -0
- package/src/integrations/api-integrations.ts +98 -11
- package/src/integrations/atlassian.ts +474 -136
- package/src/integrations/connect-authority.ts +2 -0
- package/src/integrations/connect-callback-return.ts +86 -0
- package/src/integrations/fiken.ts +354 -64
- package/src/integrations/github-app-connect.ts +435 -0
- package/src/integrations/github-installation-proof.ts +60 -0
- package/src/integrations/github-lens-connect.ts +76 -0
- package/src/integrations/github-skill-source.ts +2 -142
- package/src/integrations/google-drive.ts +820 -222
- package/src/integrations/integration-commit-authority.ts +69 -0
- package/src/integrations/marketplace-plugin.ts +48 -0
- package/src/integrations/oauth-client.ts +1356 -459
- package/src/integrations/oauth-profiles.ts +537 -0
- package/src/integrations/oauth-return-path.ts +18 -0
- package/src/integrations/personal-github-repositories.ts +674 -0
- package/src/integrations/personal-github.ts +825 -0
- package/src/integrations/pr-review-provider.ts +246 -0
- package/src/integrations/provider-oauth.ts +250 -22
- package/src/integrations/slack-app-home.ts +300 -0
- package/src/integrations/slack-bot.ts +963 -239
- package/src/integrations/slack-file-upload-flow.ts +147 -0
- package/src/integrations/slack-install.ts +83 -0
- package/src/integrations/slack-interactions.ts +3170 -474
- package/src/integrations/slack-mrkdwn.ts +193 -0
- package/src/integrations/slack-routing.ts +337 -0
- package/src/integrations/slack-session-defaults.ts +224 -0
- package/src/integrations/slack-task-file-upload.ts +323 -0
- package/src/integrations/social-oauth.ts +213 -15
- package/src/interaction-agent-access.ts +48 -0
- package/src/interaction-frame-proxy.ts +409 -0
- package/src/interaction-metrics.ts +30 -0
- package/src/mcp/action-catalog-types.ts +9 -0
- package/src/mcp/action-catalog.gen.ts +6696 -0
- package/src/mcp/capability-account-readiness.ts +17 -0
- package/src/mcp/child-read-evidence.ts +19 -0
- package/src/mcp/command-read.ts +109 -0
- package/src/mcp/company-profile-agent-admin.ts +198 -0
- package/src/mcp/contract-input.ts +141 -0
- package/src/mcp/documents.ts +65 -377
- package/src/mcp/editable-artifacts.ts +12 -6
- package/src/mcp/files.ts +80 -38
- package/src/mcp/first-party-tool-permissions.ts +305 -0
- package/src/mcp/knowledge-entries.ts +322 -0
- package/src/mcp/orchestration-failure-diagnostic.ts +43 -0
- package/src/mcp/receipts.ts +34 -0
- package/src/mcp/request-abort.ts +44 -0
- package/src/mcp/scheduled-task-input.ts +76 -0
- package/src/mcp/scheduled-task-view.ts +44 -3
- package/src/mcp/server.ts +3030 -1267
- package/src/mcp/session-event-view.ts +383 -0
- package/src/mcp/session-view.ts +84 -3
- package/src/mcp/session-wait.ts +665 -0
- package/src/mcp-oauth.ts +1123 -0
- package/src/model-catalog.ts +91 -333
- package/src/observability.ts +15 -1
- package/src/organization-mcp.ts +397 -0
- package/src/organization-recovery-notifications.ts +103 -0
- package/src/routes/analytics-consent.ts +123 -0
- package/src/routes/api-integrations.ts +364 -74
- package/src/routes/api-keys.ts +336 -10
- package/src/routes/artifact-catalog.ts +279 -0
- package/src/routes/automations.ts +768 -0
- package/src/routes/billing.ts +461 -46
- package/src/routes/browser-sessions.ts +839 -131
- package/src/routes/canonical-human-identities.ts +90 -14
- package/src/routes/capabilities.ts +107 -6
- package/src/routes/channels.ts +20 -3
- package/src/routes/claude-subscription-accounts.ts +334 -0
- package/src/routes/claude-subscription-oauth.ts +142 -0
- package/src/routes/client-errors.ts +362 -0
- package/src/routes/codex.ts +833 -116
- package/src/routes/company-brain.ts +322 -0
- package/src/routes/company-profile.ts +65 -1
- package/src/routes/computer-sessions.ts +557 -106
- package/src/routes/connect.ts +1938 -0
- package/src/routes/connections.ts +1040 -349
- package/src/routes/documents.ts +488 -287
- package/src/routes/editable-artifacts.ts +79 -9
- package/src/routes/enrollments.ts +135 -39
- package/src/routes/environments.ts +154 -58
- package/src/routes/external-identity-links.ts +201 -0
- package/src/routes/feedback.ts +113 -0
- package/src/routes/files.ts +337 -39
- package/src/routes/github-browser-pages.ts +162 -0
- package/src/routes/github.ts +446 -144
- package/src/routes/insights-response-cache.ts +83 -0
- package/src/routes/insights-usage.ts +345 -0
- package/src/routes/insights.ts +153 -19
- package/src/routes/install.ts +133 -38
- package/src/routes/integration-facets.ts +107 -33
- package/src/routes/interaction-resources.ts +30 -3
- package/src/routes/knowledge.ts +488 -0
- package/src/routes/machines.ts +313 -15
- package/src/routes/managed-auth-session-sets.ts +1218 -0
- package/src/routes/managed-onboarding.ts +337 -0
- package/src/routes/managed-sign-in-methods.ts +433 -0
- package/src/routes/memory-slack-publications.ts +3 -2
- package/src/routes/model-connection-access.ts +208 -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 +178 -0
- package/src/routes/organization-memberships.ts +1019 -27
- package/src/routes/organization-model-providers.ts +293 -0
- package/src/routes/organization-recovery.ts +325 -0
- package/src/routes/organization-service-accounts.ts +128 -0
- package/src/routes/organization-sessions.ts +350 -0
- package/src/routes/personal-github-git-broker.ts +785 -0
- package/src/routes/personal-github.ts +370 -0
- package/src/routes/plugins.ts +251 -22
- package/src/routes/pr-review-github.ts +881 -0
- package/src/routes/pr-review.ts +622 -0
- package/src/routes/preference-registry.ts +12 -93
- package/src/routes/rigs.ts +167 -50
- package/src/routes/scheduled-tasks.ts +346 -41
- package/src/routes/session-artifact-associations.ts +87 -0
- package/src/routes/session-history-imports.ts +280 -0
- package/src/routes/sessions.ts +2306 -264
- package/src/routes/skill-content.ts +297 -0
- package/src/routes/skill-install-authority.ts +64 -0
- package/src/routes/skills.ts +62 -9
- package/src/routes/social.ts +46 -18
- package/src/routes/subscription-account-pools.ts +436 -0
- package/src/routes/subscription-pool-access.ts +126 -0
- package/src/routes/supergrok.ts +219 -303
- package/src/routes/transcription-recordings.ts +38 -3
- package/src/routes/transcriptions.ts +4 -0
- package/src/routes/usage-allowances.ts +378 -0
- package/src/routes/user-resource-authorities.ts +138 -0
- package/src/routes/video-generation.ts +14 -10
- package/src/routes/workspace-artifacts.ts +275 -69
- package/src/routes/workspace-capture.ts +21 -0
- package/src/routes/workspace-integrations.ts +576 -0
- package/src/routes/workspace-learning.ts +159 -0
- package/src/routes/workspace-model-providers.ts +148 -0
- package/src/routes/workspace-state.ts +38 -25
- package/src/routes/workspaces.ts +1004 -127
- package/src/sandbox/auth-callout.ts +96 -19
- package/src/sandbox/channel-a.ts +323 -24
- package/src/sandbox/connection-authority.ts +3 -0
- package/src/sandbox/enrollment.ts +81 -6
- package/src/sandbox/machines.ts +218 -76
- package/src/sandbox/metrics-ingestion.ts +411 -62
- package/src/sandbox/rematerialize.ts +121 -19
- package/src/sandbox/session-attach-variable-sets.ts +131 -0
- package/src/sandbox/viewer.ts +280 -25
- package/src/sandbox-file-artifacts.ts +413 -0
- package/src/scheduled-task-deletion.ts +138 -0
- package/src/session-create-observability.ts +46 -0
- package/src/session-realtime-context.ts +6 -3
- package/src/site-session-origin.ts +48 -0
- package/src/site-uploads.ts +224 -0
- package/src/slack-reaction-files.ts +16 -5
- package/src/temporal-schedule-cleanup.ts +13 -0
- package/src/temporal-schedule-sync.ts +74 -0
- package/src/transcription/providers/codex-subscription.ts +2 -0
- package/src/transcription/providers/openai.ts +1 -0
- package/src/transcription/providers/xai-subscription.ts +49 -3
- package/src/transcription/segmenter.ts +8 -2
- package/src/transcription/service.ts +43 -6
- package/src/work-discovery-observability.ts +121 -0
- package/src/workspace-artifact-content.ts +144 -0
- package/src/workspace-artifact-provenance.ts +104 -0
- package/src/workspace-delete-observability.ts +75 -0
- package/src/workspace-deletion.ts +73 -0
- package/src/workspace-state-projection.ts +18 -148
- package/src/workspace-tool-gateway-observability.ts +100 -0
- package/src/workspace-tool-gateway.ts +870 -0
- package/src/workspace-webhook-dispatch.ts +190 -0
- package/src/xai-subscription-auth.ts +9 -2
- package/dist/chunk-2PQMSRCB.js +0 -49759
- package/dist/chunk-2PQMSRCB.js.map +0 -1
- package/dist/routes/packs.d.ts +0 -3
- package/src/routes/packs.ts +0 -729
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `session_wait`: one blocking first-party MCP call that replaces the
|
|
3
|
+
* `sleep 55` plus three or four `session_events`/`session_get` probes an agent
|
|
4
|
+
* otherwise runs per loop while it waits for a child or peer session.
|
|
5
|
+
*
|
|
6
|
+
* The durable `session_events` table is the only authority. The NATS event bus
|
|
7
|
+
* is live fanout only, so every wake (bus, deadline, or the initial call) is
|
|
8
|
+
* followed by a database read and the returned rows are always the exact
|
|
9
|
+
* durable events, never the bus payload. Subscriptions are opened before the
|
|
10
|
+
* first read so an event committed between the read and the subscription
|
|
11
|
+
* cannot be missed.
|
|
12
|
+
*
|
|
13
|
+
* Timing facts: the built-in `opengeni` MCP server entry carries no
|
|
14
|
+
* `timeoutMs`, so the worker's MCP client uses the SDK default request timeout
|
|
15
|
+
* of 60 s and a longer call would surface as a `-32001` tool error. The wait is
|
|
16
|
+
* therefore capped at {@link SESSION_WAIT_MAX_SECONDS} both in the tool schema
|
|
17
|
+
* and inside {@link waitForSessionChanges}. The API's `Bun.serve`
|
|
18
|
+
* `idleTimeout` is 255 s, far above that cap.
|
|
19
|
+
*
|
|
20
|
+
* Cancellation: the API serves one transport per POST, so the worker's MCP
|
|
21
|
+
* `notifications/cancelled` never reaches this handler; instead the route binds
|
|
22
|
+
* the HTTP request's own abort to `transport.close()` (`request-abort.ts`),
|
|
23
|
+
* which aborts `extra.signal`. A worker that drops the call on Steer/Pause
|
|
24
|
+
* therefore ends the server-side wait promptly; the deadline bounds it anyway.
|
|
25
|
+
*
|
|
26
|
+
* The live bus is best-effort: a failed subscription degrades the wait to the
|
|
27
|
+
* durable pre-check plus the deadline re-check and is reported as
|
|
28
|
+
* `liveFanout: false` rather than failing the tool.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import type {
|
|
32
|
+
SessionEvent,
|
|
33
|
+
SessionEventSemanticClass,
|
|
34
|
+
SessionEventType,
|
|
35
|
+
} from "@opengeni/contracts";
|
|
36
|
+
import {
|
|
37
|
+
SESSION_EVENT_SEMANTIC_CLASS_TYPES,
|
|
38
|
+
SESSION_SYSTEM_UPDATE_WAKE_CLASS,
|
|
39
|
+
compactSessionEventResult,
|
|
40
|
+
isStreamedAssistantMessageCompletion,
|
|
41
|
+
turnCompletedReply,
|
|
42
|
+
type SessionSystemUpdateKind,
|
|
43
|
+
} from "@opengeni/contracts";
|
|
44
|
+
import { SESSION_EVENT_MCP_MAX_BYTES, capPayloadValue } from "./session-view";
|
|
45
|
+
|
|
46
|
+
export const SESSION_WAIT_MAX_TARGETS = 16;
|
|
47
|
+
export const SESSION_WAIT_MAX_SECONDS = 50;
|
|
48
|
+
export const SESSION_WAIT_DEFAULT_SECONDS = 45;
|
|
49
|
+
/** Newest-first durable rows read per target on every database check. */
|
|
50
|
+
export const SESSION_WAIT_EVENTS_PER_TARGET = 20;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The durable event types that matter to a waiter: turn lifecycle, completed
|
|
54
|
+
* agent messages, blocking failures, goal facts, and session status/control
|
|
55
|
+
* changes. Raw deltas, tool receipts, sandbox/machine diagnostics, and PTY
|
|
56
|
+
* noise never wake a waiter; `session_events` remains the drill-down for them.
|
|
57
|
+
* The change mode further drops per-message completions: see
|
|
58
|
+
* {@link sessionWaitChangeEventMatches}.
|
|
59
|
+
*/
|
|
60
|
+
export const SESSION_WAIT_EVENT_TYPES = [
|
|
61
|
+
"turn.started",
|
|
62
|
+
"turn.completed",
|
|
63
|
+
"turn.failed",
|
|
64
|
+
"turn.cancelled",
|
|
65
|
+
"turn.superseded",
|
|
66
|
+
"turn.capacity_waiting",
|
|
67
|
+
"agent.message.completed",
|
|
68
|
+
"session.status.changed",
|
|
69
|
+
"session.requiresAction",
|
|
70
|
+
"session.humanInput.requested",
|
|
71
|
+
"session.control.paused",
|
|
72
|
+
"session.control.resumed",
|
|
73
|
+
"session.wait.started",
|
|
74
|
+
"session.wait.finished",
|
|
75
|
+
"tool.auth_needed",
|
|
76
|
+
"session.command.finished",
|
|
77
|
+
"credential.auth_needed",
|
|
78
|
+
"rig.setup.failed",
|
|
79
|
+
"goal.set",
|
|
80
|
+
"goal.updated",
|
|
81
|
+
"goal.progress",
|
|
82
|
+
"goal.rewrite.proposed",
|
|
83
|
+
"goal.rewrite.rejected",
|
|
84
|
+
"goal.completed",
|
|
85
|
+
"goal.paused",
|
|
86
|
+
"goal.resumed",
|
|
87
|
+
"goal.cleared",
|
|
88
|
+
"goal.continuation",
|
|
89
|
+
] as const satisfies readonly SessionEventType[];
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Settlement and blocking events that make a child result usable.
|
|
93
|
+
* Goal facts are deliberately absent: an agent can complete its durable goal
|
|
94
|
+
* before it emits the final assistant message and settles the turn. Completed
|
|
95
|
+
* agent messages are also absent because commentary messages use the same
|
|
96
|
+
* event type; an ordinary result-bearing `turn.completed` carries the
|
|
97
|
+
* authoritative final output.
|
|
98
|
+
*/
|
|
99
|
+
export const SESSION_WAIT_COMPLETION_EVENT_TYPES = [
|
|
100
|
+
"turn.completed",
|
|
101
|
+
"turn.failed",
|
|
102
|
+
"turn.cancelled",
|
|
103
|
+
"turn.superseded",
|
|
104
|
+
"turn.capacity_waiting",
|
|
105
|
+
"session.requiresAction",
|
|
106
|
+
"session.humanInput.requested",
|
|
107
|
+
"session.control.paused",
|
|
108
|
+
"tool.auth_needed",
|
|
109
|
+
"credential.auth_needed",
|
|
110
|
+
"rig.setup.failed",
|
|
111
|
+
"goal.paused",
|
|
112
|
+
] as const satisfies readonly SessionEventType[];
|
|
113
|
+
|
|
114
|
+
const SESSION_WAIT_COMPLETION_EVENT_TYPE_SET: ReadonlySet<string> = new Set(
|
|
115
|
+
SESSION_WAIT_COMPLETION_EVENT_TYPES,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* A completed turn is result-bearing only when it carries the ordinary final
|
|
120
|
+
* output. Segment-limit and maintenance turns settle one execution segment
|
|
121
|
+
* while the session still has work to do, so they must not release a parent.
|
|
122
|
+
*/
|
|
123
|
+
export function sessionWaitCompletionEventMatches(event: SessionEvent): boolean {
|
|
124
|
+
if (!SESSION_WAIT_COMPLETION_EVENT_TYPE_SET.has(event.type)) return false;
|
|
125
|
+
if (event.type !== "turn.completed") return true;
|
|
126
|
+
if (event.payload === null || typeof event.payload !== "object" || Array.isArray(event.payload)) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
const payload = event.payload as Record<string, unknown>;
|
|
130
|
+
return (
|
|
131
|
+
Object.prototype.hasOwnProperty.call(payload, "output") &&
|
|
132
|
+
!Object.prototype.hasOwnProperty.call(payload, "segmentLimit") &&
|
|
133
|
+
!Object.prototype.hasOwnProperty.call(payload, "maintenance")
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* `waitFor=change` wakes on settled changes. A per-message assistant completion
|
|
139
|
+
* (commentary, or a final message the turn is about to settle) is not one: the
|
|
140
|
+
* `turn.completed` that follows carries the answer. Waking on every progress
|
|
141
|
+
* note would only buy the waiter another poll. The phase-less, id-less
|
|
142
|
+
* completion older workers publish with `turn.completed` still matches.
|
|
143
|
+
* Readers pair this with `excludeStreamedAssistantMessages` in SQL.
|
|
144
|
+
*/
|
|
145
|
+
export function sessionWaitChangeEventMatches(event: SessionEvent): boolean {
|
|
146
|
+
return !isStreamedAssistantMessageCompletion(event);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** The self-session event that announces a newly pending machine input. */
|
|
150
|
+
export const SESSION_WAIT_OWN_PENDING_EVENT_TYPE =
|
|
151
|
+
"system.update.pending" satisfies SessionEventType;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Whether a pending own machine input of this kind ends the wait. Every
|
|
155
|
+
* pre-existing kind and `child_requires_action` are `immediate`; deferred
|
|
156
|
+
* child notices are reported but do not end the wait by themselves.
|
|
157
|
+
*/
|
|
158
|
+
export function ownPendingKindWakes(kind: string): boolean {
|
|
159
|
+
const wakeClass = SESSION_SYSTEM_UPDATE_WAKE_CLASS[kind as SessionSystemUpdateKind];
|
|
160
|
+
return wakeClass === undefined || wakeClass === "immediate";
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function ownPendingUpdateFacts(
|
|
164
|
+
kinds: readonly string[],
|
|
165
|
+
): Pick<
|
|
166
|
+
SessionWaitResult,
|
|
167
|
+
| "ownPendingUpdates"
|
|
168
|
+
| "ownPendingUpdateKinds"
|
|
169
|
+
| "ownPendingImmediateUpdates"
|
|
170
|
+
| "ownPendingDeferredUpdateKinds"
|
|
171
|
+
> {
|
|
172
|
+
const ownKinds = [...new Set(kinds)].sort();
|
|
173
|
+
return {
|
|
174
|
+
ownPendingUpdates: kinds.length,
|
|
175
|
+
ownPendingUpdateKinds: ownKinds,
|
|
176
|
+
ownPendingImmediateUpdates: kinds.filter((kind) => ownPendingKindWakes(kind)).length,
|
|
177
|
+
ownPendingDeferredUpdateKinds: ownKinds.filter((kind) => !ownPendingKindWakes(kind)),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Re-derive the caller's own pending-input facts after the returned content
|
|
183
|
+
* consumed some of that input, keeping the same byte bound.
|
|
184
|
+
*/
|
|
185
|
+
export function withOwnPendingUpdateKinds(
|
|
186
|
+
result: SessionWaitResult,
|
|
187
|
+
kinds: readonly string[],
|
|
188
|
+
): SessionWaitResult {
|
|
189
|
+
const { truncated: _truncated, bytes: _bytes, maxBytes, ...rest } = result;
|
|
190
|
+
return boundSessionWaitResult({ ...rest, ...ownPendingUpdateFacts(kinds) }, maxBytes);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const SEMANTIC_CLASS_PRIORITY: readonly SessionEventSemanticClass[] = [
|
|
194
|
+
"terminal",
|
|
195
|
+
"failure",
|
|
196
|
+
"control",
|
|
197
|
+
"checkpoint",
|
|
198
|
+
"tool_receipt",
|
|
199
|
+
"provider_account",
|
|
200
|
+
];
|
|
201
|
+
|
|
202
|
+
export function sessionWaitSemanticClass(type: SessionEventType): SessionEventSemanticClass {
|
|
203
|
+
for (const semanticClass of SEMANTIC_CLASS_PRIORITY) {
|
|
204
|
+
const types: readonly SessionEventType[] = SESSION_EVENT_SEMANTIC_CLASS_TYPES[semanticClass];
|
|
205
|
+
if (types.includes(type)) return semanticClass;
|
|
206
|
+
}
|
|
207
|
+
return "control";
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export type SessionWaitTarget = { sessionId: string; afterSequence: number };
|
|
211
|
+
|
|
212
|
+
export type SessionWaitEventSummary = {
|
|
213
|
+
/** True only when every semantic result field survived all projections. */
|
|
214
|
+
contentComplete?: boolean;
|
|
215
|
+
id: string;
|
|
216
|
+
sequence: number;
|
|
217
|
+
type: SessionEventType;
|
|
218
|
+
occurredAt: string;
|
|
219
|
+
turnId: string | null;
|
|
220
|
+
turnGeneration: number | null;
|
|
221
|
+
status: string;
|
|
222
|
+
text: string | null;
|
|
223
|
+
failure: {
|
|
224
|
+
error: string | null;
|
|
225
|
+
code: string | null;
|
|
226
|
+
retryable: boolean | null;
|
|
227
|
+
recovery: string | null;
|
|
228
|
+
} | null;
|
|
229
|
+
result?: unknown;
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
export type SessionWaitTargetResult = {
|
|
233
|
+
sessionId: string;
|
|
234
|
+
afterSequence: number;
|
|
235
|
+
/** Cursor for the next `session_wait`/`session_events after=` call. */
|
|
236
|
+
latestSequence: number;
|
|
237
|
+
hasMore: boolean;
|
|
238
|
+
events: SessionWaitEventSummary[];
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
export type SessionWaitResult = {
|
|
242
|
+
changed: SessionWaitTargetResult[];
|
|
243
|
+
ownPendingUpdates: number;
|
|
244
|
+
ownPendingUpdateKinds: string[];
|
|
245
|
+
/**
|
|
246
|
+
* Pending own inputs whose kind wakes the session by itself (every
|
|
247
|
+
* pre-existing kind plus `child_requires_action`). Only these end the wait;
|
|
248
|
+
* `deferred` child notices (resolution, pause, capacity wait, progress) are
|
|
249
|
+
* reported but keep the wait on the targets.
|
|
250
|
+
*/
|
|
251
|
+
ownPendingImmediateUpdates: number;
|
|
252
|
+
ownPendingDeferredUpdateKinds: string[];
|
|
253
|
+
waitedMs: number;
|
|
254
|
+
timedOut: boolean;
|
|
255
|
+
aborted: boolean;
|
|
256
|
+
/** False when at least one live-fanout subscription failed; the wait then relied on the deadline re-check. */
|
|
257
|
+
liveFanout: boolean;
|
|
258
|
+
truncated: boolean;
|
|
259
|
+
bytes: number;
|
|
260
|
+
maxBytes: number;
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
export type SessionWaitTargetRead = { events: readonly SessionEvent[]; hasMore: boolean };
|
|
264
|
+
|
|
265
|
+
export type SessionWaitSource = {
|
|
266
|
+
/** Durable forward read of matching events strictly after the target cursor. */
|
|
267
|
+
readTargetEvents: (target: SessionWaitTarget) => Promise<SessionWaitTargetRead>;
|
|
268
|
+
/** Kinds of the caller's own pending machine inputs; null disables self tracking. */
|
|
269
|
+
readOwnPendingUpdateKinds: (() => Promise<readonly string[]>) | null;
|
|
270
|
+
/** Live fanout subscription for one session; the returned function unsubscribes. */
|
|
271
|
+
subscribe: (
|
|
272
|
+
sessionId: string,
|
|
273
|
+
onEvents: (events: SessionEvent[]) => void | Promise<void>,
|
|
274
|
+
) => Promise<() => void>;
|
|
275
|
+
/**
|
|
276
|
+
* Re-run target authorization for the sessions about to be returned after a
|
|
277
|
+
* wait (parity with SSE re-authorization). Throws to refuse the result.
|
|
278
|
+
*/
|
|
279
|
+
reauthorizeTargets?: ((sessionIds: readonly string[]) => Promise<void>) | undefined;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
export type SessionWaitInput = {
|
|
283
|
+
targets: readonly SessionWaitTarget[];
|
|
284
|
+
ownSessionId: string | null;
|
|
285
|
+
maxWaitMs: number;
|
|
286
|
+
/** Target events that end the wait. Defaults to the ordinary activity set. */
|
|
287
|
+
targetEventTypes?: readonly SessionEventType[] | undefined;
|
|
288
|
+
/** Optional payload-aware refinement applied after the event-type filter. */
|
|
289
|
+
targetEventMatches?: ((event: SessionEvent) => boolean) | undefined;
|
|
290
|
+
source: SessionWaitSource;
|
|
291
|
+
signal?: AbortSignal | undefined;
|
|
292
|
+
now?: (() => number) | undefined;
|
|
293
|
+
maxBytes?: number | undefined;
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
type WakeReason = "bus" | "deadline" | "abort";
|
|
297
|
+
|
|
298
|
+
export async function waitForSessionChanges(input: SessionWaitInput): Promise<SessionWaitResult> {
|
|
299
|
+
const now = input.now ?? Date.now;
|
|
300
|
+
const startedAt = now();
|
|
301
|
+
// The cap is enforced here as well as in the tool schema: no caller can hold
|
|
302
|
+
// the API past the worker's 60 s MCP request timeout.
|
|
303
|
+
const deadlineAt =
|
|
304
|
+
startedAt + Math.min(Math.max(0, input.maxWaitMs), SESSION_WAIT_MAX_SECONDS * 1_000);
|
|
305
|
+
let liveFanout = true;
|
|
306
|
+
let waited = false;
|
|
307
|
+
const ownSessionId = input.source.readOwnPendingUpdateKinds ? input.ownSessionId : null;
|
|
308
|
+
const targetEventTypeSet: ReadonlySet<string> = new Set(
|
|
309
|
+
input.targetEventTypes ?? SESSION_WAIT_EVENT_TYPES,
|
|
310
|
+
);
|
|
311
|
+
const targetEventMatches = (event: SessionEvent): boolean =>
|
|
312
|
+
targetEventTypeSet.has(event.type) && (input.targetEventMatches?.(event) ?? true);
|
|
313
|
+
|
|
314
|
+
// One subscription per distinct session; a session may be both a target and
|
|
315
|
+
// the caller's own session, in which case either condition wakes the wait.
|
|
316
|
+
const targetAfter = new Map<string, number>();
|
|
317
|
+
for (const target of input.targets) {
|
|
318
|
+
const existing = targetAfter.get(target.sessionId);
|
|
319
|
+
targetAfter.set(
|
|
320
|
+
target.sessionId,
|
|
321
|
+
existing === undefined ? target.afterSequence : Math.min(existing, target.afterSequence),
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
const subscribedSessionIds = new Set<string>(targetAfter.keys());
|
|
325
|
+
if (ownSessionId !== null) subscribedSessionIds.add(ownSessionId);
|
|
326
|
+
|
|
327
|
+
let wake: (() => void) | null = null;
|
|
328
|
+
let wakePending = false;
|
|
329
|
+
const signalWake = () => {
|
|
330
|
+
wakePending = true;
|
|
331
|
+
wake?.();
|
|
332
|
+
};
|
|
333
|
+
const matchesWake = (sessionId: string, events: SessionEvent[]): boolean => {
|
|
334
|
+
const after = targetAfter.get(sessionId);
|
|
335
|
+
for (const event of events) {
|
|
336
|
+
if (event.sessionId !== sessionId) continue;
|
|
337
|
+
if (after !== undefined && event.sequence > after && targetEventMatches(event)) {
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
if (sessionId === ownSessionId && event.type === SESSION_WAIT_OWN_PENDING_EVENT_TYPE) {
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return false;
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
const unsubscribes: Array<() => void> = [];
|
|
348
|
+
const release = () => {
|
|
349
|
+
for (const unsubscribe of unsubscribes.splice(0)) {
|
|
350
|
+
try {
|
|
351
|
+
unsubscribe();
|
|
352
|
+
} catch {
|
|
353
|
+
// Releasing a live-fanout subscription is best-effort; the durable
|
|
354
|
+
// read already decided the result.
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
const readAll = async (): Promise<{
|
|
360
|
+
changed: SessionWaitTargetResult[];
|
|
361
|
+
ownPendingUpdateKinds: string[];
|
|
362
|
+
}> => {
|
|
363
|
+
const [targetReads, ownKinds] = await Promise.all([
|
|
364
|
+
Promise.all(
|
|
365
|
+
input.targets.map(async (target) => ({
|
|
366
|
+
target,
|
|
367
|
+
read: await input.source.readTargetEvents(target),
|
|
368
|
+
})),
|
|
369
|
+
),
|
|
370
|
+
input.source.readOwnPendingUpdateKinds
|
|
371
|
+
? input.source.readOwnPendingUpdateKinds()
|
|
372
|
+
: Promise.resolve([] as readonly string[]),
|
|
373
|
+
]);
|
|
374
|
+
const changed: SessionWaitTargetResult[] = [];
|
|
375
|
+
for (const { target, read } of targetReads) {
|
|
376
|
+
const events = read.events.filter(
|
|
377
|
+
(event) => event.sequence > target.afterSequence && targetEventMatches(event),
|
|
378
|
+
);
|
|
379
|
+
if (events.length === 0) continue;
|
|
380
|
+
changed.push({
|
|
381
|
+
sessionId: target.sessionId,
|
|
382
|
+
afterSequence: target.afterSequence,
|
|
383
|
+
latestSequence: events[events.length - 1]!.sequence,
|
|
384
|
+
hasMore: read.hasMore,
|
|
385
|
+
events: events.map((event) => summarizeSessionWaitEvent(event)),
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
return { changed, ownPendingUpdateKinds: [...ownKinds] };
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
const finish = async (
|
|
392
|
+
read: { changed: SessionWaitTargetResult[]; ownPendingUpdateKinds: string[] },
|
|
393
|
+
outcome: { timedOut: boolean; aborted: boolean },
|
|
394
|
+
): Promise<SessionWaitResult> => {
|
|
395
|
+
// Authorization ran immediately before the first durable read; a result
|
|
396
|
+
// produced after waiting re-proves every returned target first.
|
|
397
|
+
if (waited && read.changed.length > 0 && input.source.reauthorizeTargets) {
|
|
398
|
+
await input.source.reauthorizeTargets(read.changed.map((target) => target.sessionId));
|
|
399
|
+
}
|
|
400
|
+
return boundSessionWaitResult(
|
|
401
|
+
{
|
|
402
|
+
changed: read.changed,
|
|
403
|
+
...ownPendingUpdateFacts(read.ownPendingUpdateKinds),
|
|
404
|
+
waitedMs: Math.max(0, now() - startedAt),
|
|
405
|
+
timedOut: outcome.timedOut,
|
|
406
|
+
aborted: outcome.aborted,
|
|
407
|
+
liveFanout,
|
|
408
|
+
},
|
|
409
|
+
input.maxBytes,
|
|
410
|
+
);
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
try {
|
|
414
|
+
if (input.signal?.aborted) {
|
|
415
|
+
return await finish(
|
|
416
|
+
{ changed: [], ownPendingUpdateKinds: [] },
|
|
417
|
+
{ timedOut: false, aborted: true },
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
// Subscribe first, then read: an event committed between the read and the
|
|
421
|
+
// subscription would otherwise be missed until the deadline re-check. A
|
|
422
|
+
// failed subscription degrades to pre-check plus deadline re-check.
|
|
423
|
+
for (const sessionId of subscribedSessionIds) {
|
|
424
|
+
try {
|
|
425
|
+
const unsubscribe = await input.source.subscribe(sessionId, (events) => {
|
|
426
|
+
if (matchesWake(sessionId, events)) signalWake();
|
|
427
|
+
});
|
|
428
|
+
unsubscribes.push(unsubscribe);
|
|
429
|
+
} catch {
|
|
430
|
+
liveFanout = false;
|
|
431
|
+
}
|
|
432
|
+
if (input.signal?.aborted) break;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
for (;;) {
|
|
436
|
+
if (input.signal?.aborted) {
|
|
437
|
+
return await finish(
|
|
438
|
+
{ changed: [], ownPendingUpdateKinds: [] },
|
|
439
|
+
{ timedOut: false, aborted: true },
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
wakePending = false;
|
|
443
|
+
const read = await readAll();
|
|
444
|
+
if (
|
|
445
|
+
read.changed.length > 0 ||
|
|
446
|
+
read.ownPendingUpdateKinds.some((kind) => ownPendingKindWakes(kind))
|
|
447
|
+
) {
|
|
448
|
+
return await finish(read, { timedOut: false, aborted: false });
|
|
449
|
+
}
|
|
450
|
+
const remainingMs = deadlineAt - now();
|
|
451
|
+
if (remainingMs <= 0) {
|
|
452
|
+
return await finish(read, { timedOut: true, aborted: false });
|
|
453
|
+
}
|
|
454
|
+
if (wakePending) continue;
|
|
455
|
+
const reason = await waitForWake(remainingMs, input.signal, (resolve) => {
|
|
456
|
+
wake = resolve;
|
|
457
|
+
});
|
|
458
|
+
wake = null;
|
|
459
|
+
waited = true;
|
|
460
|
+
if (reason === "abort") {
|
|
461
|
+
return await finish(
|
|
462
|
+
{ changed: [], ownPendingUpdateKinds: [] },
|
|
463
|
+
{ timedOut: false, aborted: true },
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
// "bus" and "deadline" both re-read durable state; the deadline branch is
|
|
467
|
+
// the final re-check that covers any lost live fanout.
|
|
468
|
+
}
|
|
469
|
+
} finally {
|
|
470
|
+
wake = null;
|
|
471
|
+
release();
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function waitForWake(
|
|
476
|
+
timeoutMs: number,
|
|
477
|
+
signal: AbortSignal | undefined,
|
|
478
|
+
registerWake: (wake: () => void) => void,
|
|
479
|
+
): Promise<WakeReason> {
|
|
480
|
+
return new Promise<WakeReason>((resolve) => {
|
|
481
|
+
let settled = false;
|
|
482
|
+
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
483
|
+
const onAbort = () => settle("abort");
|
|
484
|
+
const settle = (reason: WakeReason) => {
|
|
485
|
+
if (settled) return;
|
|
486
|
+
settled = true;
|
|
487
|
+
if (timer !== null) clearTimeout(timer);
|
|
488
|
+
signal?.removeEventListener("abort", onAbort);
|
|
489
|
+
resolve(reason);
|
|
490
|
+
};
|
|
491
|
+
registerWake(() => settle("bus"));
|
|
492
|
+
timer = setTimeout(() => settle("deadline"), Math.max(1, Math.ceil(timeoutMs)));
|
|
493
|
+
if (signal) {
|
|
494
|
+
if (signal.aborted) {
|
|
495
|
+
settle("abort");
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const SUMMARY_TEXT_TIERS = [2_000, 800, 200] as const;
|
|
504
|
+
const SUMMARY_FAILURE_CHARS = 500;
|
|
505
|
+
const SUMMARY_RESULT_CHARS = 1_000;
|
|
506
|
+
|
|
507
|
+
function truncationMarker(droppedChars: number): string {
|
|
508
|
+
return `…[${droppedChars} chars omitted from this session_wait summary; use session_events view=debug payloadMode=full for the exact event]`;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function clampSummaryString(value: string, maxChars: number): string {
|
|
512
|
+
if (value.length <= maxChars) return value;
|
|
513
|
+
const dropped = value.length - maxChars;
|
|
514
|
+
const headChars = Math.max(0, Math.floor(maxChars * 0.7));
|
|
515
|
+
const tailChars = Math.max(0, maxChars - headChars);
|
|
516
|
+
const tail = tailChars > 0 ? value.slice(value.length - tailChars) : "";
|
|
517
|
+
return `${value.slice(0, headChars)}${truncationMarker(dropped)}${tail}`;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/** One bounded, result-bearing summary of a durable event for a waiter. */
|
|
521
|
+
export function summarizeSessionWaitEvent(
|
|
522
|
+
event: SessionEvent,
|
|
523
|
+
textChars: number = SUMMARY_TEXT_TIERS[0],
|
|
524
|
+
): SessionWaitEventSummary {
|
|
525
|
+
const compact = compactSessionEventResult(event, sessionWaitSemanticClass(event.type));
|
|
526
|
+
const text = compact.text === null ? null : clampSummaryString(compact.text, textChars);
|
|
527
|
+
const failure =
|
|
528
|
+
compact.failure === null
|
|
529
|
+
? null
|
|
530
|
+
: {
|
|
531
|
+
error:
|
|
532
|
+
compact.failure.error === null
|
|
533
|
+
? null
|
|
534
|
+
: clampSummaryString(compact.failure.error, SUMMARY_FAILURE_CHARS),
|
|
535
|
+
code:
|
|
536
|
+
compact.failure.code === null ? null : clampSummaryString(compact.failure.code, 128),
|
|
537
|
+
retryable: compact.failure.retryable,
|
|
538
|
+
recovery:
|
|
539
|
+
compact.failure.recovery === null
|
|
540
|
+
? null
|
|
541
|
+
: clampSummaryString(compact.failure.recovery, SUMMARY_FAILURE_CHARS),
|
|
542
|
+
};
|
|
543
|
+
const summary: SessionWaitEventSummary = {
|
|
544
|
+
id: compact.id,
|
|
545
|
+
sequence: compact.sequence,
|
|
546
|
+
type: compact.type,
|
|
547
|
+
occurredAt: compact.occurredAt,
|
|
548
|
+
turnId: compact.turnId,
|
|
549
|
+
turnGeneration: compact.turnGeneration,
|
|
550
|
+
status: compact.status,
|
|
551
|
+
text,
|
|
552
|
+
failure,
|
|
553
|
+
};
|
|
554
|
+
// `result` repeats `text` for plain message/completion events; only carry a
|
|
555
|
+
// distinct structured result so the summary stays small.
|
|
556
|
+
if (
|
|
557
|
+
compact.result !== null &&
|
|
558
|
+
compact.result !== undefined &&
|
|
559
|
+
compact.result !== compact.text &&
|
|
560
|
+
typeof compact.result !== "string"
|
|
561
|
+
) {
|
|
562
|
+
summary.result = capPayloadValue(compact.result, SUMMARY_RESULT_CHARS);
|
|
563
|
+
} else if (typeof compact.result === "string" && compact.result !== compact.text) {
|
|
564
|
+
summary.result = clampSummaryString(compact.result, textChars);
|
|
565
|
+
}
|
|
566
|
+
// Other wait summaries may omit actionable fields (e.g. human-input
|
|
567
|
+
// questions); absence of a truncation marker is not proof of full content.
|
|
568
|
+
// Neither is the empty output of a turn that ended waiting for input while
|
|
569
|
+
// it records the reply a human's message received.
|
|
570
|
+
summary.contentComplete =
|
|
571
|
+
["turn.completed", "agent.message.completed"].includes(event.type) &&
|
|
572
|
+
turnCompletedReply(event.payload) === null &&
|
|
573
|
+
!compact.truncation.truncated &&
|
|
574
|
+
text === compact.text &&
|
|
575
|
+
JSON.stringify(failure) === JSON.stringify(compact.failure) &&
|
|
576
|
+
(compact.output === null ||
|
|
577
|
+
compact.output === compact.text ||
|
|
578
|
+
JSON.stringify(compact.output) === JSON.stringify(summary.result)) &&
|
|
579
|
+
(compact.result === null ||
|
|
580
|
+
compact.result === undefined ||
|
|
581
|
+
compact.result === compact.text ||
|
|
582
|
+
JSON.stringify(summary.result) === JSON.stringify(compact.result));
|
|
583
|
+
return summary;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function prettyJsonBytes(value: unknown): number {
|
|
587
|
+
return Buffer.byteLength(JSON.stringify(value, null, 2), "utf8");
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
function measure(result: SessionWaitResult): SessionWaitResult {
|
|
591
|
+
let measured = result.bytes;
|
|
592
|
+
for (let attempt = 0; attempt < 8; attempt += 1) {
|
|
593
|
+
result.bytes = measured;
|
|
594
|
+
const next = prettyJsonBytes(result);
|
|
595
|
+
if (next === measured) return result;
|
|
596
|
+
measured = next;
|
|
597
|
+
}
|
|
598
|
+
result.bytes = measured;
|
|
599
|
+
return result;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Keep the whole model-visible result at or below the `session_events` MCP
|
|
604
|
+
* envelope. Text is tightened first; only then are newest rows dropped from the
|
|
605
|
+
* largest target, which keeps each target's `latestSequence` an exact cursor
|
|
606
|
+
* for the rows actually delivered and marks the remainder as `hasMore`.
|
|
607
|
+
*/
|
|
608
|
+
export function boundSessionWaitResult(
|
|
609
|
+
input: Omit<SessionWaitResult, "truncated" | "bytes" | "maxBytes">,
|
|
610
|
+
maxBytes: number = SESSION_EVENT_MCP_MAX_BYTES,
|
|
611
|
+
): SessionWaitResult {
|
|
612
|
+
const envelopeMaxBytes = Math.max(8 * 1024, maxBytes);
|
|
613
|
+
const build = (changed: SessionWaitTargetResult[], truncated: boolean): SessionWaitResult =>
|
|
614
|
+
measure({
|
|
615
|
+
...input,
|
|
616
|
+
changed,
|
|
617
|
+
truncated,
|
|
618
|
+
bytes: 0,
|
|
619
|
+
maxBytes: envelopeMaxBytes,
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
let candidate = build(input.changed, false);
|
|
623
|
+
if (candidate.bytes <= envelopeMaxBytes) return candidate;
|
|
624
|
+
|
|
625
|
+
// Tier 1: tighten text on every summary. Summaries carry their source id and
|
|
626
|
+
// sequence, so a tighter projection loses no identity.
|
|
627
|
+
const retextured = (textChars: number): SessionWaitTargetResult[] =>
|
|
628
|
+
input.changed.map((target) => ({
|
|
629
|
+
...target,
|
|
630
|
+
events: target.events.map((event) => ({
|
|
631
|
+
...event,
|
|
632
|
+
contentComplete: false,
|
|
633
|
+
text: event.text === null ? null : clampSummaryString(event.text, textChars),
|
|
634
|
+
...(typeof event.result === "string"
|
|
635
|
+
? { result: clampSummaryString(event.result, textChars) }
|
|
636
|
+
: {}),
|
|
637
|
+
})),
|
|
638
|
+
}));
|
|
639
|
+
let changed = input.changed;
|
|
640
|
+
for (const textChars of SUMMARY_TEXT_TIERS.slice(1)) {
|
|
641
|
+
changed = retextured(textChars);
|
|
642
|
+
candidate = build(changed, true);
|
|
643
|
+
if (candidate.bytes <= envelopeMaxBytes) return candidate;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// Tier 2: drop newest rows from the largest target until the envelope fits.
|
|
647
|
+
const working = changed.map((target) => ({ ...target, events: [...target.events] }));
|
|
648
|
+
for (;;) {
|
|
649
|
+
let largest: (typeof working)[number] | null = null;
|
|
650
|
+
for (const target of working) {
|
|
651
|
+
if (target.events.length === 0) continue;
|
|
652
|
+
if (largest === null || target.events.length > largest.events.length) largest = target;
|
|
653
|
+
}
|
|
654
|
+
if (largest === null) break;
|
|
655
|
+
largest.events.pop();
|
|
656
|
+
largest.hasMore = true;
|
|
657
|
+
largest.latestSequence =
|
|
658
|
+
largest.events.length > 0
|
|
659
|
+
? largest.events[largest.events.length - 1]!.sequence
|
|
660
|
+
: largest.afterSequence;
|
|
661
|
+
candidate = build(working, true);
|
|
662
|
+
if (candidate.bytes <= envelopeMaxBytes) return candidate;
|
|
663
|
+
}
|
|
664
|
+
throw new RangeError(`session_wait result exceeds its ${envelopeMaxBytes}-byte envelope`);
|
|
665
|
+
}
|