@opengeni/core 0.2.2 → 0.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.d.ts +18 -4
- package/dist/index.js +172 -10
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/domain/sessions.ts +217 -11
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Settings } from '@opengeni/config';
|
|
2
|
-
import { ScheduledTask, Document, Permission, AccessContext, AccessGrant, LimitAction, LimitDecision, CapabilityCatalogResponse, CreateCapabilityCatalogItemRequest, CapabilityCatalogItem, CapabilityInstallation, EnableCapabilityRequest, WorkspaceEnvironment, CapabilityPack, SocialConnection, ScheduledTaskAgentConfig, ToolRef, ResourceRef, CreateScheduledTaskRequest, UpdateScheduledTaskRequest, ReasoningEffort, SessionEvent, SessionTurn, GoalSpec, Session, WorkspaceMember } from '@opengeni/contracts';
|
|
2
|
+
import { ScheduledTask, Document, Permission, AccessContext, AccessGrant, LimitAction, LimitDecision, CapabilityCatalogResponse, CreateCapabilityCatalogItemRequest, CapabilityCatalogItem, CapabilityInstallation, EnableCapabilityRequest, WorkspaceEnvironment, CapabilityPack, SocialConnection, ScheduledTaskAgentConfig, ToolRef, ResourceRef, CreateScheduledTaskRequest, UpdateScheduledTaskRequest, ReasoningEffort, SessionMcpCredentialUpdateInput, SessionEvent, SessionTurn, GoalSpec, SessionMcpServerMetadata, Session, WorkspaceMember } from '@opengeni/contracts';
|
|
3
3
|
export { mergeToolRefs, stableJson } from '@opengeni/contracts';
|
|
4
|
-
import { Database, SandboxRecord, EnabledMcpCapabilityServer, UpdateScheduledTaskInput } from '@opengeni/db';
|
|
4
|
+
import { Database, SandboxRecord, EnabledMcpCapabilityServer, UpdateScheduledTaskInput, CreateSessionMcpServerInput, UpdateSessionMcpServerCredentialsInput } from '@opengeni/db';
|
|
5
5
|
import { DocumentServices } from '@opengeni/documents';
|
|
6
6
|
import { EventBus } from '@opengeni/events';
|
|
7
7
|
import { Observability } from '@opengeni/observability';
|
|
@@ -534,6 +534,7 @@ declare function manualScheduledTaskTriggerWorkflowId(taskId: string, triggerTok
|
|
|
534
534
|
*/
|
|
535
535
|
declare function manualScheduledTaskTriggerUsageKey(workspaceId: string, taskId: string, triggerToken: string): string;
|
|
536
536
|
|
|
537
|
+
declare function settingsWithSessionMcpServerMetadata(settings: Settings, servers: SessionMcpServerMetadata[]): Settings;
|
|
537
538
|
declare function createAndStartSession(input: {
|
|
538
539
|
db: Database;
|
|
539
540
|
bus: EventBus;
|
|
@@ -553,7 +554,10 @@ declare function createAndStartSession(input: {
|
|
|
553
554
|
name: string;
|
|
554
555
|
} | null;
|
|
555
556
|
goal?: GoalSpec | null;
|
|
557
|
+
instructions?: string | null;
|
|
556
558
|
firstPartyMcpPermissions?: Permission[] | null;
|
|
559
|
+
mcpServers?: CreateSessionMcpServerInput[];
|
|
560
|
+
sessionMcpServers?: SessionMcpServerMetadata[];
|
|
557
561
|
parentSessionId?: string | null;
|
|
558
562
|
createIdempotencyKey?: string | null;
|
|
559
563
|
sandboxGroupId?: string | null;
|
|
@@ -571,6 +575,7 @@ declare function createAndStartSession(input: {
|
|
|
571
575
|
initialMessage: string;
|
|
572
576
|
title: string | null;
|
|
573
577
|
titleSource: "user" | "agent" | null;
|
|
578
|
+
instructions: string | null;
|
|
574
579
|
resources: ({
|
|
575
580
|
kind: "repository";
|
|
576
581
|
uri: string;
|
|
@@ -597,7 +602,14 @@ declare function createAndStartSession(input: {
|
|
|
597
602
|
activeSandboxId: string | null;
|
|
598
603
|
activeEpoch: number;
|
|
599
604
|
environmentId: string | null;
|
|
600
|
-
firstPartyMcpPermissions: ("account:read" | "account:admin" | "members:manage" | "workspace:create" | "billing:read" | "billing:manage" | "workspace:read" | "workspace:admin" | "sessions:create" | "sessions:read" | "sessions:control" | "stream:view" | "stream:control" | "stream:acknowledge" | "files:upload" | "files:read" | "files:write" | "terminal:attach" | "documents:manage" | "documents:search" | "scheduled_tasks:manage" | "scheduled_tasks:run" | "github:manage" | "github:use" | "api_keys:manage" | "environments:manage" | "environments:use" | "goals:manage" | "enrollments:read" | "enrollments:manage")[] | null;
|
|
605
|
+
firstPartyMcpPermissions: ("account:read" | "account:admin" | "members:manage" | "workspace:create" | "billing:read" | "billing:manage" | "workspace:read" | "workspace:admin" | "sessions:create" | "sessions:read" | "sessions:control" | "stream:view" | "stream:control" | "stream:acknowledge" | "files:upload" | "files:read" | "files:write" | "terminal:attach" | "documents:manage" | "documents:search" | "scheduled_tasks:manage" | "scheduled_tasks:run" | "github:manage" | "github:use" | "api_keys:manage" | "environments:manage" | "environments:use" | "mcp_servers:attach" | "goals:manage" | "enrollments:read" | "enrollments:manage")[] | null;
|
|
606
|
+
mcpServers: {
|
|
607
|
+
id: string;
|
|
608
|
+
name: string | null;
|
|
609
|
+
url: string;
|
|
610
|
+
headerNames: string[];
|
|
611
|
+
credentialVersion: number;
|
|
612
|
+
}[];
|
|
601
613
|
parentSessionId: string | null;
|
|
602
614
|
createIdempotencyKey: string | null;
|
|
603
615
|
temporalWorkflowId: string | null;
|
|
@@ -650,6 +662,7 @@ declare function postUserMessageTurn(input: {
|
|
|
650
662
|
model?: string | null;
|
|
651
663
|
reasoningEffort?: Settings["openaiReasoningEffort"] | null;
|
|
652
664
|
clientEventId?: string;
|
|
665
|
+
mcpCredentialUpdates?: UpdateSessionMcpServerCredentialsInput[];
|
|
653
666
|
}): Promise<{
|
|
654
667
|
accepted: SessionEvent;
|
|
655
668
|
turn: SessionTurn;
|
|
@@ -677,6 +690,7 @@ declare function acceptSessionUserMessage(deps: ApiRouteDeps, grant: AccessGrant
|
|
|
677
690
|
model?: string | null;
|
|
678
691
|
reasoningEffort?: ReasoningEffort | null;
|
|
679
692
|
clientEventId?: string;
|
|
693
|
+
mcpCredentialUpdates?: SessionMcpCredentialUpdateInput[];
|
|
680
694
|
}): Promise<{
|
|
681
695
|
accepted: SessionEvent;
|
|
682
696
|
turn: SessionTurn;
|
|
@@ -732,4 +746,4 @@ declare function assertWorkspaceDeletable(input: {
|
|
|
732
746
|
activeSessionCount: number;
|
|
733
747
|
}): void;
|
|
734
748
|
|
|
735
|
-
export { type AccessDeps, type ApiRouteDeps, type ApiSandboxClient, type ApiSandboxSession, type AppDependencies, type ChannelARoutingServices, type DocumentIndexClient, type FleetContext, type FleetListResult, type FleetLiveness, type FleetSandboxEntry, type FleetServices, type FleetSwapResult, type LimitCheckInput, MARKETING_SOCIAL_PACK_ID, MAX_ENVIRONMENTS_PER_WORKSPACE, MAX_VARIABLES_PER_ENVIRONMENT, type ManagedAuth, type McpCapabilityProbe, type McpCapabilityProbeInput, type McpCapabilityProbeResult, type ObjectStorageDependency, type ProvisionResult, type ResumeBoxByIdInput, type ResumedSandboxSession, type RunOnOp, type RunOnResult, type SessionWorkflowClient, acceptSessionUserMessage, assertAllowedEnvironmentVariableName, assertConfiguredModel, assertPackSandboxImageCompatible, assertWorkspaceDeletable, assertWorkspaceMemberRemovable, buildCapabilityCatalog, buildFleetContextForSession, buildMarketingDailyAnalysisAgentConfig, checkLimit, createAndStartSession, createCatalogItem, createSessionForRequest, createValidatedScheduledTask, disableCapability, discoverMcpRegistryCapabilities, enableCapability, enabledCapabilityMcpToolRefs, getCapabilityPack, hasPermission, isBuiltInCapabilityPack, isUserMember, listCapabilityPacks, listFleet, listWorkspaceCapabilityPacks, manualScheduledTaskTriggerUsageKey, manualScheduledTaskTriggerWorkflowId, memberCanAdminister, mergeResourceRefs, normalizeResources, officialMcpRegistryUrl, postUserMessageTurn, provisionSandbox, reasoningEffortForSession, recordEnvironmentAuditEvent, recordWorkspaceUsage, relayConfigFromSettings, relayDialBaseFromSettings, requireAccessContext, requireAccessGrant, requireEnvironmentEncryption, requireEnvironmentForApi, requireLimit, requirePermission, requireQueuedTurnForApi, requireScheduledTaskForApi, resolveCapabilityPack, resolveMemberSubjectId, restoreScheduledTask, routingEnabled, runOnSandbox, scheduledTaskTemporalScheduleId, scheduledTaskToolsProvided, scheduledTaskTriggerToken, settingsWithEnabledCapabilityMcpServers, settingsWithMcpCapabilityServers, swapActiveSandbox, syncCreatedScheduledTask, syncUpdatedScheduledTask, updateSessionTitle, validateEnvironmentAttachment, validateFileResources, validateGitHubRepositorySelection, validateGitHubRepositorySelectionShape, validateMcpCapabilityConnection, validateToolRefs, validatedScheduledTaskUpdate, withDefaultEnabledCapabilityMcpTools, workflowIdForSession, wrapChannelABoxWithRouting };
|
|
749
|
+
export { type AccessDeps, type ApiRouteDeps, type ApiSandboxClient, type ApiSandboxSession, type AppDependencies, type ChannelARoutingServices, type DocumentIndexClient, type FleetContext, type FleetListResult, type FleetLiveness, type FleetSandboxEntry, type FleetServices, type FleetSwapResult, type LimitCheckInput, MARKETING_SOCIAL_PACK_ID, MAX_ENVIRONMENTS_PER_WORKSPACE, MAX_VARIABLES_PER_ENVIRONMENT, type ManagedAuth, type McpCapabilityProbe, type McpCapabilityProbeInput, type McpCapabilityProbeResult, type ObjectStorageDependency, type ProvisionResult, type ResumeBoxByIdInput, type ResumedSandboxSession, type RunOnOp, type RunOnResult, type SessionWorkflowClient, acceptSessionUserMessage, assertAllowedEnvironmentVariableName, assertConfiguredModel, assertPackSandboxImageCompatible, assertWorkspaceDeletable, assertWorkspaceMemberRemovable, buildCapabilityCatalog, buildFleetContextForSession, buildMarketingDailyAnalysisAgentConfig, checkLimit, createAndStartSession, createCatalogItem, createSessionForRequest, createValidatedScheduledTask, disableCapability, discoverMcpRegistryCapabilities, enableCapability, enabledCapabilityMcpToolRefs, getCapabilityPack, hasPermission, isBuiltInCapabilityPack, isUserMember, listCapabilityPacks, listFleet, listWorkspaceCapabilityPacks, manualScheduledTaskTriggerUsageKey, manualScheduledTaskTriggerWorkflowId, memberCanAdminister, mergeResourceRefs, normalizeResources, officialMcpRegistryUrl, postUserMessageTurn, provisionSandbox, reasoningEffortForSession, recordEnvironmentAuditEvent, recordWorkspaceUsage, relayConfigFromSettings, relayDialBaseFromSettings, requireAccessContext, requireAccessGrant, requireEnvironmentEncryption, requireEnvironmentForApi, requireLimit, requirePermission, requireQueuedTurnForApi, requireScheduledTaskForApi, resolveCapabilityPack, resolveMemberSubjectId, restoreScheduledTask, routingEnabled, runOnSandbox, scheduledTaskTemporalScheduleId, scheduledTaskToolsProvided, scheduledTaskTriggerToken, settingsWithEnabledCapabilityMcpServers, settingsWithMcpCapabilityServers, settingsWithSessionMcpServerMetadata, swapActiveSandbox, syncCreatedScheduledTask, syncUpdatedScheduledTask, updateSessionTitle, validateEnvironmentAttachment, validateFileResources, validateGitHubRepositorySelection, validateGitHubRepositorySelectionShape, validateMcpCapabilityConnection, validateToolRefs, validatedScheduledTaskUpdate, withDefaultEnabledCapabilityMcpTools, workflowIdForSession, wrapChannelABoxWithRouting };
|
package/dist/index.js
CHANGED
|
@@ -1864,6 +1864,7 @@ import {
|
|
|
1864
1864
|
createSessionGoal,
|
|
1865
1865
|
createSessionWithIdempotencyKey,
|
|
1866
1866
|
enqueueSessionTurn,
|
|
1867
|
+
encryptEnvironmentValue as encryptEnvironmentValue2,
|
|
1867
1868
|
getAnySessionInGroup,
|
|
1868
1869
|
getEnrollment as getEnrollment2,
|
|
1869
1870
|
listDistinctEnvironmentIdsInGroup,
|
|
@@ -1877,6 +1878,140 @@ import {
|
|
|
1877
1878
|
} from "@opengeni/db";
|
|
1878
1879
|
import { appendAndPublishEvents } from "@opengeni/events";
|
|
1879
1880
|
import { HTTPException as HTTPException8 } from "hono/http-exception";
|
|
1881
|
+
var reservedSessionMcpServerIds = /* @__PURE__ */ new Set(["opengeni", "files", "docs", "codex_apps"]);
|
|
1882
|
+
var maxSessionMcpCredentialHeaders = 16;
|
|
1883
|
+
var maxSessionMcpCredentialHeaderValueLength = 4096;
|
|
1884
|
+
var sessionMcpCredentialHeaderName = /^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/;
|
|
1885
|
+
function normalizedSessionMcpCredentialHeaders(headers) {
|
|
1886
|
+
if (!headers) {
|
|
1887
|
+
return {};
|
|
1888
|
+
}
|
|
1889
|
+
const entries = Object.entries(headers).map(([name, value]) => [name.trim(), value]).filter(([name]) => name.length > 0);
|
|
1890
|
+
if (entries.length > maxSessionMcpCredentialHeaders) {
|
|
1891
|
+
throw new HTTPException8(422, { message: `a session MCP server supports at most ${maxSessionMcpCredentialHeaders} credential headers` });
|
|
1892
|
+
}
|
|
1893
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1894
|
+
for (const [name, value] of entries) {
|
|
1895
|
+
if (!sessionMcpCredentialHeaderName.test(name)) {
|
|
1896
|
+
throw new HTTPException8(422, { message: `invalid credential header name: ${name}` });
|
|
1897
|
+
}
|
|
1898
|
+
const lower = name.toLowerCase();
|
|
1899
|
+
if (seen.has(lower)) {
|
|
1900
|
+
throw new HTTPException8(422, { message: `duplicate credential header name: ${name}` });
|
|
1901
|
+
}
|
|
1902
|
+
seen.add(lower);
|
|
1903
|
+
if (value.length === 0 || value.length > maxSessionMcpCredentialHeaderValueLength) {
|
|
1904
|
+
throw new HTTPException8(422, { message: `credential header ${name} must be 1-${maxSessionMcpCredentialHeaderValueLength} characters` });
|
|
1905
|
+
}
|
|
1906
|
+
if (/[\u0000-\u0008\u000A-\u001F\u007F]/.test(value)) {
|
|
1907
|
+
throw new HTTPException8(422, { message: `credential header ${name} contains forbidden control characters` });
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
return Object.fromEntries(entries);
|
|
1911
|
+
}
|
|
1912
|
+
function mcpServerConfigFromInput(server) {
|
|
1913
|
+
return {
|
|
1914
|
+
id: server.id,
|
|
1915
|
+
...server.name ? { name: server.name } : {},
|
|
1916
|
+
url: server.url,
|
|
1917
|
+
...server.allowedTools ? { allowedTools: server.allowedTools } : {},
|
|
1918
|
+
...server.timeoutMs ? { timeoutMs: server.timeoutMs } : {},
|
|
1919
|
+
cacheToolsList: server.cacheToolsList ?? false
|
|
1920
|
+
};
|
|
1921
|
+
}
|
|
1922
|
+
function mcpServerConfigFromMetadata(server) {
|
|
1923
|
+
return {
|
|
1924
|
+
id: server.id,
|
|
1925
|
+
...server.name ? { name: server.name } : {},
|
|
1926
|
+
url: server.url,
|
|
1927
|
+
cacheToolsList: false
|
|
1928
|
+
};
|
|
1929
|
+
}
|
|
1930
|
+
function settingsWithSessionMcpServerConfigs(settings, servers) {
|
|
1931
|
+
if (servers.length === 0) {
|
|
1932
|
+
return settings;
|
|
1933
|
+
}
|
|
1934
|
+
const sessionIds = new Set(servers.map((server) => server.id));
|
|
1935
|
+
return {
|
|
1936
|
+
...settings,
|
|
1937
|
+
mcpServers: [
|
|
1938
|
+
...settings.mcpServers.filter((server) => !sessionIds.has(server.id)),
|
|
1939
|
+
...servers
|
|
1940
|
+
]
|
|
1941
|
+
};
|
|
1942
|
+
}
|
|
1943
|
+
function settingsWithSessionMcpServerMetadata(settings, servers) {
|
|
1944
|
+
return settingsWithSessionMcpServerConfigs(settings, servers.map(mcpServerConfigFromMetadata));
|
|
1945
|
+
}
|
|
1946
|
+
function validateSessionMcpServersForCreate(settings, grant, servers) {
|
|
1947
|
+
if (servers.length === 0) {
|
|
1948
|
+
return { runtimeServers: [], dbServers: [], metadata: [] };
|
|
1949
|
+
}
|
|
1950
|
+
requirePermission(grant, "mcp_servers:attach");
|
|
1951
|
+
const encryptionKey = requireEnvironmentEncryption(settings);
|
|
1952
|
+
const existingIds = new Set(settings.mcpServers.map((server) => server.id));
|
|
1953
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
1954
|
+
const runtimeServers = [];
|
|
1955
|
+
const dbServers = [];
|
|
1956
|
+
const metadata = [];
|
|
1957
|
+
for (const server of servers) {
|
|
1958
|
+
if (seenIds.has(server.id)) {
|
|
1959
|
+
throw new HTTPException8(422, { message: `duplicate session MCP server id: ${server.id}` });
|
|
1960
|
+
}
|
|
1961
|
+
seenIds.add(server.id);
|
|
1962
|
+
if (reservedSessionMcpServerIds.has(server.id) || existingIds.has(server.id)) {
|
|
1963
|
+
throw new HTTPException8(422, { message: `MCP server id already exists: ${server.id}` });
|
|
1964
|
+
}
|
|
1965
|
+
const headers = normalizedSessionMcpCredentialHeaders(server.headers);
|
|
1966
|
+
const headersEncrypted = Object.fromEntries(
|
|
1967
|
+
Object.entries(headers).map(([name, value]) => [name, encryptEnvironmentValue2(encryptionKey, value)])
|
|
1968
|
+
);
|
|
1969
|
+
runtimeServers.push(mcpServerConfigFromInput(server));
|
|
1970
|
+
dbServers.push({
|
|
1971
|
+
id: server.id,
|
|
1972
|
+
name: server.name ?? null,
|
|
1973
|
+
url: server.url,
|
|
1974
|
+
allowedTools: server.allowedTools ?? null,
|
|
1975
|
+
timeoutMs: server.timeoutMs ?? null,
|
|
1976
|
+
cacheToolsList: server.cacheToolsList ?? false,
|
|
1977
|
+
headersEncrypted
|
|
1978
|
+
});
|
|
1979
|
+
metadata.push({
|
|
1980
|
+
id: server.id,
|
|
1981
|
+
name: server.name ?? null,
|
|
1982
|
+
url: server.url,
|
|
1983
|
+
headerNames: Object.keys(headersEncrypted).sort(),
|
|
1984
|
+
credentialVersion: 1
|
|
1985
|
+
});
|
|
1986
|
+
}
|
|
1987
|
+
return { runtimeServers, dbServers, metadata };
|
|
1988
|
+
}
|
|
1989
|
+
function validateSessionMcpCredentialUpdates(input) {
|
|
1990
|
+
if (input.updates.length === 0) {
|
|
1991
|
+
return [];
|
|
1992
|
+
}
|
|
1993
|
+
requirePermission(input.grant, "mcp_servers:attach");
|
|
1994
|
+
const encryptionKey = requireEnvironmentEncryption(input.settings);
|
|
1995
|
+
const knownIds = new Set(input.session.mcpServers.map((server) => server.id));
|
|
1996
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
1997
|
+
const encryptedUpdates = input.updates.map((update) => {
|
|
1998
|
+
if (seenIds.has(update.id)) {
|
|
1999
|
+
throw new HTTPException8(422, { message: `duplicate session MCP credential update id: ${update.id}` });
|
|
2000
|
+
}
|
|
2001
|
+
seenIds.add(update.id);
|
|
2002
|
+
if (!knownIds.has(update.id)) {
|
|
2003
|
+
throw new HTTPException8(422, { message: `unknown session MCP server id: ${update.id}` });
|
|
2004
|
+
}
|
|
2005
|
+
const headers = normalizedSessionMcpCredentialHeaders(update.headers);
|
|
2006
|
+
return {
|
|
2007
|
+
id: update.id,
|
|
2008
|
+
headersEncrypted: Object.fromEntries(
|
|
2009
|
+
Object.entries(headers).map(([name, value]) => [name, encryptEnvironmentValue2(encryptionKey, value)])
|
|
2010
|
+
)
|
|
2011
|
+
};
|
|
2012
|
+
});
|
|
2013
|
+
return encryptedUpdates;
|
|
2014
|
+
}
|
|
1880
2015
|
async function createAndStartSession(input) {
|
|
1881
2016
|
const sessionMetadata = {
|
|
1882
2017
|
...input.metadata,
|
|
@@ -1899,10 +2034,12 @@ async function createAndStartSession(input) {
|
|
|
1899
2034
|
sandboxBackend: input.sandboxBackend,
|
|
1900
2035
|
environmentId: input.environment?.id ?? null,
|
|
1901
2036
|
firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,
|
|
2037
|
+
instructions: input.instructions ?? null,
|
|
1902
2038
|
parentSessionId: input.parentSessionId ?? null,
|
|
1903
2039
|
createIdempotencyKey: input.createIdempotencyKey,
|
|
1904
2040
|
sandboxGroupId: input.sandboxGroupId ?? null,
|
|
1905
|
-
...input.sandboxOs ? { sandboxOs: input.sandboxOs } : {}
|
|
2041
|
+
...input.sandboxOs ? { sandboxOs: input.sandboxOs } : {},
|
|
2042
|
+
mcpServers: input.mcpServers ?? []
|
|
1906
2043
|
});
|
|
1907
2044
|
if (!created) {
|
|
1908
2045
|
return keyed;
|
|
@@ -1920,9 +2057,11 @@ async function createAndStartSession(input) {
|
|
|
1920
2057
|
sandboxBackend: input.sandboxBackend,
|
|
1921
2058
|
environmentId: input.environment?.id ?? null,
|
|
1922
2059
|
firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,
|
|
2060
|
+
instructions: input.instructions ?? null,
|
|
1923
2061
|
parentSessionId: input.parentSessionId ?? null,
|
|
1924
2062
|
sandboxGroupId: input.sandboxGroupId ?? null,
|
|
1925
|
-
...input.sandboxOs ? { sandboxOs: input.sandboxOs } : {}
|
|
2063
|
+
...input.sandboxOs ? { sandboxOs: input.sandboxOs } : {},
|
|
2064
|
+
mcpServers: input.mcpServers ?? []
|
|
1926
2065
|
});
|
|
1927
2066
|
return await finishStartSession(input, session);
|
|
1928
2067
|
}
|
|
@@ -1946,7 +2085,8 @@ async function finishStartSession(input, session) {
|
|
|
1946
2085
|
type: "session.created",
|
|
1947
2086
|
payload: {
|
|
1948
2087
|
status: "queued",
|
|
1949
|
-
...input.environment ? { environmentId: input.environment.id, environmentName: input.environment.name } : {}
|
|
2088
|
+
...input.environment ? { environmentId: input.environment.id, environmentName: input.environment.name } : {},
|
|
2089
|
+
...input.sessionMcpServers?.length ? { mcpServers: input.sessionMcpServers } : {}
|
|
1950
2090
|
}
|
|
1951
2091
|
},
|
|
1952
2092
|
...goal ? [{
|
|
@@ -2056,10 +2196,14 @@ async function postUserMessageTurn(input) {
|
|
|
2056
2196
|
const requestedModel = input.model ?? null;
|
|
2057
2197
|
const requestedReasoningEffort = input.reasoningEffort ?? null;
|
|
2058
2198
|
assertConfiguredModel(settings, requestedModel);
|
|
2059
|
-
const appended = await appendSessionEventsWithLockedSessionUpdate(db, workspaceId, sessionId, (lockedSession) => {
|
|
2199
|
+
const appended = await appendSessionEventsWithLockedSessionUpdate(db, workspaceId, sessionId, async (lockedSession, lockedUpdate) => {
|
|
2060
2200
|
if (lockedSession.status === "cancelled") {
|
|
2061
2201
|
throw new HTTPException8(409, { message: `session is ${lockedSession.status}; cannot accept a new user message` });
|
|
2062
2202
|
}
|
|
2203
|
+
const mcpCredentialUpdates = input.mcpCredentialUpdates?.length ? await lockedUpdate.updateSessionMcpServerCredentials(input.mcpCredentialUpdates) : { servers: [], missingIds: [] };
|
|
2204
|
+
if (mcpCredentialUpdates.missingIds.length > 0) {
|
|
2205
|
+
throw new HTTPException8(422, { message: `unknown session MCP server id: ${mcpCredentialUpdates.missingIds[0]}` });
|
|
2206
|
+
}
|
|
2063
2207
|
const nextResources = mergeResourceRefs(lockedSession.resources, input.resources);
|
|
2064
2208
|
const nextTools = mergeToolRefs(lockedSession.tools, input.tools);
|
|
2065
2209
|
const shouldQueueSession = lockedSession.status === "idle" || lockedSession.status === "failed";
|
|
@@ -2072,7 +2216,8 @@ async function postUserMessageTurn(input) {
|
|
|
2072
2216
|
...input.resources.length ? { resources: input.resources } : {},
|
|
2073
2217
|
...input.tools.length ? { tools: input.tools } : {},
|
|
2074
2218
|
...requestedModel ? { model: requestedModel } : {},
|
|
2075
|
-
...requestedReasoningEffort ? { reasoningEffort: requestedReasoningEffort } : {}
|
|
2219
|
+
...requestedReasoningEffort ? { reasoningEffort: requestedReasoningEffort } : {},
|
|
2220
|
+
...mcpCredentialUpdates.servers.length ? { mcpCredentialUpdates: mcpCredentialUpdates.servers } : {}
|
|
2076
2221
|
},
|
|
2077
2222
|
...input.clientEventId ? { clientEventId: input.clientEventId } : {}
|
|
2078
2223
|
},
|
|
@@ -2120,10 +2265,12 @@ async function postUserMessageTurn(input) {
|
|
|
2120
2265
|
async function createSessionForRequest(deps, grant, workspaceId, rawPayload) {
|
|
2121
2266
|
const { settings, db, bus, workflowClient, objectStorage } = deps;
|
|
2122
2267
|
const payload = CreateSessionRequest.parse(rawPayload);
|
|
2123
|
-
const
|
|
2268
|
+
const capabilityRuntimeSettings = await settingsWithEnabledCapabilityMcpServers(db, workspaceId, settings);
|
|
2269
|
+
const sessionMcpServers = validateSessionMcpServersForCreate(capabilityRuntimeSettings, grant, payload.mcpServers);
|
|
2270
|
+
const runtimeSettings = settingsWithSessionMcpServerConfigs(capabilityRuntimeSettings, sessionMcpServers.runtimeServers);
|
|
2124
2271
|
const resources = normalizeResources(payload.resources);
|
|
2125
2272
|
const requestedTools = validateToolRefs(payload.tools, runtimeSettings);
|
|
2126
|
-
const defaultedTools = hasOwnProperty(rawPayload, "tools") ? requestedTools : withDefaultEnabledCapabilityMcpTools(requestedTools, settings,
|
|
2273
|
+
const defaultedTools = hasOwnProperty(rawPayload, "tools") ? requestedTools : withDefaultEnabledCapabilityMcpTools(requestedTools, settings, capabilityRuntimeSettings);
|
|
2127
2274
|
const tools = withFirstPartyTools(defaultedTools, runtimeSettings);
|
|
2128
2275
|
await validateGitHubRepositorySelection(db, workspaceId, resources);
|
|
2129
2276
|
if (resources.some((resource) => resource.kind === "file") && !objectStorage) {
|
|
@@ -2226,7 +2373,13 @@ async function createSessionForRequest(deps, grant, workspaceId, rawPayload) {
|
|
|
2226
2373
|
metadata: payload.metadata,
|
|
2227
2374
|
environment: environment ? { id: environment.id, name: environment.name } : null,
|
|
2228
2375
|
goal: payload.goal ?? null,
|
|
2376
|
+
// Per-session persona instructions (already trimmed/validated by the
|
|
2377
|
+
// contracts schema). Persisted on the row; composed system-level at turn
|
|
2378
|
+
// time. Not surfaced as an event.
|
|
2379
|
+
instructions: payload.instructions ?? null,
|
|
2229
2380
|
firstPartyMcpPermissions,
|
|
2381
|
+
mcpServers: sessionMcpServers.dbServers,
|
|
2382
|
+
sessionMcpServers: sessionMcpServers.metadata,
|
|
2230
2383
|
parentSessionId,
|
|
2231
2384
|
createIdempotencyKey: payload.idempotencyKey ?? null,
|
|
2232
2385
|
// Create-time machine targeting (A-2a): when a target sandbox is named, the
|
|
@@ -2250,11 +2403,12 @@ async function createSessionForRequest(deps, grant, workspaceId, rawPayload) {
|
|
|
2250
2403
|
}
|
|
2251
2404
|
async function acceptSessionUserMessage(deps, grant, workspaceId, sessionId, input) {
|
|
2252
2405
|
const { settings, db, bus, workflowClient, objectStorage } = deps;
|
|
2253
|
-
const
|
|
2406
|
+
const capabilityRuntimeSettings = await settingsWithEnabledCapabilityMcpServers(db, workspaceId, settings);
|
|
2407
|
+
const existingSession = await requireSession2(db, workspaceId, sessionId);
|
|
2408
|
+
const runtimeSettings = settingsWithSessionMcpServerMetadata(capabilityRuntimeSettings, existingSession.mcpServers);
|
|
2254
2409
|
const requestedResources = normalizeResources(input.resources ?? []);
|
|
2255
2410
|
const validatedTools = validateToolRefs(input.tools ?? [], runtimeSettings);
|
|
2256
|
-
const requestedTools = input.toolsProvided ? validatedTools : withDefaultEnabledCapabilityMcpTools(validatedTools, settings,
|
|
2257
|
-
const existingSession = await requireSession2(db, workspaceId, sessionId);
|
|
2411
|
+
const requestedTools = input.toolsProvided ? validatedTools : withDefaultEnabledCapabilityMcpTools(validatedTools, settings, capabilityRuntimeSettings);
|
|
2258
2412
|
await requireLimit(deps, {
|
|
2259
2413
|
accountId: grant.accountId,
|
|
2260
2414
|
workspaceId,
|
|
@@ -2267,6 +2421,12 @@ async function acceptSessionUserMessage(deps, grant, workspaceId, sessionId, inp
|
|
|
2267
2421
|
}
|
|
2268
2422
|
await validateFileResources(db, workspaceId, requestedResources);
|
|
2269
2423
|
await validateGitHubRepositorySelection(db, workspaceId, [...existingSession.resources, ...requestedResources]);
|
|
2424
|
+
const mcpCredentialUpdates = validateSessionMcpCredentialUpdates({
|
|
2425
|
+
settings,
|
|
2426
|
+
grant,
|
|
2427
|
+
session: existingSession,
|
|
2428
|
+
updates: input.mcpCredentialUpdates ?? []
|
|
2429
|
+
});
|
|
2270
2430
|
const { accepted, turn } = await postUserMessageTurn({
|
|
2271
2431
|
db,
|
|
2272
2432
|
bus,
|
|
@@ -2280,6 +2440,7 @@ async function acceptSessionUserMessage(deps, grant, workspaceId, sessionId, inp
|
|
|
2280
2440
|
tools: requestedTools,
|
|
2281
2441
|
model: input.model ?? null,
|
|
2282
2442
|
reasoningEffort: input.reasoningEffort ?? null,
|
|
2443
|
+
mcpCredentialUpdates,
|
|
2283
2444
|
...input.clientEventId ? { clientEventId: input.clientEventId } : {}
|
|
2284
2445
|
});
|
|
2285
2446
|
await recordWorkspaceUsage(deps, {
|
|
@@ -2607,6 +2768,7 @@ export {
|
|
|
2607
2768
|
scheduledTaskTriggerToken,
|
|
2608
2769
|
settingsWithEnabledCapabilityMcpServers,
|
|
2609
2770
|
settingsWithMcpCapabilityServers,
|
|
2771
|
+
settingsWithSessionMcpServerMetadata,
|
|
2610
2772
|
stableJson,
|
|
2611
2773
|
swapActiveSandbox,
|
|
2612
2774
|
syncCreatedScheduledTask,
|