@opengeni/core 0.28.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/domain/personal-connection-delegations.d.ts +10 -0
- package/dist/domain/resources.d.ts +1 -1
- package/dist/domain/sessions.d.ts +3 -3
- package/dist/index.js +86 -19
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
- package/src/application/new-session-drafts.ts +8 -3
- package/src/domain/personal-connection-delegations.ts +81 -7
- package/src/domain/resources.ts +13 -2
- package/src/domain/scheduled-tasks.ts +7 -1
- package/src/domain/sessions.ts +17 -11
|
@@ -40,6 +40,16 @@ export declare function personalConnectionDelegationsFromParent(input: {
|
|
|
40
40
|
servers: McpServerConfig[];
|
|
41
41
|
parentDelegations: McpPersonalConnectionDelegation[];
|
|
42
42
|
}): McpPersonalConnectionDelegation[];
|
|
43
|
+
/**
|
|
44
|
+
* Freezes Google Drive publishing only when one exact subject-owned connection
|
|
45
|
+
* is eligible. Multiple writable Google accounts are intentionally ambiguous:
|
|
46
|
+
* callers must narrow the connection before a later turn can advertise or use
|
|
47
|
+
* the private publication tool.
|
|
48
|
+
*/
|
|
49
|
+
export declare function googleDrivePublicationDelegationFromVisibleConnections(input: {
|
|
50
|
+
subjectId: string;
|
|
51
|
+
connections: ConnectionMetadata[];
|
|
52
|
+
}): McpPersonalConnectionDelegation | null;
|
|
43
53
|
export declare function personalConnectionDelegationsEqual(left: McpPersonalConnectionDelegation[], right: McpPersonalConnectionDelegation[]): boolean;
|
|
44
54
|
export declare function personalConnectionDelegationForServer(delegations: McpPersonalConnectionDelegation[], server: Pick<McpServerConfig, "id" | "connectionRef">): McpPersonalConnectionDelegation | null;
|
|
45
55
|
type ConnectionCredentialResolver = (request: ResolveConnectionCredentialInput) => Promise<ResolveConnectionCredentialResult>;
|
|
@@ -28,5 +28,5 @@ export declare function validateGitHubRepositorySelection(db: Database, workspac
|
|
|
28
28
|
* leave the result unknown and must not cause draft hydration to delete it.
|
|
29
29
|
*/
|
|
30
30
|
export declare function isAuthoritativeGitHubRepositorySelectionError(error: unknown): boolean;
|
|
31
|
-
export declare function validateFileResources(db: Database, workspaceId: string, resources: ResourceRef[]): Promise<void>;
|
|
31
|
+
export declare function validateFileResources(db: Database, accountId: string, workspaceId: string, subjectId: string, resources: ResourceRef[]): Promise<void>;
|
|
32
32
|
export { mergeToolRefs, stableJson };
|
|
@@ -78,7 +78,7 @@ export declare function createAndStartSessionWithOutcome(input: {
|
|
|
78
78
|
initialMessage: string;
|
|
79
79
|
/** Create the session shell without an initial user event/agent turn. */
|
|
80
80
|
deferInitialTurn?: boolean;
|
|
81
|
-
|
|
81
|
+
modelContext?: string | null;
|
|
82
82
|
resources: ResourceRef[];
|
|
83
83
|
skills?: SessionSkill[];
|
|
84
84
|
tools: ToolRef[];
|
|
@@ -194,7 +194,7 @@ export declare function postUserMessageTurn(input: {
|
|
|
194
194
|
sessionId: string;
|
|
195
195
|
text: string;
|
|
196
196
|
annotations?: TimelineAnnotation[];
|
|
197
|
-
|
|
197
|
+
modelContext?: string | null;
|
|
198
198
|
resources: ResourceRef[];
|
|
199
199
|
model?: string | null;
|
|
200
200
|
reasoningEffort?: Settings["openaiReasoningEffort"] | null;
|
|
@@ -243,7 +243,7 @@ export declare function createSessionForRequest(deps: ApiRouteDeps, grant: Acces
|
|
|
243
243
|
export declare function acceptSessionUserMessageWithOutcome(deps: AcceptSessionUserMessageDependencies, grant: AccessGrant, workspaceId: string, sessionId: string, input: {
|
|
244
244
|
text: string;
|
|
245
245
|
annotations?: SubmittedTimelineAnnotation[];
|
|
246
|
-
|
|
246
|
+
modelContext?: string | null;
|
|
247
247
|
resources?: ResourceRef[];
|
|
248
248
|
model?: string | null;
|
|
249
249
|
reasoningEffort?: ReasoningEffort | null;
|
package/dist/index.js
CHANGED
|
@@ -4355,6 +4355,12 @@ async function listRigChangesForApi(deps, workspaceId, rigId, limit) {
|
|
|
4355
4355
|
}
|
|
4356
4356
|
|
|
4357
4357
|
// src/domain/personal-connection-delegations.ts
|
|
4358
|
+
import {
|
|
4359
|
+
GOOGLE_DRIVE_PROVIDER_DOMAIN,
|
|
4360
|
+
GOOGLE_DRIVE_PUBLICATION_SERVER_ID,
|
|
4361
|
+
GoogleDriveConnectionMetadata,
|
|
4362
|
+
googleDriveScopesAllowCapability
|
|
4363
|
+
} from "@opengeni/contracts/google-drive";
|
|
4358
4364
|
import {
|
|
4359
4365
|
getSessionTurnPersonalConnectionDelegations,
|
|
4360
4366
|
getConnectionMetadata as getConnectionMetadata2,
|
|
@@ -4523,9 +4529,31 @@ function personalConnectionDelegationsFromParent(input) {
|
|
|
4523
4529
|
});
|
|
4524
4530
|
return [
|
|
4525
4531
|
...mcp,
|
|
4526
|
-
...input.parentDelegations.filter(
|
|
4532
|
+
...input.parentDelegations.filter(
|
|
4533
|
+
(item) => item.connectionType === "social" || item.connectionType === "atlassian" || item.serverId === GOOGLE_DRIVE_PUBLICATION_SERVER_ID
|
|
4534
|
+
).map((item) => ({ ...item }))
|
|
4527
4535
|
];
|
|
4528
4536
|
}
|
|
4537
|
+
function googleDrivePublicationDelegationFromVisibleConnections(input) {
|
|
4538
|
+
const eligible = input.connections.filter((connection2) => {
|
|
4539
|
+
if (connection2.subjectId !== input.subjectId || connection2.status !== "active" || connection2.kind !== "oauth2" || !sameProviderDomain(connection2.providerDomain, GOOGLE_DRIVE_PROVIDER_DOMAIN) || !googleDriveScopesAllowCapability(connection2.grantedScopes, "publish_file")) {
|
|
4540
|
+
return false;
|
|
4541
|
+
}
|
|
4542
|
+
const metadata = GoogleDriveConnectionMetadata.safeParse(connection2.metadata);
|
|
4543
|
+
return Boolean(
|
|
4544
|
+
metadata.success && metadata.data.outputDestination && metadata.data.lifecycle?.state !== "paused" && (!metadata.data.lifecycle || metadata.data.lifecycle.state === "active")
|
|
4545
|
+
);
|
|
4546
|
+
});
|
|
4547
|
+
if (eligible.length !== 1) return null;
|
|
4548
|
+
const connection = eligible[0];
|
|
4549
|
+
return {
|
|
4550
|
+
serverId: GOOGLE_DRIVE_PUBLICATION_SERVER_ID,
|
|
4551
|
+
connectionId: connection.id,
|
|
4552
|
+
ownerSubjectId: input.subjectId,
|
|
4553
|
+
providerDomain: connection.providerDomain,
|
|
4554
|
+
kind: connection.kind
|
|
4555
|
+
};
|
|
4556
|
+
}
|
|
4529
4557
|
function personalConnectionDelegationsEqual(left, right) {
|
|
4530
4558
|
if (left.length !== right.length) return false;
|
|
4531
4559
|
const byServer = new Map(right.map((delegation) => [delegation.serverId, delegation]));
|
|
@@ -4558,7 +4586,10 @@ function withFrozenPersonalConnectionDelegations(input) {
|
|
|
4558
4586
|
let effectiveRequest = request;
|
|
4559
4587
|
if (request.connectionRef.subjectScope === "subject") {
|
|
4560
4588
|
const config = input.settings.mcpServers.find((server) => server.id === request.serverId);
|
|
4561
|
-
const
|
|
4589
|
+
const publicationDelegations = request.serverId === GOOGLE_DRIVE_PUBLICATION_SERVER_ID && sameProviderDomain(request.connectionRef.providerDomain, GOOGLE_DRIVE_PROVIDER_DOMAIN) ? input.personalConnectionDelegations.filter(
|
|
4590
|
+
(candidate) => candidate.serverId === GOOGLE_DRIVE_PUBLICATION_SERVER_ID && sameProviderDomain(candidate.providerDomain, GOOGLE_DRIVE_PROVIDER_DOMAIN) && candidate.kind === "oauth2" && request.connectionRef.kind === "oauth2"
|
|
4591
|
+
) : [];
|
|
4592
|
+
const delegation = config ? personalConnectionDelegationForServer(input.personalConnectionDelegations, config) : publicationDelegations.length === 1 ? publicationDelegations[0] : null;
|
|
4562
4593
|
if (!delegation || !await input.ownerHasWorkspaceMembership(delegation.ownerSubjectId)) {
|
|
4563
4594
|
return personalAuthorityUnavailable(request);
|
|
4564
4595
|
}
|
|
@@ -4597,15 +4628,20 @@ async function freezePersonalConnectionDelegations(input) {
|
|
|
4597
4628
|
)
|
|
4598
4629
|
});
|
|
4599
4630
|
return includeFirstPartyConnections ? inherited : inherited.filter(
|
|
4600
|
-
(item) => item.connectionType !== "social" && item.connectionType !== "atlassian"
|
|
4631
|
+
(item) => item.connectionType !== "social" && item.connectionType !== "atlassian" && item.serverId !== GOOGLE_DRIVE_PUBLICATION_SERVER_ID
|
|
4601
4632
|
);
|
|
4602
4633
|
}
|
|
4603
4634
|
const membership = await getWorkspaceGrant3(input.db, input.source.subjectId, input.workspaceId);
|
|
4604
4635
|
if (!membership) return [];
|
|
4636
|
+
const visibleConnections = await listConnectionsMetadata2(
|
|
4637
|
+
input.db,
|
|
4638
|
+
input.workspaceId,
|
|
4639
|
+
input.source.subjectId
|
|
4640
|
+
);
|
|
4605
4641
|
const mcp = personalConnectionDelegationsFromVisibleConnections({
|
|
4606
4642
|
servers,
|
|
4607
4643
|
subjectId: input.source.subjectId,
|
|
4608
|
-
connections:
|
|
4644
|
+
connections: visibleConnections
|
|
4609
4645
|
});
|
|
4610
4646
|
if (!includeFirstPartyConnections) return mcp;
|
|
4611
4647
|
const ownerSubjectId = input.source.subjectId;
|
|
@@ -4618,11 +4654,16 @@ async function freezePersonalConnectionDelegations(input) {
|
|
|
4618
4654
|
if (!prior || connection.updatedAt > prior.updatedAt)
|
|
4619
4655
|
latest.set(connection.provider, connection);
|
|
4620
4656
|
}
|
|
4621
|
-
const personalAtlassian =
|
|
4657
|
+
const personalAtlassian = visibleConnections.filter(
|
|
4622
4658
|
(connection) => connection.subjectId === ownerSubjectId && connection.status === "active" && sameProviderDomain(connection.providerDomain, "api.atlassian.com")
|
|
4623
4659
|
);
|
|
4660
|
+
const googleDrivePublication = googleDrivePublicationDelegationFromVisibleConnections({
|
|
4661
|
+
subjectId: ownerSubjectId,
|
|
4662
|
+
connections: visibleConnections
|
|
4663
|
+
});
|
|
4624
4664
|
return [
|
|
4625
4665
|
...mcp,
|
|
4666
|
+
...googleDrivePublication ? [googleDrivePublication] : [],
|
|
4626
4667
|
...[...latest.values()].map((connection) => ({
|
|
4627
4668
|
serverId: `social:${connection.provider}`,
|
|
4628
4669
|
connectionId: connection.id,
|
|
@@ -4659,7 +4700,10 @@ import {
|
|
|
4659
4700
|
ResourceMountPathError,
|
|
4660
4701
|
stableJson as stableJson3
|
|
4661
4702
|
} from "@opengeni/contracts";
|
|
4662
|
-
import {
|
|
4703
|
+
import {
|
|
4704
|
+
areGitHubRepositoriesAllowedForWorkspace,
|
|
4705
|
+
requireFileForSubject
|
|
4706
|
+
} from "@opengeni/db";
|
|
4663
4707
|
import { HTTPException as HTTPException8 } from "hono/http-exception";
|
|
4664
4708
|
function validateToolRefs(tools, settings) {
|
|
4665
4709
|
const mcpServerIds = new Set(settings.mcpServers.map((server) => server.id));
|
|
@@ -4864,7 +4908,7 @@ async function validateGitHubRepositorySelection(db, workspaceId, resources) {
|
|
|
4864
4908
|
function isAuthoritativeGitHubRepositorySelectionError(error) {
|
|
4865
4909
|
return error instanceof HTTPException8 && error.status === 422;
|
|
4866
4910
|
}
|
|
4867
|
-
async function validateFileResources(db, workspaceId, resources) {
|
|
4911
|
+
async function validateFileResources(db, accountId, workspaceId, subjectId, resources) {
|
|
4868
4912
|
const fileIds = /* @__PURE__ */ new Set();
|
|
4869
4913
|
for (const resource of resources) {
|
|
4870
4914
|
if (resource.kind !== "file") {
|
|
@@ -4874,7 +4918,12 @@ async function validateFileResources(db, workspaceId, resources) {
|
|
|
4874
4918
|
throw new HTTPException8(422, { message: `duplicate file resource: ${resource.fileId}` });
|
|
4875
4919
|
}
|
|
4876
4920
|
fileIds.add(resource.fileId);
|
|
4877
|
-
const file = await
|
|
4921
|
+
const file = await requireFileForSubject(db, {
|
|
4922
|
+
accountId,
|
|
4923
|
+
workspaceId,
|
|
4924
|
+
subjectId,
|
|
4925
|
+
fileId: resource.fileId
|
|
4926
|
+
}).catch(() => null);
|
|
4878
4927
|
if (!file) {
|
|
4879
4928
|
throw new HTTPException8(422, { message: `unknown file resource: ${resource.fileId}` });
|
|
4880
4929
|
}
|
|
@@ -5652,7 +5701,7 @@ async function createAndStartSessionWithOutcome(input) {
|
|
|
5652
5701
|
accountId: input.accountId,
|
|
5653
5702
|
workspaceId: input.workspaceId,
|
|
5654
5703
|
initialMessage: input.initialMessage,
|
|
5655
|
-
|
|
5704
|
+
initialModelContext: input.modelContext ?? null,
|
|
5656
5705
|
resources: input.resources,
|
|
5657
5706
|
skills: input.skills ?? [],
|
|
5658
5707
|
tools: input.tools,
|
|
@@ -5716,7 +5765,7 @@ async function createAndStartSessionWithOutcome(input) {
|
|
|
5716
5765
|
accountId: input.accountId,
|
|
5717
5766
|
workspaceId: input.workspaceId,
|
|
5718
5767
|
initialMessage: input.initialMessage,
|
|
5719
|
-
|
|
5768
|
+
initialModelContext: input.modelContext ?? null,
|
|
5720
5769
|
resources: input.resources,
|
|
5721
5770
|
skills: input.skills ?? [],
|
|
5722
5771
|
tools: input.tools,
|
|
@@ -5966,7 +6015,7 @@ async function postUserMessageTurn(input) {
|
|
|
5966
6015
|
expectedDraftRevision: input.expectedDraftRevision ?? null,
|
|
5967
6016
|
text: input.text,
|
|
5968
6017
|
annotations: input.annotations ?? [],
|
|
5969
|
-
|
|
6018
|
+
modelContext: input.modelContext ?? null,
|
|
5970
6019
|
resources: input.resources,
|
|
5971
6020
|
model: requestedModel,
|
|
5972
6021
|
reasoningEffort: requestedReasoningEffort,
|
|
@@ -6182,7 +6231,7 @@ async function createSessionForRequestWithOutcome(deps, grant, workspaceId, rawP
|
|
|
6182
6231
|
message: "object storage is not configured"
|
|
6183
6232
|
});
|
|
6184
6233
|
}
|
|
6185
|
-
await validateFileResources(db, workspaceId, resources);
|
|
6234
|
+
await validateFileResources(db, grant.accountId, workspaceId, grant.subjectId, resources);
|
|
6186
6235
|
const variableSet = payload.variableSetId ? await validateVariableSetAttachment(
|
|
6187
6236
|
{ settings, db },
|
|
6188
6237
|
grant,
|
|
@@ -6401,7 +6450,7 @@ async function createSessionForRequestWithOutcome(deps, grant, workspaceId, rawP
|
|
|
6401
6450
|
workspaceId,
|
|
6402
6451
|
initialMessage: payload.initialMessage ?? "",
|
|
6403
6452
|
deferInitialTurn: payload.startMode === "realtime",
|
|
6404
|
-
|
|
6453
|
+
modelContext: payload.modelContext ?? null,
|
|
6405
6454
|
resources,
|
|
6406
6455
|
skills,
|
|
6407
6456
|
tools,
|
|
@@ -6568,7 +6617,13 @@ async function acceptSessionUserMessageWithOutcome(deps, grant, workspaceId, ses
|
|
|
6568
6617
|
message: "object storage is not configured"
|
|
6569
6618
|
});
|
|
6570
6619
|
}
|
|
6571
|
-
await validateFileResources(
|
|
6620
|
+
await validateFileResources(
|
|
6621
|
+
db,
|
|
6622
|
+
grant.accountId,
|
|
6623
|
+
workspaceId,
|
|
6624
|
+
grant.subjectId,
|
|
6625
|
+
requestedResources
|
|
6626
|
+
);
|
|
6572
6627
|
await validateGitHubRepositorySelection(db, workspaceId, [
|
|
6573
6628
|
...existingSession.resources,
|
|
6574
6629
|
...requestedResources
|
|
@@ -6599,7 +6654,7 @@ async function acceptSessionUserMessageWithOutcome(deps, grant, workspaceId, ses
|
|
|
6599
6654
|
sessionId,
|
|
6600
6655
|
text: input.text,
|
|
6601
6656
|
annotations,
|
|
6602
|
-
|
|
6657
|
+
modelContext: input.modelContext ?? null,
|
|
6603
6658
|
resources: requestedResources,
|
|
6604
6659
|
model: input.model ?? null,
|
|
6605
6660
|
reasoningEffort: input.reasoningEffort ?? null,
|
|
@@ -7444,7 +7499,13 @@ async function validateScheduledTaskAgentConfig(input) {
|
|
|
7444
7499
|
if (resources.some((resource) => resource.kind === "file") && !input.objectStorage) {
|
|
7445
7500
|
throw new HTTPException12(503, { message: "object storage is not configured" });
|
|
7446
7501
|
}
|
|
7447
|
-
await validateFileResources(
|
|
7502
|
+
await validateFileResources(
|
|
7503
|
+
input.db,
|
|
7504
|
+
input.grant.accountId,
|
|
7505
|
+
input.workspaceId,
|
|
7506
|
+
input.grant.subjectId,
|
|
7507
|
+
resources
|
|
7508
|
+
);
|
|
7448
7509
|
if (input.payload.agentConfig.slackBotConnectionId) {
|
|
7449
7510
|
await validateOpenGeniSlackBotConnectionSelection(
|
|
7450
7511
|
input.db,
|
|
@@ -9722,7 +9783,7 @@ import {
|
|
|
9722
9783
|
NewSessionDraftAccessError,
|
|
9723
9784
|
newSessionDraftToolsProvided,
|
|
9724
9785
|
publicNewSessionDraftOptions,
|
|
9725
|
-
|
|
9786
|
+
requireFileForSubject as requireFileForSubject2,
|
|
9726
9787
|
saveNewSessionDraftInTransaction,
|
|
9727
9788
|
withWorkspaceSubjectRls
|
|
9728
9789
|
} from "@opengeni/db";
|
|
@@ -9770,7 +9831,12 @@ async function hydrateNewSessionDraft(deps, grant, workspaceId, row) {
|
|
|
9770
9831
|
continue;
|
|
9771
9832
|
}
|
|
9772
9833
|
try {
|
|
9773
|
-
const file = await
|
|
9834
|
+
const file = await requireFileForSubject2(deps.db, {
|
|
9835
|
+
accountId: grant.accountId,
|
|
9836
|
+
workspaceId,
|
|
9837
|
+
subjectId: grant.subjectId,
|
|
9838
|
+
fileId: resource.fileId
|
|
9839
|
+
});
|
|
9774
9840
|
if (file.status === "ready") resources.push(resource);
|
|
9775
9841
|
} catch {
|
|
9776
9842
|
}
|
|
@@ -9854,7 +9920,7 @@ async function saveActorNewSessionDraft(deps, grant, workspaceId, rawInput) {
|
|
|
9854
9920
|
if (resources.some((resource) => resource.kind === "file") && !deps.objectStorage) {
|
|
9855
9921
|
throw new HTTPException14(503, { message: "object storage is not configured" });
|
|
9856
9922
|
}
|
|
9857
|
-
await validateFileResources(deps.db, workspaceId, resources);
|
|
9923
|
+
await validateFileResources(deps.db, grant.accountId, workspaceId, grant.subjectId, resources);
|
|
9858
9924
|
assertConfiguredModel(deps.settings, input.model);
|
|
9859
9925
|
await assertWorkspaceModelPolicyAllows(deps.db, deps.settings, workspaceId, input.model);
|
|
9860
9926
|
try {
|
|
@@ -10655,6 +10721,7 @@ export {
|
|
|
10655
10721
|
getHumanComposerDraft,
|
|
10656
10722
|
getManagedSession,
|
|
10657
10723
|
getWorkspaceInsights,
|
|
10724
|
+
googleDrivePublicationDelegationFromVisibleConnections,
|
|
10658
10725
|
hasLiteralPermission,
|
|
10659
10726
|
hasPermission,
|
|
10660
10727
|
hasReservedFikenMetadata,
|