@opengeni/core 0.2.2 → 0.3.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 +16 -4
- package/dist/index.js +166 -10
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/domain/sessions.ts +206 -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;
|
|
@@ -554,6 +555,8 @@ declare function createAndStartSession(input: {
|
|
|
554
555
|
} | null;
|
|
555
556
|
goal?: GoalSpec | null;
|
|
556
557
|
firstPartyMcpPermissions?: Permission[] | null;
|
|
558
|
+
mcpServers?: CreateSessionMcpServerInput[];
|
|
559
|
+
sessionMcpServers?: SessionMcpServerMetadata[];
|
|
557
560
|
parentSessionId?: string | null;
|
|
558
561
|
createIdempotencyKey?: string | null;
|
|
559
562
|
sandboxGroupId?: string | null;
|
|
@@ -597,7 +600,14 @@ declare function createAndStartSession(input: {
|
|
|
597
600
|
activeSandboxId: string | null;
|
|
598
601
|
activeEpoch: number;
|
|
599
602
|
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;
|
|
603
|
+
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;
|
|
604
|
+
mcpServers: {
|
|
605
|
+
id: string;
|
|
606
|
+
name: string | null;
|
|
607
|
+
url: string;
|
|
608
|
+
headerNames: string[];
|
|
609
|
+
credentialVersion: number;
|
|
610
|
+
}[];
|
|
601
611
|
parentSessionId: string | null;
|
|
602
612
|
createIdempotencyKey: string | null;
|
|
603
613
|
temporalWorkflowId: string | null;
|
|
@@ -650,6 +660,7 @@ declare function postUserMessageTurn(input: {
|
|
|
650
660
|
model?: string | null;
|
|
651
661
|
reasoningEffort?: Settings["openaiReasoningEffort"] | null;
|
|
652
662
|
clientEventId?: string;
|
|
663
|
+
mcpCredentialUpdates?: UpdateSessionMcpServerCredentialsInput[];
|
|
653
664
|
}): Promise<{
|
|
654
665
|
accepted: SessionEvent;
|
|
655
666
|
turn: SessionTurn;
|
|
@@ -677,6 +688,7 @@ declare function acceptSessionUserMessage(deps: ApiRouteDeps, grant: AccessGrant
|
|
|
677
688
|
model?: string | null;
|
|
678
689
|
reasoningEffort?: ReasoningEffort | null;
|
|
679
690
|
clientEventId?: string;
|
|
691
|
+
mcpCredentialUpdates?: SessionMcpCredentialUpdateInput[];
|
|
680
692
|
}): Promise<{
|
|
681
693
|
accepted: SessionEvent;
|
|
682
694
|
turn: SessionTurn;
|
|
@@ -732,4 +744,4 @@ declare function assertWorkspaceDeletable(input: {
|
|
|
732
744
|
activeSessionCount: number;
|
|
733
745
|
}): void;
|
|
734
746
|
|
|
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 };
|
|
747
|
+
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,
|
|
@@ -1902,7 +2037,8 @@ async function createAndStartSession(input) {
|
|
|
1902
2037
|
parentSessionId: input.parentSessionId ?? null,
|
|
1903
2038
|
createIdempotencyKey: input.createIdempotencyKey,
|
|
1904
2039
|
sandboxGroupId: input.sandboxGroupId ?? null,
|
|
1905
|
-
...input.sandboxOs ? { sandboxOs: input.sandboxOs } : {}
|
|
2040
|
+
...input.sandboxOs ? { sandboxOs: input.sandboxOs } : {},
|
|
2041
|
+
mcpServers: input.mcpServers ?? []
|
|
1906
2042
|
});
|
|
1907
2043
|
if (!created) {
|
|
1908
2044
|
return keyed;
|
|
@@ -1922,7 +2058,8 @@ async function createAndStartSession(input) {
|
|
|
1922
2058
|
firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,
|
|
1923
2059
|
parentSessionId: input.parentSessionId ?? null,
|
|
1924
2060
|
sandboxGroupId: input.sandboxGroupId ?? null,
|
|
1925
|
-
...input.sandboxOs ? { sandboxOs: input.sandboxOs } : {}
|
|
2061
|
+
...input.sandboxOs ? { sandboxOs: input.sandboxOs } : {},
|
|
2062
|
+
mcpServers: input.mcpServers ?? []
|
|
1926
2063
|
});
|
|
1927
2064
|
return await finishStartSession(input, session);
|
|
1928
2065
|
}
|
|
@@ -1946,7 +2083,8 @@ async function finishStartSession(input, session) {
|
|
|
1946
2083
|
type: "session.created",
|
|
1947
2084
|
payload: {
|
|
1948
2085
|
status: "queued",
|
|
1949
|
-
...input.environment ? { environmentId: input.environment.id, environmentName: input.environment.name } : {}
|
|
2086
|
+
...input.environment ? { environmentId: input.environment.id, environmentName: input.environment.name } : {},
|
|
2087
|
+
...input.sessionMcpServers?.length ? { mcpServers: input.sessionMcpServers } : {}
|
|
1950
2088
|
}
|
|
1951
2089
|
},
|
|
1952
2090
|
...goal ? [{
|
|
@@ -2056,10 +2194,14 @@ async function postUserMessageTurn(input) {
|
|
|
2056
2194
|
const requestedModel = input.model ?? null;
|
|
2057
2195
|
const requestedReasoningEffort = input.reasoningEffort ?? null;
|
|
2058
2196
|
assertConfiguredModel(settings, requestedModel);
|
|
2059
|
-
const appended = await appendSessionEventsWithLockedSessionUpdate(db, workspaceId, sessionId, (lockedSession) => {
|
|
2197
|
+
const appended = await appendSessionEventsWithLockedSessionUpdate(db, workspaceId, sessionId, async (lockedSession, lockedUpdate) => {
|
|
2060
2198
|
if (lockedSession.status === "cancelled") {
|
|
2061
2199
|
throw new HTTPException8(409, { message: `session is ${lockedSession.status}; cannot accept a new user message` });
|
|
2062
2200
|
}
|
|
2201
|
+
const mcpCredentialUpdates = input.mcpCredentialUpdates?.length ? await lockedUpdate.updateSessionMcpServerCredentials(input.mcpCredentialUpdates) : { servers: [], missingIds: [] };
|
|
2202
|
+
if (mcpCredentialUpdates.missingIds.length > 0) {
|
|
2203
|
+
throw new HTTPException8(422, { message: `unknown session MCP server id: ${mcpCredentialUpdates.missingIds[0]}` });
|
|
2204
|
+
}
|
|
2063
2205
|
const nextResources = mergeResourceRefs(lockedSession.resources, input.resources);
|
|
2064
2206
|
const nextTools = mergeToolRefs(lockedSession.tools, input.tools);
|
|
2065
2207
|
const shouldQueueSession = lockedSession.status === "idle" || lockedSession.status === "failed";
|
|
@@ -2072,7 +2214,8 @@ async function postUserMessageTurn(input) {
|
|
|
2072
2214
|
...input.resources.length ? { resources: input.resources } : {},
|
|
2073
2215
|
...input.tools.length ? { tools: input.tools } : {},
|
|
2074
2216
|
...requestedModel ? { model: requestedModel } : {},
|
|
2075
|
-
...requestedReasoningEffort ? { reasoningEffort: requestedReasoningEffort } : {}
|
|
2217
|
+
...requestedReasoningEffort ? { reasoningEffort: requestedReasoningEffort } : {},
|
|
2218
|
+
...mcpCredentialUpdates.servers.length ? { mcpCredentialUpdates: mcpCredentialUpdates.servers } : {}
|
|
2076
2219
|
},
|
|
2077
2220
|
...input.clientEventId ? { clientEventId: input.clientEventId } : {}
|
|
2078
2221
|
},
|
|
@@ -2120,10 +2263,12 @@ async function postUserMessageTurn(input) {
|
|
|
2120
2263
|
async function createSessionForRequest(deps, grant, workspaceId, rawPayload) {
|
|
2121
2264
|
const { settings, db, bus, workflowClient, objectStorage } = deps;
|
|
2122
2265
|
const payload = CreateSessionRequest.parse(rawPayload);
|
|
2123
|
-
const
|
|
2266
|
+
const capabilityRuntimeSettings = await settingsWithEnabledCapabilityMcpServers(db, workspaceId, settings);
|
|
2267
|
+
const sessionMcpServers = validateSessionMcpServersForCreate(capabilityRuntimeSettings, grant, payload.mcpServers);
|
|
2268
|
+
const runtimeSettings = settingsWithSessionMcpServerConfigs(capabilityRuntimeSettings, sessionMcpServers.runtimeServers);
|
|
2124
2269
|
const resources = normalizeResources(payload.resources);
|
|
2125
2270
|
const requestedTools = validateToolRefs(payload.tools, runtimeSettings);
|
|
2126
|
-
const defaultedTools = hasOwnProperty(rawPayload, "tools") ? requestedTools : withDefaultEnabledCapabilityMcpTools(requestedTools, settings,
|
|
2271
|
+
const defaultedTools = hasOwnProperty(rawPayload, "tools") ? requestedTools : withDefaultEnabledCapabilityMcpTools(requestedTools, settings, capabilityRuntimeSettings);
|
|
2127
2272
|
const tools = withFirstPartyTools(defaultedTools, runtimeSettings);
|
|
2128
2273
|
await validateGitHubRepositorySelection(db, workspaceId, resources);
|
|
2129
2274
|
if (resources.some((resource) => resource.kind === "file") && !objectStorage) {
|
|
@@ -2227,6 +2372,8 @@ async function createSessionForRequest(deps, grant, workspaceId, rawPayload) {
|
|
|
2227
2372
|
environment: environment ? { id: environment.id, name: environment.name } : null,
|
|
2228
2373
|
goal: payload.goal ?? null,
|
|
2229
2374
|
firstPartyMcpPermissions,
|
|
2375
|
+
mcpServers: sessionMcpServers.dbServers,
|
|
2376
|
+
sessionMcpServers: sessionMcpServers.metadata,
|
|
2230
2377
|
parentSessionId,
|
|
2231
2378
|
createIdempotencyKey: payload.idempotencyKey ?? null,
|
|
2232
2379
|
// Create-time machine targeting (A-2a): when a target sandbox is named, the
|
|
@@ -2250,11 +2397,12 @@ async function createSessionForRequest(deps, grant, workspaceId, rawPayload) {
|
|
|
2250
2397
|
}
|
|
2251
2398
|
async function acceptSessionUserMessage(deps, grant, workspaceId, sessionId, input) {
|
|
2252
2399
|
const { settings, db, bus, workflowClient, objectStorage } = deps;
|
|
2253
|
-
const
|
|
2400
|
+
const capabilityRuntimeSettings = await settingsWithEnabledCapabilityMcpServers(db, workspaceId, settings);
|
|
2401
|
+
const existingSession = await requireSession2(db, workspaceId, sessionId);
|
|
2402
|
+
const runtimeSettings = settingsWithSessionMcpServerMetadata(capabilityRuntimeSettings, existingSession.mcpServers);
|
|
2254
2403
|
const requestedResources = normalizeResources(input.resources ?? []);
|
|
2255
2404
|
const validatedTools = validateToolRefs(input.tools ?? [], runtimeSettings);
|
|
2256
|
-
const requestedTools = input.toolsProvided ? validatedTools : withDefaultEnabledCapabilityMcpTools(validatedTools, settings,
|
|
2257
|
-
const existingSession = await requireSession2(db, workspaceId, sessionId);
|
|
2405
|
+
const requestedTools = input.toolsProvided ? validatedTools : withDefaultEnabledCapabilityMcpTools(validatedTools, settings, capabilityRuntimeSettings);
|
|
2258
2406
|
await requireLimit(deps, {
|
|
2259
2407
|
accountId: grant.accountId,
|
|
2260
2408
|
workspaceId,
|
|
@@ -2267,6 +2415,12 @@ async function acceptSessionUserMessage(deps, grant, workspaceId, sessionId, inp
|
|
|
2267
2415
|
}
|
|
2268
2416
|
await validateFileResources(db, workspaceId, requestedResources);
|
|
2269
2417
|
await validateGitHubRepositorySelection(db, workspaceId, [...existingSession.resources, ...requestedResources]);
|
|
2418
|
+
const mcpCredentialUpdates = validateSessionMcpCredentialUpdates({
|
|
2419
|
+
settings,
|
|
2420
|
+
grant,
|
|
2421
|
+
session: existingSession,
|
|
2422
|
+
updates: input.mcpCredentialUpdates ?? []
|
|
2423
|
+
});
|
|
2270
2424
|
const { accepted, turn } = await postUserMessageTurn({
|
|
2271
2425
|
db,
|
|
2272
2426
|
bus,
|
|
@@ -2280,6 +2434,7 @@ async function acceptSessionUserMessage(deps, grant, workspaceId, sessionId, inp
|
|
|
2280
2434
|
tools: requestedTools,
|
|
2281
2435
|
model: input.model ?? null,
|
|
2282
2436
|
reasoningEffort: input.reasoningEffort ?? null,
|
|
2437
|
+
mcpCredentialUpdates,
|
|
2283
2438
|
...input.clientEventId ? { clientEventId: input.clientEventId } : {}
|
|
2284
2439
|
});
|
|
2285
2440
|
await recordWorkspaceUsage(deps, {
|
|
@@ -2607,6 +2762,7 @@ export {
|
|
|
2607
2762
|
scheduledTaskTriggerToken,
|
|
2608
2763
|
settingsWithEnabledCapabilityMcpServers,
|
|
2609
2764
|
settingsWithMcpCapabilityServers,
|
|
2765
|
+
settingsWithSessionMcpServerMetadata,
|
|
2610
2766
|
stableJson,
|
|
2611
2767
|
swapActiveSandbox,
|
|
2612
2768
|
syncCreatedScheduledTask,
|