@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.
Files changed (546) hide show
  1. package/dist/access-grant-rls.d.ts +8 -1
  2. package/dist/admission-trace.d.ts +8 -0
  3. package/dist/app.d.ts +50 -3
  4. package/dist/app.js +10 -1
  5. package/dist/artifact-catalog-cursor.d.ts +1 -0
  6. package/dist/attached-browser-viewer.d.ts +11 -0
  7. package/dist/auth/managed-auth-attempt-context.d.ts +2 -0
  8. package/dist/auth/managed-auth-rate-limits.d.ts +167 -0
  9. package/dist/auth/managed-auth-session-adapter.d.ts +9 -1
  10. package/dist/auth/managed-auth.d.ts +72 -5
  11. package/dist/auth/managed-sign-in-notifications.d.ts +4 -0
  12. package/dist/auth/new-signups-gate.d.ts +23 -0
  13. package/dist/auth/signup-funnel-metrics.d.ts +44 -0
  14. package/dist/azure-live.d.ts +28 -0
  15. package/dist/browser-action-fences.d.ts +13 -0
  16. package/dist/browser-controller-authority.d.ts +1 -61
  17. package/dist/browser-ephemeral.d.ts +5 -0
  18. package/dist/browser-lost-runtime-end.d.ts +24 -0
  19. package/dist/browser-state-authority.d.ts +1 -27
  20. package/dist/chunk-OGQDXVXY.js +18 -0
  21. package/dist/chunk-OGQDXVXY.js.map +1 -0
  22. package/dist/{chunk-AJ62T5QN.js → chunk-OT56OY4V.js} +80503 -39869
  23. package/dist/chunk-OT56OY4V.js.map +1 -0
  24. package/dist/claude-default-models.d.ts +19 -0
  25. package/dist/claude-subscription-core.d.ts +50 -0
  26. package/dist/claude-subscription-oauth.d.ts +36 -0
  27. package/dist/claude-subscription-profile.d.ts +9 -0
  28. package/dist/claude-subscription-usage.d.ts +6 -0
  29. package/dist/claude-workspace-connection.d.ts +15 -0
  30. package/dist/codemode.d.ts +40 -5
  31. package/dist/codex-realtime.d.ts +29 -3
  32. package/dist/codex-session-pointers.d.ts +19 -0
  33. package/dist/connection-ownership.d.ts +6 -3
  34. package/dist/controller-data-plane.d.ts +16 -0
  35. package/dist/credit-promotion-snapshot.d.ts +6 -0
  36. package/dist/editable-artifact-source-session.d.ts +3 -0
  37. package/dist/editable-artifact-websocket.d.ts +5 -3
  38. package/dist/fatal-process-boundary.d.ts +9 -1
  39. package/dist/github-access.d.ts +7 -1
  40. package/dist/github-browser-flow.d.ts +1 -1
  41. package/dist/http/acting-person.d.ts +36 -0
  42. package/dist/http/api-contract-compat.d.ts +19 -0
  43. package/dist/http/api-error.d.ts +50 -1
  44. package/dist/http/auth.d.ts +8 -1
  45. package/dist/http/cors.d.ts +12 -0
  46. package/dist/http/deprecation.d.ts +42 -0
  47. package/dist/http/keyed-admission.d.ts +12 -0
  48. package/dist/http/local-browser-boundary.d.ts +72 -0
  49. package/dist/http/metrics-listener.d.ts +22 -0
  50. package/dist/http/path-identifier.d.ts +17 -0
  51. package/dist/http/registered-route-label.d.ts +16 -0
  52. package/dist/http/rejection-telemetry.d.ts +34 -0
  53. package/dist/http/request-body.d.ts +27 -0
  54. package/dist/http/request-source.d.ts +41 -3
  55. package/dist/http/sse.d.ts +12 -1
  56. package/dist/http/unmatched-route.d.ts +18 -0
  57. package/dist/http/user-content.d.ts +36 -0
  58. package/dist/http/variable-sets-removed.d.ts +41 -0
  59. package/dist/http/websocket-upgrade-dispatch.d.ts +18 -0
  60. package/dist/index.js +1279 -108
  61. package/dist/index.js.map +1 -1
  62. package/dist/integration-connect-metrics.d.ts +35 -0
  63. package/dist/integration-endpoint-test.d.ts +20 -0
  64. package/dist/integrations/api-integrations.d.ts +2 -2
  65. package/dist/integrations/atlassian.d.ts +8 -3
  66. package/dist/integrations/fiken.d.ts +3 -1
  67. package/dist/integrations/github-lens-connect.d.ts +37 -66
  68. package/dist/integrations/google-drive.d.ts +2 -0
  69. package/dist/integrations/integration-commit-authority.d.ts +13 -0
  70. package/dist/integrations/marketplace-plugin.d.ts +43 -43
  71. package/dist/integrations/oauth-client.d.ts +171 -12
  72. package/dist/integrations/oauth-profiles.d.ts +42 -13
  73. package/dist/integrations/onepassword-vault-provider.d.ts +9 -0
  74. package/dist/integrations/slack-bot.d.ts +285 -7
  75. package/dist/integrations/slack-file-upload-flow.d.ts +62 -0
  76. package/dist/integrations/slack-interactions.d.ts +89 -10
  77. package/dist/integrations/slack-mrkdwn.d.ts +41 -0
  78. package/dist/integrations/slack-routing.d.ts +1 -1
  79. package/dist/integrations/slack-session-defaults.d.ts +58 -0
  80. package/dist/integrations/slack-task-file-upload.d.ts +36 -0
  81. package/dist/integrations/slack-tool-review.d.ts +5 -0
  82. package/dist/interaction-agent-access.d.ts +13 -8
  83. package/dist/interaction-agent-version.d.ts +21 -0
  84. package/dist/interaction-holder-heartbeat.d.ts +5 -0
  85. package/dist/interaction-metrics.d.ts +27 -2
  86. package/dist/interaction-route-stages.d.ts +25 -0
  87. package/dist/interaction-secrets-vault.d.ts +20 -0
  88. package/dist/interaction-secrets.d.ts +103 -0
  89. package/dist/mcp/action-catalog-types.d.ts +14 -0
  90. package/dist/mcp/action-catalog.gen.d.ts +2 -0
  91. package/dist/mcp/action-descriptions.d.ts +4 -0
  92. package/dist/mcp/action-schema-imports.gen.d.ts +1 -0
  93. package/dist/mcp/capability-account-readiness.d.ts +7 -0
  94. package/dist/mcp/child-read-evidence.d.ts +9 -0
  95. package/dist/mcp/company-profile-agent-admin.d.ts +12 -0
  96. package/dist/mcp/contract-input.d.ts +13 -0
  97. package/dist/mcp/documents.d.ts +2 -0
  98. package/dist/mcp/first-party-tool-permissions.d.ts +3 -606
  99. package/dist/mcp/notification-tools.d.ts +26 -0
  100. package/dist/mcp/orchestration-failure-diagnostic.d.ts +43 -0
  101. package/dist/mcp/scheduled-task-input.d.ts +1309 -0
  102. package/dist/mcp/scheduled-task-view.d.ts +217 -3
  103. package/dist/mcp/secret-tools.d.ts +14 -0
  104. package/dist/mcp/server.d.ts +108 -5
  105. package/dist/mcp/session-admin-access-tools.d.ts +33 -0
  106. package/dist/mcp/session-event-errors.d.ts +28 -0
  107. package/dist/mcp/session-event-view.d.ts +62 -0
  108. package/dist/mcp/session-view.d.ts +15 -0
  109. package/dist/mcp/session-wait.d.ts +18 -0
  110. package/dist/mcp/site-agent-clamp-tools.d.ts +38 -0
  111. package/dist/mcp/site-data-tools.d.ts +22 -0
  112. package/dist/mcp/site-publication-tools.d.ts +19 -0
  113. package/dist/mcp/site-sql-tools.d.ts +27 -0
  114. package/dist/mcp-oauth.d.ts +37 -4
  115. package/dist/model-calls/chat-completions.d.ts +87 -0
  116. package/dist/model-calls/pending-usage-settlements.d.ts +57 -0
  117. package/dist/model-calls/service.d.ts +36 -0
  118. package/dist/model-catalog.d.ts +9 -3
  119. package/dist/native-push-dispatch.d.ts +69 -0
  120. package/dist/observability.d.ts +3 -1
  121. package/dist/organization-mcp.d.ts +82 -0
  122. package/dist/prepared-mcp-actor.d.ts +77 -0
  123. package/dist/prepared-mcp-permissions.d.ts +8 -0
  124. package/dist/routes/analytics-consent.d.ts +26 -0
  125. package/dist/routes/api-integrations.d.ts +11 -0
  126. package/dist/routes/api-keys.d.ts +7 -7
  127. package/dist/routes/automations.d.ts +2 -0
  128. package/dist/routes/billing.d.ts +59 -0
  129. package/dist/routes/browser-sessions.d.ts +65 -2
  130. package/dist/routes/chat-completions.d.ts +11 -0
  131. package/dist/routes/claude-core-usage.d.ts +20 -0
  132. package/dist/routes/claude-subscription-accounts.d.ts +3 -0
  133. package/dist/routes/claude-subscription-oauth.d.ts +3 -0
  134. package/dist/routes/client-errors.d.ts +182 -0
  135. package/dist/routes/codex-core.d.ts +401 -0
  136. package/dist/routes/codex.d.ts +64 -2
  137. package/dist/routes/computer-sessions.d.ts +6 -1
  138. package/dist/routes/desktop-distribution.d.ts +32 -0
  139. package/dist/routes/github-browser-fonts.gen.d.ts +2 -0
  140. package/dist/routes/github-browser-pages.d.ts +27 -0
  141. package/dist/routes/inbox.d.ts +13 -0
  142. package/dist/routes/insights-response-cache.d.ts +10 -0
  143. package/dist/routes/insights-usage.d.ts +12 -0
  144. package/dist/routes/insights.d.ts +28 -0
  145. package/dist/routes/interaction-placement-message.d.ts +7 -0
  146. package/dist/routes/managed-sign-in-methods.d.ts +6 -0
  147. package/dist/routes/model-account-choice.d.ts +13 -0
  148. package/dist/routes/model-account-settings.d.ts +19 -0
  149. package/dist/routes/native-app-auth.d.ts +12 -0
  150. package/dist/routes/organization-integration-policy.d.ts +8 -0
  151. package/dist/routes/organization-integrations.d.ts +6 -0
  152. package/dist/routes/organization-mcp-connections.d.ts +3 -0
  153. package/dist/routes/organization-model-defaults.d.ts +9 -0
  154. package/dist/routes/organization-service-accounts.d.ts +3 -0
  155. package/dist/routes/personal-api-keys.d.ts +3 -0
  156. package/dist/routes/session-admin-access.d.ts +3 -0
  157. package/dist/routes/session-artifact-associations.d.ts +4 -0
  158. package/dist/routes/session-history-imports.d.ts +20 -0
  159. package/dist/routes/sessions.d.ts +38 -2
  160. package/dist/routes/site-data.d.ts +18 -0
  161. package/dist/routes/site-publishing.d.ts +5 -0
  162. package/dist/routes/site-runtime.d.ts +31 -0
  163. package/dist/routes/site-sql.d.ts +16 -0
  164. package/dist/routes/slack-bot-access.d.ts +3 -0
  165. package/dist/routes/subscription-account-pools.d.ts +21 -0
  166. package/dist/routes/subscription-core-http.d.ts +5 -0
  167. package/dist/routes/subscription-pool-access.d.ts +37 -0
  168. package/dist/routes/subscription-pool-core.d.ts +153 -0
  169. package/dist/routes/supergrok.d.ts +6 -6
  170. package/dist/routes/usage-allowances.d.ts +12 -0
  171. package/dist/routes/variable-sets-removed.d.ts +2 -0
  172. package/dist/routes/vault-providers.d.ts +34 -0
  173. package/dist/routes/vaults.d.ts +3 -0
  174. package/dist/routes/workspace-integrations.d.ts +35 -0
  175. package/dist/routes/workspace-model-providers.d.ts +4 -0
  176. package/dist/routes/workspaces.d.ts +11 -2
  177. package/dist/sandbox/agent-update.d.ts +64 -0
  178. package/dist/sandbox/auth-callout.d.ts +8 -0
  179. package/dist/sandbox/channel-a.d.ts +15 -1
  180. package/dist/sandbox/enrollment.d.ts +26 -4
  181. package/dist/sandbox/machine-audience.d.ts +29 -0
  182. package/dist/sandbox/machines.d.ts +15 -2
  183. package/dist/sandbox/metrics-ingestion.d.ts +6 -2
  184. package/dist/sandbox/screen-control.d.ts +85 -0
  185. package/dist/sandbox/viewer.d.ts +5 -1
  186. package/dist/sandbox-file-artifacts.d.ts +17 -1
  187. package/dist/scheduled-task-blockers.d.ts +39 -0
  188. package/dist/scheduled-task-deletion.d.ts +3 -4
  189. package/dist/scheduled-task-lifecycle.d.ts +14 -0
  190. package/dist/secret-answers.d.ts +40 -0
  191. package/dist/session-create-observability.d.ts +5 -0
  192. package/dist/session-event-view-36GO3IL7.js +528 -0
  193. package/dist/session-event-view-36GO3IL7.js.map +1 -0
  194. package/dist/signed-state-secret.d.ts +18 -0
  195. package/dist/site-agent-guard.d.ts +53 -0
  196. package/dist/site-data/operations.d.ts +103 -0
  197. package/dist/site-data/service.d.ts +203 -0
  198. package/dist/site-frame-guard.d.ts +32 -0
  199. package/dist/site-publishing/agent-data-tools.d.ts +84 -0
  200. package/dist/site-publishing/agent-model.d.ts +58 -0
  201. package/dist/site-publishing/agent-session.d.ts +16 -0
  202. package/dist/site-publishing/content-scanner.d.ts +31 -0
  203. package/dist/site-publishing/edge-sync.d.ts +48 -0
  204. package/dist/site-publishing/gateway-signature.d.ts +56 -0
  205. package/dist/site-publishing/limits.d.ts +63 -0
  206. package/dist/site-publishing/page-tool-authority.d.ts +30 -0
  207. package/dist/site-publishing/platform-usage.d.ts +113 -0
  208. package/dist/site-publishing/platform.d.ts +21 -0
  209. package/dist/site-publishing/readiness.d.ts +62 -0
  210. package/dist/site-publishing/runtime.d.ts +179 -0
  211. package/dist/site-publishing/service.d.ts +264 -0
  212. package/dist/site-publishing/session-events.d.ts +22 -0
  213. package/dist/site-publishing/session-views.d.ts +36 -0
  214. package/dist/site-publishing/viewer.d.ts +40 -0
  215. package/dist/site-session-origin.d.ts +31 -6
  216. package/dist/site-sql/format.d.ts +47 -0
  217. package/dist/site-sql/gateway.d.ts +50 -0
  218. package/dist/site-sql/service.d.ts +213 -0
  219. package/dist/temporal-schedule-sync.d.ts +26 -0
  220. package/dist/transcription/billing-refusal.d.ts +8 -0
  221. package/dist/transcription/normalize.d.ts +23 -0
  222. package/dist/transcription/providers/azure-mai.d.ts +12 -0
  223. package/dist/transcription/providers/azure-openai.d.ts +4 -0
  224. package/dist/transcription/providers/openai.d.ts +16 -0
  225. package/dist/transcription/providers/subscription-core.d.ts +39 -0
  226. package/dist/transcription/service.d.ts +10 -1
  227. package/dist/transcription/wav-duration.d.ts +8 -0
  228. package/dist/workspace-tool-gateway-attestations.d.ts +37 -0
  229. package/dist/workspace-tool-gateway-observability.d.ts +16 -0
  230. package/dist/workspace-tool-gateway-secrets.d.ts +27 -0
  231. package/dist/workspace-tool-gateway.d.ts +102 -6
  232. package/dist/workspace-tool-target-fence.d.ts +116 -0
  233. package/dist/workspace-tool-target.d.ts +225 -0
  234. package/dist/workspace-webhook-dispatch.d.ts +26 -0
  235. package/dist/xai-subscription-core.d.ts +60 -0
  236. package/package.json +25 -20
  237. package/src/access-grant-rls.ts +64 -14
  238. package/src/admission-trace.ts +14 -0
  239. package/src/app.ts +1684 -252
  240. package/src/artifact-catalog-cursor.ts +1 -0
  241. package/src/attached-browser-viewer.ts +26 -0
  242. package/src/auth/managed-auth-attempt-context.ts +9 -0
  243. package/src/auth/managed-auth-rate-limits.ts +252 -0
  244. package/src/auth/managed-auth-session-adapter.ts +64 -29
  245. package/src/auth/managed-auth.ts +303 -35
  246. package/src/auth/managed-email.ts +18 -1
  247. package/src/auth/managed-sign-in-notifications.ts +81 -0
  248. package/src/auth/new-signups-gate.ts +49 -0
  249. package/src/auth/organization-user-setup.ts +3 -3
  250. package/src/auth/signup-funnel-metrics.ts +164 -0
  251. package/src/azure-live.ts +103 -0
  252. package/src/browser-action-fences.ts +45 -0
  253. package/src/browser-controller-authority.ts +1 -186
  254. package/src/browser-ephemeral.ts +39 -0
  255. package/src/browser-lost-runtime-end.ts +71 -0
  256. package/src/browser-state-authority.ts +1 -236
  257. package/src/claude-default-models.ts +37 -0
  258. package/src/claude-subscription-core.ts +154 -0
  259. package/src/claude-subscription-oauth.ts +352 -0
  260. package/src/claude-subscription-profile.ts +73 -0
  261. package/src/claude-subscription-usage.ts +51 -0
  262. package/src/claude-workspace-connection.ts +82 -0
  263. package/src/codemode.ts +236 -39
  264. package/src/codex-realtime.ts +181 -53
  265. package/src/codex-session-pointers.ts +80 -0
  266. package/src/company-brain-okf.ts +1 -1
  267. package/src/connected-machine-computer-access.ts +2 -1
  268. package/src/connection-ownership.ts +19 -13
  269. package/src/controller-data-plane.ts +34 -0
  270. package/src/credit-promotion-snapshot.ts +36 -0
  271. package/src/editable-artifact-production.ts +10 -0
  272. package/src/editable-artifact-source-session.ts +123 -0
  273. package/src/editable-artifact-websocket.ts +16 -3
  274. package/src/fatal-process-boundary.ts +67 -3
  275. package/src/gateway-realtime.ts +12 -8
  276. package/src/github-access.ts +31 -5
  277. package/src/github-browser-flow.ts +1 -1
  278. package/src/http/acting-person.ts +105 -0
  279. package/src/http/api-contract-compat.ts +49 -0
  280. package/src/http/api-error.ts +210 -2
  281. package/src/http/auth.ts +68 -4
  282. package/src/http/cors.ts +37 -5
  283. package/src/http/deprecation.ts +118 -0
  284. package/src/http/keyed-admission.ts +29 -0
  285. package/src/http/local-browser-boundary.ts +343 -0
  286. package/src/http/metrics-listener.ts +57 -0
  287. package/src/http/path-identifier.ts +54 -0
  288. package/src/http/registered-route-label.ts +34 -0
  289. package/src/http/rejection-telemetry.ts +120 -0
  290. package/src/http/request-body.ts +127 -0
  291. package/src/http/request-source.ts +154 -13
  292. package/src/http/sse.ts +88 -28
  293. package/src/http/unmatched-route.ts +60 -0
  294. package/src/http/user-content.ts +158 -0
  295. package/src/http/variable-sets-removed.ts +122 -0
  296. package/src/http/websocket-upgrade-dispatch.ts +29 -0
  297. package/src/index.ts +107 -57
  298. package/src/integration-connect-metrics.ts +228 -0
  299. package/src/integration-endpoint-test.ts +291 -0
  300. package/src/integrations/api-integrations.ts +81 -7
  301. package/src/integrations/atlassian.ts +202 -83
  302. package/src/integrations/fiken.ts +66 -38
  303. package/src/integrations/github-app-connect.ts +64 -18
  304. package/src/integrations/github-lens-connect.ts +8 -29
  305. package/src/integrations/google-drive.ts +448 -152
  306. package/src/integrations/integration-commit-authority.ts +69 -0
  307. package/src/integrations/marketplace-plugin.ts +1 -1
  308. package/src/integrations/oauth-client.ts +733 -193
  309. package/src/integrations/oauth-profiles.ts +116 -45
  310. package/src/integrations/onepassword-vault-provider.ts +16 -0
  311. package/src/integrations/personal-github-repositories.ts +1 -1
  312. package/src/integrations/personal-github.ts +61 -35
  313. package/src/integrations/provider-oauth.ts +67 -85
  314. package/src/integrations/slack-app-home.ts +5 -5
  315. package/src/integrations/slack-bot.ts +893 -201
  316. package/src/integrations/slack-file-upload-flow.ts +147 -0
  317. package/src/integrations/slack-install.ts +7 -7
  318. package/src/integrations/slack-interactions.ts +1589 -299
  319. package/src/integrations/slack-mrkdwn.ts +193 -0
  320. package/src/integrations/slack-routing.ts +2 -2
  321. package/src/integrations/slack-session-defaults.ts +224 -0
  322. package/src/integrations/slack-task-file-upload.ts +323 -0
  323. package/src/integrations/slack-tool-review.ts +65 -0
  324. package/src/integrations/social-oauth.ts +90 -58
  325. package/src/interaction-agent-access.ts +40 -20
  326. package/src/interaction-agent-version.ts +85 -0
  327. package/src/interaction-holder-heartbeat.ts +24 -8
  328. package/src/interaction-metrics.ts +164 -2
  329. package/src/interaction-route-stages.ts +94 -0
  330. package/src/interaction-secrets-vault.ts +213 -0
  331. package/src/interaction-secrets.ts +426 -0
  332. package/src/mcp/action-catalog-types.ts +14 -0
  333. package/src/mcp/action-catalog.gen.ts +8014 -0
  334. package/src/mcp/action-descriptions.ts +299 -0
  335. package/src/mcp/action-schema-imports.gen.ts +304 -0
  336. package/src/mcp/capability-account-readiness.ts +17 -0
  337. package/src/mcp/child-read-evidence.ts +19 -0
  338. package/src/mcp/company-profile-agent-admin.ts +13 -0
  339. package/src/mcp/contract-input.ts +165 -0
  340. package/src/mcp/documents.ts +9 -2
  341. package/src/mcp/editable-artifacts.ts +29 -11
  342. package/src/mcp/files.ts +5 -1
  343. package/src/mcp/first-party-tool-permissions.ts +7 -285
  344. package/src/mcp/knowledge-entries.ts +108 -34
  345. package/src/mcp/notification-tools.ts +480 -0
  346. package/src/mcp/orchestration-failure-diagnostic.ts +43 -0
  347. package/src/mcp/scheduled-task-input.ts +89 -0
  348. package/src/mcp/scheduled-task-view.ts +63 -3
  349. package/src/mcp/secret-tools.ts +185 -0
  350. package/src/mcp/server.ts +2213 -1116
  351. package/src/mcp/session-admin-access-tools.ts +163 -0
  352. package/src/mcp/session-event-errors.ts +123 -0
  353. package/src/mcp/session-event-view.ts +395 -13
  354. package/src/mcp/session-view.ts +3 -0
  355. package/src/mcp/session-wait.ts +67 -7
  356. package/src/mcp/site-agent-clamp-tools.ts +140 -0
  357. package/src/mcp/site-data-tools.ts +339 -0
  358. package/src/mcp/site-publication-tools.ts +201 -0
  359. package/src/mcp/site-sql-tools.ts +427 -0
  360. package/src/mcp-oauth.ts +635 -45
  361. package/src/model-calls/chat-completions.ts +352 -0
  362. package/src/model-calls/pending-usage-settlements.ts +125 -0
  363. package/src/model-calls/service.ts +694 -0
  364. package/src/model-catalog.ts +68 -17
  365. package/src/native-push-dispatch.ts +457 -0
  366. package/src/observability.ts +15 -1
  367. package/src/organization-mcp.ts +485 -0
  368. package/src/prepared-mcp-actor.ts +154 -0
  369. package/src/prepared-mcp-permissions.ts +38 -0
  370. package/src/routes/analytics-consent.ts +123 -0
  371. package/src/routes/api-integrations.ts +268 -9
  372. package/src/routes/api-keys.ts +164 -25
  373. package/src/routes/artifact-catalog.ts +111 -0
  374. package/src/routes/automations.ts +163 -90
  375. package/src/routes/billing.ts +535 -59
  376. package/src/routes/browser-sessions.ts +966 -342
  377. package/src/routes/canonical-human-identities.ts +61 -0
  378. package/src/routes/capabilities.ts +112 -5
  379. package/src/routes/channels.ts +4 -3
  380. package/src/routes/chat-completions.ts +235 -0
  381. package/src/routes/claude-core-usage.ts +147 -0
  382. package/src/routes/claude-subscription-accounts.ts +233 -0
  383. package/src/routes/claude-subscription-oauth.ts +175 -0
  384. package/src/routes/client-errors.ts +394 -0
  385. package/src/routes/codex-core.ts +687 -0
  386. package/src/routes/codex.ts +1277 -1119
  387. package/src/routes/company-brain.ts +4 -0
  388. package/src/routes/computer-sessions.ts +319 -85
  389. package/src/routes/connect.ts +277 -175
  390. package/src/routes/connections.ts +690 -363
  391. package/src/routes/desktop-distribution.ts +217 -0
  392. package/src/routes/documents.ts +13 -7
  393. package/src/routes/editable-artifacts.ts +74 -4
  394. package/src/routes/enrollments.ts +110 -16
  395. package/src/routes/external-identity-links.ts +13 -12
  396. package/src/routes/files.ts +41 -16
  397. package/src/routes/github-browser-fonts.gen.ts +12 -0
  398. package/src/routes/github-browser-pages.ts +258 -0
  399. package/src/routes/github.ts +200 -75
  400. package/src/routes/inbox.ts +353 -0
  401. package/src/routes/insights-response-cache.ts +83 -0
  402. package/src/routes/insights-usage.ts +345 -0
  403. package/src/routes/insights.ts +103 -8
  404. package/src/routes/install.ts +51 -10
  405. package/src/routes/integration-facets.ts +70 -28
  406. package/src/routes/interaction-placement-message.ts +12 -0
  407. package/src/routes/knowledge.ts +136 -27
  408. package/src/routes/machines.ts +189 -135
  409. package/src/routes/managed-auth-session-sets.ts +43 -10
  410. package/src/routes/managed-onboarding.ts +39 -19
  411. package/src/routes/managed-sign-in-methods.ts +433 -0
  412. package/src/routes/memory-slack-publications.ts +3 -2
  413. package/src/routes/model-account-choice.ts +194 -0
  414. package/src/routes/model-account-settings.ts +235 -0
  415. package/src/routes/model-connection-access.ts +210 -48
  416. package/src/routes/native-app-auth.ts +296 -0
  417. package/src/routes/organization-integration-policy.ts +116 -0
  418. package/src/routes/organization-integrations.ts +326 -0
  419. package/src/routes/organization-mcp-connections.ts +183 -0
  420. package/src/routes/organization-memberships.ts +205 -19
  421. package/src/routes/organization-model-defaults.ts +110 -0
  422. package/src/routes/organization-model-providers.ts +74 -3
  423. package/src/routes/organization-service-accounts.ts +128 -0
  424. package/src/routes/organization-sessions.ts +21 -5
  425. package/src/routes/personal-api-keys.ts +184 -0
  426. package/src/routes/personal-github-git-broker.ts +2 -2
  427. package/src/routes/personal-github.ts +9 -4
  428. package/src/routes/plugins.ts +46 -7
  429. package/src/routes/pr-review-github.ts +105 -118
  430. package/src/routes/pr-review.ts +88 -82
  431. package/src/routes/preference-registry.ts +18 -0
  432. package/src/routes/rigs.ts +48 -13
  433. package/src/routes/scheduled-tasks.ts +347 -27
  434. package/src/routes/session-admin-access.ts +271 -0
  435. package/src/routes/session-artifact-associations.ts +164 -0
  436. package/src/routes/session-history-imports.ts +305 -0
  437. package/src/routes/sessions.ts +1682 -363
  438. package/src/routes/site-data.ts +340 -0
  439. package/src/routes/site-publishing.ts +584 -0
  440. package/src/routes/site-runtime.ts +1944 -0
  441. package/src/routes/site-sql.ts +263 -0
  442. package/src/routes/skill-content.ts +72 -7
  443. package/src/routes/skills.ts +5 -4
  444. package/src/routes/slack-bot-access.ts +108 -0
  445. package/src/routes/social.ts +27 -15
  446. package/src/routes/subscription-account-pools.ts +209 -0
  447. package/src/routes/subscription-core-http.ts +18 -0
  448. package/src/routes/subscription-pool-access.ts +180 -0
  449. package/src/routes/subscription-pool-core.ts +552 -0
  450. package/src/routes/supergrok.ts +174 -655
  451. package/src/routes/transcription-recordings.ts +71 -4
  452. package/src/routes/transcriptions.ts +26 -2
  453. package/src/routes/usage-allowances.ts +381 -0
  454. package/src/routes/variable-sets-removed.ts +19 -0
  455. package/src/routes/vault-providers.ts +782 -0
  456. package/src/routes/vaults.ts +421 -0
  457. package/src/routes/video-generation.ts +30 -12
  458. package/src/routes/workspace-artifacts.ts +165 -53
  459. package/src/routes/workspace-integrations.ts +576 -0
  460. package/src/routes/workspace-model-providers.ts +148 -0
  461. package/src/routes/workspace-state.ts +4 -0
  462. package/src/routes/workspaces.ts +625 -117
  463. package/src/sandbox/agent-update.ts +315 -0
  464. package/src/sandbox/auth-callout.ts +104 -21
  465. package/src/sandbox/channel-a.ts +165 -55
  466. package/src/sandbox/enrollment.ts +131 -22
  467. package/src/sandbox/machine-audience.ts +192 -0
  468. package/src/sandbox/machines.ts +75 -31
  469. package/src/sandbox/metrics-ingestion.ts +133 -2
  470. package/src/sandbox/rematerialize.ts +51 -21
  471. package/src/sandbox/screen-control.ts +289 -0
  472. package/src/sandbox/viewer.ts +33 -58
  473. package/src/sandbox-file-artifacts.ts +53 -27
  474. package/src/scheduled-task-blockers.ts +293 -0
  475. package/src/scheduled-task-deletion.ts +13 -3
  476. package/src/scheduled-task-lifecycle.ts +84 -0
  477. package/src/secret-answers.ts +119 -0
  478. package/src/session-create-observability.ts +46 -0
  479. package/src/session-realtime-context.ts +26 -4
  480. package/src/signed-state-secret.ts +58 -0
  481. package/src/site-agent-guard.ts +261 -0
  482. package/src/site-data/operations.ts +777 -0
  483. package/src/site-data/service.ts +1043 -0
  484. package/src/site-frame-guard.ts +107 -0
  485. package/src/site-publishing/agent-data-tools.ts +250 -0
  486. package/src/site-publishing/agent-model.ts +127 -0
  487. package/src/site-publishing/agent-session.ts +148 -0
  488. package/src/site-publishing/content-scanner.ts +93 -0
  489. package/src/site-publishing/edge-sync.ts +148 -0
  490. package/src/site-publishing/gateway-signature.ts +198 -0
  491. package/src/site-publishing/limits.ts +315 -0
  492. package/src/site-publishing/page-tool-authority.ts +111 -0
  493. package/src/site-publishing/platform-usage.ts +479 -0
  494. package/src/site-publishing/platform.ts +98 -0
  495. package/src/site-publishing/readiness.ts +330 -0
  496. package/src/site-publishing/runtime.ts +831 -0
  497. package/src/site-publishing/service.ts +1282 -0
  498. package/src/site-publishing/session-events.ts +262 -0
  499. package/src/site-publishing/session-views.ts +262 -0
  500. package/src/site-publishing/viewer.ts +75 -0
  501. package/src/site-session-origin.ts +91 -6
  502. package/src/site-sql/format.ts +134 -0
  503. package/src/site-sql/gateway.ts +168 -0
  504. package/src/site-sql/service.ts +1636 -0
  505. package/src/site-uploads.ts +27 -5
  506. package/src/temporal-schedule-sync.ts +74 -0
  507. package/src/transcription/billing-refusal.ts +14 -0
  508. package/src/transcription/normalize.ts +77 -0
  509. package/src/transcription/providers/azure-mai.ts +98 -0
  510. package/src/transcription/providers/azure-openai.ts +16 -7
  511. package/src/transcription/providers/codex-subscription.ts +190 -67
  512. package/src/transcription/providers/openai.ts +79 -5
  513. package/src/transcription/providers/subscription-core.ts +125 -0
  514. package/src/transcription/providers/xai-subscription.ts +81 -83
  515. package/src/transcription/segmenter.ts +7 -1
  516. package/src/transcription/service.ts +239 -10
  517. package/src/transcription/wav-duration.ts +39 -0
  518. package/src/workspace-deletion.ts +25 -1
  519. package/src/workspace-tool-gateway-attestations.ts +133 -0
  520. package/src/workspace-tool-gateway-observability.ts +64 -0
  521. package/src/workspace-tool-gateway-secrets.ts +104 -0
  522. package/src/workspace-tool-gateway.ts +921 -103
  523. package/src/workspace-tool-target-fence.ts +380 -0
  524. package/src/workspace-tool-target.ts +554 -0
  525. package/src/workspace-webhook-dispatch.ts +225 -0
  526. package/src/xai-realtime.ts +85 -81
  527. package/src/xai-subscription-core.ts +172 -0
  528. package/dist/browser-auth-broker.d.ts +0 -20
  529. package/dist/chunk-AJ62T5QN.js.map +0 -1
  530. package/dist/connection-authority-owner.d.ts +0 -59
  531. package/dist/routes/connection-authorities.d.ts +0 -3
  532. package/dist/routes/environments.d.ts +0 -5
  533. package/dist/routes/host-mcp-bindings.d.ts +0 -5
  534. package/dist/routes/host-mcp-resolvers.d.ts +0 -3
  535. package/dist/routes/packs.d.ts +0 -3
  536. package/dist/session-event-view-MU3HMNV3.js +0 -264
  537. package/dist/session-event-view-MU3HMNV3.js.map +0 -1
  538. package/dist/xai-subscription-auth.d.ts +0 -23
  539. package/src/browser-auth-broker.ts +0 -155
  540. package/src/connection-authority-owner.ts +0 -61
  541. package/src/routes/connection-authorities.ts +0 -139
  542. package/src/routes/environments.ts +0 -388
  543. package/src/routes/host-mcp-bindings.ts +0 -122
  544. package/src/routes/host-mcp-resolvers.ts +0 -41
  545. package/src/routes/packs.ts +0 -784
  546. package/src/xai-subscription-auth.ts +0 -139
@@ -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!.bytes)),
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
- return (await storage.headObject(to))!.ContentLength!;
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
- storage.createGetUrl({ key: ref.contentKey, audience }),
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 url = `${input.endpoint}/openai/deployments/${encodeURIComponent(input.deployment)}/audio/transcriptions?api-version=${encodeURIComponent(input.apiVersion)}`;
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
- if (!body || typeof body.text !== "string") {
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 { buildCodexTokenResolver, type Database, listCodexAccountStatuses } from "@opengeni/db";
9
- import { fetchError, responseError } from "./openai";
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
- async function workspaceHasActiveCodexAccount(db: Database, workspaceId: string): Promise<boolean> {
14
- const account = (await listCodexAccountStatuses(db, workspaceId)).find(
15
- (candidate) => candidate.isActive && candidate.status === "active",
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 account != null;
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
- return await workspaceHasActiveCodexAccount(input.db, context.workspaceId);
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({ audio, mimeType, filename, workspaceId, requestId, signal }) {
43
- const account = (await listCodexAccountStatuses(input.db, workspaceId)).find(
44
- (candidate) => candidate.isActive && candidate.status === "active",
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
  }