@opengeni/db 0.18.1 → 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.
Files changed (35) hide show
  1. package/dist/chunk-NK2A36KP.js +5822 -0
  2. package/dist/chunk-NK2A36KP.js.map +1 -0
  3. package/dist/{chunk-T6RSJT6C.js → chunk-OTJHD33E.js} +109 -1
  4. package/dist/chunk-OTJHD33E.js.map +1 -0
  5. package/dist/index.d.ts +25 -1
  6. package/dist/index.js +5761 -2827
  7. package/dist/index.js.map +1 -1
  8. package/dist/memory-domain.d.ts +110 -1
  9. package/dist/memory-governance-schema.d.ts +562 -0
  10. package/dist/memory-governance.d.ts +41 -0
  11. package/dist/provision-roles.js +1 -1
  12. package/dist/runtime-posture.d.ts +3 -3
  13. package/dist/schema.d.ts +425 -0
  14. package/dist/schema.js +37 -1
  15. package/dist/scoped-knowledge-schema.d.ts +5341 -0
  16. package/dist/scoped-knowledge.d.ts +208 -0
  17. package/dist/session-queue-commands.d.ts +2 -1
  18. package/drizzle/0152_hierarchical_memory_foundation.sql +1589 -0
  19. package/drizzle/0153_mcp_personal_connection_delegations.sql +181 -0
  20. package/drizzle/0154_scoped_knowledge_foundation.sql +2292 -0
  21. package/package.json +3 -3
  22. package/src/connection-token-resolver.ts +3 -0
  23. package/src/index.ts +351 -12
  24. package/src/memory-domain.ts +360 -1
  25. package/src/memory-governance-schema.ts +162 -0
  26. package/src/memory-governance.ts +317 -0
  27. package/src/provision-roles.ts +72 -0
  28. package/src/runtime-posture.ts +36 -0
  29. package/src/schema.ts +87 -4
  30. package/src/scoped-knowledge-schema.ts +603 -0
  31. package/src/scoped-knowledge.ts +2891 -0
  32. package/src/session-queue-commands.ts +48 -0
  33. package/dist/chunk-T6RSJT6C.js.map +0 -1
  34. package/dist/chunk-YKWJ7QJ2.js +0 -5000
  35. package/dist/chunk-YKWJ7QJ2.js.map +0 -1
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,
@@ -238,6 +241,8 @@ export * from "./session-queue-commands";
238
241
  export * from "./new-session-drafts";
239
242
  export * from "./workspace-instruction-policies";
240
243
  export * from "./preference-registry";
244
+ export * from "./memory-governance";
245
+ export * from "./scoped-knowledge";
241
246
  export { interruptedToolCallResult } from "./session-tool-call-settlement";
242
247
  export { decryptEnvironmentValue, encryptEnvironmentValue } from "./environment-crypto";
243
248
  export {
@@ -285,6 +290,17 @@ export * from "./memory-domain";
285
290
  // `userLookup` is the injection seam for hosts on a different driver.
286
291
  // `PostgresJsDatabase<typeof schema>` is assignable to this, so standalone is
287
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
+
288
304
  export type Database = PgDatabase<any, typeof schema>;
289
305
 
290
306
  /** Raised when a durable session tool-policy write lost its version fence. */
@@ -3295,6 +3311,10 @@ export type CreateScheduledTaskInput = {
3295
3311
  runMode: ScheduledTaskRunMode;
3296
3312
  overlapPolicy: ScheduledTaskOverlapPolicy;
3297
3313
  agentConfig: ScheduledTaskAgentConfig;
3314
+ createdBy?: TurnInitiator;
3315
+ createdByContext?: TurnInitiatorContext;
3316
+ createdByActor?: AgentSessionCreationActor | null;
3317
+ personalConnectionDelegations?: McpPersonalConnectionDelegation[];
3298
3318
  variableSetId?: string | null;
3299
3319
  // The rig each run binds to (M3); active version resolved per fire at dispatch.
3300
3320
  rigId?: string | null;
@@ -3308,6 +3328,7 @@ export type UpdateScheduledTaskInput = Partial<{
3308
3328
  runMode: ScheduledTaskRunMode;
3309
3329
  overlapPolicy: ScheduledTaskOverlapPolicy;
3310
3330
  agentConfig: ScheduledTaskAgentConfig;
3331
+ personalConnectionDelegations: McpPersonalConnectionDelegation[];
3311
3332
  reusableSessionId: string | null;
3312
3333
  variableSetId: string | null;
3313
3334
  rigId: string | null;
@@ -3731,6 +3752,7 @@ export type EnqueueSessionTurnInput = {
3731
3752
  lineage?: Record<string, unknown>;
3732
3753
  initiator: TurnInitiator;
3733
3754
  initiatorContext?: TurnInitiatorContext;
3755
+ personalConnectionDelegations?: McpPersonalConnectionDelegation[];
3734
3756
  /** Steer inserts before all waiting prompts; Send appends after them. */
3735
3757
  placement?: "head" | "tail";
3736
3758
  };
@@ -3741,6 +3763,7 @@ export type EnqueueSessionTurnInput = {
3741
3763
  */
3742
3764
  export type SessionTurnForExecution = SessionTurn & {
3743
3765
  turnInstructions: string | null;
3766
+ personalConnectionDelegations: McpPersonalConnectionDelegation[];
3744
3767
  };
3745
3768
 
3746
3769
  export async function createFileUpload(
@@ -7143,7 +7166,9 @@ export async function loadConnectionCredentialForBroker(
7143
7166
  if (input.connectionId) {
7144
7167
  conditions.push(eq(schema.connections.id, input.connectionId));
7145
7168
  } else {
7146
- conditions.push(eq(schema.connections.providerDomain, input.providerDomain));
7169
+ conditions.push(
7170
+ sql`lower(${schema.connections.providerDomain}) = lower(${input.providerDomain})`,
7171
+ );
7147
7172
  if (input.kind) {
7148
7173
  conditions.push(eq(schema.connections.kind, input.kind));
7149
7174
  }
@@ -7173,6 +7198,8 @@ export async function loadConnectionCredentialForBroker(
7173
7198
  : [
7174
7199
  desc(sql`(${schema.connections.status} = 'active')`),
7175
7200
  desc(schema.connections.updatedAt),
7201
+ desc(schema.connections.createdAt),
7202
+ desc(schema.connections.id),
7176
7203
  ]),
7177
7204
  )
7178
7205
  .limit(1);
@@ -7888,7 +7915,10 @@ function memoryVectorLiteral(values: number[]): string {
7888
7915
  }
7889
7916
 
7890
7917
  const agentVisibleMemoryStatuses = [...AGENT_VISIBLE_MEMORY_STATUSES];
7891
- const visibleTextHashUniqueIndexName = "knowledge_memories_workspace_visible_text_hash_uq";
7918
+ const visibleTextHashUniqueIndexNames = new Set([
7919
+ "knowledge_memories_workspace_visible_text_hash_uq",
7920
+ "knowledge_memories_scope_visible_text_hash_uq",
7921
+ ]);
7892
7922
 
7893
7923
  function isVisibleTextHashUniqueViolation(error: unknown): boolean {
7894
7924
  const candidate = error as {
@@ -7902,14 +7932,15 @@ function isVisibleTextHashUniqueViolation(error: unknown): boolean {
7902
7932
  return false;
7903
7933
  }
7904
7934
  const constraint = candidate.constraint ?? candidate.constraint_name;
7905
- if (candidate.code === "23505" && constraint === visibleTextHashUniqueIndexName) {
7935
+ if (candidate.code === "23505" && visibleTextHashUniqueIndexNames.has(String(constraint))) {
7906
7936
  return true;
7907
7937
  }
7938
+ const message = typeof candidate.message === "string" ? candidate.message : null;
7908
7939
  if (
7909
- typeof candidate.message === "string" &&
7910
- candidate.message.includes(visibleTextHashUniqueIndexName) &&
7940
+ message !== null &&
7941
+ [...visibleTextHashUniqueIndexNames].some((name) => message.includes(name)) &&
7911
7942
  (candidate.code === "23505" ||
7912
- candidate.message.includes("duplicate key value violates unique constraint"))
7943
+ message.includes("duplicate key value violates unique constraint"))
7913
7944
  ) {
7914
7945
  return true;
7915
7946
  }
@@ -9013,7 +9044,27 @@ export async function createScheduledTask(
9013
9044
  db,
9014
9045
  { accountId: input.accountId, workspaceId: input.workspaceId },
9015
9046
  async (scopedDb) => {
9016
- 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();
9017
9068
  if (!row) {
9018
9069
  throw new Error("Failed to create scheduled task");
9019
9070
  }
@@ -9038,6 +9089,9 @@ export async function updateScheduledTask(
9038
9089
  ...(input.runMode !== undefined ? { runMode: input.runMode } : {}),
9039
9090
  ...(input.overlapPolicy !== undefined ? { overlapPolicy: input.overlapPolicy } : {}),
9040
9091
  ...(input.agentConfig !== undefined ? { agentConfig: input.agentConfig } : {}),
9092
+ ...(input.personalConnectionDelegations !== undefined
9093
+ ? { personalConnectionDelegations: input.personalConnectionDelegations }
9094
+ : {}),
9041
9095
  ...(input.reusableSessionId !== undefined
9042
9096
  ? { reusableSessionId: input.reusableSessionId }
9043
9097
  : {}),
@@ -9080,6 +9134,31 @@ export async function getScheduledTask(
9080
9134
  });
9081
9135
  }
9082
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
+
9083
9162
  export async function requireScheduledTask(
9084
9163
  db: Database,
9085
9164
  workspaceId: string,
@@ -15754,6 +15833,7 @@ export type SessionCreateInput = {
15754
15833
  sandboxGroupId?: string | null;
15755
15834
  sandboxOs?: SandboxOs;
15756
15835
  mcpServers?: CreateSessionMcpServerInput[];
15836
+ personalConnectionDelegations?: McpPersonalConnectionDelegation[];
15757
15837
  maxNestedAgentDepthOverride?: number | null;
15758
15838
  allowNestedAgentDepthIncrease?: boolean;
15759
15839
  subjectId?: string | null;
@@ -16126,6 +16206,11 @@ async function createSessionInTransaction(
16126
16206
 
16127
16207
  // Do not run mutable creator validation before keyed denial replay above.
16128
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;
16129
16214
  const [inserted] = await tx
16130
16215
  .insert(schema.sessions)
16131
16216
  .values({
@@ -16152,8 +16237,10 @@ async function createSessionInTransaction(
16152
16237
  rigVersionId: input.rigVersionId ?? null,
16153
16238
  firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,
16154
16239
  firstPartyMcpTools: input.firstPartyMcpTools ?? [...DEFAULT_FIRST_PARTY_MCP_TOOLS],
16240
+ initialPersonalConnectionDelegations: input.personalConnectionDelegations ?? [],
16155
16241
  instructions: input.instructions ?? null,
16156
16242
  parentSessionId: input.parentSessionId ?? null,
16243
+ parentTurnId,
16157
16244
  createIdempotencyKey,
16158
16245
  rootSessionId: decision.rootSessionId,
16159
16246
  nestedAgentDepth: decision.nestedAgentDepth,
@@ -16324,6 +16411,76 @@ export async function getSession(
16324
16411
  });
16325
16412
  }
16326
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
+
16327
16484
  export async function getSessionSpawnDenial(
16328
16485
  db: Database,
16329
16486
  workspaceId: string,
@@ -17687,6 +17844,56 @@ export async function listSessions(
17687
17844
  });
17688
17845
  }
17689
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
+
17690
17897
  export type SessionDiscoveryOrderBy = "createdAt" | "updatedAt";
17691
17898
  export type SessionDiscoveryCursor = {
17692
17899
  orderBy: SessionDiscoveryOrderBy;
@@ -34807,6 +35014,32 @@ export async function materializeGoalContinuation(
34807
35014
  return { action: "paused", events: [mapEvent(event)] } as const;
34808
35015
  }
34809
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
+
34810
35043
  const prompt = input.prompt(decision.goal, decision.autoContinuation, decision.cap);
34811
35044
  const payload = {
34812
35045
  type: "goal_continuation" as const,
@@ -34836,7 +35069,12 @@ export async function materializeGoalContinuation(
34836
35069
  dedupeKey: `goal-continuation:${decision.goal.id}:wake:${goalWakeRevision}`,
34837
35070
  summary: prompt,
34838
35071
  payload,
34839
- lineage: { goalId: decision.goal.id, goalWakeRevision },
35072
+ lineage: {
35073
+ goalId: decision.goal.id,
35074
+ goalWakeRevision,
35075
+ ...(causalTurn ? { causalTurnId: causalTurn.id } : {}),
35076
+ },
35077
+ personalConnectionDelegations,
34840
35078
  state: "pending",
34841
35079
  })
34842
35080
  .returning();
@@ -35190,6 +35428,10 @@ export async function initializeSessionStartAtomically(
35190
35428
  : {},
35191
35429
  lineage: {},
35192
35430
  ...initiatorColumns(creator),
35431
+ personalConnectionDelegations: parsedPersonalConnectionDelegations(
35432
+ session.initialPersonalConnectionDelegations,
35433
+ `sessions:${session.workspaceId}:${session.id}:initial`,
35434
+ ),
35193
35435
  })
35194
35436
  .returning();
35195
35437
  if (!turn) throw new Error("Failed to create initial session turn");
@@ -35350,6 +35592,7 @@ export async function enqueueSessionTurn(
35350
35592
  initiator: input.initiator,
35351
35593
  context: input.initiatorContext ?? {},
35352
35594
  }),
35595
+ personalConnectionDelegations: input.personalConnectionDelegations ?? [],
35353
35596
  })
35354
35597
  .returning();
35355
35598
  if (!row) {
@@ -35387,7 +35630,14 @@ const MAX_INTERNAL_UPDATE_EVENT_SOURCE_BYTES = 256;
35387
35630
 
35388
35631
  type BoundedSystemUpdate = Pick<
35389
35632
  typeof schema.sessionSystemUpdates.$inferSelect,
35390
- "id" | "kind" | "classification" | "sourceId" | "summary" | "payload" | "lineage"
35633
+ | "id"
35634
+ | "kind"
35635
+ | "classification"
35636
+ | "sourceId"
35637
+ | "summary"
35638
+ | "payload"
35639
+ | "lineage"
35640
+ | "personalConnectionDelegations"
35391
35641
  >;
35392
35642
 
35393
35643
  function boundedInternalUpdateEventText(
@@ -35426,10 +35676,14 @@ function internalUpdateEventMember(update: BoundedSystemUpdate) {
35426
35676
  };
35427
35677
  }
35428
35678
 
35429
- 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[] {
35430
35683
  const selected: T[] = [];
35431
35684
  let selectedBytes = 0;
35432
35685
  for (const update of updates) {
35686
+ if (selected[0] && !canCoalesce(selected[0], update)) break;
35433
35687
  const updateBytes = Buffer.byteLength(
35434
35688
  JSON.stringify({
35435
35689
  id: update.id,
@@ -35589,7 +35843,17 @@ export async function claimSessionWorkForAttempt(
35589
35843
  }
35590
35844
  validUpdates.push(update);
35591
35845
  }
35592
- 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
+ );
35593
35857
  if (deliverable.length === 0) {
35594
35858
  const cancellationEvent =
35595
35859
  cancelledUpdateIds.length > 0
@@ -36231,6 +36495,7 @@ export async function claimSessionWorkForAttempt(
36231
36495
  },
36232
36496
  ),
36233
36497
  ...initiatorColumns(compactionInitiator),
36498
+ personalConnectionDelegations: [],
36234
36499
  startedAt: now,
36235
36500
  })
36236
36501
  .returning();
@@ -36378,6 +36643,12 @@ export async function claimSessionWorkForAttempt(
36378
36643
  },
36379
36644
  });
36380
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
+ );
36381
36652
  // Agent Steer is the causal command for this inference. Ordinary
36382
36653
  // machine notices may coalesce into the same batch as context, but
36383
36654
  // their timing must not erase the steering subject's authority.
@@ -36539,6 +36810,7 @@ export async function claimSessionWorkForAttempt(
36539
36810
  { id: input.dispatchId, generation: 1, triggerEventId },
36540
36811
  ),
36541
36812
  ...initiatorColumns(internalInitiator),
36813
+ personalConnectionDelegations: internalPersonalConnectionDelegations,
36542
36814
  startedAt: now,
36543
36815
  })
36544
36816
  .returning();
@@ -37872,6 +38144,14 @@ export async function settleSessionIdleWithParentOutbox(
37872
38144
  } as const;
37873
38145
  }
37874
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
+ : [];
37875
38155
  await tx
37876
38156
  .insert(schema.sessionSystemUpdateOutbox)
37877
38157
  .values({
@@ -37892,7 +38172,9 @@ export async function settleSessionIdleWithParentOutbox(
37892
38172
  lineage: {
37893
38173
  childSessionId: session.id,
37894
38174
  parentSessionId: session.parentSessionId,
38175
+ ...(session.parentTurnId ? { parentTurnId: session.parentTurnId } : {}),
37895
38176
  },
38177
+ personalConnectionDelegations,
37896
38178
  })
37897
38179
  .onConflictDoNothing({
37898
38180
  target: [
@@ -39977,6 +40259,16 @@ export async function getSessionQueueSnapshot(
39977
40259
  .where(and(eq(schema.sessions.workspaceId, workspaceId), eq(schema.sessions.id, sessionId)))
39978
40260
  .limit(1);
39979
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
+ : [];
39980
40272
  const rows = await scopedDb
39981
40273
  .select()
39982
40274
  .from(schema.sessionTurns)
@@ -40020,6 +40312,7 @@ export async function getSessionQueueSnapshot(
40020
40312
  return {
40021
40313
  version: session.queueVersion,
40022
40314
  effectiveControl: serializeEffectiveSessionControl(effectiveControl),
40315
+ activePersonalConnections,
40023
40316
  stoppingPreviousAttempt:
40024
40317
  latestInterruption !== null &&
40025
40318
  latestInterruption.interruptionState !== "rejected_stale" &&
@@ -40068,11 +40361,19 @@ function queuedSteerReplacementAttemptId(metadata: Record<string, unknown>): str
40068
40361
  async function enqueueFailedChildOutboxForTurnTx(
40069
40362
  tx: Database,
40070
40363
  workspaceId: string,
40071
- session: Pick<typeof schema.sessions.$inferSelect, "id" | "parentSessionId">,
40364
+ session: Pick<typeof schema.sessions.$inferSelect, "id" | "parentSessionId" | "parentTurnId">,
40072
40365
  turn: Pick<typeof schema.sessionTurns.$inferSelect, "id" | "accountId" | "sessionId">,
40073
40366
  ): Promise<void> {
40074
40367
  if (!session.parentSessionId) return;
40075
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
+ : [];
40076
40377
  await tx
40077
40378
  .insert(schema.sessionSystemUpdateOutbox)
40078
40379
  .values({
@@ -40094,8 +40395,10 @@ async function enqueueFailedChildOutboxForTurnTx(
40094
40395
  lineage: {
40095
40396
  childSessionId: turn.sessionId,
40096
40397
  parentSessionId: session.parentSessionId,
40398
+ ...(session.parentTurnId ? { parentTurnId: session.parentTurnId } : {}),
40097
40399
  turnId: turn.id,
40098
40400
  },
40401
+ personalConnectionDelegations,
40099
40402
  })
40100
40403
  .onConflictDoNothing({
40101
40404
  target: [
@@ -40132,6 +40435,7 @@ export type SessionSystemUpdateOutboxDelivery = {
40132
40435
  summary: string;
40133
40436
  payload: ChildTerminalResultPayload;
40134
40437
  lineage: Record<string, unknown>;
40438
+ personalConnectionDelegations: McpPersonalConnectionDelegation[];
40135
40439
  };
40136
40440
 
40137
40441
  function mapSystemUpdateOutboxRow(row: {
@@ -40147,6 +40451,7 @@ function mapSystemUpdateOutboxRow(row: {
40147
40451
  summary: string;
40148
40452
  payload: Record<string, unknown>;
40149
40453
  lineage: Record<string, unknown>;
40454
+ personal_connection_delegations: unknown;
40150
40455
  }): SessionSystemUpdateOutboxDelivery {
40151
40456
  if (row.kind !== "child_terminal_result") {
40152
40457
  throw new Error(`System-update outbox contains retired kind ${row.kind}`);
@@ -40165,6 +40470,10 @@ function mapSystemUpdateOutboxRow(row: {
40165
40470
  summary: row.summary,
40166
40471
  payload: parseChildTerminalResultPayload(row.payload),
40167
40472
  lineage: row.lineage,
40473
+ personalConnectionDelegations: parsedPersonalConnectionDelegations(
40474
+ row.personal_connection_delegations,
40475
+ `session_system_update_outbox:${row.workspace_id}:${row.id}`,
40476
+ ),
40168
40477
  };
40169
40478
  }
40170
40479
 
@@ -40209,6 +40518,10 @@ export async function getSessionSystemUpdateOutboxByDedupeKey(
40209
40518
  summary: row.summary,
40210
40519
  payload: parseChildTerminalResultPayload(row.payload),
40211
40520
  lineage: row.lineage,
40521
+ personalConnectionDelegations: parsedPersonalConnectionDelegations(
40522
+ row.personalConnectionDelegations,
40523
+ `session_system_update_outbox:${row.workspaceId}:${row.id}`,
40524
+ ),
40212
40525
  };
40213
40526
  },
40214
40527
  );
@@ -40231,6 +40544,7 @@ export async function claimPendingSessionSystemUpdateOutbox(
40231
40544
  summary: string;
40232
40545
  payload: Record<string, unknown>;
40233
40546
  lineage: Record<string, unknown>;
40547
+ personal_connection_delegations: unknown;
40234
40548
  }>(db, sql`select * from opengeni_private.claim_session_system_update_outbox(${limit})`);
40235
40549
  return rows.map(mapSystemUpdateOutboxRow);
40236
40550
  }
@@ -40581,6 +40895,7 @@ export async function getOrCreateSessionSystemUpdateOutbox(
40581
40895
  summary: input.summary,
40582
40896
  payload: input.payload,
40583
40897
  lineage: input.lineage,
40898
+ personalConnectionDelegations: input.personalConnectionDelegations,
40584
40899
  })
40585
40900
  .onConflictDoUpdate({
40586
40901
  target: [
@@ -40613,6 +40928,10 @@ export async function getOrCreateSessionSystemUpdateOutbox(
40613
40928
  summary: row.summary,
40614
40929
  payload: parseChildTerminalResultPayload(row.payload),
40615
40930
  lineage: row.lineage,
40931
+ personalConnectionDelegations: parsedPersonalConnectionDelegations(
40932
+ row.personalConnectionDelegations,
40933
+ `session_system_update_outbox:${row.workspaceId}:${row.id}`,
40934
+ ),
40616
40935
  };
40617
40936
  });
40618
40937
  }
@@ -40694,6 +41013,7 @@ export type AddSessionSystemUpdateInput = {
40694
41013
  dedupeKey: string;
40695
41014
  summary: string;
40696
41015
  lineage?: Record<string, unknown>;
41016
+ personalConnectionDelegations?: McpPersonalConnectionDelegation[];
40697
41017
  } & SessionSystemUpdateInputVariant;
40698
41018
 
40699
41019
  export type AddSessionSystemUpdateResult =
@@ -40770,6 +41090,7 @@ export async function addSessionSystemUpdateWithSourceMutation(
40770
41090
  summary: input.summary,
40771
41091
  payload: input.payload,
40772
41092
  lineage: input.lineage ?? {},
41093
+ personalConnectionDelegations: input.personalConnectionDelegations ?? [],
40773
41094
  state: "pending",
40774
41095
  })
40775
41096
  .onConflictDoNothing({
@@ -41928,6 +42249,10 @@ function mapSessionTurn(row: typeof schema.sessionTurns.$inferSelect): SessionTu
41928
42249
  row.initiatorContext ?? {},
41929
42250
  ),
41930
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 })),
41931
42256
  cancelledBy: row.cancelledBy,
41932
42257
  cancelReason: row.cancelReason,
41933
42258
  startedAt: row.startedAt ? row.startedAt.toISOString() : null,
@@ -41943,6 +42268,10 @@ function mapSessionTurnForExecution(
41943
42268
  return {
41944
42269
  ...mapSessionTurn(row),
41945
42270
  turnInstructions: row.turnInstructions ?? null,
42271
+ personalConnectionDelegations: parsedPersonalConnectionDelegations(
42272
+ row.personalConnectionDelegations,
42273
+ `session_turns:${row.workspaceId}:${row.sessionId}:${row.id}`,
42274
+ ),
41946
42275
  };
41947
42276
  }
41948
42277
 
@@ -42006,6 +42335,16 @@ function mapScheduledTask(row: typeof schema.scheduledTasks.$inferSelect): Sched
42006
42335
  runMode: row.runMode as ScheduledTaskRunMode,
42007
42336
  overlapPolicy: row.overlapPolicy as ScheduledTaskOverlapPolicy,
42008
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 })),
42009
42348
  reusableSessionId: row.reusableSessionId,
42010
42349
  variableSetId: row.variableSetId,
42011
42350
  environmentId: row.variableSetId,