@opengeni/api-router 0.26.1 → 0.30.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.
Files changed (87) hide show
  1. package/dist/app.d.ts +1 -0
  2. package/dist/app.js +5 -3
  3. package/dist/auth/canonical-human-session-admission.d.ts +27 -0
  4. package/dist/browser-auth-broker.d.ts +20 -0
  5. package/dist/browser-controller-authority.d.ts +19 -1
  6. package/dist/browser-network-route.d.ts +8 -0
  7. package/dist/{chunk-JIKNR5YL.js → chunk-2PQMSRCB.js} +15518 -6863
  8. package/dist/chunk-2PQMSRCB.js.map +1 -0
  9. package/dist/controller-data-plane.d.ts +12 -0
  10. package/dist/http/auth.d.ts +1 -1
  11. package/dist/http/sse.d.ts +18 -1
  12. package/dist/index.js +1 -1
  13. package/dist/integrations/api-integrations.d.ts +2 -2
  14. package/dist/integrations/fiken.d.ts +233 -0
  15. package/dist/integrations/google-drive.d.ts +6 -6
  16. package/dist/integrations/provider-oauth.d.ts +0 -2
  17. package/dist/integrations/slack-bot.d.ts +171 -1
  18. package/dist/integrations/slack-interactions.d.ts +17 -5
  19. package/dist/interaction-holder-heartbeat.d.ts +17 -0
  20. package/dist/interaction-metrics.d.ts +11 -0
  21. package/dist/mcp/server.d.ts +3 -2
  22. package/dist/model-catalog.d.ts +1 -0
  23. package/dist/routes/canonical-human-identities.d.ts +3 -0
  24. package/dist/routes/channels.d.ts +3 -0
  25. package/dist/routes/integration-facets.d.ts +3 -0
  26. package/dist/routes/interaction-resources.d.ts +5 -0
  27. package/dist/routes/organization-memberships.d.ts +3 -0
  28. package/dist/routes/sessions.d.ts +2 -1
  29. package/dist/routes/slack-task-policy.d.ts +3 -0
  30. package/dist/routes/supergrok.d.ts +3 -0
  31. package/dist/sandbox/channel-a.d.ts +8 -1
  32. package/dist/sandbox/machines.d.ts +2 -2
  33. package/dist/sandbox/viewer.d.ts +3 -1
  34. package/dist/slack-reaction-files.d.ts +27 -0
  35. package/dist/transcription/providers/xai-subscription.d.ts +8 -0
  36. package/dist/xai-realtime.d.ts +26 -0
  37. package/dist/xai-subscription-auth.d.ts +23 -0
  38. package/package.json +17 -16
  39. package/src/app.ts +352 -49
  40. package/src/auth/canonical-human-session-admission.ts +116 -0
  41. package/src/auth/managed-auth.ts +101 -0
  42. package/src/browser-auth-broker.ts +155 -0
  43. package/src/browser-controller-authority.ts +50 -1
  44. package/src/browser-network-route.ts +34 -0
  45. package/src/controller-data-plane.ts +35 -0
  46. package/src/http/auth.ts +27 -9
  47. package/src/http/sse.ts +229 -5
  48. package/src/integrations/api-integrations.ts +57 -42
  49. package/src/integrations/fiken.ts +1230 -0
  50. package/src/integrations/google-drive.ts +31 -26
  51. package/src/integrations/provider-oauth.ts +70 -91
  52. package/src/integrations/slack-bot.ts +638 -9
  53. package/src/integrations/slack-interactions.ts +1583 -73
  54. package/src/interaction-holder-heartbeat.ts +95 -0
  55. package/src/interaction-metrics.ts +159 -0
  56. package/src/mcp/documents.ts +115 -6
  57. package/src/mcp/server.ts +865 -242
  58. package/src/model-catalog.ts +19 -6
  59. package/src/routes/api-integrations.ts +32 -29
  60. package/src/routes/browser-identities.ts +24 -0
  61. package/src/routes/browser-sessions.ts +2122 -183
  62. package/src/routes/canonical-human-identities.ts +156 -0
  63. package/src/routes/channels.ts +90 -0
  64. package/src/routes/computer-sessions.ts +441 -86
  65. package/src/routes/connections.ts +141 -4
  66. package/src/routes/{integration-features.ts → integration-facets.ts} +63 -63
  67. package/src/routes/interaction-resources.ts +595 -0
  68. package/src/routes/organization-memberships.ts +53 -0
  69. package/src/routes/plugins.ts +2 -1
  70. package/src/routes/sessions.ts +419 -43
  71. package/src/routes/skills.ts +92 -10
  72. package/src/routes/slack-task-policy.ts +115 -0
  73. package/src/routes/supergrok.ts +717 -0
  74. package/src/routes/transcription-recordings.ts +9 -2
  75. package/src/routes/transcriptions.ts +2 -1
  76. package/src/routes/video-generation.ts +34 -4
  77. package/src/routes/workspaces.ts +22 -4
  78. package/src/sandbox/channel-a.ts +29 -2
  79. package/src/sandbox/machines.ts +5 -5
  80. package/src/sandbox/viewer.ts +10 -3
  81. package/src/slack-reaction-files.ts +181 -0
  82. package/src/transcription/providers/xai-subscription.ts +110 -0
  83. package/src/transcription/service.ts +17 -2
  84. package/src/xai-realtime.ts +216 -0
  85. package/src/xai-subscription-auth.ts +132 -0
  86. package/dist/chunk-JIKNR5YL.js.map +0 -1
  87. package/dist/routes/integration-features.d.ts +0 -3
@@ -3,6 +3,7 @@ import { OPENGENI_SLACK_BOT_CREDENTIAL_LABEL, OPENGENI_SLACK_BOT_CREDENTIAL_ROLE
3
3
  import { type Database } from "@opengeni/db";
4
4
  import { type FetchLike } from "@opengeni/network";
5
5
  import { HTTPException } from "hono/http-exception";
6
+ export declare const SLACK_REACTION_IMAGE_MAX_BYTES: number;
6
7
  declare const SLACK_REACTION_CONTEXT_CHECKPOINT_VERSION = 1;
7
8
  type SlackPayload = Record<string, unknown> & {
8
9
  ok?: unknown;
@@ -20,6 +21,19 @@ export type VerifiedOpenGeniSlackBot = {
20
21
  grantedScopes: string[];
21
22
  metadata: OpenGeniSlackBotConnectionMetadata;
22
23
  };
24
+ export type PreparedSlackReactionImage = Readonly<{
25
+ fileId: string;
26
+ filename: string;
27
+ declaredMimeType: string;
28
+ declaredSizeBytes: number | null;
29
+ downloadUrl: URL | null;
30
+ }>;
31
+ export type DownloadedSlackReactionImage = Readonly<{
32
+ fileId: string;
33
+ filename: string;
34
+ contentType: "image/png" | "image/jpeg" | "image/webp";
35
+ bytes: Uint8Array;
36
+ }>;
23
37
  export declare function exchangeOpenGeniSlackAuthorizationCode(input: {
24
38
  code: string;
25
39
  clientId: string;
@@ -35,7 +49,32 @@ export type SlackBotReceipt = {
35
49
  operationId?: string;
36
50
  clientMessageId?: string;
37
51
  };
38
- type SlackBotOperation = "channels.list" | "channel_history.read" | "thread_replies.read" | "users.list" | "files.list" | "file.info" | "file.content.read" | "message.post" | "message.delete";
52
+ export type SlackMessageBlock = {
53
+ type: "section";
54
+ block_id?: string;
55
+ text: {
56
+ type: "mrkdwn" | "plain_text";
57
+ text: string;
58
+ emoji?: boolean;
59
+ };
60
+ } | {
61
+ type: "actions";
62
+ block_id: string;
63
+ elements: Array<{
64
+ type: "button";
65
+ action_id: string;
66
+ value: string;
67
+ text: {
68
+ type: "plain_text";
69
+ text: string;
70
+ emoji?: boolean;
71
+ };
72
+ style?: "primary" | "danger";
73
+ }>;
74
+ } | {
75
+ type: "divider";
76
+ };
77
+ type SlackBotOperation = "channels.list" | "channel_history.read" | "thread_replies.read" | "users.list" | "files.list" | "file.info" | "file.content.read" | "message.post" | "message.update" | "message.delete";
39
78
  type SlackBotContext = {
40
79
  accountId: string;
41
80
  workspaceId: string;
@@ -127,10 +166,15 @@ export declare class OpenGeniSlackBotClient {
127
166
  isPrivate: boolean;
128
167
  isMember: boolean;
129
168
  isDirectMessage: boolean;
169
+ isMpim: boolean;
130
170
  isArchived: boolean;
131
171
  isShared: boolean;
132
172
  isExternallyShared: boolean;
133
173
  isOrgShared: boolean;
174
+ isPendingExternallyShared: boolean;
175
+ contextTeamId: string | null;
176
+ connectedTeamIds: string[] | null;
177
+ sharedTeamIds: string[] | null;
134
178
  topic: string;
135
179
  purpose: string;
136
180
  numMembers: number | null;
@@ -145,20 +189,76 @@ export declare class OpenGeniSlackBotClient {
145
189
  isPrivate: boolean;
146
190
  isMember: boolean;
147
191
  isDirectMessage: boolean;
192
+ isMpim: boolean;
148
193
  isArchived: boolean;
149
194
  isShared: boolean;
150
195
  isExternallyShared: boolean;
151
196
  isOrgShared: boolean;
197
+ isPendingExternallyShared: boolean;
198
+ contextTeamId: string | null;
199
+ connectedTeamIds: string[] | null;
200
+ sharedTeamIds: string[] | null;
152
201
  topic: string;
153
202
  purpose: string;
154
203
  numMembers: number | null;
155
204
  }>;
205
+ slackTaskPolicyFacts(channelId: string, userId: string): Promise<({
206
+ conversation: {
207
+ id: string;
208
+ name: string;
209
+ isPrivate: boolean;
210
+ isMember: boolean;
211
+ isDirectMessage: boolean;
212
+ isMpim: boolean;
213
+ isArchived: boolean;
214
+ isShared: boolean;
215
+ isExternallyShared: boolean;
216
+ isOrgShared: boolean;
217
+ isPendingExternallyShared: boolean;
218
+ contextTeamId: string | null;
219
+ connectedTeamIds: string[] | null;
220
+ sharedTeamIds: string[] | null;
221
+ topic: string;
222
+ purpose: string;
223
+ numMembers: number | null;
224
+ };
225
+ initiator: null;
226
+ } | {
227
+ conversation: {
228
+ id: string;
229
+ name: string;
230
+ isPrivate: boolean;
231
+ isMember: boolean;
232
+ isDirectMessage: boolean;
233
+ isMpim: boolean;
234
+ isArchived: boolean;
235
+ isShared: boolean;
236
+ isExternallyShared: boolean;
237
+ isOrgShared: boolean;
238
+ isPendingExternallyShared: boolean;
239
+ contextTeamId: string | null;
240
+ connectedTeamIds: string[] | null;
241
+ sharedTeamIds: string[] | null;
242
+ topic: string;
243
+ purpose: string;
244
+ numMembers: number | null;
245
+ };
246
+ initiator: {
247
+ id: string;
248
+ teamId: string | null;
249
+ isGuest: boolean | null;
250
+ isExternal: boolean | null;
251
+ };
252
+ }) & {
253
+ receipt: SlackBotReceipt;
254
+ }>;
156
255
  channelHistory(input: {
157
256
  channelId: string;
158
257
  limit?: number;
159
258
  cursor?: string;
160
259
  latest?: string;
161
260
  inclusive?: boolean;
261
+ authorizeRead?: () => Promise<void>;
162
262
  }): Promise<{
163
263
  channel: {
164
264
  id: string;
@@ -166,10 +266,15 @@ export declare class OpenGeniSlackBotClient {
166
266
  isPrivate: boolean;
167
267
  isMember: boolean;
168
268
  isDirectMessage: boolean;
269
+ isMpim: boolean;
169
270
  isArchived: boolean;
170
271
  isShared: boolean;
171
272
  isExternallyShared: boolean;
172
273
  isOrgShared: boolean;
274
+ isPendingExternallyShared: boolean;
275
+ contextTeamId: string | null;
276
+ connectedTeamIds: string[] | null;
277
+ sharedTeamIds: string[] | null;
173
278
  topic: string;
174
279
  purpose: string;
175
280
  numMembers: number | null;
@@ -201,6 +306,10 @@ export declare class OpenGeniSlackBotClient {
201
306
  threadTimestamp: string;
202
307
  limit?: number;
203
308
  cursor?: string;
309
+ oldest?: string;
310
+ latest?: string;
311
+ inclusive?: boolean;
312
+ authorizeRead?: () => Promise<void>;
204
313
  }): Promise<{
205
314
  channel: {
206
315
  id: string;
@@ -208,10 +317,15 @@ export declare class OpenGeniSlackBotClient {
208
317
  isPrivate: boolean;
209
318
  isMember: boolean;
210
319
  isDirectMessage: boolean;
320
+ isMpim: boolean;
211
321
  isArchived: boolean;
212
322
  isShared: boolean;
213
323
  isExternallyShared: boolean;
214
324
  isOrgShared: boolean;
325
+ isPendingExternallyShared: boolean;
326
+ contextTeamId: string | null;
327
+ connectedTeamIds: string[] | null;
328
+ sharedTeamIds: string[] | null;
215
329
  topic: string;
216
330
  purpose: string;
217
331
  numMembers: number | null;
@@ -252,10 +366,15 @@ export declare class OpenGeniSlackBotClient {
252
366
  isPrivate: boolean;
253
367
  isMember: boolean;
254
368
  isDirectMessage: boolean;
369
+ isMpim: boolean;
255
370
  isArchived: boolean;
256
371
  isShared: boolean;
257
372
  isExternallyShared: boolean;
258
373
  isOrgShared: boolean;
374
+ isPendingExternallyShared: boolean;
375
+ contextTeamId: string | null;
376
+ connectedTeamIds: string[] | null;
377
+ sharedTeamIds: string[] | null;
259
378
  topic: string;
260
379
  purpose: string;
261
380
  numMembers: number | null;
@@ -301,6 +420,22 @@ export declare class OpenGeniSlackBotClient {
301
420
  } & {
302
421
  receipt: SlackBotReceipt;
303
422
  }>;
423
+ /**
424
+ * Re-fetch and authorize the exact reacted-message files before any byte or
425
+ * workspace-storage mutation. The returned private URLs are process-local
426
+ * capabilities only and must never be persisted, logged, or projected into
427
+ * session input.
428
+ */
429
+ prepareReactionImageDownloads(input: {
430
+ channelId: string;
431
+ files: readonly {
432
+ id: string;
433
+ name: string;
434
+ title: string;
435
+ }[];
436
+ }): Promise<PreparedSlackReactionImage[]>;
437
+ /** Download and fully validate one previously authorized Slack image. */
438
+ downloadReactionImage(input: PreparedSlackReactionImage): Promise<DownloadedSlackReactionImage>;
304
439
  listUsers(input?: {
305
440
  limit?: number;
306
441
  cursor?: string;
@@ -328,10 +463,15 @@ export declare class OpenGeniSlackBotClient {
328
463
  isPrivate: boolean;
329
464
  isMember: boolean;
330
465
  isDirectMessage: boolean;
466
+ isMpim: boolean;
331
467
  isArchived: boolean;
332
468
  isShared: boolean;
333
469
  isExternallyShared: boolean;
334
470
  isOrgShared: boolean;
471
+ isPendingExternallyShared: boolean;
472
+ contextTeamId: string | null;
473
+ connectedTeamIds: string[] | null;
474
+ sharedTeamIds: string[] | null;
335
475
  topic: string;
336
476
  purpose: string;
337
477
  numMembers: number | null;
@@ -362,10 +502,15 @@ export declare class OpenGeniSlackBotClient {
362
502
  isPrivate: boolean;
363
503
  isMember: boolean;
364
504
  isDirectMessage: boolean;
505
+ isMpim: boolean;
365
506
  isArchived: boolean;
366
507
  isShared: boolean;
367
508
  isExternallyShared: boolean;
368
509
  isOrgShared: boolean;
510
+ isPendingExternallyShared: boolean;
511
+ contextTeamId: string | null;
512
+ connectedTeamIds: string[] | null;
513
+ sharedTeamIds: string[] | null;
369
514
  topic: string;
370
515
  purpose: string;
371
516
  numMembers: number | null;
@@ -396,10 +541,15 @@ export declare class OpenGeniSlackBotClient {
396
541
  isPrivate: boolean;
397
542
  isMember: boolean;
398
543
  isDirectMessage: boolean;
544
+ isMpim: boolean;
399
545
  isArchived: boolean;
400
546
  isShared: boolean;
401
547
  isExternallyShared: boolean;
402
548
  isOrgShared: boolean;
549
+ isPendingExternallyShared: boolean;
550
+ contextTeamId: string | null;
551
+ connectedTeamIds: string[] | null;
552
+ sharedTeamIds: string[] | null;
403
553
  topic: string;
404
554
  purpose: string;
405
555
  numMembers: number | null;
@@ -423,12 +573,18 @@ export declare class OpenGeniSlackBotClient {
423
573
  } & {
424
574
  receipt: SlackBotReceipt;
425
575
  }>;
576
+ /**
577
+ * Internal server-owned delivery only. Generic model-facing MCP callers do
578
+ * not have a trustworthy durable logical-delivery identity and must never
579
+ * reach this method with a caller-generated operation ID.
580
+ */
426
581
  postMessage(input: {
427
582
  operationId: string;
428
583
  channelId?: string;
429
584
  userId?: string;
430
585
  threadTimestamp?: string;
431
586
  text: string;
587
+ blocks?: SlackMessageBlock[];
432
588
  requireActiveNonSharedChannel?: boolean;
433
589
  }): Promise<{
434
590
  channelId: string;
@@ -436,6 +592,17 @@ export declare class OpenGeniSlackBotClient {
436
592
  threadTimestamp: string | null;
437
593
  receipt: SlackBotReceipt;
438
594
  }>;
595
+ updateMessage(input: {
596
+ operationId: string;
597
+ channelId: string;
598
+ timestamp: string;
599
+ text: string;
600
+ blocks?: SlackMessageBlock[];
601
+ }): Promise<{
602
+ channelId: string;
603
+ timestamp: string;
604
+ receipt: SlackBotReceipt;
605
+ }>;
439
606
  deleteMessage(input: {
440
607
  operationId: string;
441
608
  channelId: string;
@@ -447,6 +614,7 @@ export declare class OpenGeniSlackBotClient {
447
614
  receipt: SlackBotReceipt;
448
615
  }>;
449
616
  private slackMessageExists;
617
+ private reconcilePostMessage;
450
618
  private requireMemberChannel;
451
619
  private requireActiveNonSharedMemberChannel;
452
620
  private requireFileForChannel;
@@ -461,6 +629,7 @@ export declare class OpenGeniSlackBotClient {
461
629
  private completedPostResult;
462
630
  private completedDeleteResult;
463
631
  private postRequestDigest;
632
+ private updateRequestDigest;
464
633
  private deleteRequestDigest;
465
634
  private deletePrincipal;
466
635
  private fileListPage;
@@ -484,6 +653,7 @@ export declare function createOpenGeniSlackBotInteractionClient(deps: {
484
653
  subjectId: string;
485
654
  sessionId?: string | null;
486
655
  }): Promise<OpenGeniSlackBotClient>;
656
+ export declare function sniffSlackReactionImageMime(bytes: Uint8Array): "image/png" | "image/jpeg" | "image/webp" | null;
487
657
  export declare function resolveSlackFilesListPage(input: {
488
658
  channelId: string;
489
659
  limit?: number;
@@ -1,11 +1,12 @@
1
- import { type WorkspaceSlackReactionSummonSettings } from "@opengeni/contracts";
1
+ import { type FileResourceRef, type WorkspaceSlackReactionSummonSettings } from "@opengeni/contracts";
2
2
  import { type SlackInstallationRoute, type SlackInteractionInboxEntry, type SlackInteractionTriggerKind } from "@opengeni/db";
3
3
  import { type ApiRouteDeps } from "@opengeni/core";
4
4
  import type { Hono } from "hono";
5
5
  import { type OpenGeniSlackBotClient } from "./slack-bot.js";
6
+ import { type ImportedSlackReactionImage } from "../slack-reaction-files.js";
6
7
  export declare const SLACK_INTERACTION_MAX_BODY_BYTES: number;
7
8
  export declare const SLACK_SIGNATURE_REPLAY_WINDOW_SECONDS = 300;
8
- export declare const SLACK_DELIVERY_EVENT_TYPES: readonly ["agent.message.completed", "session.humanInput.requested", "turn.completed", "turn.failed", "turn.cancelled", "session.status.changed"];
9
+ export declare const SLACK_DELIVERY_EVENT_TYPES: readonly ["agent.message.completed", "session.humanInput.requested", "session.requiresAction", "turn.completed", "turn.failed", "turn.cancelled", "session.status.changed"];
9
10
  export declare const SLACK_TASK_INSTRUCTIONS: string;
10
11
  /**
11
12
  * Slack-originated tasks may retrieve the workspace bot's bounded read surface
@@ -13,7 +14,7 @@ export declare const SLACK_TASK_INSTRUCTIONS: string;
13
14
  * selection at session creation while keeping Slack mutations out of the model
14
15
  * surface; interaction delivery remains owned by the durable delivery pump.
15
16
  */
16
- export declare const SLACK_TASK_FIRST_PARTY_MCP_TOOLS: ("artifacts_create" | "artifacts_get_source" | "artifacts_list" | "artifacts_publish" | "artifacts_rollback" | "atlassian_get" | "atlassian_search" | "atlassian_sources_list" | "browser_act" | "browser_debug" | "browser_identity" | "browser_lifecycle" | "browser_observe" | "browser_open" | "browser_publish" | "browser_tabs" | "capability_authorization_request" | "capability_catalog_search" | "computer_act" | "computer_lifecycle" | "computer_observe" | "computer_open" | "computer_targets" | "connected_machine_remove" | "editable_artifact_apply" | "editable_artifact_create" | "editable_artifact_export" | "editable_artifact_export_status" | "editable_artifact_get" | "editable_artifact_import" | "editable_artifact_inspect" | "editable_artifact_list" | "environment_list" | "environment_set_variable" | "github_connect_link" | "github_repositories_list" | "goal_complete" | "goal_pause" | "goal_set" | "goal_update" | "interaction_discover" | "memory_correct" | "memory_save" | "memory_search" | "preference_registry_get" | "preference_registry_summary" | "reddit_accounts_list" | "reddit_mentions_live" | "reddit_post_reply" | "reddit_posts_sync" | "reddit_search_live" | "reddit_thread_fetch" | "rig_get" | "rig_list" | "rig_promote" | "rig_propose_change" | "rig_verify" | "run_on" | "sandbox_attach" | "sandbox_provision" | "sandbox_swap" | "sandboxes_list" | "scheduled_task_runs_list" | "scheduled_tasks_create" | "scheduled_tasks_delete" | "scheduled_tasks_get" | "scheduled_tasks_list" | "scheduled_tasks_pause" | "scheduled_tasks_resume" | "scheduled_tasks_trigger" | "scheduled_tasks_update" | "session_create" | "session_events" | "session_get" | "session_pause" | "session_resume" | "session_send_message" | "session_steer" | "sessions_list" | "set_other_session_title" | "set_session_title" | "slack_bot_channel_history" | "slack_bot_delete_message" | "slack_bot_file_content" | "slack_bot_file_info" | "slack_bot_list_channels" | "slack_bot_list_files" | "slack_bot_list_users" | "slack_bot_post_message" | "slack_bot_thread_replies" | "social_connections_list" | "social_daily_analysis_context" | "social_mentions_live" | "social_post_reply" | "social_posts_recent" | "social_posts_sync" | "social_search_live" | "social_thread_fetch" | "variable_set_get_variable" | "variable_set_list" | "variable_set_set_variable" | "x_accounts_list" | "x_mentions_live" | "x_post_reply" | "x_posts_sync" | "x_search_live" | "x_thread_fetch")[];
17
+ export declare const SLACK_TASK_FIRST_PARTY_MCP_TOOLS: ("artifacts_create" | "artifacts_get_source" | "artifacts_list" | "artifacts_publish" | "artifacts_rollback" | "atlassian_get" | "atlassian_search" | "atlassian_sources_list" | "browser_act" | "browser_auth" | "browser_clipboard" | "browser_debug" | "browser_identity" | "browser_lifecycle" | "browser_observe" | "browser_open" | "browser_publish" | "browser_tabs" | "capability_authorization_request" | "capability_catalog_search" | "computer_act" | "computer_clipboard" | "computer_lifecycle" | "computer_observe" | "computer_open" | "computer_targets" | "connected_machine_remove" | "editable_artifact_apply" | "editable_artifact_create" | "editable_artifact_export" | "editable_artifact_export_status" | "editable_artifact_get" | "editable_artifact_import" | "editable_artifact_inspect" | "editable_artifact_list" | "environment_list" | "environment_set_variable" | "fiken_bank_accounts_list" | "fiken_companies_list" | "fiken_contact_create" | "fiken_contacts_list" | "fiken_invoice_draft_create" | "fiken_invoice_get" | "fiken_invoices_list" | "fiken_products_list" | "fiken_purchases_list" | "fiken_sales_list" | "github_connect_link" | "github_repositories_list" | "goal_complete" | "goal_pause" | "goal_progress" | "goal_set" | "goal_update" | "interaction_discover" | "interaction_request_human" | "memory_correct" | "memory_save" | "memory_search" | "preference_registry_get" | "preference_registry_summary" | "reddit_accounts_list" | "reddit_mentions_live" | "reddit_post_reply" | "reddit_posts_sync" | "reddit_search_live" | "reddit_thread_fetch" | "rig_get" | "rig_list" | "rig_promote" | "rig_propose_change" | "rig_verify" | "run_on" | "sandbox_attach" | "sandbox_provision" | "sandbox_swap" | "sandboxes_list" | "scheduled_task_runs_list" | "scheduled_tasks_create" | "scheduled_tasks_delete" | "scheduled_tasks_get" | "scheduled_tasks_list" | "scheduled_tasks_pause" | "scheduled_tasks_resume" | "scheduled_tasks_trigger" | "scheduled_tasks_update" | "session_create" | "session_events" | "session_get" | "session_pause" | "session_resume" | "session_send_message" | "session_steer" | "sessions_list" | "set_other_session_title" | "set_session_title" | "slack_bot_channel_history" | "slack_bot_delete_message" | "slack_bot_file_content" | "slack_bot_file_info" | "slack_bot_list_channels" | "slack_bot_list_files" | "slack_bot_list_users" | "slack_bot_post_message" | "slack_bot_thread_replies" | "social_connections_list" | "social_daily_analysis_context" | "social_mentions_live" | "social_post_reply" | "social_posts_recent" | "social_posts_sync" | "social_search_live" | "social_thread_fetch" | "task_note_archive" | "task_note_save" | "task_notes_list" | "variable_set_get_variable" | "variable_set_list" | "variable_set_set_variable" | "x_accounts_list" | "x_mentions_live" | "x_post_reply" | "x_posts_sync" | "x_search_live" | "x_thread_fetch")[];
17
18
  export type NormalizedSlackInteraction = {
18
19
  providerEventId: string;
19
20
  providerMessageId: string;
@@ -24,8 +25,11 @@ export type NormalizedSlackInteraction = {
24
25
  slackThreadTs: string | null;
25
26
  triggerKind: SlackInteractionTriggerKind;
26
27
  text: string;
28
+ hasFiles: boolean;
27
29
  };
28
- export declare function slackInteractionRoutePolicy(entry: Pick<SlackInteractionInboxEntry, "triggerKind" | "slackChannelId" | "slackThreadTs" | "slackMessageTs" | "slackUserId">): {
30
+ export declare function slackInteractionRoutePolicy(entry: Pick<SlackInteractionInboxEntry, "triggerKind" | "slackChannelId" | "slackThreadTs" | "slackMessageTs" | "slackUserId">, options?: {
31
+ privateHandoff?: boolean;
32
+ }): {
29
33
  directMessageShortcut: boolean;
30
34
  requiresChannelAccess: boolean;
31
35
  visibility: "private" | "workspace";
@@ -51,7 +55,15 @@ export type SlackInvocationMessageContext = {
51
55
  };
52
56
  export declare function slackInvocationTaskText(entry: Pick<SlackInteractionInboxEntry, "slackMessageTs" | "slackUserId" | "text">, context: SlackInvocationMessageContext): string;
53
57
  type SlackReactionMessageContext = Awaited<ReturnType<OpenGeniSlackBotClient["reactionMessageContext"]>>;
54
- export declare function slackReactionTaskText(context: SlackReactionMessageContext): string;
58
+ type PreparedSlackReactionTask = Readonly<{
59
+ resources: FileResourceRef[];
60
+ attachments: ImportedSlackReactionImage[];
61
+ omissionCodes: string[];
62
+ omittedCount: number;
63
+ }>;
64
+ export declare function slackReactionTaskText(context: SlackReactionMessageContext, prepared?: PreparedSlackReactionTask): string;
65
+ export declare function slackDeliveryTextsCoalesce(left: string, right: string): boolean;
66
+ export declare function normalizedBlockActionInteraction(payload: Record<string, unknown>): NormalizedSlackInteraction;
55
67
  type SlackUserLinkToken = {
56
68
  workspaceId: string;
57
69
  connectionId: string;
@@ -0,0 +1,17 @@
1
+ import type { AccessGrant } from "@opengeni/contracts";
2
+ import type { ApiRouteDeps } from "@opengeni/core";
3
+ /**
4
+ * Keep one durable interaction operation—and its sandbox holder when present—
5
+ * live while a bounded controller mutation is in flight. Browser profile
6
+ * capture/restore can legitimately take minutes; without this pulse a lifecycle
7
+ * reaper cannot distinguish that request from a caller that disappeared.
8
+ */
9
+ export declare function withInteractionHolderHeartbeat<T>(deps: ApiRouteDeps, input: {
10
+ grant: AccessGrant;
11
+ workspaceId: string;
12
+ sandboxGroupId: string | null;
13
+ holderId: string;
14
+ operationId: string;
15
+ resourceId: string;
16
+ controllerGeneration: string;
17
+ }, run: () => Promise<T>): Promise<T>;
@@ -0,0 +1,11 @@
1
+ import type { AuthRunMutationResponse, BrowserActionReceipt, BrowserActionRequest, PublishBrowserRevisionResponse, BrowserSessionMutationResponse, ComputerActionReceipt, ComputerActionRequest, ComputerSessionMutationResponse, InteractionInterventionMutationResponse, ProtectedAuthFillResponse } from "@opengeni/contracts";
2
+ import { type Observability } from "@opengeni/observability";
3
+ type InteractionLifecycleMutation = BrowserSessionMutationResponse | ComputerSessionMutationResponse;
4
+ type AuthMutation = AuthRunMutationResponse | ProtectedAuthFillResponse;
5
+ export declare function observeBrowserActionResult(observability: Observability | null | undefined, startedAtMs: number, request: BrowserActionRequest, receipt: BrowserActionReceipt): void;
6
+ export declare function observeComputerActionResult(observability: Observability | null | undefined, startedAtMs: number, request: ComputerActionRequest, receipt: ComputerActionReceipt): void;
7
+ export declare function observeLifecycleResult(observability: Observability | null | undefined, startedAtMs: number, response: InteractionLifecycleMutation): void;
8
+ export declare function observeBrowserRevisionPublication(observability: Observability | null | undefined, startedAtMs: number, response: PublishBrowserRevisionResponse): void;
9
+ export declare function observeAuthMutation(observability: Observability | null | undefined, startedAtMs: number, response: AuthMutation): void;
10
+ export declare function observeInterventionMutation(observability: Observability | null | undefined, response: InteractionInterventionMutationResponse): void;
11
+ export {};
@@ -1,10 +1,11 @@
1
- import { type AccessGrant, type SessionAuthorizationActor } from "@opengeni/contracts";
1
+ import { type AccessGrant, type SessionAuthorizationActor, type WorkspaceMemoryPromptMode } from "@opengeni/contracts";
2
2
  import { listSessionDiscoverySummaries, type SessionDiscoveryCursor, type SessionDiscoveryOrderBy } from "@opengeni/db";
3
3
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
4
  import type { ApiRouteDeps } from "@opengeni/core";
5
5
  export type McpServerOptions = {
6
6
  requestOrigin?: string | null;
7
7
  workspaceMemoryEnabled?: boolean | undefined;
8
+ workspaceMemoryPromptMode?: WorkspaceMemoryPromptMode | undefined;
8
9
  };
9
10
  export declare function buildOpenGeniMcpServer(deps: ApiRouteDeps, grant: AccessGrant, options?: McpServerOptions): McpServer;
10
11
  /** Only a prompt explicitly supplied through the human/API channel may redirect a user-paused goal. */
@@ -81,7 +82,7 @@ export declare function capSessionDiscoveryPage(page: Awaited<ReturnType<typeof
81
82
  truncated: boolean;
82
83
  };
83
84
  latestMessage?: {
84
- type: "agent.message.completed" | "agent.message.delta" | "agent.model.request" | "agent.model.usage" | "agent.reasoning.delta" | "agent.toolCall.created" | "agent.toolCall.output" | "agent.updated" | "artifact.created" | "codex.account.switched" | "codex.capacity.resumed" | "codex.capacity.superseded" | "codex.capacity.waiting" | "codex.credential.selected" | "codex.fleet.decision" | "credential.auth_needed" | "fs.changed" | "git.changed" | "goal.cleared" | "goal.completed" | "goal.continuation" | "goal.paused" | "goal.resumed" | "goal.set" | "goal.updated" | "machine.link.lost" | "machine.link.restored" | "machine.op.failed" | "machine.op.recovered" | "machine.runner.restarted" | "memory.corrected" | "memory.saved" | "recording.available" | "recording.failed" | "recording.started" | "rig.setup.completed" | "rig.setup.failed" | "rig.setup.skipped" | "rig.setup.started" | "sandbox.box.created" | "sandbox.box.lost" | "sandbox.box.snapshot" | "sandbox.box.terminated" | "sandbox.command.output.delta" | "sandbox.env.drift" | "sandbox.operation.completed" | "sandbox.operation.failed" | "sandbox.operation.started" | "session.context.cleared" | "session.context.compacted" | "session.context.compaction.requested" | "session.context.compaction.skipped" | "session.context.compaction.started" | "session.control.paused" | "session.control.resumed" | "session.control.steer_requested" | "session.created" | "session.event.envelope_omitted" | "session.humanInput.requested" | "session.mcp.approval_policy.updated" | "session.queue.changed" | "session.queue.history" | "session.queue.prompt.cancelled" | "session.realtime.ended" | "session.realtime.started" | "session.requiresAction" | "session.route.reconciled" | "session.status.changed" | "session.title_set" | "session.tool_policy.updated" | "stream.closed" | "stream.opened" | "stream.revoked" | "stream.url.rotated" | "system.update.cancelled" | "system.update.delivered" | "system.update.pending" | "system.update.settled" | "system.update.superseded" | "terminal.pty.exited" | "terminal.pty.output.delta" | "terminal.pty.started" | "tool.auth_needed" | "turn.cancelled" | "turn.capacity_waiting" | "turn.completed" | "turn.event.rejected_late" | "turn.failed" | "turn.queued" | "turn.recovery.requested" | "turn.started" | "turn.superseded" | "user.approvalDecision" | "user.humanInputResponse" | "user.message" | "user.pause" | "workspace.inference.paused" | "workspace.inference.resumed" | "workspace.revision.captured" | "workspace.revision.degraded";
85
+ type: "agent.message.completed" | "agent.message.delta" | "agent.model.request" | "agent.model.usage" | "agent.reasoning.delta" | "agent.toolCall.created" | "agent.toolCall.output" | "agent.updated" | "artifact.created" | "codex.account.switched" | "codex.capacity.resumed" | "codex.capacity.superseded" | "codex.capacity.waiting" | "codex.credential.selected" | "codex.fleet.decision" | "credential.auth_needed" | "fs.changed" | "git.changed" | "goal.cleared" | "goal.completed" | "goal.continuation" | "goal.paused" | "goal.progress" | "goal.resumed" | "goal.rewrite.proposed" | "goal.rewrite.rejected" | "goal.set" | "goal.updated" | "machine.link.lost" | "machine.link.restored" | "machine.op.failed" | "machine.op.recovered" | "machine.runner.restarted" | "memory.corrected" | "memory.saved" | "recording.available" | "recording.failed" | "recording.started" | "rig.setup.completed" | "rig.setup.failed" | "rig.setup.skipped" | "rig.setup.started" | "sandbox.box.created" | "sandbox.box.lost" | "sandbox.box.snapshot" | "sandbox.box.terminated" | "sandbox.command.output.delta" | "sandbox.env.drift" | "sandbox.operation.completed" | "sandbox.operation.failed" | "sandbox.operation.started" | "session.context.cleared" | "session.context.compacted" | "session.context.compaction.requested" | "session.context.compaction.skipped" | "session.context.compaction.started" | "session.control.paused" | "session.control.resumed" | "session.control.steer_requested" | "session.created" | "session.event.envelope_omitted" | "session.humanInput.requested" | "session.mcp.approval_policy.updated" | "session.queue.changed" | "session.queue.history" | "session.queue.prompt.cancelled" | "session.realtime.ended" | "session.realtime.started" | "session.requiresAction" | "session.route.reconciled" | "session.status.changed" | "session.title_set" | "session.tool_policy.updated" | "session.visibility.changed" | "stream.closed" | "stream.opened" | "stream.revoked" | "stream.url.rotated" | "system.update.cancelled" | "system.update.delivered" | "system.update.pending" | "system.update.settled" | "system.update.superseded" | "terminal.pty.exited" | "terminal.pty.output.delta" | "terminal.pty.started" | "tool.auth_needed" | "turn.cancelled" | "turn.capacity_waiting" | "turn.completed" | "turn.event.rejected_late" | "turn.failed" | "turn.queued" | "turn.recovery.requested" | "turn.started" | "turn.superseded" | "user.approvalDecision" | "user.humanInputResponse" | "user.message" | "user.pause" | "workspace.inference.paused" | "workspace.inference.resumed" | "workspace.revision.captured" | "workspace.revision.degraded";
85
86
  preview: string | null;
86
87
  previewTruncated: boolean;
87
88
  } | null;
@@ -32,6 +32,7 @@ export declare function buildWorkspaceModelCatalog(input: {
32
32
  settings: Settings;
33
33
  policy: WorkspaceModelPolicyContract | null;
34
34
  codexSubscriptionActive: boolean;
35
+ xaiSubscriptionActive?: boolean;
35
36
  workspaceGatewayConnectionActive?: boolean;
36
37
  credentialReadinessObservations?: Readonly<Record<string, ModelCredentialReadinessObservation>> | undefined;
37
38
  observations?: Readonly<Record<string, ModelAvailabilityObservation>> | undefined;
@@ -0,0 +1,3 @@
1
+ import type { ApiRouteDeps } from "@opengeni/core";
2
+ import type { Hono } from "hono";
3
+ export declare function registerCanonicalHumanIdentityRoutes(app: Hono, deps: ApiRouteDeps): void;
@@ -0,0 +1,3 @@
1
+ import type { Hono } from "hono";
2
+ import type { ApiRouteDeps } from "@opengeni/core";
3
+ export declare function registerChannelRoutes(app: Hono, deps: ApiRouteDeps): void;
@@ -0,0 +1,3 @@
1
+ import { type ApiRouteDeps } from "@opengeni/core";
2
+ import type { Hono } from "hono";
3
+ export declare function registerIntegrationFacetRoutes(app: Hono, deps: ApiRouteDeps): void;
@@ -0,0 +1,5 @@
1
+ import { type ApiRouteDeps } from "@opengeni/core";
2
+ import type { Hono } from "hono";
3
+ import { HTTPException } from "hono/http-exception";
4
+ export declare function registerInteractionResourceRoutes(app: Hono, deps: ApiRouteDeps): void;
5
+ export declare function interactionResourceRouteError(error: unknown): HTTPException;
@@ -0,0 +1,3 @@
1
+ import { type ApiRouteDeps } from "@opengeni/core";
2
+ import type { Hono } from "hono";
3
+ export declare function registerOrganizationMembershipRoutes(app: Hono, deps: ApiRouteDeps): void;
@@ -1,10 +1,11 @@
1
- import { ClientSessionEvent, SteerSessionMessageRequest, type SessionAuthorizationOperation } from "@opengeni/contracts";
1
+ import { ClientSessionEvent, SteerSessionMessageRequest, type SessionGoalRevision, type SessionAuthorizationOperation } from "@opengeni/contracts";
2
2
  import { type SessionDiscoveryCursor } from "@opengeni/db";
3
3
  import type { Context, Hono } from "hono";
4
4
  import type { ApiRouteDeps } from "@opengeni/core";
5
5
  import { type ViewerServices } from "../sandbox/viewer.js";
6
6
  type SessionRouteDeps = ApiRouteDeps & Pick<ViewerServices, "establishSandboxSession">;
7
7
  export declare function registerSessionRoutes(app: Hono, deps: SessionRouteDeps): void;
8
+ export declare function goalProposalMatchesExpectedRevision(revision: Pick<SessionGoalRevision, "baseObjectiveRevision">, expectedObjectiveRevision: number): boolean;
8
9
  /**
9
10
  * Map every mounted session-addressed HTTP path to the host-neutral operation
10
11
  * the embedding port authorizes. Returning null is deliberately fail-closed in
@@ -0,0 +1,3 @@
1
+ import { type ApiRouteDeps } from "@opengeni/core";
2
+ import type { Hono } from "hono";
3
+ export declare function registerSlackTaskPolicyRoutes(app: Hono, deps: ApiRouteDeps): void;
@@ -0,0 +1,3 @@
1
+ import { type ApiRouteDeps } from "@opengeni/core";
2
+ import type { Hono } from "hono";
3
+ export declare function registerSuperGrokRoutes(app: Hono, deps: ApiRouteDeps): void;
@@ -10,7 +10,7 @@ export type ChannelAServices = {
10
10
  bus: EventBus;
11
11
  observability?: Observability | undefined;
12
12
  };
13
- export type ChannelAOperation = "fs.list" | "fs.list-batch" | "fs.read" | "fs.write" | "fs.delete" | "fs.move" | "fs.mkdir" | "git.status" | "git.diff" | "git.read-batch" | "git.log" | "git.show" | "terminal.exec" | "terminal.pty.open" | "terminal.pty.write" | "terminal.pty.resize" | "terminal.pty.close" | "browser.create" | "browser.resume" | "browser.suspend" | "browser.end" | "browser.read" | "browser.control" | "browser.attach" | "computer.create" | "computer.end" | "computer.read" | "computer.control" | "computer.attach";
13
+ export type ChannelAOperation = "fs.list" | "fs.list-batch" | "fs.read" | "fs.write" | "fs.delete" | "fs.move" | "fs.mkdir" | "git.status" | "git.diff" | "git.read-batch" | "git.log" | "git.show" | "terminal.exec" | "terminal.pty.open" | "terminal.pty.write" | "terminal.pty.resize" | "terminal.pty.close" | "browser.create" | "browser.resume" | "browser.suspend" | "browser.end" | "browser.read" | "browser.action" | "browser.control" | "browser.download.save" | "browser.attach" | "computer.create" | "computer.end" | "computer.read" | "computer.action" | "computer.control" | "computer.attach";
14
14
  export type ChannelAContext = {
15
15
  accountId: string;
16
16
  workspaceId: string;
@@ -20,6 +20,11 @@ export type ChannelAContext = {
20
20
  waitSignal?: AbortSignal | undefined;
21
21
  /** Bounded route identity for metrics and safe operator diagnostics. */
22
22
  operation?: ChannelAOperation | undefined;
23
+ /** The callback is an interaction-controller read or an exactly-once action.
24
+ * A controller transport failure may therefore rebuild the exact fenced
25
+ * provider handle and replay the request. Tab/lifecycle mutations that lack
26
+ * a controller operation id must never opt into this recovery. */
27
+ retryControllerTransport?: boolean | undefined;
23
28
  };
24
29
  export type ChannelAOperationFailureReason = "request_cancelled" | "provider_read_busy" | "provider_unavailable" | "lifecycle_conflict" | "request_rejected" | "unexpected";
25
30
  export type ChannelAOperationFailureDiagnostic = {
@@ -60,6 +65,8 @@ type ChannelAReadRecoveryOptions = {
60
65
  maxFreshHandleRetries?: 1 | 2;
61
66
  /** Never start another provider attempt after the originating request ends. */
62
67
  waitSignal?: AbortSignal | undefined;
68
+ /** Additional callback-specific failure that is safe to replay. */
69
+ retryableError?: ((error: unknown) => boolean) | undefined;
63
70
  };
64
71
  /** Retry a side-effect-free Channel-A read only after the caller has discarded
65
72
  * and freshly re-established its provider handle. The ordinary provider-neutral
@@ -18,8 +18,8 @@ export type MachinesServices = {
18
18
  export declare function metricRowToSample(row: MachineMetricsRow): MetricSample;
19
19
  /**
20
20
  * Build the Machines dashboard response for a workspace. When `sessionId` is
21
- * supplied (an in-session view) the session's synthetic Modal group box is
22
- * prepended (`isSessionGroup:true`) and the active-sandbox pointer is echoed;
21
+ * supplied (an in-session view) the session's synthetic home group box is
22
+ * prepended when one exists (`isSessionGroup:true`) and the active-sandbox pointer is echoed;
23
23
  * without it (the pure workspace dashboard) `activeSandboxId` is null and only
24
24
  * the enrolled machines are listed.
25
25
  */
@@ -191,7 +191,9 @@ export type TerminalStreamMint = {
191
191
  token: string;
192
192
  expiresAt: string;
193
193
  leaseEpoch: number;
194
+ transport: "pty-ws" | "relay-pty";
194
195
  };
196
+ type SelfhostedStreamMint = Omit<TerminalStreamMint, "transport">;
195
197
  export type MintTerminalStreamInput = {
196
198
  accountId: string;
197
199
  workspaceId: string;
@@ -249,5 +251,5 @@ export type MintSelfhostedStreamInput = {
249
251
  * query param (the relay validates the in-band token); the relay's stale-viewer
250
252
  * fence uses the token's leaseEpoch claim (== activeEpoch here).
251
253
  */
252
- export declare function mintSelfhostedStream(services: ViewerServices, input: MintSelfhostedStreamInput): Promise<TerminalStreamMint | null>;
254
+ export declare function mintSelfhostedStream(services: ViewerServices, input: MintSelfhostedStreamInput): Promise<SelfhostedStreamMint | null>;
253
255
  export {};
@@ -0,0 +1,27 @@
1
+ import type { FileResourceRef } from "@opengeni/contracts";
2
+ import { completeFileUpload, prepareGeneratedWorkspaceFile, type Database } from "@opengeni/db";
3
+ import type { ObjectStorage } from "@opengeni/storage";
4
+ import type { DownloadedSlackReactionImage } from "./integrations/slack-bot.js";
5
+ export type SlackReactionImageImportSource = Readonly<{
6
+ accountId: string;
7
+ workspaceId: string;
8
+ connectionId: string;
9
+ slackTeamId: string;
10
+ slackChannelId: string;
11
+ slackMessageTs: string;
12
+ }>;
13
+ export type ImportedSlackReactionImage = Readonly<{
14
+ resource: FileResourceRef;
15
+ filename: string;
16
+ contentType: "image/png" | "image/jpeg" | "image/webp";
17
+ sizeBytes: number;
18
+ }>;
19
+ export declare function importSlackReactionImage(dependencies: Readonly<{
20
+ db: Database;
21
+ objectStorage: ObjectStorage;
22
+ now?: () => Date;
23
+ prepareFile?: typeof prepareGeneratedWorkspaceFile;
24
+ completeFile?: typeof completeFileUpload;
25
+ }>, source: SlackReactionImageImportSource, image: DownloadedSlackReactionImage, ordinal: number): Promise<ImportedSlackReactionImage>;
26
+ export declare function slackReactionImageIdentity(source: SlackReactionImageImportSource, slackFileId: string): string;
27
+ export declare function safeSlackImageFilename(value: string, contentType: "image/png" | "image/jpeg" | "image/webp"): string;
@@ -0,0 +1,8 @@
1
+ import { type Settings } from "@opengeni/config";
2
+ import { type TranscriptionProvider } from "@opengeni/core";
3
+ import { type Database } from "@opengeni/db";
4
+ export declare function createXaiSubscriptionTranscriptionProvider(input: {
5
+ settings: Settings;
6
+ db: Database;
7
+ fetch?: typeof fetch;
8
+ }): TranscriptionProvider;