@opengeni/core 3.0.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/README.md +1 -1
  2. package/dist/application/connect-operation.d.ts +3 -0
  3. package/dist/application/sandbox-recovery.d.ts +49 -0
  4. package/dist/{chunk-H7X52RI2.js → chunk-TFHSE7XR.js} +13 -2
  5. package/dist/chunk-TFHSE7XR.js.map +1 -0
  6. package/dist/dependencies.d.ts +1 -1
  7. package/dist/domain/capabilities.d.ts +2 -2
  8. package/dist/domain/connection-account-selection-error.d.ts +6 -0
  9. package/dist/domain/connector-tool-permissions.d.ts +27 -0
  10. package/dist/domain/editable-artifacts/agent-application.d.ts +8 -0
  11. package/dist/domain/environments.d.ts +3 -7
  12. package/dist/domain/insights-timing.d.ts +16 -0
  13. package/dist/domain/insights.d.ts +4 -1
  14. package/dist/domain/knowledge-files.d.ts +1 -1
  15. package/dist/domain/knowledge-preparation.d.ts +9 -0
  16. package/dist/domain/knowledge-preparation.test.d.ts +1 -0
  17. package/dist/domain/mcp-account-bindings.d.ts +19 -0
  18. package/dist/domain/native-mcp-connection-admission.d.ts +3 -0
  19. package/dist/domain/organization-integration-catalog.d.ts +15 -0
  20. package/dist/domain/personal-connection-delegations.d.ts +19 -10
  21. package/dist/domain/pr-review.d.ts +56 -4
  22. package/dist/domain/scheduled-tasks.d.ts +8 -5
  23. package/dist/domain/session-file-access.d.ts +4 -0
  24. package/dist/domain/sessions.d.ts +8 -6
  25. package/dist/domain/skills.d.ts +29 -1
  26. package/dist/editable-artifacts.js +1 -1
  27. package/dist/index.d.ts +7 -5
  28. package/dist/index.js +4868 -4803
  29. package/dist/index.js.map +1 -1
  30. package/dist/sandbox/routing.d.ts +2 -1
  31. package/dist/sandbox/runtime-settings.d.ts +1 -15
  32. package/package.json +11 -19
  33. package/src/application/composer-submit.ts +2 -1
  34. package/src/application/connect-operation.ts +32 -3
  35. package/src/application/sandbox-recovery.ts +55 -0
  36. package/src/application/user-resource-grants.ts +1 -16
  37. package/src/dependencies.ts +5 -1
  38. package/src/domain/capabilities.ts +169 -122
  39. package/src/domain/connection-account-selection-error.ts +9 -0
  40. package/src/domain/connector-tool-permissions.ts +305 -0
  41. package/src/domain/editable-artifacts/agent-application.ts +31 -2
  42. package/src/domain/environments.ts +4 -9
  43. package/src/domain/file-owner.ts +16 -1
  44. package/src/domain/insights-timing.ts +95 -0
  45. package/src/domain/insights.ts +59 -35
  46. package/src/domain/knowledge-files.ts +10 -3
  47. package/src/domain/knowledge-messages.ts +1 -0
  48. package/src/domain/knowledge-preparation.test.ts +251 -0
  49. package/src/domain/knowledge-preparation.ts +126 -0
  50. package/src/domain/mcp-account-bindings.ts +152 -0
  51. package/src/domain/native-mcp-connection-admission.ts +14 -0
  52. package/src/domain/organization-integration-catalog.ts +83 -0
  53. package/src/domain/personal-connection-delegations.ts +226 -177
  54. package/src/domain/pr-review.ts +22 -6
  55. package/src/domain/resources.ts +9 -2
  56. package/src/domain/scheduled-tasks.ts +200 -155
  57. package/src/domain/session-file-access.ts +47 -0
  58. package/src/domain/session-tool-policy.ts +12 -4
  59. package/src/domain/sessions.ts +390 -261
  60. package/src/domain/skills.ts +9 -0
  61. package/src/index.ts +10 -6
  62. package/src/rigs/index.ts +17 -17
  63. package/src/sandbox/routing.ts +18 -7
  64. package/src/sandbox/runtime-settings.ts +7 -91
  65. package/dist/application/host-mcp-owner.d.ts +0 -6
  66. package/dist/application/host-mcp-resolvers.d.ts +0 -13
  67. package/dist/chunk-5WZYFL45.js +0 -266
  68. package/dist/chunk-5WZYFL45.js.map +0 -1
  69. package/dist/chunk-H7X52RI2.js.map +0 -1
  70. package/dist/domain/connection-authority.d.ts +0 -97
  71. package/dist/domain/connection-authority.js +0 -169
  72. package/dist/domain/connection-authority.js.map +0 -1
  73. package/dist/domain/host-mcp-authority-source-admission.d.ts +0 -10
  74. package/dist/domain/host-mcp-task-admission.d.ts +0 -18
  75. package/dist/domain/packs.d.ts +0 -59
  76. package/dist/domain/product-integration-pack.d.ts +0 -44
  77. package/dist/domain/product-integration-skill.gen.d.ts +0 -5
  78. package/dist/remote-mcp-credentials.d.ts +0 -23
  79. package/dist/remote-mcp-credentials.js +0 -11
  80. package/dist/remote-mcp-credentials.js.map +0 -1
  81. package/src/application/host-mcp-owner.ts +0 -41
  82. package/src/application/host-mcp-resolvers.ts +0 -84
  83. package/src/domain/connection-authority.ts +0 -329
  84. package/src/domain/host-mcp-authority-source-admission.ts +0 -25
  85. package/src/domain/host-mcp-task-admission.ts +0 -121
  86. package/src/domain/packs.ts +0 -699
  87. package/src/domain/product-integration-pack.ts +0 -42
  88. package/src/domain/product-integration-skill.gen.ts +0 -52
  89. package/src/remote-mcp-credentials.ts +0 -361
@@ -1,329 +0,0 @@
1
- import type {
2
- ConnectionKind,
3
- ConnectionStatus,
4
- SessionTenancyVisibility,
5
- UserResourceDelegation,
6
- UserResourceGrantMode,
7
- UserResourceGrantStatus,
8
- } from "@opengeni/contracts";
9
- import {
10
- ConnectionAuthorityEnvelope,
11
- ConnectionUseAttribution,
12
- ConnectionUseAuthoritySnapshot,
13
- type ConnectionUseAuthorizationResult,
14
- type ConnectionAuthoritySelectionSource,
15
- type ConnectionUseDenialReason,
16
- type ConnectionUseSelectionSource,
17
- } from "@opengeni/contracts/connection-authority";
18
-
19
- export type ConnectionAuthorityCandidate = {
20
- id: string;
21
- organizationId: string;
22
- workspaceId: string;
23
- generation: number;
24
- status: ConnectionStatus;
25
- providerDomain: string;
26
- kind: ConnectionKind;
27
- subjectId: string | null;
28
- ownerOrganizationMembershipId: string | null;
29
- };
30
-
31
- export type UserConnectionAuthorityCandidate = {
32
- id: string;
33
- organizationId: string;
34
- resourceKind: "connection";
35
- resourceId: string;
36
- originWorkspaceId: string;
37
- ownerSubjectId: string;
38
- ownerOrganizationMembershipId: string;
39
- ownerMembershipAuthorizationRevision: number;
40
- generation: number;
41
- status: "active" | "retained" | "revoked";
42
- };
43
-
44
- export class ConnectionAuthorityInvariantError extends Error {
45
- constructor(readonly code: string) {
46
- super(`connection authority invariant failed: ${code}`);
47
- this.name = "ConnectionAuthorityInvariantError";
48
- }
49
- }
50
-
51
- export function captureConnectionUseAuthority(input: {
52
- organizationId: string;
53
- targetWorkspaceId: string;
54
- targetSessionId: string;
55
- targetSessionVisibility: SessionTenancyVisibility;
56
- targetSessionAuthorityEpoch: number;
57
- acceptedWork:
58
- | { kind: "turn"; turnId: string }
59
- | {
60
- kind: "scheduled_task";
61
- taskId: string;
62
- taskAuthorityRevision: number;
63
- runId: string;
64
- };
65
- connection: ConnectionAuthorityCandidate;
66
- authority?: unknown;
67
- authorityWasOmitted?: boolean;
68
- userAuthority?: UserConnectionAuthorityCandidate | null;
69
- selectionSources: ConnectionUseSelectionSource[];
70
- }): ConnectionUseAuthoritySnapshot {
71
- const authority = ConnectionAuthorityEnvelope.parse(input.authority ?? {});
72
- const connection = input.connection;
73
- if (connection.organizationId !== input.organizationId) {
74
- throw new ConnectionAuthorityInvariantError("tenant_mismatch");
75
- }
76
- if (connection.status !== "active") {
77
- throw new ConnectionAuthorityInvariantError("connection_status_inactive");
78
- }
79
-
80
- let authoritySource: ConnectionAuthoritySelectionSource;
81
- let userDelegation: UserResourceDelegation | null = null;
82
- if (authority.scope === "workspace") {
83
- if (connection.subjectId !== null || connection.ownerOrganizationMembershipId !== null) {
84
- throw new ConnectionAuthorityInvariantError("workspace_borrowed_personal_connection");
85
- }
86
- if (connection.workspaceId !== input.targetWorkspaceId) {
87
- throw new ConnectionAuthorityInvariantError("workspace_connection_scope_mismatch");
88
- }
89
- authoritySource = input.authorityWasOmitted
90
- ? "legacy_workspace_omission"
91
- : "explicit_workspace";
92
- } else {
93
- const delegation = authority.userDelegation;
94
- const resourceAuthority = input.userAuthority;
95
- if (!delegation || !resourceAuthority) {
96
- throw new ConnectionAuthorityInvariantError("user_authority_missing");
97
- }
98
- if (!connection.subjectId || !connection.ownerOrganizationMembershipId) {
99
- throw new ConnectionAuthorityInvariantError("personal_owner_missing");
100
- }
101
- if (
102
- resourceAuthority.id !== delegation.authorityId ||
103
- resourceAuthority.organizationId !== input.organizationId ||
104
- resourceAuthority.resourceKind !== "connection" ||
105
- resourceAuthority.resourceId !== connection.id ||
106
- resourceAuthority.originWorkspaceId !== connection.workspaceId ||
107
- resourceAuthority.ownerSubjectId !== connection.subjectId ||
108
- resourceAuthority.ownerOrganizationMembershipId !==
109
- connection.ownerOrganizationMembershipId ||
110
- resourceAuthority.generation !== delegation.authorityGeneration ||
111
- resourceAuthority.status !== "active"
112
- ) {
113
- throw new ConnectionAuthorityInvariantError("user_authority_mismatch");
114
- }
115
- userDelegation = delegation;
116
- authoritySource = "user_delegation";
117
- }
118
-
119
- return ConnectionUseAuthoritySnapshot.parse({
120
- organizationId: input.organizationId,
121
- originWorkspaceId: connection.workspaceId,
122
- targetWorkspaceId: input.targetWorkspaceId,
123
- targetSessionId: input.targetSessionId,
124
- targetSessionVisibility: input.targetSessionVisibility,
125
- targetSessionAuthorityEpoch: input.targetSessionAuthorityEpoch,
126
- acceptedWork: input.acceptedWork,
127
- connectionId: connection.id,
128
- connectionGeneration: connection.generation,
129
- connectionStatus: "active",
130
- providerDomain: connection.providerDomain.toLowerCase(),
131
- connectionKind: connection.kind,
132
- scope: authority.scope,
133
- ownerSubjectId: connection.subjectId,
134
- ownerOrganizationMembershipId: connection.ownerOrganizationMembershipId,
135
- ownerMembershipAuthorizationRevision:
136
- authority.scope === "user" ? input.userAuthority!.ownerMembershipAuthorizationRevision : null,
137
- authoritySource,
138
- selectionSources: input.selectionSources,
139
- userDelegation,
140
- });
141
- }
142
-
143
- export type LiveConnectionUseState = {
144
- organizationId: string;
145
- targetWorkspaceId: string;
146
- targetWorkspaceAccessActive: boolean;
147
- session: {
148
- id: string;
149
- organizationId: string;
150
- workspaceId: string;
151
- visibility: SessionTenancyVisibility;
152
- authorityEpoch: number;
153
- active: boolean;
154
- };
155
- connection: ConnectionAuthorityCandidate | null;
156
- ownerMembership: {
157
- id: string;
158
- organizationId: string;
159
- subjectId: string;
160
- status: "provisioning" | "active" | "suspended" | "revoked";
161
- authorizationRevision: number;
162
- } | null;
163
- userAuthority: UserConnectionAuthorityCandidate | null;
164
- grant: {
165
- id: string;
166
- authorityId: string;
167
- organizationId: string;
168
- workspaceId: string;
169
- sessionId: string | null;
170
- action: string;
171
- mode: UserResourceGrantMode;
172
- context: SessionTenancyVisibility;
173
- authorityEpoch: number | null;
174
- generation: number;
175
- status: UserResourceGrantStatus;
176
- expiresAt: string | null;
177
- consumed: boolean;
178
- } | null;
179
- };
180
-
181
- function denied(reason: ConnectionUseDenialReason): ConnectionUseAuthorizationResult {
182
- return { status: "denied", reason };
183
- }
184
-
185
- /**
186
- * Revalidates every mutable fence immediately before provider use. Callers must
187
- * resolve the live state in one DB authority boundary; this pure function does
188
- * not cache, refresh, decrypt, or invoke a provider.
189
- */
190
- export function revalidateConnectionUseAuthority(input: {
191
- snapshot: ConnectionUseAuthoritySnapshot;
192
- live: LiveConnectionUseState;
193
- now?: Date;
194
- }): ConnectionUseAuthorizationResult {
195
- const snapshot = ConnectionUseAuthoritySnapshot.parse(input.snapshot);
196
- const live = input.live;
197
- const now = input.now ?? new Date();
198
- if (
199
- live.organizationId !== snapshot.organizationId ||
200
- live.targetWorkspaceId !== snapshot.targetWorkspaceId
201
- ) {
202
- return denied("tenant_mismatch");
203
- }
204
- if (!live.targetWorkspaceAccessActive) return denied("workspace_access_inactive");
205
- if (!live.session.active) return denied("session_inactive");
206
- if (
207
- live.session.id !== snapshot.targetSessionId ||
208
- live.session.organizationId !== snapshot.organizationId ||
209
- live.session.workspaceId !== snapshot.targetWorkspaceId
210
- ) {
211
- return denied("session_identity_changed");
212
- }
213
- if (live.session.visibility !== snapshot.targetSessionVisibility) {
214
- return denied("session_visibility_changed");
215
- }
216
- if (live.session.authorityEpoch !== snapshot.targetSessionAuthorityEpoch) {
217
- return denied("session_authority_epoch_changed");
218
- }
219
- const connection = live.connection;
220
- if (!connection) return denied("connection_missing");
221
- if (
222
- connection.id !== snapshot.connectionId ||
223
- connection.organizationId !== snapshot.organizationId ||
224
- connection.workspaceId !== snapshot.originWorkspaceId ||
225
- connection.providerDomain.toLowerCase() !== snapshot.providerDomain ||
226
- connection.kind !== snapshot.connectionKind
227
- ) {
228
- return denied("connection_identity_changed");
229
- }
230
- if (connection.generation !== snapshot.connectionGeneration) {
231
- return denied("connection_generation_changed");
232
- }
233
- if (connection.status !== "active") return denied("connection_status_inactive");
234
- if (
235
- connection.subjectId !== snapshot.ownerSubjectId ||
236
- connection.ownerOrganizationMembershipId !== snapshot.ownerOrganizationMembershipId
237
- ) {
238
- return denied("connection_owner_changed");
239
- }
240
-
241
- if (snapshot.scope === "workspace") {
242
- if (connection.subjectId !== null || connection.workspaceId !== snapshot.targetWorkspaceId) {
243
- return denied("connection_owner_changed");
244
- }
245
- return {
246
- status: "authorized",
247
- attribution: ConnectionUseAttribution.parse({
248
- organizationId: snapshot.organizationId,
249
- workspaceId: snapshot.targetWorkspaceId,
250
- sessionId: snapshot.targetSessionId,
251
- connectionId: snapshot.connectionId,
252
- connectionGeneration: snapshot.connectionGeneration,
253
- scope: "workspace",
254
- ownerSubjectId: null,
255
- authorityId: null,
256
- grantId: null,
257
- }),
258
- };
259
- }
260
-
261
- const delegation = snapshot.userDelegation!;
262
- const membership = live.ownerMembership;
263
- if (
264
- !membership ||
265
- membership.status !== "active" ||
266
- membership.id !== snapshot.ownerOrganizationMembershipId ||
267
- membership.organizationId !== snapshot.organizationId ||
268
- membership.subjectId !== snapshot.ownerSubjectId ||
269
- membership.authorizationRevision !== snapshot.ownerMembershipAuthorizationRevision
270
- ) {
271
- return denied("owner_membership_inactive");
272
- }
273
- const authority = live.userAuthority;
274
- if (!authority) return denied("authority_missing");
275
- if (
276
- authority.id !== delegation.authorityId ||
277
- authority.organizationId !== snapshot.organizationId ||
278
- authority.resourceKind !== "connection" ||
279
- authority.resourceId !== snapshot.connectionId ||
280
- authority.originWorkspaceId !== snapshot.originWorkspaceId ||
281
- authority.ownerSubjectId !== snapshot.ownerSubjectId ||
282
- authority.ownerOrganizationMembershipId !== snapshot.ownerOrganizationMembershipId
283
- ) {
284
- return denied("authority_identity_changed");
285
- }
286
- if (authority.generation !== delegation.authorityGeneration) {
287
- return denied("authority_generation_changed");
288
- }
289
- if (authority.status !== "active") return denied("authority_status_inactive");
290
-
291
- const grant = live.grant;
292
- if (!grant) return denied("grant_missing");
293
- if (
294
- grant.id !== delegation.grantId ||
295
- grant.authorityId !== delegation.authorityId ||
296
- grant.organizationId !== snapshot.organizationId ||
297
- grant.workspaceId !== snapshot.targetWorkspaceId ||
298
- grant.sessionId !== delegation.sessionId ||
299
- grant.action !== "connection.use" ||
300
- grant.mode !== delegation.mode ||
301
- grant.context !== snapshot.targetSessionVisibility ||
302
- grant.authorityEpoch !== delegation.authorityEpoch
303
- ) {
304
- return denied("grant_identity_changed");
305
- }
306
- if (grant.generation !== delegation.grantGeneration) {
307
- return denied("grant_generation_changed");
308
- }
309
- if (grant.status !== "active") return denied("grant_status_inactive");
310
- if (grant.expiresAt !== null && Date.parse(grant.expiresAt) <= now.getTime()) {
311
- return denied("grant_expired");
312
- }
313
- if (grant.mode === "once" && grant.consumed) return denied("grant_already_consumed");
314
-
315
- return {
316
- status: "authorized",
317
- attribution: ConnectionUseAttribution.parse({
318
- organizationId: snapshot.organizationId,
319
- workspaceId: snapshot.targetWorkspaceId,
320
- sessionId: snapshot.targetSessionId,
321
- connectionId: snapshot.connectionId,
322
- connectionGeneration: snapshot.connectionGeneration,
323
- scope: "user",
324
- ownerSubjectId: snapshot.ownerSubjectId,
325
- authorityId: delegation.authorityId,
326
- grantId: delegation.grantId,
327
- }),
328
- };
329
- }
@@ -1,25 +0,0 @@
1
- import type { Settings } from "@opengeni/config";
2
- import type { McpServerConnectionRef } from "@opengeni/contracts";
3
- import { HTTPException } from "hono/http-exception";
4
-
5
- /**
6
- * Explicit host-owned MCP refs change which credential authority executes an
7
- * opaque connection id. Admit new external refs only after the operator has
8
- * completed the two-phase fleet rollout. Readers and inheritance remain
9
- * tolerant regardless of this switch, and markerless legacy refs retain their
10
- * bounded non-UUID compatibility path.
11
- */
12
- export function assertHostMcpAuthoritySourceAdmissionEnabled(
13
- settings: Pick<Settings, "hostMcpAuthoritySourceAdmissionEnabled">,
14
- connectionRef: McpServerConnectionRef | null | undefined,
15
- ): void {
16
- if (
17
- connectionRef?.authoritySource === "host" &&
18
- !settings.hostMcpAuthoritySourceAdmissionEnabled
19
- ) {
20
- throw new HTTPException(422, {
21
- message:
22
- "new host-owned MCP connection refs are not admitted; upgrade the complete API/worker/web fleet, then set OPENGENI_HOST_MCP_AUTHORITY_SOURCE_ADMISSION_ENABLED=true",
23
- });
24
- }
25
- }
@@ -1,121 +0,0 @@
1
- import { HTTPException } from "hono/http-exception";
2
- import type { Settings } from "@opengeni/config";
3
- import type { ToolRef, ScheduledTask, AccessGrant } from "@opengeni/contracts";
4
- import {
5
- hostMcpBindingMatchesSelection,
6
- HostMcpCreateSelections,
7
- } from "@opengeni/contracts/host-mcp-bindings";
8
- import {
9
- captureHostMcpTaskAuthorities,
10
- getHostMcpBinding,
11
- getHostMcpDelegation,
12
- HostMcpDelegationAuthorityError,
13
- inheritHostMcpTaskAuthoritiesFromAttempt,
14
- type Database,
15
- } from "@opengeni/db";
16
- import { hasPermission, type AccessGrantAuthorization } from "../access";
17
- import { prepareHostMcpOwnerAuthorization } from "../application/host-mcp-owner";
18
- import { assertHostMcpAuthoritySourceAdmissionEnabled } from "./host-mcp-authority-source-admission";
19
-
20
- /** Internal closure, not a caller-provided callback or durable key dependency. */
21
- export function prepareHostMcpTaskAdmission(input: {
22
- settings: Settings;
23
- tools: ToolRef[];
24
- grant: AccessGrant;
25
- authorization?: AccessGrantAuthorization;
26
- selections: unknown;
27
- }): (tx: Database, task: ScheduledTask) => Promise<void> {
28
- const selections = HostMcpCreateSelections.parse(input.selections);
29
- if (
30
- !input.authorization ||
31
- input.authorization.grant.accountId !== input.grant.accountId ||
32
- input.authorization.grant.subjectId !== input.grant.subjectId ||
33
- input.authorization?.grant.workspaceId !== input.grant.workspaceId ||
34
- input.grant.metadata?.["sessionId"] ||
35
- !hasPermission(input.authorization?.grant.permissions ?? [], "connections:read") ||
36
- !hasPermission(input.grant.permissions, "connections:read")
37
- )
38
- throw new HTTPException(403, {
39
- message: "Host task selection requires a verified owner",
40
- });
41
- const reauthorize = prepareHostMcpOwnerAuthorization(
42
- input.authorization,
43
- input.grant.workspaceId,
44
- "connections:read",
45
- );
46
- const prepared = selections.map((selection) => {
47
- const server = input.settings.mcpServers.find(
48
- (candidate) => candidate.id === selection.serverId,
49
- );
50
- if (
51
- !server?.url ||
52
- server.connectionRef?.authoritySource !== "host" ||
53
- !server.connectionRef.hostBinding ||
54
- !input.tools.some((tool) => tool.kind === "mcp" && tool.id === selection.serverId)
55
- )
56
- throw new HTTPException(422, {
57
- message: "Host task selection must match a selected configured server",
58
- });
59
- assertHostMcpAuthoritySourceAdmissionEnabled(input.settings, server.connectionRef);
60
- return {
61
- delegationId: selection.delegationId,
62
- generation: selection.generation,
63
- configured: structuredClone({
64
- serverId: selection.serverId,
65
- destinationUrl: server.url,
66
- connectionRef: server.connectionRef,
67
- }),
68
- };
69
- });
70
- return async (tx, task) => {
71
- const owner = await reauthorize(tx);
72
- try {
73
- const selected = [];
74
- for (const selection of prepared) {
75
- const delegation = await getHostMcpDelegation(tx, owner, selection.delegationId);
76
- const binding = delegation
77
- ? await getHostMcpBinding(tx, owner, delegation.bindingId)
78
- : null;
79
- if (!binding || !hostMcpBindingMatchesSelection(binding, selection.configured))
80
- throw new HostMcpDelegationAuthorityError("Host task selection changed");
81
- selected.push({
82
- delegationId: selection.delegationId,
83
- generation: selection.generation,
84
- bindingId: binding.id,
85
- bindingGeneration: binding.generation,
86
- definition: binding.definition,
87
- });
88
- }
89
- if (selected.length) await captureHostMcpTaskAuthorities(tx, owner, task, selected);
90
- } catch (error) {
91
- if (error instanceof HostMcpDelegationAuthorityError)
92
- throw new HTTPException(403, { message: error.message });
93
- throw error;
94
- }
95
- };
96
- }
97
-
98
- export function prepareInheritedHostMcpTaskAdmission(
99
- settings: Settings,
100
- tools: ToolRef[],
101
- source: { sessionId: string; turnId: string; attemptId: string; executionGeneration: number },
102
- ): (tx: Database, task: ScheduledTask) => Promise<void> {
103
- const configured = settings.mcpServers.flatMap((server) => {
104
- if (
105
- !tools.some((tool) => tool.kind === "mcp" && tool.id === server.id) ||
106
- server.connectionRef?.authoritySource !== "host" ||
107
- !server.connectionRef.hostBinding ||
108
- !server.url
109
- )
110
- return [];
111
- assertHostMcpAuthoritySourceAdmissionEnabled(settings, server.connectionRef);
112
- return [
113
- structuredClone({
114
- serverId: server.id,
115
- destinationUrl: server.url,
116
- connectionRef: server.connectionRef,
117
- }),
118
- ];
119
- });
120
- return (tx, task) => inheritHostMcpTaskAuthoritiesFromAttempt(tx, task, source, configured);
121
- }