@opengeni/core 0.20.11 → 0.20.12
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/capabilities.d.ts +1 -0
- package/dist/domain/personal-connection-delegations.d.ts +10 -1
- package/dist/index.js +87 -11
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
- package/src/domain/capabilities.ts +5 -4
- package/src/domain/personal-connection-delegations.ts +96 -5
- package/src/domain/scheduled-tasks.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/core",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.12",
|
|
4
4
|
"description": "OpenGeni framework-agnostic core: the domain, access, and billing layers (neutral access, off-HTTP V2 surface). Behavior-preserving extraction from apps/api — keeps Hono's HTTPException for error throwing (typed-errors cleanup deferred).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -35,14 +35,14 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
37
37
|
"@opengeni/codex": "^0.2.10",
|
|
38
|
-
"@opengeni/config": "^0.10.
|
|
39
|
-
"@opengeni/contracts": "^0.38.
|
|
40
|
-
"@opengeni/db": "^0.27.
|
|
41
|
-
"@opengeni/documents": "^0.5.
|
|
42
|
-
"@opengeni/events": "^0.3.
|
|
43
|
-
"@opengeni/observability": "^0.4.
|
|
44
|
-
"@opengeni/runtime": "^0.18.
|
|
45
|
-
"@opengeni/storage": "^0.2.
|
|
38
|
+
"@opengeni/config": "^0.10.12",
|
|
39
|
+
"@opengeni/contracts": "^0.38.2",
|
|
40
|
+
"@opengeni/db": "^0.27.9",
|
|
41
|
+
"@opengeni/documents": "^0.5.5",
|
|
42
|
+
"@opengeni/events": "^0.3.75",
|
|
43
|
+
"@opengeni/observability": "^0.4.15",
|
|
44
|
+
"@opengeni/runtime": "^0.18.11",
|
|
45
|
+
"@opengeni/storage": "^0.2.65",
|
|
46
46
|
"hono": "^4.12.18"
|
|
47
47
|
},
|
|
48
48
|
"engines": {
|
|
@@ -72,6 +72,7 @@ export async function buildCapabilityCatalog(input: {
|
|
|
72
72
|
db: Database;
|
|
73
73
|
workspaceId: string;
|
|
74
74
|
settings: Settings;
|
|
75
|
+
subjectId?: string | null;
|
|
75
76
|
}): Promise<CapabilityCatalogResponse> {
|
|
76
77
|
const [
|
|
77
78
|
persistedItems,
|
|
@@ -86,7 +87,7 @@ export async function buildCapabilityCatalog(input: {
|
|
|
86
87
|
listCapabilityInstallations(input.db, input.workspaceId),
|
|
87
88
|
listPackInstallations(input.db, input.workspaceId),
|
|
88
89
|
listWorkspaceCapabilityPacks(input.db, input.workspaceId),
|
|
89
|
-
listSocialConnections(input.db, input.workspaceId, 500),
|
|
90
|
+
listSocialConnections(input.db, input.workspaceId, 500, input.subjectId),
|
|
90
91
|
discoverBundledSkills(),
|
|
91
92
|
discoverCuratedSkillLibraryItems(),
|
|
92
93
|
]);
|
|
@@ -998,13 +999,13 @@ function platformApiCatalogItems(socialConnections: SocialConnection[]): Capabil
|
|
|
998
999
|
enabled: xEnabled,
|
|
999
1000
|
enabledReason: xEnabled
|
|
1000
1001
|
? xConnection.status === "connected"
|
|
1001
|
-
?
|
|
1002
|
-
:
|
|
1002
|
+
? `${xConnection.ownership} social account connected`
|
|
1003
|
+
: `${xConnection.ownership} social account needs reconnection`
|
|
1003
1004
|
: null,
|
|
1004
1005
|
metadata: {
|
|
1005
1006
|
connectorMode: "first_party_social",
|
|
1006
1007
|
provider: "x",
|
|
1007
|
-
ownership: "workspace",
|
|
1008
|
+
ownership: xConnection?.ownership ?? "workspace",
|
|
1008
1009
|
firstPartyMcpTools: [
|
|
1009
1010
|
"social_connections_list",
|
|
1010
1011
|
"social_posts_recent",
|
|
@@ -4,12 +4,15 @@ import type {
|
|
|
4
4
|
ConnectionMetadata,
|
|
5
5
|
McpPersonalConnectionDelegation,
|
|
6
6
|
SessionTurn,
|
|
7
|
+
SocialConnection,
|
|
7
8
|
ToolRef,
|
|
8
9
|
} from "@opengeni/contracts";
|
|
9
10
|
import {
|
|
10
11
|
getSessionTurnPersonalConnectionDelegations,
|
|
12
|
+
getSocialConnection,
|
|
11
13
|
getWorkspaceGrant,
|
|
12
14
|
listConnectionsMetadata,
|
|
15
|
+
listSocialConnections,
|
|
13
16
|
type Database,
|
|
14
17
|
type ResolveConnectionCredentialInput,
|
|
15
18
|
type ResolveConnectionCredentialResult,
|
|
@@ -19,6 +22,7 @@ export type PersonalConnectionDelegationSource =
|
|
|
19
22
|
| { kind: "subject"; subjectId: string }
|
|
20
23
|
| { kind: "turn"; sessionId: string; turnId: string }
|
|
21
24
|
| { kind: "none" };
|
|
25
|
+
export type AuthorizedSocialConnection = { connection: SocialConnection; subjectId: string | null };
|
|
22
26
|
|
|
23
27
|
export function directPersonalConnectionSubjectId(
|
|
24
28
|
turn: Pick<SessionTurn, "source" | "initiator" | "initiatorContext">,
|
|
@@ -51,6 +55,58 @@ export function personalConnectionDelegationSourceForGrant(
|
|
|
51
55
|
return { kind: "subject", subjectId: grant.subjectId };
|
|
52
56
|
}
|
|
53
57
|
|
|
58
|
+
export async function authorizedSocialConnectionsForGrant(input: {
|
|
59
|
+
db: Database;
|
|
60
|
+
grant: AccessGrant;
|
|
61
|
+
limit?: number;
|
|
62
|
+
}): Promise<AuthorizedSocialConnection[]> {
|
|
63
|
+
const workspace = await listSocialConnections(
|
|
64
|
+
input.db,
|
|
65
|
+
input.grant.workspaceId,
|
|
66
|
+
input.limit ?? 500,
|
|
67
|
+
null,
|
|
68
|
+
);
|
|
69
|
+
const source = personalConnectionDelegationSourceForGrant(input.grant);
|
|
70
|
+
if (source.kind === "none")
|
|
71
|
+
return workspace.map((connection) => ({ connection, subjectId: null }));
|
|
72
|
+
if (source.kind === "subject") {
|
|
73
|
+
const visible = await listSocialConnections(
|
|
74
|
+
input.db,
|
|
75
|
+
input.grant.workspaceId,
|
|
76
|
+
input.limit ?? 500,
|
|
77
|
+
source.subjectId,
|
|
78
|
+
);
|
|
79
|
+
return visible.map((connection) => ({
|
|
80
|
+
connection,
|
|
81
|
+
subjectId: connection.ownership === "personal" ? source.subjectId : null,
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
const delegations = (
|
|
85
|
+
await getSessionTurnPersonalConnectionDelegations(
|
|
86
|
+
input.db,
|
|
87
|
+
input.grant.workspaceId,
|
|
88
|
+
source.sessionId,
|
|
89
|
+
source.turnId,
|
|
90
|
+
)
|
|
91
|
+
).filter((item) => item.connectionType === "social");
|
|
92
|
+
const personal: AuthorizedSocialConnection[] = [];
|
|
93
|
+
for (const delegation of delegations) {
|
|
94
|
+
if (!(await getWorkspaceGrant(input.db, delegation.ownerSubjectId, input.grant.workspaceId)))
|
|
95
|
+
continue;
|
|
96
|
+
const connection = await getSocialConnection(
|
|
97
|
+
input.db,
|
|
98
|
+
input.grant.workspaceId,
|
|
99
|
+
delegation.connectionId,
|
|
100
|
+
delegation.ownerSubjectId,
|
|
101
|
+
);
|
|
102
|
+
if (!connection || connection.ownership !== "personal") continue;
|
|
103
|
+
const domain = connection.provider === "x" ? "x.com" : `${connection.provider}.com`;
|
|
104
|
+
if (!sameProviderDomain(domain, delegation.providerDomain)) continue;
|
|
105
|
+
personal.push({ connection, subjectId: delegation.ownerSubjectId });
|
|
106
|
+
}
|
|
107
|
+
return [...workspace.map((connection) => ({ connection, subjectId: null })), ...personal];
|
|
108
|
+
}
|
|
109
|
+
|
|
54
110
|
export function selectedPersonalConnectionServers(
|
|
55
111
|
settings: Pick<Settings, "mcpServers">,
|
|
56
112
|
tools: ToolRef[],
|
|
@@ -111,7 +167,7 @@ export function personalConnectionDelegationsFromParent(input: {
|
|
|
111
167
|
servers: McpServerConfig[];
|
|
112
168
|
parentDelegations: McpPersonalConnectionDelegation[];
|
|
113
169
|
}): McpPersonalConnectionDelegation[] {
|
|
114
|
-
|
|
170
|
+
const mcp = input.servers.flatMap((server) => {
|
|
115
171
|
const ref = server.connectionRef;
|
|
116
172
|
if (!ref || ref.subjectScope !== "subject") return [];
|
|
117
173
|
const delegation = input.parentDelegations.find(
|
|
@@ -122,6 +178,12 @@ export function personalConnectionDelegationsFromParent(input: {
|
|
|
122
178
|
);
|
|
123
179
|
return delegation ? [{ ...delegation }] : [];
|
|
124
180
|
});
|
|
181
|
+
return [
|
|
182
|
+
...mcp,
|
|
183
|
+
...input.parentDelegations
|
|
184
|
+
.filter((item) => item.connectionType === "social")
|
|
185
|
+
.map((item) => ({ ...item })),
|
|
186
|
+
];
|
|
125
187
|
}
|
|
126
188
|
|
|
127
189
|
export function personalConnectionDelegationsEqual(
|
|
@@ -136,7 +198,8 @@ export function personalConnectionDelegationsEqual(
|
|
|
136
198
|
other?.connectionId === delegation.connectionId &&
|
|
137
199
|
other.ownerSubjectId === delegation.ownerSubjectId &&
|
|
138
200
|
sameProviderDomain(other.providerDomain, delegation.providerDomain) &&
|
|
139
|
-
other.kind === delegation.kind
|
|
201
|
+
other.kind === delegation.kind &&
|
|
202
|
+
other.connectionType === delegation.connectionType
|
|
140
203
|
);
|
|
141
204
|
});
|
|
142
205
|
}
|
|
@@ -225,9 +288,10 @@ export async function freezePersonalConnectionDelegations(input: {
|
|
|
225
288
|
source: PersonalConnectionDelegationSource;
|
|
226
289
|
}): Promise<McpPersonalConnectionDelegation[]> {
|
|
227
290
|
const servers = selectedPersonalConnectionServers(input.settings, input.tools);
|
|
228
|
-
|
|
291
|
+
const includeSocial = input.tools.some((tool) => tool.id === "opengeni");
|
|
292
|
+
if ((servers.length === 0 && !includeSocial) || input.source.kind === "none") return [];
|
|
229
293
|
if (input.source.kind === "turn") {
|
|
230
|
-
|
|
294
|
+
const inherited = personalConnectionDelegationsFromParent({
|
|
231
295
|
servers,
|
|
232
296
|
parentDelegations: await getSessionTurnPersonalConnectionDelegations(
|
|
233
297
|
input.db,
|
|
@@ -236,12 +300,39 @@ export async function freezePersonalConnectionDelegations(input: {
|
|
|
236
300
|
input.source.turnId,
|
|
237
301
|
),
|
|
238
302
|
});
|
|
303
|
+
return includeSocial ? inherited : inherited.filter((item) => item.connectionType !== "social");
|
|
239
304
|
}
|
|
240
305
|
const membership = await getWorkspaceGrant(input.db, input.source.subjectId, input.workspaceId);
|
|
241
306
|
if (!membership) return [];
|
|
242
|
-
|
|
307
|
+
const mcp = personalConnectionDelegationsFromVisibleConnections({
|
|
243
308
|
servers,
|
|
244
309
|
subjectId: input.source.subjectId,
|
|
245
310
|
connections: await listConnectionsMetadata(input.db, input.workspaceId, input.source.subjectId),
|
|
246
311
|
});
|
|
312
|
+
if (!includeSocial) return mcp;
|
|
313
|
+
const ownerSubjectId = input.source.subjectId;
|
|
314
|
+
const visible = await listSocialConnections(input.db, input.workspaceId, 500, ownerSubjectId);
|
|
315
|
+
const latest = new Map<"x" | "reddit", (typeof visible)[number]>();
|
|
316
|
+
for (const connection of visible) {
|
|
317
|
+
if (
|
|
318
|
+
connection.ownership !== "personal" ||
|
|
319
|
+
connection.status !== "connected" ||
|
|
320
|
+
(connection.provider !== "x" && connection.provider !== "reddit")
|
|
321
|
+
)
|
|
322
|
+
continue;
|
|
323
|
+
const prior = latest.get(connection.provider);
|
|
324
|
+
if (!prior || connection.updatedAt > prior.updatedAt)
|
|
325
|
+
latest.set(connection.provider, connection);
|
|
326
|
+
}
|
|
327
|
+
return [
|
|
328
|
+
...mcp,
|
|
329
|
+
...[...latest.values()].map((connection) => ({
|
|
330
|
+
serverId: `social:${connection.provider}`,
|
|
331
|
+
connectionId: connection.id,
|
|
332
|
+
ownerSubjectId,
|
|
333
|
+
providerDomain: connection.provider === "x" ? "x.com" : `${connection.provider}.com`,
|
|
334
|
+
kind: "oauth2" as const,
|
|
335
|
+
connectionType: "social" as const,
|
|
336
|
+
})),
|
|
337
|
+
];
|
|
247
338
|
}
|
|
@@ -113,7 +113,7 @@ export async function createValidatedScheduledTask(input: {
|
|
|
113
113
|
db: input.db,
|
|
114
114
|
workspaceId: input.grant.workspaceId,
|
|
115
115
|
settings: runtimeSettings,
|
|
116
|
-
tools: agentConfig.tools,
|
|
116
|
+
tools: [...agentConfig.tools, { kind: "mcp", id: "opengeni" }],
|
|
117
117
|
source: personalConnectionDelegationSourceForGrant(input.grant),
|
|
118
118
|
});
|
|
119
119
|
const creationInitiator = creationInitiatorForGrant(input.grant);
|
|
@@ -260,7 +260,7 @@ export async function validatedScheduledTaskUpdate(input: {
|
|
|
260
260
|
db: input.db,
|
|
261
261
|
workspaceId: input.existing.workspaceId,
|
|
262
262
|
settings: runtimeSettings,
|
|
263
|
-
tools: nextAgentConfig.tools,
|
|
263
|
+
tools: [...nextAgentConfig.tools, { kind: "mcp", id: "opengeni" }],
|
|
264
264
|
source: personalConnectionDelegationSourceForGrant(input.grant),
|
|
265
265
|
});
|
|
266
266
|
if (input.existing.reusableSessionId && input.existing.runMode === "reusable_session") {
|