@opengeni/db 0.19.0 → 0.21.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.
package/src/index.ts CHANGED
@@ -33,6 +33,7 @@ import type {
33
33
  HostUsageExport,
34
34
  HostUsageExportBatch,
35
35
  ManagedAccount,
36
+ McpPersonalConnectionDelegation,
36
37
  Permission,
37
38
  PackInstallation,
38
39
  PackInstallationStatus,
@@ -103,6 +104,7 @@ import type {
103
104
  } from "@opengeni/contracts";
104
105
  import {
105
106
  DEFAULT_FIRST_PARTY_MCP_TOOLS,
107
+ McpPersonalConnectionDelegations,
106
108
  SESSION_AUTHORIZATION_LIST_SCOPE_MAX_IDS,
107
109
  backendForNativeSnapshotProvider,
108
110
  canonicalModalCheckpointProviderBinding,
@@ -110,6 +112,7 @@ import {
110
112
  parseWorkspaceArchiveDescriptor,
111
113
  stableJson,
112
114
  } from "@opengeni/contracts";
115
+
113
116
  import {
114
117
  approvalIdentifier,
115
118
  boundWorkspaceControlEvent,
@@ -239,6 +242,7 @@ export * from "./new-session-drafts";
239
242
  export * from "./workspace-instruction-policies";
240
243
  export * from "./preference-registry";
241
244
  export * from "./memory-governance";
245
+ export * from "./scoped-knowledge";
242
246
  export { interruptedToolCallResult } from "./session-tool-call-settlement";
243
247
  export { decryptEnvironmentValue, encryptEnvironmentValue } from "./environment-crypto";
244
248
  export {
@@ -286,6 +290,17 @@ export * from "./memory-domain";
286
290
  // `userLookup` is the injection seam for hosts on a different driver.
287
291
  // `PostgresJsDatabase<typeof schema>` is assignable to this, so standalone is
288
292
  // unaffected.
293
+ function parsedPersonalConnectionDelegations(
294
+ value: unknown,
295
+ context: string,
296
+ ): McpPersonalConnectionDelegation[] {
297
+ const parsed = McpPersonalConnectionDelegations.safeParse(value);
298
+ if (!parsed.success) {
299
+ throw new Error(`Invalid personal MCP delegation snapshot at ${context}`);
300
+ }
301
+ return parsed.data.map((delegation) => ({ ...delegation }));
302
+ }
303
+
289
304
  export type Database = PgDatabase<any, typeof schema>;
290
305
 
291
306
  /** Raised when a durable session tool-policy write lost its version fence. */
@@ -3296,6 +3311,10 @@ export type CreateScheduledTaskInput = {
3296
3311
  runMode: ScheduledTaskRunMode;
3297
3312
  overlapPolicy: ScheduledTaskOverlapPolicy;
3298
3313
  agentConfig: ScheduledTaskAgentConfig;
3314
+ createdBy?: TurnInitiator;
3315
+ createdByContext?: TurnInitiatorContext;
3316
+ createdByActor?: AgentSessionCreationActor | null;
3317
+ personalConnectionDelegations?: McpPersonalConnectionDelegation[];
3299
3318
  variableSetId?: string | null;
3300
3319
  // The rig each run binds to (M3); active version resolved per fire at dispatch.
3301
3320
  rigId?: string | null;
@@ -3309,6 +3328,7 @@ export type UpdateScheduledTaskInput = Partial<{
3309
3328
  runMode: ScheduledTaskRunMode;
3310
3329
  overlapPolicy: ScheduledTaskOverlapPolicy;
3311
3330
  agentConfig: ScheduledTaskAgentConfig;
3331
+ personalConnectionDelegations: McpPersonalConnectionDelegation[];
3312
3332
  reusableSessionId: string | null;
3313
3333
  variableSetId: string | null;
3314
3334
  rigId: string | null;
@@ -3732,6 +3752,7 @@ export type EnqueueSessionTurnInput = {
3732
3752
  lineage?: Record<string, unknown>;
3733
3753
  initiator: TurnInitiator;
3734
3754
  initiatorContext?: TurnInitiatorContext;
3755
+ personalConnectionDelegations?: McpPersonalConnectionDelegation[];
3735
3756
  /** Steer inserts before all waiting prompts; Send appends after them. */
3736
3757
  placement?: "head" | "tail";
3737
3758
  };
@@ -3742,6 +3763,7 @@ export type EnqueueSessionTurnInput = {
3742
3763
  */
3743
3764
  export type SessionTurnForExecution = SessionTurn & {
3744
3765
  turnInstructions: string | null;
3766
+ personalConnectionDelegations: McpPersonalConnectionDelegation[];
3745
3767
  };
3746
3768
 
3747
3769
  export async function createFileUpload(
@@ -7144,7 +7166,9 @@ export async function loadConnectionCredentialForBroker(
7144
7166
  if (input.connectionId) {
7145
7167
  conditions.push(eq(schema.connections.id, input.connectionId));
7146
7168
  } else {
7147
- conditions.push(eq(schema.connections.providerDomain, input.providerDomain));
7169
+ conditions.push(
7170
+ sql`lower(${schema.connections.providerDomain}) = lower(${input.providerDomain})`,
7171
+ );
7148
7172
  if (input.kind) {
7149
7173
  conditions.push(eq(schema.connections.kind, input.kind));
7150
7174
  }
@@ -7174,6 +7198,8 @@ export async function loadConnectionCredentialForBroker(
7174
7198
  : [
7175
7199
  desc(sql`(${schema.connections.status} = 'active')`),
7176
7200
  desc(schema.connections.updatedAt),
7201
+ desc(schema.connections.createdAt),
7202
+ desc(schema.connections.id),
7177
7203
  ]),
7178
7204
  )
7179
7205
  .limit(1);
@@ -9018,7 +9044,27 @@ export async function createScheduledTask(
9018
9044
  db,
9019
9045
  { accountId: input.accountId, workspaceId: input.workspaceId },
9020
9046
  async (scopedDb) => {
9021
- const [row] = await scopedDb.insert(schema.scheduledTasks).values(input).returning();
9047
+ const frozenCreator = await frozenSessionCreatorForInsert(scopedDb, input);
9048
+ const [row] = await scopedDb
9049
+ .insert(schema.scheduledTasks)
9050
+ .values({
9051
+ id: input.id,
9052
+ accountId: input.accountId,
9053
+ workspaceId: input.workspaceId,
9054
+ name: input.name,
9055
+ status: input.status,
9056
+ schedule: input.schedule,
9057
+ temporalScheduleId: input.temporalScheduleId,
9058
+ runMode: input.runMode,
9059
+ overlapPolicy: input.overlapPolicy,
9060
+ agentConfig: input.agentConfig,
9061
+ ...creatorColumns(frozenCreator),
9062
+ personalConnectionDelegations: input.personalConnectionDelegations ?? [],
9063
+ variableSetId: input.variableSetId ?? null,
9064
+ rigId: input.rigId ?? null,
9065
+ metadata: input.metadata,
9066
+ })
9067
+ .returning();
9022
9068
  if (!row) {
9023
9069
  throw new Error("Failed to create scheduled task");
9024
9070
  }
@@ -9043,6 +9089,9 @@ export async function updateScheduledTask(
9043
9089
  ...(input.runMode !== undefined ? { runMode: input.runMode } : {}),
9044
9090
  ...(input.overlapPolicy !== undefined ? { overlapPolicy: input.overlapPolicy } : {}),
9045
9091
  ...(input.agentConfig !== undefined ? { agentConfig: input.agentConfig } : {}),
9092
+ ...(input.personalConnectionDelegations !== undefined
9093
+ ? { personalConnectionDelegations: input.personalConnectionDelegations }
9094
+ : {}),
9046
9095
  ...(input.reusableSessionId !== undefined
9047
9096
  ? { reusableSessionId: input.reusableSessionId }
9048
9097
  : {}),
@@ -9085,6 +9134,31 @@ export async function getScheduledTask(
9085
9134
  });
9086
9135
  }
9087
9136
 
9137
+ export async function getScheduledTaskPersonalConnectionDelegations(
9138
+ db: Database,
9139
+ workspaceId: string,
9140
+ taskId: string,
9141
+ ): Promise<McpPersonalConnectionDelegation[]> {
9142
+ return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
9143
+ const [row] = await scopedDb
9144
+ .select({ delegations: schema.scheduledTasks.personalConnectionDelegations })
9145
+ .from(schema.scheduledTasks)
9146
+ .where(
9147
+ and(
9148
+ eq(schema.scheduledTasks.workspaceId, workspaceId),
9149
+ eq(schema.scheduledTasks.id, taskId),
9150
+ ),
9151
+ )
9152
+ .limit(1);
9153
+ return row
9154
+ ? parsedPersonalConnectionDelegations(
9155
+ row.delegations,
9156
+ `scheduled_tasks:${workspaceId}:${taskId}`,
9157
+ )
9158
+ : [];
9159
+ });
9160
+ }
9161
+
9088
9162
  export async function requireScheduledTask(
9089
9163
  db: Database,
9090
9164
  workspaceId: string,
@@ -15759,6 +15833,7 @@ export type SessionCreateInput = {
15759
15833
  sandboxGroupId?: string | null;
15760
15834
  sandboxOs?: SandboxOs;
15761
15835
  mcpServers?: CreateSessionMcpServerInput[];
15836
+ personalConnectionDelegations?: McpPersonalConnectionDelegation[];
15762
15837
  maxNestedAgentDepthOverride?: number | null;
15763
15838
  allowNestedAgentDepthIncrease?: boolean;
15764
15839
  subjectId?: string | null;
@@ -16131,6 +16206,11 @@ async function createSessionInTransaction(
16131
16206
 
16132
16207
  // Do not run mutable creator validation before keyed denial replay above.
16133
16208
  const frozenCreator = await frozenSessionCreatorForInsert(tx, input);
16209
+ const parentTurnId = input.parentSessionId
16210
+ ? input.createdByActor?.sessionId === input.parentSessionId
16211
+ ? input.createdByActor.turnId
16212
+ : null
16213
+ : null;
16134
16214
  const [inserted] = await tx
16135
16215
  .insert(schema.sessions)
16136
16216
  .values({
@@ -16157,8 +16237,10 @@ async function createSessionInTransaction(
16157
16237
  rigVersionId: input.rigVersionId ?? null,
16158
16238
  firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,
16159
16239
  firstPartyMcpTools: input.firstPartyMcpTools ?? [...DEFAULT_FIRST_PARTY_MCP_TOOLS],
16240
+ initialPersonalConnectionDelegations: input.personalConnectionDelegations ?? [],
16160
16241
  instructions: input.instructions ?? null,
16161
16242
  parentSessionId: input.parentSessionId ?? null,
16243
+ parentTurnId,
16162
16244
  createIdempotencyKey,
16163
16245
  rootSessionId: decision.rootSessionId,
16164
16246
  nestedAgentDepth: decision.nestedAgentDepth,
@@ -16329,6 +16411,76 @@ export async function getSession(
16329
16411
  });
16330
16412
  }
16331
16413
 
16414
+ async function personalConnectionDelegationsForTurnInTransaction(
16415
+ db: Database,
16416
+ workspaceId: string,
16417
+ sessionId: string,
16418
+ turnId: string,
16419
+ ): Promise<McpPersonalConnectionDelegation[]> {
16420
+ const [row] = await db
16421
+ .select({ delegations: schema.sessionTurns.personalConnectionDelegations })
16422
+ .from(schema.sessionTurns)
16423
+ .where(
16424
+ and(
16425
+ eq(schema.sessionTurns.workspaceId, workspaceId),
16426
+ eq(schema.sessionTurns.sessionId, sessionId),
16427
+ eq(schema.sessionTurns.id, turnId),
16428
+ ),
16429
+ )
16430
+ .limit(1);
16431
+ return row
16432
+ ? parsedPersonalConnectionDelegations(
16433
+ row.delegations,
16434
+ `session_turns:${workspaceId}:${sessionId}:${turnId}`,
16435
+ )
16436
+ : [];
16437
+ }
16438
+
16439
+ export async function getSessionTurnPersonalConnectionDelegations(
16440
+ db: Database,
16441
+ workspaceId: string,
16442
+ sessionId: string,
16443
+ turnId: string,
16444
+ ): Promise<McpPersonalConnectionDelegation[]> {
16445
+ return await withWorkspaceRls(
16446
+ db,
16447
+ workspaceId,
16448
+ async (scopedDb) =>
16449
+ await personalConnectionDelegationsForTurnInTransaction(
16450
+ scopedDb,
16451
+ workspaceId,
16452
+ sessionId,
16453
+ turnId,
16454
+ ),
16455
+ );
16456
+ }
16457
+
16458
+ export async function getSessionParentPersonalConnectionDelegations(
16459
+ db: Database,
16460
+ workspaceId: string,
16461
+ childSessionId: string,
16462
+ ): Promise<McpPersonalConnectionDelegation[]> {
16463
+ return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
16464
+ const [child] = await scopedDb
16465
+ .select({
16466
+ parentSessionId: schema.sessions.parentSessionId,
16467
+ parentTurnId: schema.sessions.parentTurnId,
16468
+ })
16469
+ .from(schema.sessions)
16470
+ .where(
16471
+ and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, childSessionId)),
16472
+ )
16473
+ .limit(1);
16474
+ if (!child?.parentSessionId || !child.parentTurnId) return [];
16475
+ return await personalConnectionDelegationsForTurnInTransaction(
16476
+ scopedDb,
16477
+ workspaceId,
16478
+ child.parentSessionId,
16479
+ child.parentTurnId,
16480
+ );
16481
+ });
16482
+ }
16483
+
16332
16484
  export async function getSessionSpawnDenial(
16333
16485
  db: Database,
16334
16486
  workspaceId: string,
@@ -17692,6 +17844,56 @@ export async function listSessions(
17692
17844
  });
17693
17845
  }
17694
17846
 
17847
+ /**
17848
+ * Return the model most recently chosen by one human subject in their own
17849
+ * workspace sessions. A later subject-initiated turn supersedes the session's
17850
+ * creation-time default; sessions with no such turn fall back to sessions.model.
17851
+ * Turn timestamp ties use queue position then UUID, and session ties use the
17852
+ * immutable session timestamp/UUID. Other subjects' turns never influence the
17853
+ * result. The workspace filter remains authoritative under FORCE RLS.
17854
+ */
17855
+ export async function getLatestSessionModelForSubject(
17856
+ db: Database,
17857
+ workspaceId: string,
17858
+ subjectId: string,
17859
+ ): Promise<string | null> {
17860
+ return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
17861
+ const rows = await scopedDb.execute<{ model: string }>(sql`
17862
+ select coalesce(latest_subject_turn.model, subject_session.model) as model
17863
+ from ${schema.sessions} subject_session
17864
+ left join lateral (
17865
+ select
17866
+ subject_turn.id,
17867
+ subject_turn.model,
17868
+ subject_turn.position,
17869
+ subject_turn.created_at
17870
+ from ${schema.sessionTurns} subject_turn
17871
+ where subject_turn.workspace_id = ${workspaceId}
17872
+ and subject_turn.session_id = subject_session.id
17873
+ and subject_turn.initiator_kind = 'subject'
17874
+ and subject_turn.initiator_subject_id = ${subjectId}
17875
+ order by
17876
+ subject_turn.created_at desc,
17877
+ subject_turn.position desc,
17878
+ subject_turn.id desc
17879
+ limit 1
17880
+ ) latest_subject_turn on true
17881
+ where subject_session.workspace_id = ${workspaceId}
17882
+ and subject_session.created_by_kind = 'subject'
17883
+ and subject_session.created_by_subject_id = ${subjectId}
17884
+ order by
17885
+ coalesce(latest_subject_turn.created_at, subject_session.created_at) desc,
17886
+ (latest_subject_turn.id is not null) desc,
17887
+ subject_session.created_at desc,
17888
+ subject_session.id desc,
17889
+ latest_subject_turn.position desc nulls last,
17890
+ latest_subject_turn.id desc nulls last
17891
+ limit 1
17892
+ `);
17893
+ return rows[0]?.model ?? null;
17894
+ });
17895
+ }
17896
+
17695
17897
  export type SessionDiscoveryOrderBy = "createdAt" | "updatedAt";
17696
17898
  export type SessionDiscoveryCursor = {
17697
17899
  orderBy: SessionDiscoveryOrderBy;
@@ -34812,6 +35014,32 @@ export async function materializeGoalContinuation(
34812
35014
  return { action: "paused", events: [mapEvent(event)] } as const;
34813
35015
  }
34814
35016
 
35017
+ const [causalTurn] = await tx
35018
+ .select({
35019
+ id: schema.sessionTurns.id,
35020
+ personalConnectionDelegations: schema.sessionTurns.personalConnectionDelegations,
35021
+ })
35022
+ .from(schema.sessionTurns)
35023
+ .where(
35024
+ and(
35025
+ eq(schema.sessionTurns.workspaceId, input.workspaceId),
35026
+ eq(schema.sessionTurns.sessionId, input.sessionId),
35027
+ sql`${schema.sessionTurns.finishedAt} is not null`,
35028
+ ),
35029
+ )
35030
+ .orderBy(
35031
+ desc(schema.sessionTurns.position),
35032
+ desc(schema.sessionTurns.createdAt),
35033
+ desc(schema.sessionTurns.id),
35034
+ )
35035
+ .limit(1);
35036
+ const personalConnectionDelegations = causalTurn
35037
+ ? parsedPersonalConnectionDelegations(
35038
+ causalTurn.personalConnectionDelegations,
35039
+ `session_turns:${input.workspaceId}:${input.sessionId}:${causalTurn.id}`,
35040
+ )
35041
+ : [];
35042
+
34815
35043
  const prompt = input.prompt(decision.goal, decision.autoContinuation, decision.cap);
34816
35044
  const payload = {
34817
35045
  type: "goal_continuation" as const,
@@ -34841,7 +35069,12 @@ export async function materializeGoalContinuation(
34841
35069
  dedupeKey: `goal-continuation:${decision.goal.id}:wake:${goalWakeRevision}`,
34842
35070
  summary: prompt,
34843
35071
  payload,
34844
- lineage: { goalId: decision.goal.id, goalWakeRevision },
35072
+ lineage: {
35073
+ goalId: decision.goal.id,
35074
+ goalWakeRevision,
35075
+ ...(causalTurn ? { causalTurnId: causalTurn.id } : {}),
35076
+ },
35077
+ personalConnectionDelegations,
34845
35078
  state: "pending",
34846
35079
  })
34847
35080
  .returning();
@@ -35195,6 +35428,10 @@ export async function initializeSessionStartAtomically(
35195
35428
  : {},
35196
35429
  lineage: {},
35197
35430
  ...initiatorColumns(creator),
35431
+ personalConnectionDelegations: parsedPersonalConnectionDelegations(
35432
+ session.initialPersonalConnectionDelegations,
35433
+ `sessions:${session.workspaceId}:${session.id}:initial`,
35434
+ ),
35198
35435
  })
35199
35436
  .returning();
35200
35437
  if (!turn) throw new Error("Failed to create initial session turn");
@@ -35355,6 +35592,7 @@ export async function enqueueSessionTurn(
35355
35592
  initiator: input.initiator,
35356
35593
  context: input.initiatorContext ?? {},
35357
35594
  }),
35595
+ personalConnectionDelegations: input.personalConnectionDelegations ?? [],
35358
35596
  })
35359
35597
  .returning();
35360
35598
  if (!row) {
@@ -35392,7 +35630,14 @@ const MAX_INTERNAL_UPDATE_EVENT_SOURCE_BYTES = 256;
35392
35630
 
35393
35631
  type BoundedSystemUpdate = Pick<
35394
35632
  typeof schema.sessionSystemUpdates.$inferSelect,
35395
- "id" | "kind" | "classification" | "sourceId" | "summary" | "payload" | "lineage"
35633
+ | "id"
35634
+ | "kind"
35635
+ | "classification"
35636
+ | "sourceId"
35637
+ | "summary"
35638
+ | "payload"
35639
+ | "lineage"
35640
+ | "personalConnectionDelegations"
35396
35641
  >;
35397
35642
 
35398
35643
  function boundedInternalUpdateEventText(
@@ -35431,10 +35676,14 @@ function internalUpdateEventMember(update: BoundedSystemUpdate) {
35431
35676
  };
35432
35677
  }
35433
35678
 
35434
- function selectBoundedSystemUpdateBatch<T extends BoundedSystemUpdate>(updates: readonly T[]): T[] {
35679
+ function selectBoundedSystemUpdateBatch<T extends BoundedSystemUpdate>(
35680
+ updates: readonly T[],
35681
+ canCoalesce: (first: T, candidate: T) => boolean = () => true,
35682
+ ): T[] {
35435
35683
  const selected: T[] = [];
35436
35684
  let selectedBytes = 0;
35437
35685
  for (const update of updates) {
35686
+ if (selected[0] && !canCoalesce(selected[0], update)) break;
35438
35687
  const updateBytes = Buffer.byteLength(
35439
35688
  JSON.stringify({
35440
35689
  id: update.id,
@@ -35594,7 +35843,17 @@ export async function claimSessionWorkForAttempt(
35594
35843
  }
35595
35844
  validUpdates.push(update);
35596
35845
  }
35597
- const deliverable = selectBoundedSystemUpdateBatch(validUpdates);
35846
+ const delegationKey = (update: (typeof validUpdates)[number]): string =>
35847
+ stableJson(
35848
+ parsedPersonalConnectionDelegations(
35849
+ update.personalConnectionDelegations,
35850
+ `session_system_updates:${workspaceId}:${sessionId}:${update.id}`,
35851
+ ),
35852
+ );
35853
+ const deliverable = selectBoundedSystemUpdateBatch(
35854
+ validUpdates,
35855
+ (first, candidate) => delegationKey(first) === delegationKey(candidate),
35856
+ );
35598
35857
  if (deliverable.length === 0) {
35599
35858
  const cancellationEvent =
35600
35859
  cancelledUpdateIds.length > 0
@@ -36236,6 +36495,7 @@ export async function claimSessionWorkForAttempt(
36236
36495
  },
36237
36496
  ),
36238
36497
  ...initiatorColumns(compactionInitiator),
36498
+ personalConnectionDelegations: [],
36239
36499
  startedAt: now,
36240
36500
  })
36241
36501
  .returning();
@@ -36383,6 +36643,12 @@ export async function claimSessionWorkForAttempt(
36383
36643
  },
36384
36644
  });
36385
36645
  let internalInitiator: FrozenTurnInitiator;
36646
+ const authorityUpdate = delivered.updates[0];
36647
+ if (!authorityUpdate) throw new Error("Delivered update batch has no authority source");
36648
+ const internalPersonalConnectionDelegations = parsedPersonalConnectionDelegations(
36649
+ authorityUpdate.personalConnectionDelegations,
36650
+ `session_system_updates:${workspaceId}:${sessionId}:${authorityUpdate.id}`,
36651
+ );
36386
36652
  // Agent Steer is the causal command for this inference. Ordinary
36387
36653
  // machine notices may coalesce into the same batch as context, but
36388
36654
  // their timing must not erase the steering subject's authority.
@@ -36544,6 +36810,7 @@ export async function claimSessionWorkForAttempt(
36544
36810
  { id: input.dispatchId, generation: 1, triggerEventId },
36545
36811
  ),
36546
36812
  ...initiatorColumns(internalInitiator),
36813
+ personalConnectionDelegations: internalPersonalConnectionDelegations,
36547
36814
  startedAt: now,
36548
36815
  })
36549
36816
  .returning();
@@ -37877,6 +38144,14 @@ export async function settleSessionIdleWithParentOutbox(
37877
38144
  } as const;
37878
38145
  }
37879
38146
  const dedupeKey = `child-completion:${session.id}:${episodeKey}`;
38147
+ const personalConnectionDelegations = session.parentTurnId
38148
+ ? await personalConnectionDelegationsForTurnInTransaction(
38149
+ tx as unknown as Database,
38150
+ workspaceId,
38151
+ session.parentSessionId,
38152
+ session.parentTurnId,
38153
+ )
38154
+ : [];
37880
38155
  await tx
37881
38156
  .insert(schema.sessionSystemUpdateOutbox)
37882
38157
  .values({
@@ -37897,7 +38172,9 @@ export async function settleSessionIdleWithParentOutbox(
37897
38172
  lineage: {
37898
38173
  childSessionId: session.id,
37899
38174
  parentSessionId: session.parentSessionId,
38175
+ ...(session.parentTurnId ? { parentTurnId: session.parentTurnId } : {}),
37900
38176
  },
38177
+ personalConnectionDelegations,
37901
38178
  })
37902
38179
  .onConflictDoNothing({
37903
38180
  target: [
@@ -39982,6 +40259,16 @@ export async function getSessionQueueSnapshot(
39982
40259
  .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)))
39983
40260
  .limit(1);
39984
40261
  if (!session) return null;
40262
+ const activePersonalConnections = session.activeTurnId
40263
+ ? (
40264
+ await personalConnectionDelegationsForTurnInTransaction(
40265
+ scopedDb,
40266
+ workspaceId,
40267
+ sessionId,
40268
+ session.activeTurnId,
40269
+ )
40270
+ ).map(({ serverId, providerDomain }) => ({ serverId, providerDomain }))
40271
+ : [];
39985
40272
  const rows = await scopedDb
39986
40273
  .select()
39987
40274
  .from(schema.sessionTurns)
@@ -40025,6 +40312,7 @@ export async function getSessionQueueSnapshot(
40025
40312
  return {
40026
40313
  version: session.queueVersion,
40027
40314
  effectiveControl: serializeEffectiveSessionControl(effectiveControl),
40315
+ activePersonalConnections,
40028
40316
  stoppingPreviousAttempt:
40029
40317
  latestInterruption !== null &&
40030
40318
  latestInterruption.interruptionState !== "rejected_stale" &&
@@ -40073,11 +40361,19 @@ function queuedSteerReplacementAttemptId(metadata: Record<string, unknown>): str
40073
40361
  async function enqueueFailedChildOutboxForTurnTx(
40074
40362
  tx: Database,
40075
40363
  workspaceId: string,
40076
- session: Pick<typeof schema.sessions.$inferSelect, "id" | "parentSessionId">,
40364
+ session: Pick<typeof schema.sessions.$inferSelect, "id" | "parentSessionId" | "parentTurnId">,
40077
40365
  turn: Pick<typeof schema.sessionTurns.$inferSelect, "id" | "accountId" | "sessionId">,
40078
40366
  ): Promise<void> {
40079
40367
  if (!session.parentSessionId) return;
40080
40368
  const dedupeKey = `child-completion:${turn.sessionId}:turn:${turn.id}`;
40369
+ const personalConnectionDelegations = session.parentTurnId
40370
+ ? await personalConnectionDelegationsForTurnInTransaction(
40371
+ tx,
40372
+ workspaceId,
40373
+ session.parentSessionId,
40374
+ session.parentTurnId,
40375
+ )
40376
+ : [];
40081
40377
  await tx
40082
40378
  .insert(schema.sessionSystemUpdateOutbox)
40083
40379
  .values({
@@ -40099,8 +40395,10 @@ async function enqueueFailedChildOutboxForTurnTx(
40099
40395
  lineage: {
40100
40396
  childSessionId: turn.sessionId,
40101
40397
  parentSessionId: session.parentSessionId,
40398
+ ...(session.parentTurnId ? { parentTurnId: session.parentTurnId } : {}),
40102
40399
  turnId: turn.id,
40103
40400
  },
40401
+ personalConnectionDelegations,
40104
40402
  })
40105
40403
  .onConflictDoNothing({
40106
40404
  target: [
@@ -40137,6 +40435,7 @@ export type SessionSystemUpdateOutboxDelivery = {
40137
40435
  summary: string;
40138
40436
  payload: ChildTerminalResultPayload;
40139
40437
  lineage: Record<string, unknown>;
40438
+ personalConnectionDelegations: McpPersonalConnectionDelegation[];
40140
40439
  };
40141
40440
 
40142
40441
  function mapSystemUpdateOutboxRow(row: {
@@ -40152,6 +40451,7 @@ function mapSystemUpdateOutboxRow(row: {
40152
40451
  summary: string;
40153
40452
  payload: Record<string, unknown>;
40154
40453
  lineage: Record<string, unknown>;
40454
+ personal_connection_delegations: unknown;
40155
40455
  }): SessionSystemUpdateOutboxDelivery {
40156
40456
  if (row.kind !== "child_terminal_result") {
40157
40457
  throw new Error(`System-update outbox contains retired kind ${row.kind}`);
@@ -40170,6 +40470,10 @@ function mapSystemUpdateOutboxRow(row: {
40170
40470
  summary: row.summary,
40171
40471
  payload: parseChildTerminalResultPayload(row.payload),
40172
40472
  lineage: row.lineage,
40473
+ personalConnectionDelegations: parsedPersonalConnectionDelegations(
40474
+ row.personal_connection_delegations,
40475
+ `session_system_update_outbox:${row.workspace_id}:${row.id}`,
40476
+ ),
40173
40477
  };
40174
40478
  }
40175
40479
 
@@ -40214,6 +40518,10 @@ export async function getSessionSystemUpdateOutboxByDedupeKey(
40214
40518
  summary: row.summary,
40215
40519
  payload: parseChildTerminalResultPayload(row.payload),
40216
40520
  lineage: row.lineage,
40521
+ personalConnectionDelegations: parsedPersonalConnectionDelegations(
40522
+ row.personalConnectionDelegations,
40523
+ `session_system_update_outbox:${row.workspaceId}:${row.id}`,
40524
+ ),
40217
40525
  };
40218
40526
  },
40219
40527
  );
@@ -40236,6 +40544,7 @@ export async function claimPendingSessionSystemUpdateOutbox(
40236
40544
  summary: string;
40237
40545
  payload: Record<string, unknown>;
40238
40546
  lineage: Record<string, unknown>;
40547
+ personal_connection_delegations: unknown;
40239
40548
  }>(db, sql`select * from opengeni_private.claim_session_system_update_outbox(${limit})`);
40240
40549
  return rows.map(mapSystemUpdateOutboxRow);
40241
40550
  }
@@ -40586,6 +40895,7 @@ export async function getOrCreateSessionSystemUpdateOutbox(
40586
40895
  summary: input.summary,
40587
40896
  payload: input.payload,
40588
40897
  lineage: input.lineage,
40898
+ personalConnectionDelegations: input.personalConnectionDelegations,
40589
40899
  })
40590
40900
  .onConflictDoUpdate({
40591
40901
  target: [
@@ -40618,6 +40928,10 @@ export async function getOrCreateSessionSystemUpdateOutbox(
40618
40928
  summary: row.summary,
40619
40929
  payload: parseChildTerminalResultPayload(row.payload),
40620
40930
  lineage: row.lineage,
40931
+ personalConnectionDelegations: parsedPersonalConnectionDelegations(
40932
+ row.personalConnectionDelegations,
40933
+ `session_system_update_outbox:${row.workspaceId}:${row.id}`,
40934
+ ),
40621
40935
  };
40622
40936
  });
40623
40937
  }
@@ -40699,6 +41013,7 @@ export type AddSessionSystemUpdateInput = {
40699
41013
  dedupeKey: string;
40700
41014
  summary: string;
40701
41015
  lineage?: Record<string, unknown>;
41016
+ personalConnectionDelegations?: McpPersonalConnectionDelegation[];
40702
41017
  } & SessionSystemUpdateInputVariant;
40703
41018
 
40704
41019
  export type AddSessionSystemUpdateResult =
@@ -40775,6 +41090,7 @@ export async function addSessionSystemUpdateWithSourceMutation(
40775
41090
  summary: input.summary,
40776
41091
  payload: input.payload,
40777
41092
  lineage: input.lineage ?? {},
41093
+ personalConnectionDelegations: input.personalConnectionDelegations ?? [],
40778
41094
  state: "pending",
40779
41095
  })
40780
41096
  .onConflictDoNothing({
@@ -41933,6 +42249,10 @@ function mapSessionTurn(row: typeof schema.sessionTurns.$inferSelect): SessionTu
41933
42249
  row.initiatorContext ?? {},
41934
42250
  ),
41935
42251
  initiatorContext: row.initiatorContext ?? {},
42252
+ personalConnections: parsedPersonalConnectionDelegations(
42253
+ row.personalConnectionDelegations,
42254
+ `session_turns:${row.workspaceId}:${row.sessionId}:${row.id}`,
42255
+ ).map(({ serverId, providerDomain }) => ({ serverId, providerDomain })),
41936
42256
  cancelledBy: row.cancelledBy,
41937
42257
  cancelReason: row.cancelReason,
41938
42258
  startedAt: row.startedAt ? row.startedAt.toISOString() : null,
@@ -41948,6 +42268,10 @@ function mapSessionTurnForExecution(
41948
42268
  return {
41949
42269
  ...mapSessionTurn(row),
41950
42270
  turnInstructions: row.turnInstructions ?? null,
42271
+ personalConnectionDelegations: parsedPersonalConnectionDelegations(
42272
+ row.personalConnectionDelegations,
42273
+ `session_turns:${row.workspaceId}:${row.sessionId}:${row.id}`,
42274
+ ),
41951
42275
  };
41952
42276
  }
41953
42277
 
@@ -42011,6 +42335,16 @@ function mapScheduledTask(row: typeof schema.scheduledTasks.$inferSelect): Sched
42011
42335
  runMode: row.runMode as ScheduledTaskRunMode,
42012
42336
  overlapPolicy: row.overlapPolicy as ScheduledTaskOverlapPolicy,
42013
42337
  agentConfig: row.agentConfig as ScheduledTaskAgentConfig,
42338
+ createdBy: initiatorFromStorage(
42339
+ row.createdByKind,
42340
+ row.createdBySubjectId,
42341
+ row.createdByContext as TurnInitiatorContext,
42342
+ ),
42343
+ createdByContext: row.createdByContext as TurnInitiatorContext,
42344
+ personalConnections: parsedPersonalConnectionDelegations(
42345
+ row.personalConnectionDelegations,
42346
+ `scheduled_tasks:${row.workspaceId}:${row.id}`,
42347
+ ).map(({ serverId, providerDomain }) => ({ serverId, providerDomain })),
42014
42348
  reusableSessionId: row.reusableSessionId,
42015
42349
  variableSetId: row.variableSetId,
42016
42350
  environmentId: row.variableSetId,