@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/access/index.d.ts +13 -0
- package/dist/application/site-session-cancellation.d.ts +14 -0
- package/dist/domain/insights-usage.d.ts +24 -1
- package/dist/goal-admission.d.ts +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +242 -98
- package/dist/index.js.map +1 -1
- package/package.json +13 -13
- package/src/access/index.ts +100 -0
- package/src/application/site-session-cancellation.ts +47 -0
- package/src/domain/capabilities.ts +44 -16
- package/src/domain/file-owner.ts +1 -0
- package/src/domain/insights-usage.ts +20 -1
- package/src/domain/session-tool-policy.ts +3 -0
- package/src/index.ts +1 -0
- package/src/sandbox/fleet.ts +1 -0
- package/src/session-authorization.ts +113 -81
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
|
|
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
|
-
|
|
160
|
-
getSessionAuthorizationTargetProjection,
|
|
159
|
+
currentSiteViewerRlsContext,
|
|
161
160
|
getSession as getSession2,
|
|
162
|
-
|
|
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
|
|
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
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
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 =
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
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 =
|
|
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
|
|
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
|
-
|
|
548
|
-
|
|
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
|
-
|
|
567
|
-
|
|
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
|
-
|
|
579
|
-
|
|
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
|
|
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
|
-
] =
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
22096
|
-
getSessionAuthorityProjection as
|
|
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
|
|
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
|
|
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
|
|
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 {
|
|
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
|
|
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
|
|
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,
|