@opengeni/api-router 0.30.3 → 2.2.0-canary.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 (165) hide show
  1. package/dist/api-websocket.d.ts +18 -0
  2. package/dist/app.js +1 -1
  3. package/dist/auth/managed-auth.d.ts +6 -0
  4. package/dist/{chunk-WCXHI3FF.js → chunk-3TP54PPX.js} +26692 -15389
  5. package/dist/chunk-3TP54PPX.js.map +1 -0
  6. package/dist/codemode.d.ts +8 -1
  7. package/dist/company-brain-okf.d.ts +24 -0
  8. package/dist/connected-machine-computer-access.d.ts +11 -0
  9. package/dist/connection-authority-owner.d.ts +59 -0
  10. package/dist/connection-ownership.d.ts +47 -0
  11. package/dist/controller-data-plane.d.ts +16 -0
  12. package/dist/editable-artifact-websocket.d.ts +5 -15
  13. package/dist/editable-artifact-workspace-files.d.ts +1 -1
  14. package/dist/http/api-error.d.ts +10 -0
  15. package/dist/http/cors.d.ts +5 -0
  16. package/dist/http/interaction-control-error.d.ts +13 -0
  17. package/dist/http/sse.d.ts +2 -3
  18. package/dist/index.d.ts +5 -2
  19. package/dist/index.js +326 -82
  20. package/dist/index.js.map +1 -1
  21. package/dist/integrations/atlassian.d.ts +17 -0
  22. package/dist/integrations/fiken.d.ts +7 -2
  23. package/dist/integrations/google-drive.d.ts +18 -0
  24. package/dist/integrations/oauth-client.d.ts +22 -3
  25. package/dist/integrations/oauth-profiles.d.ts +195 -0
  26. package/dist/integrations/personal-github-repositories.d.ts +45 -0
  27. package/dist/integrations/personal-github.d.ts +40 -0
  28. package/dist/integrations/pr-review-provider.d.ts +22 -0
  29. package/dist/integrations/provider-oauth.d.ts +8 -0
  30. package/dist/integrations/slack-app-home.d.ts +24 -0
  31. package/dist/integrations/slack-bot.d.ts +157 -9
  32. package/dist/integrations/slack-interactions.d.ts +39 -5
  33. package/dist/integrations/slack-routing.d.ts +120 -0
  34. package/dist/integrations/social-oauth.d.ts +5 -0
  35. package/dist/interaction-frame-proxy.d.ts +68 -0
  36. package/dist/mcp/company-brain-governed-writes.d.ts +26 -0
  37. package/dist/mcp/company-profile-agent-admin.d.ts +44 -0
  38. package/dist/mcp/documents.d.ts +1 -0
  39. package/dist/mcp/remember.d.ts +28 -0
  40. package/dist/mcp/request-abort.d.ts +19 -0
  41. package/dist/mcp/scheduled-task-view.d.ts +4 -4
  42. package/dist/mcp/server.d.ts +15 -2
  43. package/dist/mcp/session-view.d.ts +4 -0
  44. package/dist/mcp/session-wait.d.ts +137 -0
  45. package/dist/routes/automations.d.ts +4 -0
  46. package/dist/routes/billing.d.ts +5 -0
  47. package/dist/routes/browser-sessions.d.ts +4 -1
  48. package/dist/routes/company-brain.d.ts +3 -0
  49. package/dist/routes/company-profile.d.ts +2 -1
  50. package/dist/routes/connection-authorities.d.ts +3 -0
  51. package/dist/routes/personal-github-git-broker.d.ts +29 -0
  52. package/dist/routes/personal-github.d.ts +3 -0
  53. package/dist/routes/pr-review.d.ts +3 -0
  54. package/dist/routes/sessions.d.ts +1 -0
  55. package/dist/routes/user-resource-authorities.d.ts +3 -0
  56. package/dist/routes/workspace-capture.d.ts +10 -2
  57. package/dist/routes/workspace-learning.d.ts +3 -0
  58. package/dist/routes/workspaces.d.ts +19 -0
  59. package/dist/sandbox/channel-a.d.ts +11 -1
  60. package/dist/sandbox/connection-authority.d.ts +3 -0
  61. package/dist/sandbox/enrollment.d.ts +2 -0
  62. package/dist/sandbox/machines.d.ts +2 -2
  63. package/dist/sandbox/metrics-ingestion.d.ts +10 -20
  64. package/dist/sandbox/viewer.d.ts +24 -1
  65. package/dist/sandbox-file-artifacts.d.ts +11 -0
  66. package/dist/scheduled-task-deletion.d.ts +14 -0
  67. package/dist/slack-reaction-files.d.ts +1 -1
  68. package/dist/temporal-schedule-cleanup.d.ts +1 -0
  69. package/package.json +20 -18
  70. package/src/api-websocket.ts +23 -0
  71. package/src/app.ts +161 -23
  72. package/src/auth/managed-auth.ts +25 -3
  73. package/src/codemode.ts +53 -23
  74. package/src/codex-realtime.ts +8 -2
  75. package/src/company-brain-okf.ts +340 -0
  76. package/src/connected-machine-computer-access.ts +33 -0
  77. package/src/connection-authority-owner.ts +61 -0
  78. package/src/connection-ownership.ts +180 -0
  79. package/src/controller-data-plane.ts +47 -0
  80. package/src/editable-artifact-native-kernel.ts +26 -15
  81. package/src/editable-artifact-office-import.ts +28 -3
  82. package/src/editable-artifact-production.ts +13 -7
  83. package/src/editable-artifact-websocket.ts +11 -18
  84. package/src/editable-artifact-workspace-files.ts +31 -6
  85. package/src/http/api-error.ts +28 -0
  86. package/src/http/auth.ts +4 -0
  87. package/src/http/cors.ts +35 -0
  88. package/src/http/interaction-control-error.ts +164 -0
  89. package/src/http/sse.ts +112 -66
  90. package/src/index.ts +46 -6
  91. package/src/integrations/atlassian.ts +146 -35
  92. package/src/integrations/fiken.ts +102 -22
  93. package/src/integrations/google-drive.ts +301 -92
  94. package/src/integrations/oauth-client.ts +272 -143
  95. package/src/integrations/oauth-profiles.ts +477 -0
  96. package/src/integrations/personal-github-repositories.ts +445 -0
  97. package/src/integrations/personal-github.ts +705 -0
  98. package/src/integrations/pr-review-provider.ts +246 -0
  99. package/src/integrations/provider-oauth.ts +121 -5
  100. package/src/integrations/slack-app-home.ts +300 -0
  101. package/src/integrations/slack-bot.ts +342 -57
  102. package/src/integrations/slack-interactions.ts +1898 -259
  103. package/src/integrations/slack-routing.ts +337 -0
  104. package/src/integrations/social-oauth.ts +25 -0
  105. package/src/interaction-frame-proxy.ts +409 -0
  106. package/src/mcp/company-brain-governed-writes.ts +262 -0
  107. package/src/mcp/company-profile-agent-admin.ts +205 -0
  108. package/src/mcp/documents.ts +37 -6
  109. package/src/mcp/files.ts +16 -1
  110. package/src/mcp/remember.ts +181 -0
  111. package/src/mcp/request-abort.ts +44 -0
  112. package/src/mcp/scheduled-task-view.ts +1 -0
  113. package/src/mcp/server.ts +719 -369
  114. package/src/mcp/session-view.ts +54 -0
  115. package/src/mcp/session-wait.ts +554 -0
  116. package/src/model-catalog.ts +20 -12
  117. package/src/routes/api-integrations.ts +4 -0
  118. package/src/routes/api-keys.ts +1 -0
  119. package/src/routes/automations.ts +534 -0
  120. package/src/routes/billing.ts +57 -1
  121. package/src/routes/browser-sessions.ts +329 -79
  122. package/src/routes/channels.ts +17 -1
  123. package/src/routes/codex.ts +50 -0
  124. package/src/routes/company-brain.ts +367 -0
  125. package/src/routes/company-profile.ts +1 -1
  126. package/src/routes/computer-sessions.ts +320 -93
  127. package/src/routes/connection-authorities.ts +139 -0
  128. package/src/routes/connections.ts +144 -34
  129. package/src/routes/documents.ts +353 -4
  130. package/src/routes/editable-artifacts.ts +11 -3
  131. package/src/routes/enrollments.ts +116 -26
  132. package/src/routes/environments.ts +127 -55
  133. package/src/routes/files.ts +72 -11
  134. package/src/routes/install.ts +82 -28
  135. package/src/routes/integration-facets.ts +29 -0
  136. package/src/routes/interaction-resources.ts +20 -2
  137. package/src/routes/machines.ts +275 -13
  138. package/src/routes/organization-memberships.ts +717 -28
  139. package/src/routes/packs.ts +4 -3
  140. package/src/routes/personal-github-git-broker.ts +785 -0
  141. package/src/routes/personal-github.ts +319 -0
  142. package/src/routes/pr-review.ts +531 -0
  143. package/src/routes/rigs.ts +104 -39
  144. package/src/routes/scheduled-tasks.ts +19 -21
  145. package/src/routes/sessions.ts +775 -38
  146. package/src/routes/social.ts +14 -2
  147. package/src/routes/supergrok.ts +23 -4
  148. package/src/routes/transcription-recordings.ts +8 -2
  149. package/src/routes/user-resource-authorities.ts +138 -0
  150. package/src/routes/workspace-artifacts.ts +4 -1
  151. package/src/routes/workspace-capture.ts +21 -0
  152. package/src/routes/workspace-learning.ts +228 -0
  153. package/src/routes/workspaces.ts +59 -6
  154. package/src/sandbox/auth-callout.ts +38 -12
  155. package/src/sandbox/channel-a.ts +242 -19
  156. package/src/sandbox/connection-authority.ts +3 -0
  157. package/src/sandbox/enrollment.ts +15 -3
  158. package/src/sandbox/machines.ts +186 -64
  159. package/src/sandbox/metrics-ingestion.ts +220 -58
  160. package/src/sandbox/viewer.ts +243 -19
  161. package/src/sandbox-file-artifacts.ts +329 -0
  162. package/src/scheduled-task-deletion.ts +127 -0
  163. package/src/slack-reaction-files.ts +16 -5
  164. package/src/temporal-schedule-cleanup.ts +13 -0
  165. package/dist/chunk-WCXHI3FF.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { type Settings } from "@opengeni/config";
2
- import { OPENGENI_SLACK_BOT_CREDENTIAL_LABEL, OPENGENI_SLACK_BOT_CREDENTIAL_ROLE, type AccessGrant, type ConnectionMetadata, type OpenGeniSlackBotConnectionMetadata } from "@opengeni/contracts";
2
+ import { OPENGENI_SLACK_BOT_CREDENTIAL_LABEL, OPENGENI_SLACK_BOT_CREDENTIAL_ROLE, type AccessGrant, type ConnectionMetadata, type OpenGeniSlackBotDisplayName, type OpenGeniSlackBotConnectionMetadata } from "@opengeni/contracts";
3
3
  import { type Database } from "@opengeni/db";
4
4
  import { type FetchLike } from "@opengeni/network";
5
5
  import { HTTPException } from "hono/http-exception";
@@ -34,12 +34,16 @@ export type DownloadedSlackReactionImage = Readonly<{
34
34
  contentType: "image/png" | "image/jpeg" | "image/webp";
35
35
  bytes: Uint8Array;
36
36
  }>;
37
+ export type ExchangedOpenGeniSlackAuthorization = Readonly<{
38
+ accessToken: string;
39
+ appId: string;
40
+ }>;
37
41
  export declare function exchangeOpenGeniSlackAuthorizationCode(input: {
38
42
  code: string;
39
43
  clientId: string;
40
44
  clientSecret: string;
41
45
  redirectUri: string;
42
- }, fetchImpl?: FetchLike): Promise<string>;
46
+ }, fetchImpl?: FetchLike): Promise<ExchangedOpenGeniSlackAuthorization>;
43
47
  export type SlackBotReceipt = {
44
48
  credentialRole: typeof OPENGENI_SLACK_BOT_CREDENTIAL_ROLE;
45
49
  credentialLabel: typeof OPENGENI_SLACK_BOT_CREDENTIAL_LABEL;
@@ -71,10 +75,69 @@ export type SlackMessageBlock = {
71
75
  };
72
76
  style?: "primary" | "danger";
73
77
  }>;
78
+ } | {
79
+ type: "context";
80
+ block_id?: string;
81
+ elements: Array<{
82
+ type: "mrkdwn" | "plain_text";
83
+ text: string;
84
+ emoji?: boolean;
85
+ }>;
74
86
  } | {
75
87
  type: "divider";
76
88
  };
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";
89
+ export type SlackHomeBlock = {
90
+ type: "header";
91
+ block_id?: string;
92
+ text: {
93
+ type: "plain_text";
94
+ text: string;
95
+ emoji?: boolean;
96
+ };
97
+ } | {
98
+ type: "section";
99
+ block_id?: string;
100
+ text: {
101
+ type: "mrkdwn" | "plain_text";
102
+ text: string;
103
+ emoji?: boolean;
104
+ };
105
+ accessory?: {
106
+ type: "button";
107
+ action_id: string;
108
+ text: {
109
+ type: "plain_text";
110
+ text: string;
111
+ emoji?: boolean;
112
+ };
113
+ url: string;
114
+ };
115
+ } | {
116
+ type: "context";
117
+ block_id?: string;
118
+ elements: Array<{
119
+ type: "mrkdwn" | "plain_text";
120
+ text: string;
121
+ emoji?: boolean;
122
+ }>;
123
+ } | {
124
+ type: "actions";
125
+ block_id: string;
126
+ elements: Array<{
127
+ type: "button";
128
+ action_id: string;
129
+ text: {
130
+ type: "plain_text";
131
+ text: string;
132
+ emoji?: boolean;
133
+ };
134
+ url: string;
135
+ style?: "primary" | "danger";
136
+ }>;
137
+ } | {
138
+ type: "divider";
139
+ };
140
+ type SlackBotOperation = "channels.list" | "search.context" | "channel_history.read" | "thread_replies.read" | "users.list" | "files.list" | "file.info" | "file.content.read" | "home.publish" | "message.post" | "message.update" | "message.delete";
78
141
  type SlackBotContext = {
79
142
  accountId: string;
80
143
  workspaceId: string;
@@ -82,6 +145,7 @@ type SlackBotContext = {
82
145
  sessionId?: string | null;
83
146
  scheduledTaskId?: string | null;
84
147
  };
148
+ type SlackProviderAuthorization = () => Promise<boolean | void>;
85
149
  export type SlackReactionContextCheckpointBinding = {
86
150
  inboxId: string;
87
151
  accountId: string;
@@ -125,6 +189,14 @@ export declare class SlackBotProviderError extends Error {
125
189
  readonly retryAfterMs: number | null;
126
190
  constructor(code: string, retryAfterMs?: number | null);
127
191
  }
192
+ export declare function authorizeSlackSharedImageRead(channel: {
193
+ isArchived: boolean;
194
+ isShared: boolean;
195
+ isExternallyShared: boolean;
196
+ isOrgShared: boolean;
197
+ isPendingExternallyShared: boolean;
198
+ isMpim: boolean;
199
+ }, authorizeSharedRead: (() => Promise<void>) | undefined): Promise<void>;
128
200
  export type SlackBotCredentialVerificationFailureReason = "scope_mismatch" | "identity_mismatch";
129
201
  export declare class SlackBotCredentialVerificationError extends HTTPException {
130
202
  readonly failureReason: SlackBotCredentialVerificationFailureReason;
@@ -132,11 +204,14 @@ export declare class SlackBotCredentialVerificationError extends HTTPException {
132
204
  }
133
205
  /**
134
206
  * Validates a write-only xoxb credential before it can enter encrypted storage.
135
- * Slack does not expose the app's display_information name to this scope set;
136
- * users.info provides the authoritative installed bot display name, while the
137
- * documented manifest fixes the app name itself to the same exact value.
207
+ * The OAuth exchange's app_id is the immutable app authority. Slack bot profile
208
+ * names are mutable presentation data and may lag manifest/App Home changes, so
209
+ * they must not decide whether a credential belongs to this installation.
138
210
  */
139
- export declare function verifyOpenGeniSlackBotCredential(token: string, fetchImpl?: FetchLike, now?: Date): Promise<VerifiedOpenGeniSlackBot>;
211
+ export declare function verifyOpenGeniSlackBotCredential(token: string, expected: Readonly<{
212
+ appId: string;
213
+ displayName: OpenGeniSlackBotDisplayName;
214
+ }>, fetchImpl?: FetchLike, now?: Date): Promise<VerifiedOpenGeniSlackBot>;
140
215
  export declare function resolveSlackBotConnectionForTool(input: {
141
216
  db: Database;
142
217
  grant: AccessGrant;
@@ -154,8 +229,9 @@ export declare class OpenGeniSlackBotClient {
154
229
  private readonly metadata;
155
230
  private readonly context;
156
231
  private readonly fetchImpl;
232
+ private readonly authorizeProviderRequest?;
157
233
  private readonly resolveCredential;
158
- constructor(db: Database, settings: Settings, connection: ConnectionMetadata, metadata: OpenGeniSlackBotConnectionMetadata, context: SlackBotContext, fetchImpl?: FetchLike);
234
+ constructor(db: Database, settings: Settings, connection: ConnectionMetadata, metadata: OpenGeniSlackBotConnectionMetadata, context: SlackBotContext, fetchImpl?: FetchLike, authorizeProviderRequest?: SlackProviderAuthorization | undefined);
159
235
  listChannels(input?: {
160
236
  limit?: number;
161
237
  cursor?: string;
@@ -202,6 +278,20 @@ export declare class OpenGeniSlackBotClient {
202
278
  purpose: string;
203
279
  numMembers: number | null;
204
280
  }>;
281
+ /**
282
+ * Replace one Slack user's private App Home view. `views.publish` is a
283
+ * naturally convergent replace operation: Slack event retries may safely
284
+ * repeat the exact bounded view without creating duplicate provider state.
285
+ */
286
+ publishHomeView(input: {
287
+ userId: string;
288
+ blocks: SlackHomeBlock[];
289
+ hash?: string | null;
290
+ }): Promise<{
291
+ viewId: string;
292
+ } & {
293
+ receipt: SlackBotReceipt;
294
+ }>;
205
295
  slackTaskPolicyFacts(channelId: string, userId: string): Promise<({
206
296
  conversation: {
207
297
  id: string;
@@ -433,9 +523,10 @@ export declare class OpenGeniSlackBotClient {
433
523
  name: string;
434
524
  title: string;
435
525
  }[];
526
+ authorizeSharedRead?: () => Promise<void>;
436
527
  }): Promise<PreparedSlackReactionImage[]>;
437
528
  /** Download and fully validate one previously authorized Slack image. */
438
- downloadReactionImage(input: PreparedSlackReactionImage): Promise<DownloadedSlackReactionImage>;
529
+ downloadReactionImage(input: PreparedSlackReactionImage, authorizeSharedRead?: () => Promise<void>): Promise<DownloadedSlackReactionImage>;
439
530
  listUsers(input?: {
440
531
  limit?: number;
441
532
  cursor?: string;
@@ -452,6 +543,61 @@ export declare class OpenGeniSlackBotClient {
452
543
  } & {
453
544
  receipt: SlackBotReceipt;
454
545
  }>;
546
+ /**
547
+ * Workspace-wide public search through Slack's Real-time Search API
548
+ * (`assistant.search.context`) under the bot identity.
549
+ *
550
+ * The bot never carries private-search authority: `channel_types` is pinned
551
+ * to `public_channel` server-side regardless of caller input, so private
552
+ * channels, DMs, and MPIMs remain reachable only through a member's personal
553
+ * hosted-MCP grant. An install predating the search scopes fails closed with
554
+ * a reinstall hint instead of leaking Slack's `missing_scope` error.
555
+ */
556
+ searchContext(input: {
557
+ query: string;
558
+ contentTypes?: readonly ("messages" | "files" | "channels")[];
559
+ includeBots?: boolean;
560
+ /** UNIX seconds bounds on message timestamps. */
561
+ before?: number;
562
+ after?: number;
563
+ sort?: "score" | "timestamp";
564
+ sortDir?: "asc" | "desc";
565
+ cursor?: string;
566
+ limit?: number;
567
+ }): Promise<{
568
+ messages: {
569
+ channelId: string;
570
+ channelName: string;
571
+ ts: string;
572
+ authorUserId: string;
573
+ authorName: string;
574
+ isAuthorBot: boolean;
575
+ content: string;
576
+ permalink: string | null;
577
+ }[];
578
+ files: {
579
+ id: string;
580
+ title: string;
581
+ filetype: string;
582
+ authorUserId: string;
583
+ authorName: string;
584
+ dateCreated: number | null;
585
+ dateUpdated: number | null;
586
+ content: string;
587
+ permalink: string | null;
588
+ }[];
589
+ channels: {
590
+ name: string;
591
+ topic: string;
592
+ purpose: string;
593
+ creatorUserId: string;
594
+ dateCreated: number | null;
595
+ permalink: string | null;
596
+ }[];
597
+ nextCursor: string | null;
598
+ } & {
599
+ receipt: SlackBotReceipt;
600
+ }>;
455
601
  listFiles(input: {
456
602
  channelId: string;
457
603
  limit?: number;
@@ -641,11 +787,13 @@ export declare function createOpenGeniSlackBotClient(deps: {
641
787
  db: Database;
642
788
  settings: Settings;
643
789
  slackFetch?: typeof fetch;
790
+ authorizeProviderRequest?: SlackProviderAuthorization;
644
791
  }, resolved: Awaited<ReturnType<typeof resolveSlackBotConnectionForTool>>): OpenGeniSlackBotClient;
645
792
  export declare function createOpenGeniSlackBotInteractionClient(deps: {
646
793
  db: Database;
647
794
  settings: Settings;
648
795
  slackFetch?: typeof fetch;
796
+ authorizeProviderRequest?: SlackProviderAuthorization;
649
797
  }, input: {
650
798
  accountId: string;
651
799
  workspaceId: string;
@@ -1,12 +1,12 @@
1
1
  import { type FileResourceRef, type WorkspaceSlackReactionSummonSettings } from "@opengeni/contracts";
2
- import { type SlackInstallationRoute, type SlackInteractionInboxEntry, type SlackInteractionTriggerKind } from "@opengeni/db";
2
+ import { type SlackInstallationRoute, type SlackInteraction, type SlackInteractionInboxEntry, type SlackInteractionTriggerKind } from "@opengeni/db";
3
3
  import { type ApiRouteDeps } from "@opengeni/core";
4
4
  import type { Hono } from "hono";
5
- import { type OpenGeniSlackBotClient } from "./slack-bot.js";
5
+ import { type OpenGeniSlackBotClient, type SlackMessageBlock } from "./slack-bot.js";
6
6
  import { type ImportedSlackReactionImage } from "../slack-reaction-files.js";
7
7
  export declare const SLACK_INTERACTION_MAX_BODY_BYTES: number;
8
8
  export declare const SLACK_SIGNATURE_REPLAY_WINDOW_SECONDS = 300;
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
+ 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", "system.update.pending", "goal.paused"];
10
10
  /**
11
11
  * Slack delivery restrictions are durable session-level authority, not
12
12
  * attacker-adjacent user-message context. Migration 0240 backfills this exact
@@ -19,7 +19,7 @@ export declare const SLACK_SESSION_INSTRUCTIONS: string;
19
19
  * selection at session creation while keeping Slack mutations out of the model
20
20
  * surface; interaction delivery remains owned by the durable delivery pump.
21
21
  */
22
- 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")[];
22
+ 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" | "company_profile_confirm" | "company_profile_propose" | "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" | "goal_wait" | "instruction_policy_propose" | "interaction_discover" | "interaction_request_human" | "knowledge_correct" | "knowledge_propose" | "memory_correct" | "memory_save" | "memory_search" | "preference_propose" | "preference_registry_get" | "preference_registry_summary" | "reddit_accounts_list" | "reddit_mentions_live" | "reddit_post_reply" | "reddit_posts_sync" | "reddit_search_live" | "reddit_thread_fetch" | "remember" | "remember_confirm" | "rig_get" | "rig_list" | "rig_promote" | "rig_propose_change" | "rig_verify" | "run_on" | "sandbox_attach" | "sandbox_file_publish" | "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_human_input_respond" | "session_pause" | "session_resume" | "session_send_message" | "session_steer" | "session_wait" | "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_search" | "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_promote_instruction_policy" | "task_note_promote_knowledge" | "task_note_promote_preference" | "task_note_replace" | "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")[];
23
23
  export type NormalizedSlackInteraction = {
24
24
  providerEventId: string;
25
25
  providerMessageId: string;
@@ -53,12 +53,45 @@ export declare function startSlackInteractionPump(deps: ApiRouteDeps, options?:
53
53
  intervalMs?: number;
54
54
  maxPerTick?: number;
55
55
  }): () => void;
56
+ /**
57
+ * Say where the work went, quietly.
58
+ *
59
+ * The line exists to stop work landing somewhere surprising, so it appears only
60
+ * when the routing decision was a genuine choice: a null label means routing is
61
+ * off, or the person had exactly one workspace anyway, and a constant footer on
62
+ * every message would be noise rather than information.
63
+ *
64
+ * The label is frozen on the interaction rather than looked up here, because a
65
+ * workspace rename between the original post and a reconciliation would make the
66
+ * post ledger's byte comparison raise.
67
+ */
68
+ export declare function withWorkspaceLine(label: string | null, text: string, blocks?: SlackMessageBlock[]): {
69
+ text: string;
70
+ blocks?: SlackMessageBlock[];
71
+ };
72
+ /**
73
+ * The post-ledger seed for one interaction's messages.
74
+ *
75
+ * The ledger binds one operation id to a digest over the rendered bytes, so
76
+ * adding the workspace line under an unchanged id would wedge every interaction
77
+ * with a claimed-but-unposted row. But bumping the id for interactions whose
78
+ * bytes did NOT change is not free either: their ledger rows become unreachable,
79
+ * so a repair or a cross-deploy retry posts a duplicate instead of finding the
80
+ * completed original, and an action handle still points at the old operation.
81
+ *
82
+ * Only a labelled interaction renders different bytes, and the label is written
83
+ * once at insert and never updated, so it is a stable discriminator. Version the
84
+ * id on the label rather than on the release: a labelled interaction can only
85
+ * have been created by an image that already renders the line, and every
86
+ * pre-existing and unlabelled interaction keeps its exact ledger identity.
87
+ */
88
+ export declare function slackPostSeed(interaction: Pick<SlackInteraction, "routedWorkspaceLabel">, seed: string): string;
56
89
  export type SlackInvocationMessageContext = {
57
90
  messages: Awaited<ReturnType<OpenGeniSlackBotClient["threadReplies"]>>["messages"];
58
91
  nextCursor: string | null;
59
92
  kind: "thread" | "channel";
60
93
  };
61
- export declare function slackInvocationTaskText(entry: Pick<SlackInteractionInboxEntry, "slackMessageTs" | "slackUserId" | "text">, context: SlackInvocationMessageContext): string;
94
+ export declare function slackInvocationModelContext(invocationTimestamp: string, context: SlackInvocationMessageContext): string;
62
95
  type SlackReactionMessageContext = Awaited<ReturnType<OpenGeniSlackBotClient["reactionMessageContext"]>>;
63
96
  type PreparedSlackReactionTask = Readonly<{
64
97
  resources: FileResourceRef[];
@@ -69,6 +102,7 @@ type PreparedSlackReactionTask = Readonly<{
69
102
  export declare function slackReactionTaskText(context: SlackReactionMessageContext, prepared?: PreparedSlackReactionTask): string;
70
103
  export declare function slackDeliveryTextsCoalesce(left: string, right: string): boolean;
71
104
  export declare function normalizedBlockActionInteraction(payload: Record<string, unknown>): NormalizedSlackInteraction;
105
+ export declare function isSlackInfoCommand(text: string): boolean;
72
106
  type SlackUserLinkToken = {
73
107
  workspaceId: string;
74
108
  connectionId: string;
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Per-channel and per-DM Slack workspace routing.
3
+ *
4
+ * Routing is decided BEFORE any agent runs, from durable facts only, so it can
5
+ * never be a model judgement. The resolver is pure with respect to the database
6
+ * reads it is handed: it returns a decision, and the caller persists and acts on
7
+ * it.
8
+ *
9
+ * Two rules are load-bearing and easy to break by accident:
10
+ *
11
+ * A mapped thread keeps the workspace it was created in, unconditionally,
12
+ * including after the channel has been re-pointed. Otherwise a live
13
+ * conversation would silently change tenants mid-thread.
14
+ *
15
+ * A subject who lacks access to the routed workspace is NEVER quietly served
16
+ * from another workspace they happen to belong to. Every failure is explicit
17
+ * and creates no session.
18
+ */
19
+ import type { AccessGrant } from "@opengeni/contracts";
20
+ import type { SlackChannelRoute, SlackInteractionInboxEntry, SlackRoutableWorkspace, SlackUserDmRoute } from "@opengeni/db";
21
+ export type SlackRouteTenancy = {
22
+ accountId: string;
23
+ workspaceId: string;
24
+ };
25
+ export type SlackRouteResolution = (SlackRouteTenancy & {
26
+ kind: "resolved";
27
+ label: string | null;
28
+ source: "thread" | "prefix" | "channel" | "dm_route" | "dm_personal" | "sole_candidate" | "installation";
29
+ }) | {
30
+ kind: "ask";
31
+ candidates: readonly SlackRoutableWorkspace[];
32
+ } | {
33
+ kind: "denied";
34
+ reason: "no_access_to_named" | "no_access_to_route" | "no_candidates";
35
+ requested: string | null;
36
+ candidates: readonly SlackRoutableWorkspace[];
37
+ };
38
+ /**
39
+ * A Slack direct message to the bot, by any trigger that can carry one.
40
+ *
41
+ * `isDirectMessageShortcut` is deliberately narrower: it means "a message
42
+ * shortcut invoked inside a DM", which is a private-handoff concern. Routing
43
+ * cares about the broader question of whether this conversation is one human's
44
+ * private channel with the bot, which is also true of an ordinary `dm` event.
45
+ */
46
+ export declare function isSlackDirectMessageConversation(entry: Pick<SlackInteractionInboxEntry, "triggerKind" | "slackChannelId">): boolean;
47
+ /**
48
+ * Split a leading bot mention off the message text.
49
+ *
50
+ * Slack delivers an `app_mention` with the mention still in the text
51
+ * (`<@U123> do the thing`), and OpenGeni stores it verbatim. The workspace
52
+ * prefix is only an override when it is the first thing the person typed, so it
53
+ * is parsed after the mention rather than at byte 0 of the raw text. Everything
54
+ * split off here is put back, so the message the model sees is unchanged apart
55
+ * from the addressing the person used to route it.
56
+ */
57
+ export declare function splitSlackLeadingMention(text: string, botUserId: string | null): {
58
+ lead: string;
59
+ rest: string;
60
+ };
61
+ /**
62
+ * The strict `in <workspace>: ...` override.
63
+ *
64
+ * Parsed only at byte 0, so ordinary prose that happens to contain the word
65
+ * cannot trigger it, and matched case-insensitively against the exact label of a
66
+ * workspace the subject can already start work in. A prefix that names nothing
67
+ * recognizable is NOT a suggestion that falls through: it is a refusal, because
68
+ * silently ignoring an explicit override is how a message lands somewhere the
69
+ * person did not intend.
70
+ */
71
+ export declare function parseSlackWorkspacePrefix(text: string): {
72
+ requested: string;
73
+ remainder: string;
74
+ } | null;
75
+ export type SlackRouteInputs = {
76
+ /** The installation binding's tenancy. Always the fallback, never a silent one. */
77
+ home: SlackRouteTenancy;
78
+ entry: Pick<SlackInteractionInboxEntry, "triggerKind" | "slackChannelId" | "slackUserId" | "text">;
79
+ /**
80
+ * The tenancy of an interaction already mapped to this thread, if any. A
81
+ * mapped thread wins unconditionally.
82
+ */
83
+ threadTenancy: SlackRouteTenancy | null;
84
+ channelRoute: SlackChannelRoute | null;
85
+ dmRoute: SlackUserDmRoute | null;
86
+ /** The subject's own personal workspace in the home organization, if any. */
87
+ personalWorkspaceId: string | null;
88
+ /** Workspaces this subject may actually start work in, ordered stably. */
89
+ candidates: readonly SlackRoutableWorkspace[];
90
+ /** The installation's bot user, so a mention does not hide the prefix. */
91
+ botUserId: string | null;
92
+ /** `OPENGENI_SLACK_WORKSPACE_ROUTING_ENABLED`. */
93
+ routingEnabled: boolean;
94
+ /** Whether the first-use picker exists yet. Until it does, ambiguity keeps home. */
95
+ askEnabled: boolean;
96
+ };
97
+ /**
98
+ * Decide which workspace this Slack message starts work in.
99
+ *
100
+ * First match wins, and the order is deliberate: continuity beats an explicit
101
+ * override beats configuration beats derivation beats asking.
102
+ */
103
+ export declare function resolveSlackWorkspaceRoute(input: SlackRouteInputs): SlackRouteResolution;
104
+ /**
105
+ * The message text the model actually sees.
106
+ *
107
+ * A prefix override is addressing information, not part of the request, so it is
108
+ * stripped exactly once and only when it matched.
109
+ */
110
+ export declare function slackRoutedRequestText(text: string, resolution: SlackRouteResolution, botUserId: string | null): string;
111
+ export type SlackRouteAuthorization = {
112
+ kind: "authorized";
113
+ grant: AccessGrant;
114
+ tenancy: SlackRouteTenancy;
115
+ label: string | null;
116
+ } | {
117
+ kind: "denied";
118
+ reason: "no_access_to_route";
119
+ tenancy: SlackRouteTenancy;
120
+ };
@@ -45,6 +45,11 @@ export type SocialOAuthStartContext = {
45
45
  accountId: string;
46
46
  workspaceId: string;
47
47
  subjectId: string;
48
+ /**
49
+ * False for every principal that cannot own a personal Connection. Resolved
50
+ * by the route from the live authenticated principal, never inferred here.
51
+ */
52
+ personalOwnershipAllowed: boolean;
48
53
  requestUrl: string;
49
54
  payload: SocialOAuthStartRequest;
50
55
  };
@@ -0,0 +1,68 @@
1
+ import type { ApiWebSocketConnection, ApiWebSocketLike, ApiWebSocketUpgradeServer } from "./api-websocket.js";
2
+ export declare const INTERACTION_FRAME_PROXY_PATH = "/v1/interaction/frame-proxy";
3
+ export declare const INTERACTION_FRAME_PROXY_PROTOCOL_PREFIX = "opengeni-frame-proxy.";
4
+ type ProxyGrant = Readonly<{
5
+ version: 1;
6
+ upstreamUrl: string;
7
+ upstreamProtocols: readonly string[];
8
+ responseProtocol: string;
9
+ origin: string | null;
10
+ expiresAt: number;
11
+ }>;
12
+ export type InteractionFrameProxyAttachment = Readonly<{
13
+ url: string;
14
+ protocols: readonly string[];
15
+ }>;
16
+ /** Docker boxes cannot carry browserd's WebSocket subprotocol grant to the
17
+ * viewer. Unsigned OpenSandbox Channel B still uses the lifecycle proxy, so
18
+ * it needs the same hatch. Signed URI-mode ingress keeps native subprotocols;
19
+ * `openSandboxInteractionFrameProxy` is an emergency override only. */
20
+ export declare function placementUsesInteractionFrameProxy(backend: string | null | undefined, options?: {
21
+ openSandboxSignedEndpoints?: boolean;
22
+ openSandboxInteractionFrameProxy?: boolean;
23
+ }): boolean;
24
+ /** Public origin the browser can open. TLS-terminating reverse proxies make
25
+ * `requestUrl` `http://127.0.0.1` / the API container; that would mint `ws://`
26
+ * and Chrome blocks it from an `https://` console. */
27
+ export declare function resolveInteractionFrameProxyRequestUrl(input: {
28
+ requestUrl: string;
29
+ publicBaseUrl?: string | undefined;
30
+ webBaseUrl?: string | undefined;
31
+ forwardedProto?: string | null | undefined;
32
+ forwardedHost?: string | null | undefined;
33
+ }): string;
34
+ export declare function createInteractionFrameProxyAttachment(input: {
35
+ requestUrl: string;
36
+ publicBaseUrl?: string | undefined;
37
+ webBaseUrl?: string | undefined;
38
+ forwardedProto?: string | null | undefined;
39
+ forwardedHost?: string | null | undefined;
40
+ rootSecret: string;
41
+ upstreamUrl: string;
42
+ upstreamProtocols: readonly string[];
43
+ origin: string | null;
44
+ expiresAt: string;
45
+ }): InteractionFrameProxyAttachment;
46
+ export declare class InteractionFrameProxyTransport {
47
+ private readonly rootSecret;
48
+ private readonly clock;
49
+ constructor(rootSecret: string | undefined, clock?: () => number);
50
+ handles(request: Request): boolean;
51
+ upgrade(request: Request, server: ApiWebSocketUpgradeServer): Response | undefined;
52
+ }
53
+ export declare class InteractionFrameProxyConnection implements ApiWebSocketConnection {
54
+ private readonly grant;
55
+ private socket;
56
+ private upstream;
57
+ private upstreamOpen;
58
+ private terminal;
59
+ private queued;
60
+ private queuedBytes;
61
+ constructor(grant: ProxyGrant);
62
+ attach(socket: ApiWebSocketLike): void;
63
+ receive(message: string | Uint8Array | ArrayBuffer): void;
64
+ transportClosed(): void;
65
+ private fail;
66
+ private clear;
67
+ }
68
+ export {};
@@ -0,0 +1,26 @@
1
+ import { type CompanyBrainGovernedWriteAttempt } from "@opengeni/contracts";
2
+ import { createCompanyBrainLearningPolicyRouter } from "@opengeni/core";
3
+ import type { Database } from "@opengeni/db";
4
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ type JsonResult = (value: unknown) => {
6
+ content: {
7
+ type: "text";
8
+ text: string;
9
+ }[];
10
+ };
11
+ export type RegisterCompanyBrainGovernedWriteToolsInput = {
12
+ server: McpServer;
13
+ db: Database;
14
+ attempt: CompanyBrainGovernedWriteAttempt;
15
+ authorize: () => Promise<void>;
16
+ json: JsonResult;
17
+ router?: Pick<ReturnType<typeof createCompanyBrainLearningPolicyRouter>, "write">;
18
+ };
19
+ /**
20
+ * Register explicit proposal-only Company Brain tools. The signed host attempt
21
+ * owns tenant/session authority and the exact evidence id owns the learning
22
+ * policy source override. Tool input cannot select scope, active authority, or
23
+ * another policy source.
24
+ */
25
+ export declare function registerCompanyBrainGovernedWriteTools(input: RegisterCompanyBrainGovernedWriteToolsInput): void;
26
+ export {};
@@ -0,0 +1,44 @@
1
+ import { type CompanyProfileAgentAttempt, type CompanyProfileEntry } from "@opengeni/contracts";
2
+ import { createCompanyProfileAgentAdminRouter } from "@opengeni/core";
3
+ import type { Database } from "@opengeni/db";
4
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import * as z from "zod/v4";
6
+ type JsonResult = (value: unknown) => {
7
+ content: {
8
+ type: "text";
9
+ text: string;
10
+ }[];
11
+ };
12
+ export type RegisterCompanyProfileAgentAdminToolsInput = {
13
+ server: McpServer;
14
+ db: Database;
15
+ attempt: CompanyProfileAgentAttempt;
16
+ authorize: () => Promise<void>;
17
+ json: JsonResult;
18
+ router?: Pick<ReturnType<typeof createCompanyProfileAgentAdminRouter>, "propose" | "confirm">;
19
+ };
20
+ declare const entry: z.ZodObject<{
21
+ key: z.ZodOptional<z.ZodString>;
22
+ content: z.ZodString;
23
+ }, z.core.$strip>;
24
+ type EntryInput = z.infer<typeof entry>;
25
+ /**
26
+ * Derive a stable key from entry content: the first few words, normalized into
27
+ * the company-profile key alphabet and bounded to the stable-key length.
28
+ */
29
+ export declare function deriveCompanyProfileStableKey(content: string): string;
30
+ /**
31
+ * Resolve explicit or derived keys for one list and de-duplicate by suffixing
32
+ * `-2`, `-3`, ... so the profile passes the unique-key contract.
33
+ */
34
+ export declare function resolveCompanyProfileEntries(input: readonly EntryInput[]): CompanyProfileEntry[];
35
+ /**
36
+ * Register the explicit owner-confirmed organization profile path. This is
37
+ * administration, not derived learning: workspace learning mode is never
38
+ * consulted, the initiating human must be the organization's active owner (the
39
+ * same authority as the manual `account:admin` route), and the proposal cannot
40
+ * become active without the exact bound human-input response returned by the
41
+ * first call.
42
+ */
43
+ export declare function registerCompanyProfileAgentAdminTools(input: RegisterCompanyProfileAgentAdminToolsInput): void;
44
+ export {};
@@ -3,6 +3,7 @@ import { type Database } from "@opengeni/db";
3
3
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
4
  export declare function buildDocumentsMcpServer(db: Database, accountId: string, workspaceId: string, documentServices: DocumentServices, options: {
5
5
  createdBySessionId?: string | undefined;
6
+ attemptId?: string | undefined;
6
7
  /** Immutable human subject whose agent is making this retrieval request. */
7
8
  initiatingSubjectId: string;
8
9
  }): McpServer;
@@ -0,0 +1,28 @@
1
+ import { type CompanyBrainGovernedWriteAttempt } from "@opengeni/contracts";
2
+ import { createRememberRouter } from "@opengeni/core";
3
+ import type { Database } from "@opengeni/db";
4
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ type JsonResult = (value: unknown) => {
6
+ content: {
7
+ type: "text";
8
+ text: string;
9
+ }[];
10
+ };
11
+ export type RegisterRememberToolsInput = {
12
+ server: McpServer;
13
+ db: Database;
14
+ attempt: CompanyBrainGovernedWriteAttempt;
15
+ authorize: () => Promise<void>;
16
+ json: JsonResult;
17
+ router?: Pick<ReturnType<typeof createRememberRouter>, "remember" | "confirm">;
18
+ };
19
+ /**
20
+ * Explicit user-directed remember. Content becomes exact task-note evidence,
21
+ * promotion runs through the frozen workspace learning policy, and activation
22
+ * is either automatic (preference under Automatic mode) or requires exactly one
23
+ * bound human confirmation through the built-in `request_human_input` tool.
24
+ * Tool input cannot select scope beyond the workspace, active authority, or
25
+ * another learning-policy source.
26
+ */
27
+ export declare function registerRememberTools(input: RegisterRememberToolsInput): void;
28
+ export {};