@opengeni/core 3.2.2 → 3.4.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/dist/index.js CHANGED
@@ -140,7 +140,7 @@ import {
140
140
 
141
141
  // src/domain/session-file-access.ts
142
142
  import {
143
- getSessionAuthorityProjection as getSessionAuthorityProjection2,
143
+ getSessionAuthorityProjection,
144
144
  getFilesForSubject,
145
145
  readSessionFileAttachments,
146
146
  withSessionRlsActorContext as withSessionRlsActorContext2
@@ -156,11 +156,9 @@ import {
156
156
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
157
157
  import {
158
158
  currentSessionRlsActorIdentityKey,
159
- getSessionAuthorityProjection,
160
- getSessionAuthorizationTargetProjection,
159
+ currentSiteViewerRlsContext,
161
160
  getSession as getSession2,
162
- getSessionTurnForAttempt,
163
- getSlackInteractionSessionAccessForSession,
161
+ getSessionAuthorizationFacts,
164
162
  withSessionRlsActorContext
165
163
  } from "@opengeni/db";
166
164
 
@@ -395,7 +393,8 @@ function relatedSessionAccessForAgentAttempt(actor, targetSessionId) {
395
393
  function sessionRlsActorForAuthorization(authorization) {
396
394
  return authorization.actor.kind === "agent_attempt" ? {
397
395
  subjectId: authorization.actor.subjectId,
398
- initiatingHumanSubjectId: authorization.actor.initiatingHumanSubjectId
396
+ initiatingHumanSubjectId: authorization.actor.initiatingHumanSubjectId,
397
+ agentRootSessionId: authorization.actor.callerRootSessionId
399
398
  } : { subjectId: authorization.actor.subjectId };
400
399
  }
401
400
  async function withResolvedSessionAuthorization(authorization, fn) {
@@ -403,7 +402,9 @@ async function withResolvedSessionAuthorization(authorization, fn) {
403
402
  }
404
403
  async function requireLiveAgentAttemptAuthorization(db, grant, callerSessionId) {
405
404
  const reads = claimSessionAuthorizationReads();
406
- const { actor } = await resolveSessionAuthorizationActor(db, grant, reads);
405
+ const claims = agentAttemptClaims(grant);
406
+ const facts = claims ? await readSessionAuthorizationFacts(db, grant, claims.callerSessionId, claims, reads) : null;
407
+ const { actor } = resolveSessionAuthorizationActor(grant, claims, facts);
407
408
  if (actor.kind !== "agent_attempt" || actor.callerSessionId !== callerSessionId) {
408
409
  throw new SessionAuthorizationDeniedError("caller_stale");
409
410
  }
@@ -413,19 +414,19 @@ async function requireSessionAuthorization(deps, grant, input) {
413
414
  const reads = claimSessionAuthorizationReads();
414
415
  const port = deps.sessionAuthorization;
415
416
  const isAgentAttempt = grantHasAgentAttemptAuthority(grant);
416
- const slackAccess = await getSlackInteractionSessionAccessForSession(deps.db, {
417
- accountId: grant.accountId,
418
- workspaceId: grant.workspaceId,
419
- sessionId: input.sessionId
420
- });
421
- const authority = await getSessionAuthorityProjection(
422
- deps.db,
423
- grant.workspaceId,
424
- input.sessionId
425
- );
417
+ const claims = agentAttemptClaims(grant);
418
+ const facts = await readSessionAuthorizationFacts(deps.db, grant, input.sessionId, claims, reads);
419
+ const authority = facts.target;
420
+ const slackAccess = authority?.slackAccess ?? null;
426
421
  if (!authority && input.surface !== "core") {
427
422
  throw new SessionAuthorizationDeniedError("not_found");
428
423
  }
424
+ if (authority?.siteAccessRootId) {
425
+ const viewer = currentSiteViewerRlsContext();
426
+ const actor2 = resolveSessionAuthorizationActor(grant, claims, facts).actor;
427
+ const allowed = actor2.kind === "agent_attempt" ? authority.siteOwnerSubjectId !== null && authority.siteOwnerSubjectId === actor2.initiatingHumanSubjectId || actor2.callerRootSessionId === authority.rootSessionId && authority.siteAccessRootId === authority.rootSessionId : authority.siteOwnerSubjectId === actor2.subjectId || actor2.subjectId === `site:${authority.siteId}` && viewer?.siteId === authority.siteId && viewer.principal === authority.siteViewerPrincipal;
428
+ if (!allowed) throw new SessionAuthorizationDeniedError("not_found");
429
+ }
429
430
  const siteOrigin = currentSiteSessionOrigin();
430
431
  if (siteOrigin && authority && !input.operation.endsWith(".read")) {
431
432
  const session = await getSession2(deps.db, grant.workspaceId, input.sessionId);
@@ -436,15 +437,15 @@ async function requireSessionAuthorization(deps, grant, input) {
436
437
  return null;
437
438
  }
438
439
  if (!authority) throw new SessionAuthorizationDeniedError("not_found");
439
- const resolvedActor = await resolveSessionAuthorizationActor(deps.db, grant, reads);
440
- const resolvedTarget = await resolveSessionAuthorizationTarget(
441
- deps.db,
442
- grant,
443
- input.sessionId,
444
- reads
445
- );
440
+ const resolvedActor = resolveSessionAuthorizationActor(grant, claims, facts);
441
+ if (authority.accountId !== grant.accountId) {
442
+ throw new SessionAuthorizationDeniedError("not_found");
443
+ }
446
444
  const actor = resolvedActor.actor;
447
- const target = resolvedTarget.target;
445
+ const target = {
446
+ sessionId: authority.sessionId,
447
+ rootSessionId: authority.rootSessionId
448
+ };
448
449
  const agentRelatedSessionAccess = actor.kind === "agent_attempt" ? relatedSessionAccessForAgentAttempt(actor, target.sessionId) : null;
449
450
  if (actor.kind === "agent_attempt" && input.operation === "session.approval.write") {
450
451
  throw new SessionAuthorizationDeniedError("forbidden");
@@ -515,7 +516,9 @@ async function requireSessionAuthorizationListScope(deps, grant, surface) {
515
516
  const port = deps.sessionAuthorization;
516
517
  const isAgentAttempt = grantHasAgentAttemptAuthority(grant);
517
518
  if (!port && !isAgentAttempt) return null;
518
- const { actor, callerAccess } = await resolveSessionAuthorizationActor(deps.db, grant, reads);
519
+ const claims = agentAttemptClaims(grant);
520
+ const facts = claims ? await readSessionAuthorizationFacts(deps.db, grant, claims.callerSessionId, claims, reads) : null;
521
+ const { actor, callerAccess } = resolveSessionAuthorizationActor(grant, claims, facts);
519
522
  const viewer = actor.kind === "agent_attempt" && callerAccess ? {
520
523
  callerRootSessionId: actor.callerRootSessionId,
521
524
  agentAccess: callerAccess.agentAccess,
@@ -544,27 +547,39 @@ async function requireSessionAuthorizationListScope(deps, grant, surface) {
544
547
  };
545
548
  return viewer ? agentAccessListScopeForViewer(viewer, hostScope) : hostScope;
546
549
  }
547
- async function resolveSessionAuthorizationTarget(db, grant, sessionId, reads) {
548
- const session = await reusableAuthorizationRead(
549
- reads,
550
- db,
551
- ["target-identity", grant.workspaceId, sessionId],
552
- () => getSessionAuthorizationTargetProjection(db, grant.workspaceId, sessionId)
553
- );
554
- if (!session || session.accountId !== grant.accountId) {
555
- throw new SessionAuthorizationDeniedError("not_found");
556
- }
557
- return {
558
- target: { sessionId: session.id, rootSessionId: session.rootSessionId }
559
- };
560
- }
561
- async function resolveSessionAuthorizationActor(db, grant, reads) {
550
+ function agentAttemptClaims(grant) {
551
+ if (!grantHasAgentAttemptAuthority(grant)) return null;
562
552
  const callerSessionId = grant.metadata?.["sessionId"];
563
553
  const turnId = grant.metadata?.["turnId"];
564
554
  const attemptId = grant.metadata?.["attemptId"];
565
555
  const executionGeneration = grant.metadata?.["executionGeneration"];
566
- const isAgentAttempt = grantHasAgentAttemptAuthority(grant);
567
- if (!isAgentAttempt) {
556
+ if (typeof callerSessionId !== "string" || typeof turnId !== "string" || typeof attemptId !== "string" || typeof executionGeneration !== "number" || !Number.isSafeInteger(executionGeneration) || executionGeneration < 1) {
557
+ return null;
558
+ }
559
+ return { callerSessionId, turnId, attemptId, executionGeneration };
560
+ }
561
+ async function readSessionAuthorizationFacts(db, grant, sessionId, claims, reads) {
562
+ return await reusableAuthorizationRead(
563
+ reads,
564
+ db,
565
+ [
566
+ "authorization-facts",
567
+ grant.accountId,
568
+ grant.workspaceId,
569
+ sessionId,
570
+ claims?.callerSessionId ?? "",
571
+ claims?.attemptId ?? ""
572
+ ],
573
+ () => getSessionAuthorizationFacts(db, {
574
+ accountId: grant.accountId,
575
+ workspaceId: grant.workspaceId,
576
+ sessionId,
577
+ caller: claims ? { sessionId: claims.callerSessionId, attemptId: claims.attemptId } : void 0
578
+ })
579
+ );
580
+ }
581
+ function resolveSessionAuthorizationActor(grant, claims, facts) {
582
+ if (!grantHasAgentAttemptAuthority(grant)) {
568
583
  return {
569
584
  actor: SessionAuthorizationActor.parse({
570
585
  kind: "subject",
@@ -575,33 +590,20 @@ async function resolveSessionAuthorizationActor(db, grant, reads) {
575
590
  callerAccess: null
576
591
  };
577
592
  }
578
- if (typeof callerSessionId !== "string" || typeof turnId !== "string" || typeof attemptId !== "string" || typeof executionGeneration !== "number" || !Number.isSafeInteger(executionGeneration) || executionGeneration < 1) {
579
- throw new SessionAuthorizationDeniedError("caller_stale");
580
- }
581
- const callerSession = await reusableAuthorizationRead(
582
- reads,
583
- db,
584
- ["session", grant.workspaceId, callerSessionId],
585
- () => getSession2(db, grant.workspaceId, callerSessionId)
586
- );
587
- const turn = await reusableAuthorizationRead(
588
- reads,
589
- db,
590
- ["turn", grant.workspaceId, callerSessionId, attemptId],
591
- () => getSessionTurnForAttempt(db, grant.workspaceId, callerSessionId, attemptId)
592
- );
593
- if (!callerSession || callerSession.accountId !== grant.accountId || !turn || turn.id !== turnId || turn.executionGeneration !== executionGeneration || callerSession.activeTurnId !== turn.id) {
593
+ const callerSession = facts?.caller?.session ?? null;
594
+ const turn = facts?.caller?.turn ?? null;
595
+ if (!claims || !callerSession || callerSession.accountId !== grant.accountId || !turn || turn.id !== claims.turnId || turn.executionGeneration !== claims.executionGeneration) {
594
596
  throw new SessionAuthorizationDeniedError("caller_stale");
595
597
  }
596
598
  return {
597
599
  actor: SessionAuthorizationActor.parse({
598
600
  kind: "agent_attempt",
599
601
  subjectId: grant.subjectId,
600
- callerSessionId,
602
+ callerSessionId: claims.callerSessionId,
601
603
  callerRootSessionId: callerSession.rootSessionId,
602
- turnId,
603
- attemptId,
604
- executionGeneration,
604
+ turnId: claims.turnId,
605
+ attemptId: claims.attemptId,
606
+ executionGeneration: claims.executionGeneration,
605
607
  initiator: turn.initiator,
606
608
  initiatorContext: turn.initiatorContext,
607
609
  initiatingHumanSubjectId: turn.initiatingHumanSubjectId ?? (turn.initiator.kind === "subject" ? turn.initiator.subjectId : null)
@@ -616,7 +618,7 @@ async function resolveSessionAuthorizationActor(db, grant, reads) {
616
618
 
617
619
  // src/domain/session-file-access.ts
618
620
  async function readSessionAttachmentFiles(deps, grant, sessionId, fileIds) {
619
- const authority = await getSessionAuthorityProjection2(deps.db, grant.workspaceId, sessionId);
621
+ const authority = await getSessionAuthorityProjection(deps.db, grant.workspaceId, sessionId);
620
622
  if (!authority) return [];
621
623
  const authorization = await requireSessionAuthorization(deps, grant, {
622
624
  sessionId,
@@ -1042,6 +1044,7 @@ import {
1042
1044
  getCapabilityCatalogItem,
1043
1045
  getCapabilityInstallation,
1044
1046
  getConnectionMetadata as getConnectionMetadata3,
1047
+ isTransactionHandle,
1045
1048
  readCodexCutoverDisposition,
1046
1049
  resolveSubscriptionCoreCodexAppsDesignation,
1047
1050
  rlsContextForWorkspace,
@@ -1507,6 +1510,21 @@ var maxMcpCredentialHeaders = 16;
1507
1510
  var maxMcpCredentialHeaderValueLength = 4096;
1508
1511
  var mcpCredentialHeaderName = /^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/;
1509
1512
  async function buildCapabilityCatalog(input) {
1513
+ const serial = isTransactionHandle(input.db);
1514
+ const reads = [
1515
+ () => listCapabilityCatalogItems(input.db, input.workspaceId),
1516
+ () => listCapabilityInstallations(input.db, input.workspaceId),
1517
+ () => listSocialConnections(input.db, input.workspaceId, 500, input.subjectId),
1518
+ () => listConnectionsMetadata(input.db, input.workspaceId, null),
1519
+ () => discoverCuratedSkillLibraryItems(),
1520
+ () => listInstalledSkills(input.db, input.workspaceId),
1521
+ () => input.settings.codexConnectedAppsEnabled ? resolveCodexAppsDesignationForRun(
1522
+ input.db,
1523
+ input.workspaceId,
1524
+ input.accountId ? { accountId: input.accountId } : {}
1525
+ ) : Promise.resolve(null),
1526
+ () => listEnabledMcpCapabilityServers(input.db, input.workspaceId)
1527
+ ];
1510
1528
  const [
1511
1529
  persistedItems,
1512
1530
  capabilityInstallations,
@@ -1516,19 +1534,24 @@ async function buildCapabilityCatalog(input) {
1516
1534
  installedSkills,
1517
1535
  codexAppsDesignation,
1518
1536
  runnableMcpServers
1519
- ] = await Promise.all([
1520
- listCapabilityCatalogItems(input.db, input.workspaceId),
1521
- listCapabilityInstallations(input.db, input.workspaceId),
1522
- listSocialConnections(input.db, input.workspaceId, 500, input.subjectId),
1523
- listConnectionsMetadata(input.db, input.workspaceId, null),
1524
- discoverCuratedSkillLibraryItems(),
1525
- listInstalledSkills(input.db, input.workspaceId),
1526
- input.settings.codexConnectedAppsEnabled ? resolveCodexAppsDesignationForRun(
1527
- input.db,
1528
- input.workspaceId,
1529
- input.accountId ? { accountId: input.accountId } : {}
1530
- ) : Promise.resolve(null),
1531
- listEnabledMcpCapabilityServers(input.db, input.workspaceId)
1537
+ ] = serial ? [
1538
+ await reads[0](),
1539
+ await reads[1](),
1540
+ await reads[2](),
1541
+ await reads[3](),
1542
+ await reads[4](),
1543
+ await reads[5](),
1544
+ await reads[6](),
1545
+ await reads[7]()
1546
+ ] : await Promise.all([
1547
+ reads[0](),
1548
+ reads[1](),
1549
+ reads[2](),
1550
+ reads[3](),
1551
+ reads[4](),
1552
+ reads[5](),
1553
+ reads[6](),
1554
+ reads[7]()
1532
1555
  ]);
1533
1556
  const runnableCapabilityIds = new Set(runnableMcpServers.map((server) => server.capabilityId));
1534
1557
  const operatorOAuthClientConfigured = operatorOAuthClientResolver(input.settings);
@@ -4430,6 +4453,7 @@ import {
4430
4453
  listWorkspacesForSubject,
4431
4454
  findActiveApiKeyByHash,
4432
4455
  getWorkspaceGrant,
4456
+ subjectHasLiveWorkspaceAuthorityInScope,
4433
4457
  requireWorkspace,
4434
4458
  resolveNamedManagedPersonalWorkspaceGrant
4435
4459
  } from "@opengeni/db";
@@ -4552,6 +4576,7 @@ var delegatedHumanAuthorizationSchema = z2.object({
4552
4576
  });
4553
4577
  var delegatedHumanRequests = /* @__PURE__ */ new WeakMap();
4554
4578
  var delegatedHumanContexts = /* @__PURE__ */ new WeakMap();
4579
+ var verifiedSiteViewerProofs = /* @__PURE__ */ new WeakSet();
4555
4580
  var delegatedHumanProfileSchema = z2.object({
4556
4581
  id: z2.string(),
4557
4582
  name: z2.string().nullable(),
@@ -4581,6 +4606,27 @@ function stampDelegatedHumanAuthorization(request, input) {
4581
4606
  Object.freeze(proof.permissions);
4582
4607
  delegatedHumanRequests.set(request, Object.freeze(proof));
4583
4608
  }
4609
+ function stampSiteViewerSessionAuthorization(request, input) {
4610
+ if (input.subjectId.startsWith("user:")) {
4611
+ stampDelegatedHumanAuthorization(request, {
4612
+ ...input,
4613
+ workspaceScope: { kind: "selected", workspaceIds: [input.workspaceId] }
4614
+ });
4615
+ return;
4616
+ }
4617
+ if (delegatedHumanRequests.has(request) || accessResolvedRequests.has(request))
4618
+ throw new HTTPException8(403, { message: "request access authorization already resolved" });
4619
+ const parsed = delegatedHumanAuthorizationSchema.extend({
4620
+ subjectId: z2.string().max(1024).regex(/^external_user:[^\s\u0000-\u001f\u007f]+$/)
4621
+ }).parse({ ...input, workspaceScope: { kind: "selected", workspaceIds: [input.workspaceId] } });
4622
+ if (parsed.workspaceScope.kind !== "selected") throw new Error("Site workspace scope required");
4623
+ Object.freeze(parsed.permissions);
4624
+ Object.freeze(parsed.workspaceScope.workspaceIds);
4625
+ Object.freeze(parsed.workspaceScope);
4626
+ const proof = Object.freeze(parsed);
4627
+ verifiedSiteViewerProofs.add(proof);
4628
+ delegatedHumanRequests.set(request, proof);
4629
+ }
4584
4630
  var PERSONAL_API_KEY_TOKEN_PREFIX = "ogp_";
4585
4631
  async function stampPersonalApiKeyRequest(request, deps) {
4586
4632
  const authorization = request.headers.get("authorization");
@@ -5262,6 +5308,55 @@ async function resolveDelegatedHumanAccessContext(deps, proof) {
5262
5308
  message: "delegated humans require native organization access"
5263
5309
  });
5264
5310
  }
5311
+ if (verifiedSiteViewerProofs.has(proof)) {
5312
+ const workspaceId = proof.workspaceScope.kind === "selected" && proof.workspaceScope.workspaceIds.length === 1 ? proof.workspaceScope.workspaceIds[0] : null;
5313
+ if (!workspaceId)
5314
+ throw new HTTPException8(403, { message: "Site viewer workspace unavailable" });
5315
+ const grant = await withWorkspaceSubjectRls(
5316
+ deps.db,
5317
+ workspaceId,
5318
+ proof.subjectId,
5319
+ async (tx) => {
5320
+ if (!await subjectHasLiveWorkspaceAuthorityInScope(tx, {
5321
+ accountId: proof.organizationId,
5322
+ workspaceId,
5323
+ subjectId: proof.subjectId
5324
+ }))
5325
+ return null;
5326
+ return getWorkspaceGrant(tx, proof.subjectId, workspaceId, {
5327
+ principalKind: "human_session"
5328
+ });
5329
+ }
5330
+ );
5331
+ if (!grant || grant.accountId !== proof.organizationId)
5332
+ throw new HTTPException8(403, { message: "Site viewer membership unavailable" });
5333
+ const bounded = Object.freeze({
5334
+ ...grant,
5335
+ permissionMode: "explicit",
5336
+ permissions: Object.freeze(
5337
+ explicitPermissions(
5338
+ Permission.options.filter(
5339
+ (permission) => hasPermission(grant.permissions, permission) && hasPermission(proof.permissions, permission, "explicit")
5340
+ )
5341
+ )
5342
+ )
5343
+ });
5344
+ const accountGrant2 = Object.freeze({
5345
+ accountId: proof.organizationId,
5346
+ subjectId: proof.subjectId,
5347
+ permissions: Object.freeze([])
5348
+ });
5349
+ const context2 = Object.freeze({
5350
+ mode: "managed",
5351
+ subjectId: proof.subjectId,
5352
+ accountGrants: Object.freeze([accountGrant2]),
5353
+ workspaceGrants: Object.freeze([bounded]),
5354
+ defaultAccountId: proof.organizationId,
5355
+ defaultWorkspaceId: workspaceId
5356
+ });
5357
+ delegatedHumanContexts.set(context2, proof);
5358
+ return context2;
5359
+ }
5265
5360
  const userId = proof.subjectId.slice("user:".length);
5266
5361
  const profiles = await getManagedUserProfilesByIds(deps.db, [userId]);
5267
5362
  const parsedProfile = delegatedHumanProfileSchema.safeParse(
@@ -5752,7 +5847,7 @@ import { withSessionRlsActorContext as withSessionRlsActorContext4 } from "@open
5752
5847
  // src/domain/file-owner.ts
5753
5848
  import {
5754
5849
  freezeAgentLearningPolicy,
5755
- getSessionAuthorityProjection as getSessionAuthorityProjection3
5850
+ getSessionAuthorityProjection as getSessionAuthorityProjection2
5756
5851
  } from "@opengeni/db";
5757
5852
  async function fileOwnerContextForAccess(deps, access, permission) {
5758
5853
  if (access.grant.principalKind === "agent_attempt")
@@ -5782,7 +5877,7 @@ async function fileOwnerContextForAgent(deps, grant, permission) {
5782
5877
  executionGeneration: attempt.executionGeneration
5783
5878
  }
5784
5879
  });
5785
- const sessionAuthority = await getSessionAuthorityProjection3(
5880
+ const sessionAuthority = await getSessionAuthorityProjection2(
5786
5881
  deps.db,
5787
5882
  grant.workspaceId,
5788
5883
  sessionId
@@ -5796,6 +5891,7 @@ async function fileOwnerContextForAgent(deps, grant, permission) {
5796
5891
  },
5797
5892
  subjectId: grant.subjectId,
5798
5893
  initiatingHumanSubjectId: attempt.initiatingHumanSubjectId,
5894
+ agentRootSessionId: attempt.callerRootSessionId,
5799
5895
  privateFileOwnerSubjectId: snapshot.defaultScope === "personal" ? snapshot.subjectId : null
5800
5896
  };
5801
5897
  }
@@ -5955,14 +6051,14 @@ import {
5955
6051
  getSession as getSession5,
5956
6052
  getInitializedSessionCreateReplay,
5957
6053
  getSessionGoal,
5958
- getSessionAuthorityProjection as getSessionAuthorityProjection4,
6054
+ getSessionAuthorityProjection as getSessionAuthorityProjection3,
5959
6055
  SessionIdConflictError,
5960
6056
  NewSessionDraftConflictError,
5961
6057
  getWorkspaceControlEvent,
5962
6058
  getSessionLineage,
5963
6059
  getSessionTurn,
5964
6060
  getSessionTurnInitiatingHumanSubjectId,
5965
- getSessionTurnForAttempt as getSessionTurnForAttempt3,
6061
+ getSessionTurnForAttempt as getSessionTurnForAttempt2,
5966
6062
  getSessionTurnPersonalConnectionDelegations as getSessionTurnPersonalConnectionDelegations2,
5967
6063
  getSessionTurnXaiProviderAccountAuthoritySnapshot,
5968
6064
  getSessionTurnClaudeProviderAccountAuthoritySnapshot,
@@ -6018,7 +6114,7 @@ import {
6018
6114
  captureExternalLinkTurnAuthority,
6019
6115
  captureExternalLinkTaskAuthority,
6020
6116
  getExternalLinkTurnSnapshot,
6021
- getSessionTurnForAttempt as getSessionTurnForAttempt2
6117
+ getSessionTurnForAttempt
6022
6118
  } from "@opengeni/db";
6023
6119
 
6024
6120
  // src/application/external-continuation.ts
@@ -6138,7 +6234,7 @@ function prepareExternalLinkTaskAdmission(authorization, actor) {
6138
6234
  } : void 0;
6139
6235
  }
6140
6236
  return async (tx, task) => {
6141
- const turn = await getSessionTurnForAttempt2(
6237
+ const turn = await getSessionTurnForAttempt(
6142
6238
  tx,
6143
6239
  task.workspaceId,
6144
6240
  actor.sessionId,
@@ -8989,7 +9085,8 @@ function runOnOperationAdmission(services, enrollment) {
8989
9085
  operationResourcePolicy: enrollment.operationPolicy,
8990
9086
  operationResourcePolicySupported: enrollment.agentCapabilities.operationResourcePolicy === true,
8991
9087
  operationCpuQuotaSupported: enrollment.agentCapabilities.operationCpuQuota === true,
8992
- transactionalFsWriteSupported: enrollment.agentCapabilities.transactionalFsWrite === true
9088
+ transactionalFsWriteSupported: enrollment.agentCapabilities.transactionalFsWrite === true,
9089
+ browserControlHttpSupported: enrollment.agentCapabilities.browserControlHttp === true
8993
9090
  };
8994
9091
  }
8995
9092
  function hasSecretFileReference(carry) {
@@ -10931,6 +11028,9 @@ function sessionEffectiveToolProjectionInput(session, toolRefs, context) {
10931
11028
  "request_human_input",
10932
11029
  "list_models",
10933
11030
  ...webSearchPlan.providerTools,
11031
+ // Interaction entry tools stay visible even with progressive disclosure;
11032
+ // the remaining authorized family tools are disclosed after opening.
11033
+ ...firstPartyMcpTools.filter((name) => name === "browser_open" || name === "computer_open"),
10934
11034
  ...toolRefs.some((ref) => ref.id === "opengeni" && ref.eager === true) || !progressiveDisclosure ? firstPartyMcpTools.filter((name) => !interactionNames.has(name) || !progressiveDisclosure) : [],
10935
11035
  ...!progressiveDisclosure ? runtimeToolNames : [],
10936
11036
  ...nativeComputerTools && !progressiveDisclosure ? CUA_DESKTOP_TOOLS.map((tool) => `interaction__cua_${tool.name}`) : []
@@ -13267,7 +13367,7 @@ async function createSessionForRequestInFileScope(unresolvedDeps, grant, workspa
13267
13367
  () => requireWorkspace5(db, workspaceId)
13268
13368
  );
13269
13369
  const workspaceSessionToolDefaults = resolveWorkspaceSessionToolDefaults2(workspace.settings);
13270
- const parentAuthority = parentSession ? await getSessionAuthorityProjection4(db, workspaceId, parentSession.id) : null;
13370
+ const parentAuthority = parentSession ? await getSessionAuthorityProjection3(db, workspaceId, parentSession.id) : null;
13271
13371
  if (parentSession && !parentAuthority) {
13272
13372
  throw new HTTPException21(403, {
13273
13373
  message: "parent session authority is unavailable"
@@ -13328,7 +13428,7 @@ async function createSessionForRequestInFileScope(unresolvedDeps, grant, workspa
13328
13428
  payload.instructions = agentResolution.instructions;
13329
13429
  }
13330
13430
  bundledSkillIds = bundledSkillSelectionForAgentConfig2(bundledSkillIds, agentConfig);
13331
- const parentCallingTurn = parentSession && creationInitiator.actor ? await getSessionTurnForAttempt3(
13431
+ const parentCallingTurn = parentSession && creationInitiator.actor ? await getSessionTurnForAttempt2(
13332
13432
  db,
13333
13433
  workspaceId,
13334
13434
  parentSession.id,
@@ -17588,7 +17688,7 @@ import { RotateSessionMcpCredentialsRequest } from "@opengeni/contracts";
17588
17688
  import {
17589
17689
  encryptVariableSetValue as encryptVariableSetValue3,
17590
17690
  getWorkspaceGrant as getWorkspaceGrant3,
17591
- subjectHasLiveWorkspaceAuthorityInScope
17691
+ subjectHasLiveWorkspaceAuthorityInScope as subjectHasLiveWorkspaceAuthorityInScope2
17592
17692
  } from "@opengeni/db";
17593
17693
  import {
17594
17694
  rotateSessionMcpCredentialsAtomically,
@@ -17733,7 +17833,7 @@ async function rotateSessionMcpCredentialsForRequest(deps, authorization, sessio
17733
17833
  } else if (!hasVerifiedOwningUserAuthorization(authorization)) {
17734
17834
  throw new HTTPException24(403, { message: "credential rotation authority changed" });
17735
17835
  }
17736
- if (!await subjectHasLiveWorkspaceAuthorityInScope(tx, scope)) {
17836
+ if (!await subjectHasLiveWorkspaceAuthorityInScope2(tx, scope)) {
17737
17837
  throw new HTTPException24(403, { message: "credential rotation authority changed" });
17738
17838
  }
17739
17839
  }
@@ -21066,7 +21166,7 @@ import {
21066
21166
  SignedJsonAutomationEnvelope,
21067
21167
  readTurnExecutionPolicyV1 as readTurnExecutionPolicyV13
21068
21168
  } from "@opengeni/contracts";
21069
- import { getSession as getSession7, getSessionTurnForAttempt as getSessionTurnForAttempt4 } from "@opengeni/db";
21169
+ import { getSession as getSession7, getSessionTurnForAttempt as getSessionTurnForAttempt3 } from "@opengeni/db";
21070
21170
  import { HTTPException as HTTPException30 } from "hono/http-exception";
21071
21171
 
21072
21172
  // src/domain/pr-review.ts
@@ -21590,7 +21690,7 @@ async function automationCredentialRestrictionForGrant(db, grant) {
21590
21690
  if (isDeveloperSetupGrant(grant)) return "developer_setup";
21591
21691
  const actor = creationInitiatorForGrant(grant).actor;
21592
21692
  if (!actor) return void 0;
21593
- const turn = await getSessionTurnForAttempt4(
21693
+ const turn = await getSessionTurnForAttempt3(
21594
21694
  db,
21595
21695
  grant.workspaceId,
21596
21696
  actor.sessionId,
@@ -22092,8 +22192,8 @@ import {
22092
22192
  getSandbox as getSandbox5,
22093
22193
  getSessionTurnXaiProviderAccountAuthoritySnapshot as getSessionTurnXaiProviderAccountAuthoritySnapshot2,
22094
22194
  getSession as getSession8,
22095
- getSessionTurnForAttempt as getSessionTurnForAttempt5,
22096
- getSessionAuthorityProjection as getSessionAuthorityProjection5,
22195
+ getSessionTurnForAttempt as getSessionTurnForAttempt4,
22196
+ getSessionAuthorityProjection as getSessionAuthorityProjection4,
22097
22197
  getWorkspaceDefaultRigId as getWorkspaceDefaultRigId2,
22098
22198
  withSessionRlsActorContext as withSessionRlsActorContext5,
22099
22199
  nestedPostgresSqlState as nestedPostgresSqlState8,
@@ -22675,7 +22775,7 @@ async function frozenScheduledTaskCreatorPolicy(input) {
22675
22775
  message: "the calling agent session is not available in this workspace"
22676
22776
  });
22677
22777
  }
22678
- const turn = await getSessionTurnForAttempt5(
22778
+ const turn = await getSessionTurnForAttempt4(
22679
22779
  input.db,
22680
22780
  input.grant.workspaceId,
22681
22781
  input.actor.sessionId,
@@ -22879,7 +22979,7 @@ async function scheduledTaskCredentialRestrictionForGrant(db, grant, actor) {
22879
22979
  if (isDeveloperSetupGrant(grant)) return "developer_setup";
22880
22980
  if (!actor) return void 0;
22881
22981
  const session = await getSession8(db, grant.workspaceId, actor.sessionId);
22882
- const turn = await getSessionTurnForAttempt5(
22982
+ const turn = await getSessionTurnForAttempt4(
22883
22983
  db,
22884
22984
  grant.workspaceId,
22885
22985
  actor.sessionId,
@@ -23839,7 +23939,7 @@ async function validateScheduledTaskAgentConfig(input) {
23839
23939
  }
23840
23940
  const fileActor = resources.some((resource) => resource.kind === "file") && hasPermission(input.grant.permissions, "files:read") ? input.authorization ? await fileOwnerContextForAccess({ db: input.db }, input.authorization, "files:read") : input.grant.principalKind === "agent_attempt" ? await fileOwnerContextForAgent({ db: input.db }, input.grant, "files:read") : { subjectId: input.grant.subjectId, privateFileOwnerSubjectId: null } : { subjectId: input.grant.subjectId, privateFileOwnerSubjectId: null };
23841
23941
  await withSessionRlsActorContext5(fileActor, async () => {
23842
- const target = input.payload.targetSessionId && input.payload.runMode !== "new_session_per_run" ? await getSessionAuthorityProjection5(
23942
+ const target = input.payload.targetSessionId && input.payload.runMode !== "new_session_per_run" ? await getSessionAuthorityProjection4(
23843
23943
  input.db,
23844
23944
  input.workspaceId,
23845
23945
  input.payload.targetSessionId
@@ -25359,7 +25459,14 @@ async function getWorkspaceInsights(db, settings, input, observePhase) {
25359
25459
  }
25360
25460
 
25361
25461
  // src/domain/insights-usage.ts
25362
- import { readInsightsCalls, readInsightsUsage } from "@opengeni/db";
25462
+ import {
25463
+ readInsightsCalls,
25464
+ readInsightsUsage,
25465
+ readInsightsSiteUsage
25466
+ } from "@opengeni/db";
25467
+ async function getInsightsSiteUsage(db, input) {
25468
+ return readInsightsSiteUsage(db, { ...input, now: input.now ?? /* @__PURE__ */ new Date() });
25469
+ }
25363
25470
  async function getInsightsUsage(db, input) {
25364
25471
  return await readInsightsUsage(db, { ...input, now: input.now ?? /* @__PURE__ */ new Date() });
25365
25472
  }
@@ -28282,6 +28389,40 @@ async function controlHumanWorkspaceTimer(deps, context, input) {
28282
28389
  ]);
28283
28390
  }
28284
28391
 
28392
+ // src/application/site-session-cancellation.ts
28393
+ import { cancelSiteRuntimeConversation } from "@opengeni/db";
28394
+ import {
28395
+ publishDurableSessionEvents as publishDurableSessionEvents4,
28396
+ publishDurableWorkspaceControlEvent as publishDurableWorkspaceControlEvent3
28397
+ } from "@opengeni/events";
28398
+ async function cancelPublishedSiteSession(deps, input) {
28399
+ const result = await cancelSiteRuntimeConversation(deps.db, input);
28400
+ if (!result) return null;
28401
+ const bySession = /* @__PURE__ */ new Map();
28402
+ for (const event of result.events) {
28403
+ const group = bySession.get(event.sessionId) ?? [];
28404
+ group.push(event);
28405
+ bySession.set(event.sessionId, group);
28406
+ }
28407
+ const effects = await Promise.allSettled([
28408
+ ...[...bySession].map(
28409
+ ([sessionId, events]) => publishDurableSessionEvents4(deps.bus, input.workspaceId, sessionId, events)
28410
+ ),
28411
+ ...result.workspaceEvent ? [publishDurableWorkspaceControlEvent3(deps.bus, input.workspaceId, result.workspaceEvent)] : [],
28412
+ ...result.wakeCount > 0 ? [deps.workflowClient.requestSessionWorkflowWakeDispatch()] : []
28413
+ ]);
28414
+ if (effects.some((effect) => effect.status === "rejected"))
28415
+ console.warn(
28416
+ "[site-lifecycle] post-commit fanout failed; durable events and wake outbox retained"
28417
+ );
28418
+ return {
28419
+ receiptId: result.receiptId,
28420
+ replay: result.replay,
28421
+ cancelledSessionCount: result.cancelledSessionCount,
28422
+ cancelledTurnCount: result.cancelledTurnCount
28423
+ };
28424
+ }
28425
+
28285
28426
  // src/application/archived-session-imports.ts
28286
28427
  import {
28287
28428
  AppendArchivedSessionEventsRequest,
@@ -28296,7 +28437,7 @@ import {
28296
28437
  importArchivedSession,
28297
28438
  withSessionRlsActorContext as withSessionRlsActorContext7
28298
28439
  } from "@opengeni/db";
28299
- import { publishDurableSessionEvents as publishDurableSessionEvents4 } from "@opengeni/events";
28440
+ import { publishDurableSessionEvents as publishDurableSessionEvents5 } from "@opengeni/events";
28300
28441
  import { HTTPException as HTTPException38 } from "hono/http-exception";
28301
28442
  import { ArchivedSessionImportError as ArchivedSessionImportError2 } from "@opengeni/db";
28302
28443
  function requireImportAuthorization(authorization, workspaceId, permission) {
@@ -28327,7 +28468,7 @@ function importerScope(authorization, workspaceId, permission, fileOwnerSubjectI
28327
28468
  async function publishImportedEvents(deps, workspaceId, sessionId, events) {
28328
28469
  if (!events.length) return;
28329
28470
  try {
28330
- await publishDurableSessionEvents4(deps.bus, workspaceId, sessionId, events);
28471
+ await publishDurableSessionEvents5(deps.bus, workspaceId, sessionId, events);
28331
28472
  } catch {
28332
28473
  console.warn("[session-import] committed timeline fanout deferred to replay", { sessionId });
28333
28474
  }
@@ -29502,6 +29643,7 @@ export {
29502
29643
  buildFleetContextForSession,
29503
29644
  buildMissingSecretAskCard2 as buildMissingSecretAskCard,
29504
29645
  cancelExternalWorkspaceMemberGrantForRequest,
29646
+ cancelPublishedSiteSession,
29505
29647
  canonicalConfiguredModel,
29506
29648
  canonicalConversationDeliveryCommandJson,
29507
29649
  canonicalConversationDeliveryOutcomeJson,
@@ -29644,6 +29786,7 @@ export {
29644
29786
  getAutomationAdapter,
29645
29787
  getConnectorToolPermissions,
29646
29788
  getHumanComposerDraft,
29789
+ getInsightsSiteUsage,
29647
29790
  getInsightsUsage,
29648
29791
  getManagedAuthRequestActorAbortSignal,
29649
29792
  getManagedAuthRequestActorAdmissionStamp,
@@ -30024,6 +30167,7 @@ export {
30024
30167
  stableJson,
30025
30168
  stampDelegatedHumanAuthorization,
30026
30169
  stampPersonalApiKeyRequest,
30170
+ stampSiteViewerSessionAuthorization,
30027
30171
  statusForVoiceInputError,
30028
30172
  steerAgentSession,
30029
30173
  steerHumanQueuePrompt,