@opengeni/core 0.12.2 → 0.12.7
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.d.ts +21 -4
- package/dist/index.js +92 -17
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/access/index.ts +8 -1
- package/src/dependencies.ts +4 -2
- package/src/domain/capabilities.ts +83 -24
- package/src/domain/sessions.ts +53 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/core",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.7",
|
|
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.7",
|
|
38
|
-
"@opengeni/config": "^0.7.
|
|
39
|
-
"@opengeni/contracts": "^0.
|
|
40
|
-
"@opengeni/db": "^0.
|
|
41
|
-
"@opengeni/documents": "^0.2.
|
|
42
|
-
"@opengeni/events": "^0.3.
|
|
38
|
+
"@opengeni/config": "^0.7.11",
|
|
39
|
+
"@opengeni/contracts": "^0.22.0",
|
|
40
|
+
"@opengeni/db": "^0.14.0",
|
|
41
|
+
"@opengeni/documents": "^0.2.42",
|
|
42
|
+
"@opengeni/events": "^0.3.33",
|
|
43
43
|
"@opengeni/observability": "^0.3.0",
|
|
44
|
-
"@opengeni/runtime": "^0.
|
|
45
|
-
"@opengeni/storage": "^0.2.
|
|
44
|
+
"@opengeni/runtime": "^0.14.1",
|
|
45
|
+
"@opengeni/storage": "^0.2.35",
|
|
46
46
|
"hono": "^4.12.18"
|
|
47
47
|
},
|
|
48
48
|
"engines": {
|
package/src/access/index.ts
CHANGED
|
@@ -86,6 +86,10 @@ export function hasPermission(permissions: Permission[], permission: Permission)
|
|
|
86
86
|
|
|
87
87
|
async function resolveAccessContext(c: Context, deps: AccessDeps): Promise<AccessContext | null> {
|
|
88
88
|
if (deps.settings.productAccessMode === "local") {
|
|
89
|
+
const delegated = await delegatedAccessContext(c, deps, "local");
|
|
90
|
+
if (delegated) {
|
|
91
|
+
return delegated;
|
|
92
|
+
}
|
|
89
93
|
return await bootstrapWorkspace(deps.db, {
|
|
90
94
|
accountExternalSource: "opengeni:local",
|
|
91
95
|
accountExternalId: "default",
|
|
@@ -198,7 +202,7 @@ async function apiKeyAccessContext(
|
|
|
198
202
|
async function delegatedAccessContext(
|
|
199
203
|
c: Context,
|
|
200
204
|
deps: AccessDeps,
|
|
201
|
-
mode: "configured" | "managed",
|
|
205
|
+
mode: "local" | "configured" | "managed",
|
|
202
206
|
token = bearerToken(c),
|
|
203
207
|
): Promise<AccessContext | null> {
|
|
204
208
|
if (!token || !deps.settings.delegationSecret) {
|
|
@@ -232,6 +236,9 @@ async function delegatedAccessContext(
|
|
|
232
236
|
metadata: {
|
|
233
237
|
delegated: true,
|
|
234
238
|
...(payload.sessionId ? { sessionId: payload.sessionId } : {}),
|
|
239
|
+
...(payload.firstPartyMcpTools !== undefined
|
|
240
|
+
? { firstPartyMcpTools: payload.firstPartyMcpTools }
|
|
241
|
+
: {}),
|
|
235
242
|
// Caller identity: the turn that minted this token. Tools classify the
|
|
236
243
|
// CALLER from this instead of re-reading the live active pointer.
|
|
237
244
|
...(payload.turnId ? { turnId: payload.turnId } : {}),
|
package/src/dependencies.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
GitHubAppApiPort,
|
|
6
6
|
ScheduledTask,
|
|
7
7
|
SessionAuthorizationPort,
|
|
8
|
+
TurnInitiator,
|
|
8
9
|
} from "@opengeni/contracts";
|
|
9
10
|
import type { Database } from "@opengeni/db";
|
|
10
11
|
import type { DocumentServices } from "@opengeni/documents";
|
|
@@ -53,8 +54,9 @@ export type SessionWorkflowClient = {
|
|
|
53
54
|
deleteScheduledTaskSchedule: (input: { temporalScheduleId: string }) => Promise<void>;
|
|
54
55
|
triggerScheduledTask: (input: {
|
|
55
56
|
task: ScheduledTask;
|
|
56
|
-
agentRunUsageIdempotencyKey
|
|
57
|
-
triggerWorkflowId
|
|
57
|
+
agentRunUsageIdempotencyKey: string;
|
|
58
|
+
triggerWorkflowId: string;
|
|
59
|
+
initiator: TurnInitiator;
|
|
58
60
|
}) => Promise<void>;
|
|
59
61
|
startRigVerification: (input: {
|
|
60
62
|
workspaceId: string;
|
|
@@ -12,6 +12,12 @@ import {
|
|
|
12
12
|
type EnableCapabilityRequest,
|
|
13
13
|
type McpServerConnectionRef,
|
|
14
14
|
} from "@opengeni/contracts";
|
|
15
|
+
import {
|
|
16
|
+
CODEX_APPS_MCP_SERVER_ID,
|
|
17
|
+
CODEX_APPS_MCP_SERVER_NAME,
|
|
18
|
+
CODEX_APPS_MCP_URL,
|
|
19
|
+
CODEX_APPS_STARTUP_TIMEOUT_MS,
|
|
20
|
+
} from "@opengeni/codex";
|
|
15
21
|
import {
|
|
16
22
|
decryptVariableSetValue,
|
|
17
23
|
decryptedCapabilityHeaders,
|
|
@@ -27,6 +33,7 @@ import {
|
|
|
27
33
|
getVariableSet,
|
|
28
34
|
listCapabilityCatalogItems,
|
|
29
35
|
listCapabilityInstallations,
|
|
36
|
+
listConnectionsMetadata,
|
|
30
37
|
listEnabledMcpCapabilityServers,
|
|
31
38
|
listPackInstallations,
|
|
32
39
|
mcpServerIdForCapability,
|
|
@@ -424,14 +431,10 @@ async function validateMcpCapabilityConnectionRef(
|
|
|
424
431
|
item: CapabilityCatalogItem,
|
|
425
432
|
ref: McpServerConnectionRef,
|
|
426
433
|
): Promise<McpServerConnectionRef> {
|
|
427
|
-
|
|
428
|
-
throw new HTTPException(422, {
|
|
429
|
-
message: "subject-owned connection refs are not supported for agent runtime use yet",
|
|
430
|
-
});
|
|
431
|
-
}
|
|
434
|
+
const subjectScope = ref.subjectScope ?? "workspace";
|
|
432
435
|
const normalized: McpServerConnectionRef = {
|
|
433
436
|
providerDomain: ref.providerDomain.trim(),
|
|
434
|
-
subjectScope
|
|
437
|
+
subjectScope,
|
|
435
438
|
...(ref.connectionId ? { connectionId: ref.connectionId } : {}),
|
|
436
439
|
...(ref.provider ? { provider: ref.provider.trim() } : {}),
|
|
437
440
|
...(ref.kind ? { kind: ref.kind } : {}),
|
|
@@ -450,23 +453,41 @@ async function validateMcpCapabilityConnectionRef(
|
|
|
450
453
|
"MCP capabilities need a remote streamable HTTP endpoint before they can use a connectionRef",
|
|
451
454
|
});
|
|
452
455
|
}
|
|
453
|
-
|
|
454
|
-
|
|
456
|
+
|
|
457
|
+
let connection = normalized.connectionId
|
|
458
|
+
? await getConnectionMetadata(
|
|
459
|
+
input.db,
|
|
460
|
+
input.workspaceId,
|
|
461
|
+
normalized.connectionId,
|
|
462
|
+
input.grant.subjectId,
|
|
463
|
+
)
|
|
464
|
+
: null;
|
|
465
|
+
if (!connection && subjectScope === "subject" && !normalized.connectionId) {
|
|
466
|
+
const visible = await listConnectionsMetadata(
|
|
467
|
+
input.db,
|
|
468
|
+
input.workspaceId,
|
|
469
|
+
input.grant.subjectId,
|
|
470
|
+
);
|
|
471
|
+
connection =
|
|
472
|
+
visible.find(
|
|
473
|
+
(candidate) =>
|
|
474
|
+
candidate.subjectId === input.grant.subjectId &&
|
|
475
|
+
candidate.providerDomain === normalized.providerDomain &&
|
|
476
|
+
(!normalized.kind || candidate.kind === normalized.kind) &&
|
|
477
|
+
candidate.status === "active",
|
|
478
|
+
) ?? null;
|
|
455
479
|
}
|
|
456
|
-
const connection = await getConnectionMetadata(
|
|
457
|
-
input.db,
|
|
458
|
-
input.workspaceId,
|
|
459
|
-
normalized.connectionId,
|
|
460
|
-
input.grant.subjectId,
|
|
461
|
-
);
|
|
462
480
|
if (!connection) {
|
|
463
481
|
throw new HTTPException(422, {
|
|
464
|
-
message: "connectionRef
|
|
482
|
+
message: "connectionRef does not reference a visible active connection",
|
|
465
483
|
});
|
|
466
484
|
}
|
|
467
|
-
if (
|
|
485
|
+
if (
|
|
486
|
+
(subjectScope === "subject" && connection.subjectId !== input.grant.subjectId) ||
|
|
487
|
+
(subjectScope === "workspace" && connection.subjectId !== null)
|
|
488
|
+
) {
|
|
468
489
|
throw new HTTPException(422, {
|
|
469
|
-
message:
|
|
490
|
+
message: `connectionRef does not reference a ${subjectScope}-owned connection`,
|
|
470
491
|
});
|
|
471
492
|
}
|
|
472
493
|
if (connection.status !== "active") {
|
|
@@ -484,6 +505,11 @@ async function validateMcpCapabilityConnectionRef(
|
|
|
484
505
|
message: "connectionRef.kind does not match the referenced connection",
|
|
485
506
|
});
|
|
486
507
|
}
|
|
508
|
+
if (subjectScope === "subject") {
|
|
509
|
+
const genericSubjectRef = { ...normalized, kind: connection.kind };
|
|
510
|
+
delete genericSubjectRef.connectionId;
|
|
511
|
+
return genericSubjectRef;
|
|
512
|
+
}
|
|
487
513
|
return normalized;
|
|
488
514
|
}
|
|
489
515
|
|
|
@@ -691,7 +717,36 @@ export async function settingsWithEnabledCapabilityMcpServers(
|
|
|
691
717
|
settings: Settings,
|
|
692
718
|
): Promise<Settings> {
|
|
693
719
|
const enabled = await listEnabledMcpCapabilityServers(db, workspaceId);
|
|
694
|
-
return settingsWithMcpCapabilityServers(settings, enabled);
|
|
720
|
+
return settingsWithCodexAppsMcpServer(settingsWithMcpCapabilityServers(settings, enabled));
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* Register Codex Apps as an optional runtime MCP when the deployment enables
|
|
725
|
+
* it. Registration only makes the server selectable; the session tool policy
|
|
726
|
+
* decides whether the model sees it, and Codex credential resolution
|
|
727
|
+
* independently decides whether calls can authenticate.
|
|
728
|
+
*/
|
|
729
|
+
export function settingsWithCodexAppsMcpServer(settings: Settings): Settings {
|
|
730
|
+
if (
|
|
731
|
+
!settings.codexConnectedAppsEnabled ||
|
|
732
|
+
settings.mcpServers.some((server) => server.id === CODEX_APPS_MCP_SERVER_ID)
|
|
733
|
+
) {
|
|
734
|
+
return settings;
|
|
735
|
+
}
|
|
736
|
+
return {
|
|
737
|
+
...settings,
|
|
738
|
+
mcpServers: [
|
|
739
|
+
...settings.mcpServers,
|
|
740
|
+
{
|
|
741
|
+
id: CODEX_APPS_MCP_SERVER_ID,
|
|
742
|
+
name: CODEX_APPS_MCP_SERVER_NAME,
|
|
743
|
+
url: CODEX_APPS_MCP_URL,
|
|
744
|
+
timeoutMs: CODEX_APPS_STARTUP_TIMEOUT_MS,
|
|
745
|
+
// Availability is credential-specific, so discover on every run.
|
|
746
|
+
cacheToolsList: false,
|
|
747
|
+
},
|
|
748
|
+
],
|
|
749
|
+
};
|
|
695
750
|
}
|
|
696
751
|
|
|
697
752
|
export function settingsWithMcpCapabilityServers(
|
|
@@ -1157,12 +1212,16 @@ function installationConnectionRef(
|
|
|
1157
1212
|
if (!ref || typeof ref !== "object") {
|
|
1158
1213
|
return null;
|
|
1159
1214
|
}
|
|
1160
|
-
const { connectionId, providerDomain, kind } = ref as Record<string, unknown>;
|
|
1161
|
-
if (
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1215
|
+
const { connectionId, providerDomain, kind, subjectScope } = ref as Record<string, unknown>;
|
|
1216
|
+
if (typeof providerDomain !== "string" || typeof kind !== "string") {
|
|
1217
|
+
return null;
|
|
1218
|
+
}
|
|
1219
|
+
if (subjectScope === "subject") {
|
|
1220
|
+
// Never project a personal connection UUID through workspace-visible
|
|
1221
|
+
// capability configuration, including legacy rows that still contain one.
|
|
1222
|
+
return { providerDomain, kind, subjectScope: "subject" };
|
|
1223
|
+
}
|
|
1224
|
+
if (typeof connectionId !== "string") {
|
|
1166
1225
|
return null;
|
|
1167
1226
|
}
|
|
1168
1227
|
return { connectionId, providerDomain, kind };
|
package/src/domain/sessions.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
CreateSessionRequest,
|
|
11
11
|
DEFAULT_FIRST_PARTY_MCP_PERMISSIONS,
|
|
12
|
+
DEFAULT_FIRST_PARTY_MCP_TOOLS,
|
|
12
13
|
OPENGENI_SLACK_BOT_SESSION_METADATA_KEY,
|
|
13
14
|
SessionSpawnDenial,
|
|
14
15
|
ServiceTurnInitiator,
|
|
@@ -19,10 +20,12 @@ import {
|
|
|
19
20
|
type AccessGrant,
|
|
20
21
|
type CreateSessionResponse,
|
|
21
22
|
type GoalSpec,
|
|
23
|
+
type FirstPartyMcpToolName,
|
|
22
24
|
type Permission,
|
|
23
25
|
type ReasoningEffort,
|
|
24
26
|
type ResourceRef,
|
|
25
27
|
type Session,
|
|
28
|
+
type SessionSkill,
|
|
26
29
|
type SessionEvent,
|
|
27
30
|
SessionMcpApprovalPolicy,
|
|
28
31
|
type SessionMcpCredentialUpdateInput,
|
|
@@ -126,6 +129,21 @@ export class SessionSpawnDeniedError extends Error {
|
|
|
126
129
|
}
|
|
127
130
|
}
|
|
128
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Resolve per-session first-party tool visibility without consulting
|
|
134
|
+
* authorization. Top-level omission uses the minimal runtime default (stored
|
|
135
|
+
* as null); child omission snapshots the parent's exact effective selection.
|
|
136
|
+
* Explicit [] is authoritative and must never widen.
|
|
137
|
+
*/
|
|
138
|
+
export function resolveFirstPartyMcpToolsForCreate(
|
|
139
|
+
requested: FirstPartyMcpToolName[] | undefined,
|
|
140
|
+
parentStored: FirstPartyMcpToolName[] | null | undefined,
|
|
141
|
+
): FirstPartyMcpToolName[] | null {
|
|
142
|
+
if (requested !== undefined) return [...requested];
|
|
143
|
+
if (parentStored === undefined) return null;
|
|
144
|
+
return [...(parentStored ?? DEFAULT_FIRST_PARTY_MCP_TOOLS)];
|
|
145
|
+
}
|
|
146
|
+
|
|
129
147
|
function sessionSpawnDeniedMessage(denial: SessionSpawnDenial): string {
|
|
130
148
|
if (denial.code === "nested_agent_depth_override_forbidden") {
|
|
131
149
|
return `requested nested-agent depth limit ${denial.requestedMaxNestedAgentDepthOverride ?? "unknown"} exceeds inherited limit ${denial.effectiveMaxNestedAgentDepth}; workspace:admin is required to increase it`;
|
|
@@ -491,6 +509,7 @@ export async function createAndStartSession(input: {
|
|
|
491
509
|
initialMessage: string;
|
|
492
510
|
turnInstructions?: string | null;
|
|
493
511
|
resources: ResourceRef[];
|
|
512
|
+
skills?: SessionSkill[];
|
|
494
513
|
tools: ToolRef[];
|
|
495
514
|
// Public admission always supplies provenance; optional keeps internal
|
|
496
515
|
// callers that predate durable tool-policy provenance source-compatible
|
|
@@ -520,6 +539,9 @@ export async function createAndStartSession(input: {
|
|
|
520
539
|
instructions?: string | null;
|
|
521
540
|
// Validated against the creating grant before this is called.
|
|
522
541
|
firstPartyMcpPermissions?: Permission[] | null;
|
|
542
|
+
// Model-visible first-party tool names. Authorization remains controlled by
|
|
543
|
+
// firstPartyMcpPermissions and the target resource checks.
|
|
544
|
+
firstPartyMcpTools?: FirstPartyMcpToolName[] | null;
|
|
523
545
|
// Encrypted DB rows plus matching safe metadata for create-time per-session
|
|
524
546
|
// MCP servers. Metadata is the only shape emitted in events/responses.
|
|
525
547
|
mcpServers?: CreateSessionMcpServerInput[];
|
|
@@ -578,6 +600,7 @@ export async function createAndStartSession(input: {
|
|
|
578
600
|
initialMessage: input.initialMessage,
|
|
579
601
|
initialTurnInstructions: input.turnInstructions ?? null,
|
|
580
602
|
resources: input.resources,
|
|
603
|
+
skills: input.skills ?? [],
|
|
581
604
|
tools: input.tools,
|
|
582
605
|
...(input.toolPolicy ? { toolPolicy: input.toolPolicy } : {}),
|
|
583
606
|
metadata: sessionMetadata,
|
|
@@ -590,6 +613,7 @@ export async function createAndStartSession(input: {
|
|
|
590
613
|
rigId: input.rigId ?? null,
|
|
591
614
|
rigVersionId: input.rigVersionId ?? null,
|
|
592
615
|
firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,
|
|
616
|
+
firstPartyMcpTools: input.firstPartyMcpTools ?? null,
|
|
593
617
|
instructions: input.instructions ?? null,
|
|
594
618
|
parentSessionId: input.parentSessionId ?? null,
|
|
595
619
|
createIdempotencyKey: input.createIdempotencyKey,
|
|
@@ -621,6 +645,7 @@ export async function createAndStartSession(input: {
|
|
|
621
645
|
initialMessage: input.initialMessage,
|
|
622
646
|
initialTurnInstructions: input.turnInstructions ?? null,
|
|
623
647
|
resources: input.resources,
|
|
648
|
+
skills: input.skills ?? [],
|
|
624
649
|
tools: input.tools,
|
|
625
650
|
...(input.toolPolicy ? { toolPolicy: input.toolPolicy } : {}),
|
|
626
651
|
metadata: sessionMetadata,
|
|
@@ -633,6 +658,7 @@ export async function createAndStartSession(input: {
|
|
|
633
658
|
rigId: input.rigId ?? null,
|
|
634
659
|
rigVersionId: input.rigVersionId ?? null,
|
|
635
660
|
firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,
|
|
661
|
+
firstPartyMcpTools: input.firstPartyMcpTools ?? null,
|
|
636
662
|
instructions: input.instructions ?? null,
|
|
637
663
|
parentSessionId: input.parentSessionId ?? null,
|
|
638
664
|
sandboxGroupId: input.sandboxGroupId ?? null,
|
|
@@ -1090,6 +1116,9 @@ export async function createSessionForRequest(
|
|
|
1090
1116
|
? payload.resources
|
|
1091
1117
|
: (parentSession?.resources ?? payload.resources),
|
|
1092
1118
|
);
|
|
1119
|
+
const skills = hasOwnProperty(rawPayload, "skills")
|
|
1120
|
+
? payload.skills
|
|
1121
|
+
: (parentSession?.skills ?? payload.skills);
|
|
1093
1122
|
const toolsProvided = hasOwnProperty(rawPayload, "tools");
|
|
1094
1123
|
const requestedTools = validateToolRefs(
|
|
1095
1124
|
toolsProvided ? payload.tools : (parentSession?.tools ?? payload.tools),
|
|
@@ -1135,12 +1164,10 @@ export async function createSessionForRequest(
|
|
|
1135
1164
|
);
|
|
1136
1165
|
toolPolicy = { mode: "workspace_default", inheritedFromSessionId: null };
|
|
1137
1166
|
}
|
|
1138
|
-
// The first-party MCP server is attached to EVERY session.
|
|
1139
|
-
//
|
|
1140
|
-
//
|
|
1141
|
-
//
|
|
1142
|
-
// the server is attached, so a bare chat still gets titling while the
|
|
1143
|
-
// dangerous tools stay off by default.
|
|
1167
|
+
// The first-party MCP server is attached to EVERY session. Registration is
|
|
1168
|
+
// independently intersected with the exact model-visible selection and the
|
|
1169
|
+
// tool's permission/target authorization predicate, so attachment alone
|
|
1170
|
+
// exposes nothing.
|
|
1144
1171
|
const tools = withFirstPartyTools(selectedTools, runtimeSettings);
|
|
1145
1172
|
await validateGitHubRepositorySelection(db, workspaceId, resources);
|
|
1146
1173
|
if (resources.some((resource) => resource.kind === "file") && !objectStorage) {
|
|
@@ -1269,6 +1296,24 @@ export async function createSessionForRequest(
|
|
|
1269
1296
|
"goal-bearing sessions require goals:manage in the resulting first-party MCP permission set",
|
|
1270
1297
|
});
|
|
1271
1298
|
}
|
|
1299
|
+
// Tool visibility is independent from permission authority. A child that
|
|
1300
|
+
// omits the field inherits the parent's exact effective selection; a
|
|
1301
|
+
// top-level omission resolves to the fixed minimal default at execution.
|
|
1302
|
+
const firstPartyMcpTools = resolveFirstPartyMcpToolsForCreate(
|
|
1303
|
+
payload.firstPartyMcpTools,
|
|
1304
|
+
parentSession ? parentSession.firstPartyMcpTools : undefined,
|
|
1305
|
+
);
|
|
1306
|
+
if (payload.goal) {
|
|
1307
|
+
const effectiveTools = firstPartyMcpTools ?? [...DEFAULT_FIRST_PARTY_MCP_TOOLS];
|
|
1308
|
+
const missingGoalTools = ["goal_update", "goal_complete", "goal_pause"].filter(
|
|
1309
|
+
(name) => !effectiveTools.includes(name as FirstPartyMcpToolName),
|
|
1310
|
+
);
|
|
1311
|
+
if (missingGoalTools.length > 0) {
|
|
1312
|
+
throw new HTTPException(422, {
|
|
1313
|
+
message: `goal-bearing sessions require first-party MCP tools: ${missingGoalTools.join(", ")}`,
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1272
1317
|
// Parent linkage: a worker is linked to its manager ONLY from the
|
|
1273
1318
|
// worker-signed sessionId claim on the creating grant — the manager
|
|
1274
1319
|
// session's own id, signed into the delegated token by the worker and never
|
|
@@ -1501,6 +1546,7 @@ export async function createSessionForRequest(
|
|
|
1501
1546
|
initialMessage: payload.initialMessage,
|
|
1502
1547
|
turnInstructions: payload.turnInstructions ?? null,
|
|
1503
1548
|
resources,
|
|
1549
|
+
skills,
|
|
1504
1550
|
tools,
|
|
1505
1551
|
toolPolicy,
|
|
1506
1552
|
...(payload.clientEventId ? { clientEventId: payload.clientEventId } : {}),
|
|
@@ -1533,6 +1579,7 @@ export async function createSessionForRequest(
|
|
|
1533
1579
|
// time. Not surfaced as an event.
|
|
1534
1580
|
instructions: payload.instructions ?? null,
|
|
1535
1581
|
firstPartyMcpPermissions,
|
|
1582
|
+
firstPartyMcpTools,
|
|
1536
1583
|
mcpServers: sessionMcpServers.dbServers,
|
|
1537
1584
|
sessionMcpServers: sessionMcpServers.metadata,
|
|
1538
1585
|
parentSessionId,
|