@opengeni/core 0.16.2 → 0.17.1

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.
@@ -0,0 +1,48 @@
1
+ import type { McpServerConfig, Settings } from "@opengeni/config";
2
+ import type { AccessGrant, ConnectionMetadata, McpPersonalConnectionDelegation, SessionTurn, ToolRef } from "@opengeni/contracts";
3
+ import { type Database, type ResolveConnectionCredentialInput, type ResolveConnectionCredentialResult } from "@opengeni/db";
4
+ export type PersonalConnectionDelegationSource = {
5
+ kind: "subject";
6
+ subjectId: string;
7
+ } | {
8
+ kind: "turn";
9
+ sessionId: string;
10
+ turnId: string;
11
+ } | {
12
+ kind: "none";
13
+ };
14
+ export declare function directPersonalConnectionSubjectId(turn: Pick<SessionTurn, "source" | "initiator" | "initiatorContext">): string | undefined;
15
+ export declare function personalConnectionDelegationSourceForGrant(grant: AccessGrant): PersonalConnectionDelegationSource;
16
+ export declare function selectedPersonalConnectionServers(settings: Pick<Settings, "mcpServers">, tools: ToolRef[]): McpServerConfig[];
17
+ export declare function personalConnectionDelegationsFromVisibleConnections(input: {
18
+ servers: McpServerConfig[];
19
+ subjectId: string;
20
+ connections: ConnectionMetadata[];
21
+ }): McpPersonalConnectionDelegation[];
22
+ export declare function personalConnectionDelegationsFromParent(input: {
23
+ servers: McpServerConfig[];
24
+ parentDelegations: McpPersonalConnectionDelegation[];
25
+ }): McpPersonalConnectionDelegation[];
26
+ export declare function personalConnectionDelegationsEqual(left: McpPersonalConnectionDelegation[], right: McpPersonalConnectionDelegation[]): boolean;
27
+ export declare function personalConnectionDelegationForServer(delegations: McpPersonalConnectionDelegation[], server: Pick<McpServerConfig, "id" | "connectionRef">): McpPersonalConnectionDelegation | null;
28
+ type ConnectionCredentialResolver = (request: ResolveConnectionCredentialInput) => Promise<ResolveConnectionCredentialResult>;
29
+ /**
30
+ * Resolves subject-owned MCP credentials only through the exact authority
31
+ * frozen on the causal turn. A direct human subject, worker Toolspace caller,
32
+ * retry, or recovery can identify the caller, but none may widen or replace
33
+ * the persisted connection UUID.
34
+ */
35
+ export declare function withFrozenPersonalConnectionDelegations(input: {
36
+ resolveCredential: ConnectionCredentialResolver;
37
+ settings: Pick<Settings, "mcpServers">;
38
+ personalConnectionDelegations: McpPersonalConnectionDelegation[];
39
+ ownerHasWorkspaceMembership: (subjectId: string) => Promise<boolean>;
40
+ }): ConnectionCredentialResolver;
41
+ export declare function freezePersonalConnectionDelegations(input: {
42
+ db: Database;
43
+ workspaceId: string;
44
+ settings: Pick<Settings, "mcpServers">;
45
+ tools: ToolRef[];
46
+ source: PersonalConnectionDelegationSource;
47
+ }): Promise<McpPersonalConnectionDelegation[]>;
48
+ export {};
@@ -1,5 +1,5 @@
1
1
  import type { Settings } from "@opengeni/config";
2
- import type { AccessGrant, ScheduledTask, CreateScheduledTaskRequest as CreateScheduledTaskPayload, UpdateScheduledTaskRequest as UpdateScheduledTaskPayload } from "@opengeni/contracts";
2
+ import type { AccessGrant, McpPersonalConnectionDelegation, ScheduledTask, CreateScheduledTaskRequest as CreateScheduledTaskPayload, UpdateScheduledTaskRequest as UpdateScheduledTaskPayload } from "@opengeni/contracts";
3
3
  import { type Database, type UpdateScheduledTaskInput } from "@opengeni/db";
4
4
  import type { SessionWorkflowClient } from "../dependencies";
5
5
  import type { ObjectStorageDependency } from "../dependencies";
@@ -32,7 +32,12 @@ export declare function validatedScheduledTaskUpdate(input: {
32
32
  toolsProvided?: boolean;
33
33
  }): Promise<UpdateScheduledTaskInput>;
34
34
  export declare function requireScheduledTaskForApi(db: Database, workspaceId: string, taskId: string): Promise<ScheduledTask>;
35
- export declare function restoreScheduledTask(db: Database, task: ScheduledTask): Promise<ScheduledTask>;
35
+ export type ScheduledTaskRestoreState = {
36
+ task: ScheduledTask;
37
+ personalConnectionDelegations: McpPersonalConnectionDelegation[];
38
+ };
39
+ export declare function captureScheduledTaskRestoreState(db: Database, task: ScheduledTask): Promise<ScheduledTaskRestoreState>;
40
+ export declare function restoreScheduledTask(db: Database, previous: ScheduledTaskRestoreState): Promise<ScheduledTask>;
36
41
  export declare function syncCreatedScheduledTask(input: {
37
42
  db: Database;
38
43
  workflowClient: SessionWorkflowClient;
@@ -41,7 +46,7 @@ export declare function syncCreatedScheduledTask(input: {
41
46
  export declare function syncUpdatedScheduledTask(input: {
42
47
  db: Database;
43
48
  workflowClient: SessionWorkflowClient;
44
- previous: ScheduledTask;
49
+ previous: ScheduledTaskRestoreState;
45
50
  task: ScheduledTask;
46
51
  }): Promise<void>;
47
52
  export declare function scheduledTaskTemporalScheduleId(taskId: string): string;
@@ -1,5 +1,5 @@
1
1
  import { type Settings } from "@opengeni/config";
2
- import { SessionSpawnDenial, type AccessGrant, type CreateSessionResponse, type GoalSpec, type FirstPartyMcpToolName, type Permission, type ReasoningEffort, type ResourceRef, type Session, type SessionSkill, type SessionEvent, SessionMcpApprovalPolicy, type SessionMcpCredentialUpdateInput, type SessionMcpServerMetadata, type UpdateSessionMcpApprovalPolicyResponse, type UpdateSessionToolPolicyRequest, type SessionAuthorizationPort, type SessionToolPolicy, type SessionTurn, type ToolRef, type TurnInitiator, type TurnInitiatorContext, type TurnExecutionPolicyV1 } from "@opengeni/contracts";
2
+ import { SessionSpawnDenial, type AccessGrant, type CreateSessionResponse, type GoalSpec, type FirstPartyMcpToolName, type McpPersonalConnectionDelegation, type Permission, type ReasoningEffort, type ResourceRef, type Session, type SessionSkill, type SessionEvent, SessionMcpApprovalPolicy, type SessionMcpCredentialUpdateInput, type SessionMcpServerMetadata, type UpdateSessionMcpApprovalPolicyResponse, type UpdateSessionToolPolicyRequest, type SessionAuthorizationPort, type SessionToolPolicy, type SessionTurn, type ToolRef, type TurnInitiator, type TurnInitiatorContext, type TurnExecutionPolicyV1 } from "@opengeni/contracts";
3
3
  import { type CreateSessionMcpServerInput, type Database, type UpdateSessionMcpServerCredentialsInput, type SessionCommandActor } from "@opengeni/db";
4
4
  import { type EventBus } from "@opengeni/events";
5
5
  import type { AcceptSessionUserMessageDependencies, ApiRouteDeps, SessionWorkflowClient } from "../dependencies";
@@ -40,6 +40,14 @@ export declare function sessionSpawnDenialEnvelope(error: SessionSpawnDeniedErro
40
40
  };
41
41
  };
42
42
  };
43
+ export type FrozenCreationInitiator = {
44
+ initiator?: TurnInitiator;
45
+ context?: TurnInitiatorContext;
46
+ actor?: Extract<SessionCommandActor, {
47
+ type: "agent_attempt";
48
+ }>;
49
+ };
50
+ export declare function creationInitiatorForGrant(grant: AccessGrant): FrozenCreationInitiator;
43
51
  export declare function settingsWithSessionMcpServerMetadata(settings: Settings, servers: SessionMcpServerMetadata[]): Settings;
44
52
  export declare function createAndStartSession(input: {
45
53
  requestedSessionId?: string;
@@ -79,6 +87,7 @@ export declare function createAndStartSession(input: {
79
87
  firstPartyMcpTools: FirstPartyMcpToolName[];
80
88
  mcpServers?: CreateSessionMcpServerInput[];
81
89
  sessionMcpServers?: SessionMcpServerMetadata[];
90
+ personalConnectionDelegations?: McpPersonalConnectionDelegation[];
82
91
  parentSessionId?: string | null;
83
92
  createIdempotencyKey?: string | null;
84
93
  sandboxGroupId?: string | null;
@@ -165,6 +174,7 @@ export declare function postUserMessageTurn(input: {
165
174
  latencyMode?: "standard" | "priority" | "fast" | null;
166
175
  clientEventId?: string;
167
176
  mcpCredentialUpdates?: UpdateSessionMcpServerCredentialsInput[];
177
+ personalConnectionDelegations?: McpPersonalConnectionDelegation[];
168
178
  delivery?: "send" | "steer";
169
179
  origin?: "human" | "operator";
170
180
  actor?: string;
package/dist/index.d.ts CHANGED
@@ -12,6 +12,7 @@ export * from "./domain/capabilities";
12
12
  export * from "./domain/environments";
13
13
  export * from "./rigs";
14
14
  export * from "./domain/packs";
15
+ export * from "./domain/personal-connection-delegations";
15
16
  export * from "./domain/resources";
16
17
  export * from "./domain/session-tool-policy";
17
18
  export * from "./domain/scheduled-tasks";
package/dist/index.js CHANGED
@@ -354,6 +354,7 @@ function wrapChannelABoxWithRouting(services, ids, established) {
354
354
  return pointer ?? { activeSandboxId: null, activeEpoch: 0 };
355
355
  },
356
356
  resolveActiveBackend: resolver,
357
+ ...services.onSandboxOperation ? { onOperation: services.onSandboxOperation } : {},
357
358
  ...beforeMutation ? { beforeMutation } : {},
358
359
  ...afterMutation ? { afterMutation } : {},
359
360
  ...beforeProcessMutation ? { beforeProcessMutation } : {},
@@ -3150,6 +3151,158 @@ async function listRigChangesForApi(deps, workspaceId, rigId, limit) {
3150
3151
  return await listRigChanges(deps.db, workspaceId, rigId, limit);
3151
3152
  }
3152
3153
 
3154
+ // src/domain/personal-connection-delegations.ts
3155
+ import {
3156
+ getSessionTurnPersonalConnectionDelegations,
3157
+ getWorkspaceGrant as getWorkspaceGrant2,
3158
+ listConnectionsMetadata as listConnectionsMetadata2
3159
+ } from "@opengeni/db";
3160
+ function directPersonalConnectionSubjectId(turn) {
3161
+ if (turn.source !== "user" && turn.source !== "api" || turn.initiator.kind !== "subject") {
3162
+ return void 0;
3163
+ }
3164
+ return ["via", "viaTruncated", "provenanceError", "backfill"].some(
3165
+ (key) => Object.prototype.hasOwnProperty.call(turn.initiatorContext, key)
3166
+ ) ? void 0 : turn.initiator.subjectId;
3167
+ }
3168
+ function personalConnectionDelegationSourceForGrant(grant) {
3169
+ const callerSessionId = grant.metadata?.["sessionId"];
3170
+ const callerTurnId = grant.metadata?.["turnId"];
3171
+ if (typeof callerSessionId === "string" && typeof callerTurnId === "string") {
3172
+ return { kind: "turn", sessionId: callerSessionId, turnId: callerTurnId };
3173
+ }
3174
+ if (grant.principalKind === "agent_attempt" || grant.principalKind === "service" || grant.serviceInitiator) {
3175
+ return { kind: "none" };
3176
+ }
3177
+ return { kind: "subject", subjectId: grant.subjectId };
3178
+ }
3179
+ function selectedPersonalConnectionServers(settings, tools) {
3180
+ const selected = new Set(tools.map((tool) => tool.id));
3181
+ return settings.mcpServers.filter(
3182
+ (server) => selected.has(server.id) && server.connectionRef?.subjectScope === "subject"
3183
+ );
3184
+ }
3185
+ function canonicalPersonalConnections(connections) {
3186
+ return [...connections].sort((left, right) => {
3187
+ const active = Number(right.status === "active") - Number(left.status === "active");
3188
+ if (active !== 0) return active;
3189
+ const updated = Date.parse(right.updatedAt) - Date.parse(left.updatedAt);
3190
+ if (updated !== 0) return updated;
3191
+ const created = Date.parse(right.createdAt) - Date.parse(left.createdAt);
3192
+ if (created !== 0) return created;
3193
+ return right.id.localeCompare(left.id);
3194
+ });
3195
+ }
3196
+ function sameProviderDomain(left, right) {
3197
+ return left.toLowerCase() === right.toLowerCase();
3198
+ }
3199
+ function personalConnectionDelegationsFromVisibleConnections(input) {
3200
+ const delegations = [];
3201
+ const connections = canonicalPersonalConnections(input.connections);
3202
+ for (const server of input.servers) {
3203
+ const ref = server.connectionRef;
3204
+ if (!ref || ref.subjectScope !== "subject") continue;
3205
+ const connection = connections.find(
3206
+ (candidate) => candidate.subjectId === input.subjectId && candidate.status === "active" && sameProviderDomain(candidate.providerDomain, ref.providerDomain) && (!ref.kind || candidate.kind === ref.kind) && (!ref.connectionId || candidate.id === ref.connectionId)
3207
+ );
3208
+ if (!connection) continue;
3209
+ delegations.push({
3210
+ serverId: server.id,
3211
+ connectionId: connection.id,
3212
+ ownerSubjectId: input.subjectId,
3213
+ providerDomain: connection.providerDomain,
3214
+ kind: connection.kind
3215
+ });
3216
+ }
3217
+ return delegations;
3218
+ }
3219
+ function personalConnectionDelegationsFromParent(input) {
3220
+ return input.servers.flatMap((server) => {
3221
+ const ref = server.connectionRef;
3222
+ if (!ref || ref.subjectScope !== "subject") return [];
3223
+ const delegation = input.parentDelegations.find(
3224
+ (candidate) => candidate.serverId === server.id && sameProviderDomain(candidate.providerDomain, ref.providerDomain) && (!ref.kind || !candidate.kind || candidate.kind === ref.kind)
3225
+ );
3226
+ return delegation ? [{ ...delegation }] : [];
3227
+ });
3228
+ }
3229
+ function personalConnectionDelegationsEqual(left, right) {
3230
+ if (left.length !== right.length) return false;
3231
+ const byServer = new Map(right.map((delegation) => [delegation.serverId, delegation]));
3232
+ return left.every((delegation) => {
3233
+ const other = byServer.get(delegation.serverId);
3234
+ return other?.connectionId === delegation.connectionId && other.ownerSubjectId === delegation.ownerSubjectId && sameProviderDomain(other.providerDomain, delegation.providerDomain) && other.kind === delegation.kind;
3235
+ });
3236
+ }
3237
+ function personalConnectionDelegationForServer(delegations, server) {
3238
+ const ref = server.connectionRef;
3239
+ if (!ref || ref.subjectScope !== "subject") return null;
3240
+ return delegations.find(
3241
+ (delegation) => delegation.serverId === server.id && sameProviderDomain(delegation.providerDomain, ref.providerDomain) && (!ref.kind || !delegation.kind || delegation.kind === ref.kind)
3242
+ ) ?? null;
3243
+ }
3244
+ function personalAuthorityUnavailable(request) {
3245
+ const ref = request.connectionRef;
3246
+ return {
3247
+ status: "auth_needed",
3248
+ reason: "personal_authority_unavailable",
3249
+ providerDomain: ref.providerDomain,
3250
+ ...ref.provider ? { provider: ref.provider } : {},
3251
+ ...ref.scopes ? { scopes: ref.scopes } : {},
3252
+ ...ref.resource ? { resource: ref.resource } : {},
3253
+ ...ref.selectedResources ? { selectedResources: ref.selectedResources } : {}
3254
+ };
3255
+ }
3256
+ function withFrozenPersonalConnectionDelegations(input) {
3257
+ return async (request) => {
3258
+ let effectiveRequest = request;
3259
+ if (request.connectionRef.subjectScope === "subject") {
3260
+ const config = input.settings.mcpServers.find((server) => server.id === request.serverId);
3261
+ const delegation = config ? personalConnectionDelegationForServer(input.personalConnectionDelegations, config) : null;
3262
+ if (!delegation || !await input.ownerHasWorkspaceMembership(delegation.ownerSubjectId)) {
3263
+ return personalAuthorityUnavailable(request);
3264
+ }
3265
+ effectiveRequest = {
3266
+ ...request,
3267
+ subjectId: delegation.ownerSubjectId,
3268
+ connectionRef: {
3269
+ ...request.connectionRef,
3270
+ providerDomain: delegation.providerDomain,
3271
+ connectionId: delegation.connectionId,
3272
+ ...delegation.kind ? { kind: delegation.kind } : {}
3273
+ }
3274
+ };
3275
+ }
3276
+ const result = await input.resolveCredential(effectiveRequest);
3277
+ if (result.status === "ok" || request.connectionRef.subjectScope !== "subject") {
3278
+ return result;
3279
+ }
3280
+ return personalAuthorityUnavailable(request);
3281
+ };
3282
+ }
3283
+ async function freezePersonalConnectionDelegations(input) {
3284
+ const servers = selectedPersonalConnectionServers(input.settings, input.tools);
3285
+ if (servers.length === 0 || input.source.kind === "none") return [];
3286
+ if (input.source.kind === "turn") {
3287
+ return personalConnectionDelegationsFromParent({
3288
+ servers,
3289
+ parentDelegations: await getSessionTurnPersonalConnectionDelegations(
3290
+ input.db,
3291
+ input.workspaceId,
3292
+ input.source.sessionId,
3293
+ input.source.turnId
3294
+ )
3295
+ });
3296
+ }
3297
+ const membership = await getWorkspaceGrant2(input.db, input.source.subjectId, input.workspaceId);
3298
+ if (!membership) return [];
3299
+ return personalConnectionDelegationsFromVisibleConnections({
3300
+ servers,
3301
+ subjectId: input.source.subjectId,
3302
+ connections: await listConnectionsMetadata2(input.db, input.workspaceId, input.source.subjectId)
3303
+ });
3304
+ }
3305
+
3153
3306
  // src/domain/resources.ts
3154
3307
  import {
3155
3308
  gitCredentialBindingIdForRepository,
@@ -3551,6 +3704,7 @@ import {
3551
3704
  getNestedAgentDepthDeploymentPolicy,
3552
3705
  getRig as getRig3,
3553
3706
  getScheduledTask,
3707
+ getScheduledTaskPersonalConnectionDelegations,
3554
3708
  requireWorkspace as requireWorkspace2,
3555
3709
  updateScheduledTask
3556
3710
  } from "@opengeni/db";
@@ -4008,6 +4162,7 @@ async function createAndStartSession(input) {
4008
4162
  sandboxGroupId: input.sandboxGroupId ?? null,
4009
4163
  ...input.sandboxOs ? { sandboxOs: input.sandboxOs } : {},
4010
4164
  mcpServers: input.mcpServers ?? [],
4165
+ personalConnectionDelegations: input.personalConnectionDelegations ?? [],
4011
4166
  maxNestedAgentDepthOverride: input.maxNestedAgentDepthOverride ?? null,
4012
4167
  allowNestedAgentDepthIncrease: input.allowNestedAgentDepthIncrease ?? false,
4013
4168
  subjectId: input.subjectId ?? null
@@ -4052,6 +4207,7 @@ async function createAndStartSession(input) {
4052
4207
  sandboxGroupId: input.sandboxGroupId ?? null,
4053
4208
  ...input.sandboxOs ? { sandboxOs: input.sandboxOs } : {},
4054
4209
  mcpServers: input.mcpServers ?? [],
4210
+ personalConnectionDelegations: input.personalConnectionDelegations ?? [],
4055
4211
  maxNestedAgentDepthOverride: input.maxNestedAgentDepthOverride ?? null,
4056
4212
  allowNestedAgentDepthIncrease: input.allowNestedAgentDepthIncrease ?? false,
4057
4213
  subjectId: input.subjectId ?? null
@@ -4250,6 +4406,7 @@ async function postUserMessageTurn(input) {
4250
4406
  reasoningEffortFallback: input.reasoningEffortFallback ?? settings.openaiReasoningEffort,
4251
4407
  turnExecutionPolicy: input.turnExecutionPolicy,
4252
4408
  source: input.origin === "operator" ? "api" : "user",
4409
+ personalConnectionDelegations: input.personalConnectionDelegations ?? [],
4253
4410
  mcpCredentialUpdates: input.mcpCredentialUpdates ?? []
4254
4411
  })
4255
4412
  )
@@ -4404,6 +4561,13 @@ async function createSessionForRequest(deps, grant, workspaceId, rawPayload) {
4404
4561
  toolPolicy = { mode: "workspace_default", inheritedFromSessionId: null };
4405
4562
  }
4406
4563
  const tools = withFirstPartyTools(selectedTools, runtimeSettings);
4564
+ const personalConnectionDelegations = await freezePersonalConnectionDelegations({
4565
+ db,
4566
+ workspaceId,
4567
+ settings: runtimeSettings,
4568
+ tools,
4569
+ source: personalConnectionDelegationSourceForGrant(grant)
4570
+ });
4407
4571
  await validateGitHubRepositorySelection(db, workspaceId, resources);
4408
4572
  if (resources.some((resource) => resource.kind === "file") && !objectStorage) {
4409
4573
  throw new HTTPException10(503, { message: "object storage is not configured" });
@@ -4639,6 +4803,7 @@ async function createSessionForRequest(deps, grant, workspaceId, rawPayload) {
4639
4803
  firstPartyMcpTools,
4640
4804
  mcpServers: sessionMcpServers.dbServers,
4641
4805
  sessionMcpServers: sessionMcpServers.metadata,
4806
+ personalConnectionDelegations,
4642
4807
  parentSessionId,
4643
4808
  createIdempotencyKey: payload.idempotencyKey ?? null,
4644
4809
  maxNestedAgentDepthOverride: payload.maxNestedAgentDepth ?? null,
@@ -4741,6 +4906,14 @@ async function acceptSessionUserMessage(deps, grant, workspaceId, sessionId, inp
4741
4906
  session: existingSession,
4742
4907
  updates: input.mcpCredentialUpdates ?? []
4743
4908
  });
4909
+ const runtimeSettings = await settingsWithEnabledCapabilityMcpServers(db, workspaceId, settings);
4910
+ const personalConnectionDelegations = await freezePersonalConnectionDelegations({
4911
+ db,
4912
+ workspaceId,
4913
+ settings: runtimeSettings,
4914
+ tools: existingSession.tools,
4915
+ source: personalConnectionDelegationSourceForGrant(grant)
4916
+ });
4744
4917
  const delegatedServiceInitiator = serviceInitiatorForGrant(grant);
4745
4918
  const { accepted, turn } = await postUserMessageTurn({
4746
4919
  db,
@@ -4759,6 +4932,7 @@ async function acceptSessionUserMessage(deps, grant, workspaceId, sessionId, inp
4759
4932
  reasoningEffortFallback: sessionReasoningEffort,
4760
4933
  turnExecutionPolicy,
4761
4934
  mcpCredentialUpdates,
4935
+ personalConnectionDelegations,
4762
4936
  delivery: input.delivery ?? "send",
4763
4937
  origin: delegatedServiceInitiator ? "operator" : input.origin ?? "human",
4764
4938
  actor: grant.subjectId,
@@ -5100,6 +5274,19 @@ async function createValidatedScheduledTask(input) {
5100
5274
  if (input.payload.rigId) {
5101
5275
  await requireScheduledTaskRig(input.db, input.grant.workspaceId, input.payload.rigId);
5102
5276
  }
5277
+ const runtimeSettings = await settingsWithEnabledCapabilityMcpServers(
5278
+ input.db,
5279
+ input.grant.workspaceId,
5280
+ input.settings
5281
+ );
5282
+ const personalConnectionDelegations = await freezePersonalConnectionDelegations({
5283
+ db: input.db,
5284
+ workspaceId: input.grant.workspaceId,
5285
+ settings: runtimeSettings,
5286
+ tools: agentConfig.tools,
5287
+ source: personalConnectionDelegationSourceForGrant(input.grant)
5288
+ });
5289
+ const creationInitiator = creationInitiatorForGrant(input.grant);
5103
5290
  return await createScheduledTask(input.db, {
5104
5291
  id,
5105
5292
  accountId: input.grant.accountId,
@@ -5111,6 +5298,10 @@ async function createValidatedScheduledTask(input) {
5111
5298
  runMode: input.payload.runMode,
5112
5299
  overlapPolicy: input.payload.overlapPolicy,
5113
5300
  agentConfig,
5301
+ ...creationInitiator.initiator ? { createdBy: creationInitiator.initiator } : {},
5302
+ ...creationInitiator.context ? { createdByContext: creationInitiator.context } : {},
5303
+ createdByActor: creationInitiator.actor ?? null,
5304
+ personalConnectionDelegations,
5114
5305
  variableSetId: input.payload.variableSetId ?? null,
5115
5306
  rigId: input.payload.rigId ?? null,
5116
5307
  metadata: input.payload.metadata
@@ -5191,6 +5382,31 @@ async function validatedScheduledTaskUpdate(input) {
5191
5382
  });
5192
5383
  }
5193
5384
  update.agentConfig = nextAgentConfig;
5385
+ const runtimeSettings = await settingsWithEnabledCapabilityMcpServers(
5386
+ input.db,
5387
+ input.existing.workspaceId,
5388
+ input.settings
5389
+ );
5390
+ const personalConnectionDelegations = await freezePersonalConnectionDelegations({
5391
+ db: input.db,
5392
+ workspaceId: input.existing.workspaceId,
5393
+ settings: runtimeSettings,
5394
+ tools: nextAgentConfig.tools,
5395
+ source: personalConnectionDelegationSourceForGrant(input.grant)
5396
+ });
5397
+ if (input.existing.reusableSessionId && input.existing.runMode === "reusable_session") {
5398
+ const existingDelegations = await getScheduledTaskPersonalConnectionDelegations(
5399
+ input.db,
5400
+ input.existing.workspaceId,
5401
+ input.existing.id
5402
+ );
5403
+ if (!personalConnectionDelegationsEqual(existingDelegations, personalConnectionDelegations)) {
5404
+ throw new HTTPException11(409, {
5405
+ message: "cannot change personal MCP connections of a task with a live reusable session; recreate the task"
5406
+ });
5407
+ }
5408
+ }
5409
+ update.personalConnectionDelegations = personalConnectionDelegations;
5194
5410
  }
5195
5411
  return update;
5196
5412
  }
@@ -5201,7 +5417,18 @@ async function requireScheduledTaskForApi(db, workspaceId, taskId) {
5201
5417
  }
5202
5418
  return task;
5203
5419
  }
5204
- async function restoreScheduledTask(db, task) {
5420
+ async function captureScheduledTaskRestoreState(db, task) {
5421
+ return {
5422
+ task,
5423
+ personalConnectionDelegations: await getScheduledTaskPersonalConnectionDelegations(
5424
+ db,
5425
+ task.workspaceId,
5426
+ task.id
5427
+ )
5428
+ };
5429
+ }
5430
+ async function restoreScheduledTask(db, previous) {
5431
+ const { task } = previous;
5205
5432
  return await updateScheduledTask(db, task.workspaceId, task.id, {
5206
5433
  name: task.name,
5207
5434
  status: task.status,
@@ -5209,8 +5436,10 @@ async function restoreScheduledTask(db, task) {
5209
5436
  runMode: task.runMode,
5210
5437
  overlapPolicy: task.overlapPolicy,
5211
5438
  agentConfig: task.agentConfig,
5439
+ personalConnectionDelegations: previous.personalConnectionDelegations,
5212
5440
  reusableSessionId: task.reusableSessionId,
5213
5441
  variableSetId: task.variableSetId,
5442
+ rigId: task.rigId,
5214
5443
  metadata: task.metadata
5215
5444
  });
5216
5445
  }
@@ -6483,6 +6712,7 @@ export {
6483
6712
  buildFleetContextForSession,
6484
6713
  buildMarketingDailyAnalysisAgentConfig,
6485
6714
  canonicalConfiguredModel,
6715
+ captureScheduledTaskRestoreState,
6486
6716
  checkLimit,
6487
6717
  classifyRigVerificationOutcome,
6488
6718
  controlAgentSessionWorkstream,
@@ -6494,9 +6724,11 @@ export {
6494
6724
  createRigVersionForApi,
6495
6725
  createSessionForRequest,
6496
6726
  createValidatedScheduledTask,
6727
+ creationInitiatorForGrant,
6497
6728
  defaultSessionMcpServerIds,
6498
6729
  deleteHumanQueuePrompt,
6499
6730
  deleteRigForApi,
6731
+ directPersonalConnectionSubjectId,
6500
6732
  disableCapability,
6501
6733
  discoverMcpRegistryCapabilities,
6502
6734
  editHumanQueuePrompt,
@@ -6504,6 +6736,7 @@ export {
6504
6736
  enabledCapabilityMcpToolRefs,
6505
6737
  executeRunOnSelfhostedMachine,
6506
6738
  filenameForMimeType,
6739
+ freezePersonalConnectionDelegations,
6507
6740
  getActorNewSessionDraft,
6508
6741
  getCapabilityPack,
6509
6742
  getHumanComposerDraft,
@@ -6533,6 +6766,11 @@ export {
6533
6766
  normalizeResources,
6534
6767
  officialMcpRegistryUrl,
6535
6768
  openGeniSlackBotMetadata,
6769
+ personalConnectionDelegationForServer,
6770
+ personalConnectionDelegationSourceForGrant,
6771
+ personalConnectionDelegationsEqual,
6772
+ personalConnectionDelegationsFromParent,
6773
+ personalConnectionDelegationsFromVisibleConnections,
6536
6774
  postUserMessageTurn,
6537
6775
  promoteSetupAppendChange,
6538
6776
  promoteVerifiedDefinitionEditChangeForApi,
@@ -6574,6 +6812,7 @@ export {
6574
6812
  scheduledTaskTemporalScheduleId,
6575
6813
  scheduledTaskToolsProvided,
6576
6814
  scheduledTaskTriggerToken,
6815
+ selectedPersonalConnectionServers,
6577
6816
  sendAgentSessionMessage,
6578
6817
  sessionSpawnDenialEnvelope,
6579
6818
  sessionWithEffectiveToolPolicy,
@@ -6603,6 +6842,7 @@ export {
6603
6842
  validateVariableSetAttachment,
6604
6843
  validatedScheduledTaskUpdate,
6605
6844
  withDefaultEnabledCapabilityMcpTools,
6845
+ withFrozenPersonalConnectionDelegations,
6606
6846
  workflowIdForSession,
6607
6847
  workspaceSessionToolPolicyDefaultServerIds,
6608
6848
  workspaceSessionToolPolicyServerIds,