@opengeni/core 2.6.4-canary.0 → 2.7.2-canary.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.
@@ -2,11 +2,13 @@ import { CODEX_MODEL_ID_PREFIX, isCodexBilledModel } from "@opengeni/codex";
2
2
  import {
3
3
  canonicalizeConfiguredModelId,
4
4
  configuredAllowedModels,
5
- WORKSPACE_GATEWAY_MODEL_ID_PREFIX,
6
- WORKSPACE_OPENROUTER_MODEL_ID_PREFIX,
5
+ ORGANIZATION_GATEWAY_MODEL_ID_PREFIX,
6
+ ORGANIZATION_OPENROUTER_MODEL_ID_PREFIX,
7
7
  resolveFirstPartyMcpToolPolicy,
8
8
  policyProviderIdForModel,
9
9
  resolveTurnExecutionPolicyV1,
10
+ WORKSPACE_GATEWAY_MODEL_ID_PREFIX,
11
+ WORKSPACE_OPENROUTER_MODEL_ID_PREFIX,
10
12
  XAI_SUBSCRIPTION_MODEL_ID_PREFIX,
11
13
  type Settings,
12
14
  } from "@opengeni/config";
@@ -18,6 +20,7 @@ import {
18
20
  DraftTimelineAnnotations,
19
21
  FIRST_PARTY_MCP_TOOL_NAMES,
20
22
  OPENGENI_SLACK_BOT_SESSION_METADATA_KEY,
23
+ SessionSkills,
21
24
  SessionSpawnDenial,
22
25
  ServiceTurnInitiator,
23
26
  ServiceTurnInitiatorContext,
@@ -63,6 +66,7 @@ import {
63
66
  type XaiProviderAccountAuthoritySnapshotV1,
64
67
  } from "@opengeni/contracts";
65
68
  import {
69
+ assertExactNewSessionDraftInTransaction,
66
70
  createSession,
67
71
  createSessionWithIdempotencyKeyResult,
68
72
  canonicalSessionCommandHash,
@@ -74,6 +78,7 @@ import {
74
78
  getWorkspaceDefaultRigId,
75
79
  listDistinctVariableSetSelectionsInGroup,
76
80
  listDistinctRigVersionIdsInGroup,
81
+ listInstalledPortableSkills,
77
82
  getSandbox,
78
83
  getSession,
79
84
  getInitializedSessionCreateReplay,
@@ -91,9 +96,9 @@ import {
91
96
  initializeSessionStartAtomically,
92
97
  listSessionTurns,
93
98
  listSessionMcpServersForChildInheritance,
94
- lockActiveWorkspaceGatewayCustomModelForAdmission,
95
- lockActiveWorkspaceOpenRouterCustomModelForAdmission,
96
99
  requireSession,
100
+ setActiveSandbox,
101
+ setSubjectRlsContext,
97
102
  replaySubmittedHumanPromptFromBoundaryReceipt,
98
103
  submitHumanPromptInTransaction,
99
104
  appendSessionEventsWithLockedSessionUpdate,
@@ -134,10 +139,16 @@ import {
134
139
  requireSessionAuthorization,
135
140
  SessionAuthorizationDeniedError,
136
141
  } from "../session-authorization";
137
- import { swapActiveSandbox, type FleetContext } from "../sandbox/fleet";
142
+ import { assertHostMcpAuthoritySourceAdmissionEnabled } from "./host-mcp-authority-source-admission";
143
+ import {
144
+ preflightCreateTimeSandboxTarget,
145
+ swapActiveSandbox,
146
+ type FleetContext,
147
+ } from "../sandbox/fleet";
138
148
  import { managedSessionGroupBackend } from "../sandbox/runtime-settings";
139
149
  import {
140
150
  isWorkspaceCustomModelId,
151
+ lockActiveCustomModelForAdmission,
141
152
  resolveWorkspaceCatalogSettings,
142
153
  workspaceCustomModelReference,
143
154
  } from "../model-catalog";
@@ -170,6 +181,15 @@ const maxSessionMcpCredentialHeaderValueLength = 4096;
170
181
  // Keep the durable snapshot below the shared event-preview array boundary so
171
182
  // the generic lossy projection cannot silently rewrite this audit fact.
172
183
  const maxToolPolicyAuditRefs = 40;
184
+
185
+ function isCatalogOverlayModel(modelId: string | null | undefined): boolean {
186
+ return (
187
+ modelId?.startsWith(WORKSPACE_GATEWAY_MODEL_ID_PREFIX) === true ||
188
+ modelId?.startsWith(WORKSPACE_OPENROUTER_MODEL_ID_PREFIX) === true ||
189
+ modelId?.startsWith(ORGANIZATION_GATEWAY_MODEL_ID_PREFIX) === true ||
190
+ modelId?.startsWith(ORGANIZATION_OPENROUTER_MODEL_ID_PREFIX) === true
191
+ );
192
+ }
173
193
  // RFC 9110 field-name token characters.
174
194
  const sessionMcpCredentialHeaderName = /^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/;
175
195
 
@@ -482,6 +502,7 @@ function validateSessionMcpServersForCreate(
482
502
  const dbServers: CreateSessionMcpServerInput[] = [];
483
503
  const metadata: SessionMcpServerMetadata[] = [];
484
504
  for (const server of servers) {
505
+ assertHostMcpAuthoritySourceAdmissionEnabled(settings, server.connectionRef);
485
506
  if (seenIds.has(server.id)) {
486
507
  throw new HTTPException(422, {
487
508
  message: `duplicate session MCP server id: ${server.id}`,
@@ -705,7 +726,11 @@ export async function createAndStartSessionWithOutcome(input: {
705
726
  createdByActor?: Extract<SessionCommandActor, { type: "agent_attempt" }> | null;
706
727
  // Ordered low-to-high precedence. Names/ids only; session.created never
707
728
  // carries variable values.
708
- variableSets?: Array<{ id: string; name: string; scope: VariableSet["scope"] }>;
729
+ variableSets?: Array<{
730
+ id: string;
731
+ name: string;
732
+ scope: VariableSet["scope"];
733
+ }>;
709
734
  // The rig + frozen active rig version resolved at create (M3). Both null ⇒ a
710
735
  // rig-less session (byte-for-byte today's behavior). Frozen here so a later
711
736
  // rig promote never moves an existing session's version.
@@ -747,6 +772,9 @@ export async function createAndStartSessionWithOutcome(input: {
747
772
  // session. Every caller repairs or re-delivers the winner's one atomic start;
748
773
  // the durable initializer prevents duplicate events or turns.
749
774
  createIdempotencyKey?: string | null;
775
+ // Exact explicit installed-Skill selection. The database stores this only as
776
+ // keyed-create identity; runtime behavior comes from the frozen Skill content.
777
+ selectedInstalledSkillIds?: string[];
750
778
  // The shared-sandbox group this session's box joins (addendum 05 §D). Null/
751
779
  // omitted ⇒ a singleton group (the new row's own id, today's 1:1 behavior); a
752
780
  // shared/{groupId} spawn passes the resolved group so both run in ONE box.
@@ -757,11 +785,11 @@ export async function createAndStartSessionWithOutcome(input: {
757
785
  // OS-labeling surfaces honestly reflect the machine.
758
786
  sandboxOs?: Session["sandboxOs"];
759
787
  // Create-time machine targeting (A-2a, RACE-FREE): the enrolled machine (a
760
- // sandbox id) to run this session on. When set, the active-sandbox pointer is
761
- // resolved+validated+seeded (epoch-fenced) INSIDE finishStartSession, AFTER the
762
- // session row exists but BEFORE the first turn is enqueued/the workflow woken,
763
- // so the FIRST turn routes to the chosen machine. An invalid/unowned/offline
764
- // target fails the create (422) — never a silent fall-back to the default box.
788
+ // sandbox id) to run this session on. When set, target liveness is preflighted
789
+ // before insertion, then the active-sandbox pointer is authority-checked and
790
+ // seeded (epoch-fenced) in the SAME transaction as the session row. The FIRST
791
+ // turn therefore routes to the chosen machine, while an invalid/unowned/offline
792
+ // target fails the create (422) without leaving a queued session shell.
765
793
  // `workingDir` (optional) is the path/cwd base the chosen machine runs under,
766
794
  // seeded alongside the pointer through the epoch-fenced CAS.
767
795
  seedTargetSandbox?: {
@@ -814,36 +842,97 @@ export async function createAndStartSessionWithOutcome(input: {
814
842
  (input.workspaceCustomModel === true || input.workspaceGatewayCustomModel === true) &&
815
843
  input.retainWorkspaceCustomModel !== true &&
816
844
  input.retainWorkspaceGatewayModel !== true;
845
+ const seedTargetForNewSession = input.seedTargetSandbox ?? null;
846
+ const preflightTarget = seedTargetForNewSession
847
+ ? await preflightCreateTimeSandboxTarget(
848
+ {
849
+ db: input.db,
850
+ settings: seedTargetForNewSession.settings,
851
+ bus: input.bus,
852
+ },
853
+ {
854
+ accountId: input.accountId,
855
+ workspaceId: input.workspaceId,
856
+ ...(seedTargetForNewSession.resourceSubjectId
857
+ ? { subjectId: seedTargetForNewSession.resourceSubjectId }
858
+ : {}),
859
+ },
860
+ seedTargetForNewSession.sandboxId,
861
+ seedTargetForNewSession.workingDir ?? null,
862
+ )
863
+ : null;
864
+ const targetPreflightFailureMessage =
865
+ preflightTarget && !preflightTarget.ok
866
+ ? `cannot target sandbox ${seedTargetForNewSession!.sandboxId}: ${preflightTarget.reason}`
867
+ : null;
868
+ let targetSeededBeforeCreateCommit = false;
817
869
  const beforeCreateCommit =
818
- requiresActiveWorkspaceCustomModel || input.beforeCreateCommit
870
+ requiresActiveWorkspaceCustomModel ||
871
+ input.consumeNewSessionDraft ||
872
+ input.beforeCreateCommit ||
873
+ preflightTarget ||
874
+ targetPreflightFailureMessage
819
875
  ? async (tx: Database, sessionId: string, context?: { created: boolean }): Promise<void> => {
820
876
  // A committed keyed replay already crossed this fence when its shell
821
877
  // was first accepted. Revalidate only the transaction inserting a new
822
878
  // session, while still running caller linkage on every replay.
879
+ if (targetPreflightFailureMessage && context?.created !== false) {
880
+ throw new HTTPException(422, {
881
+ message: targetPreflightFailureMessage,
882
+ });
883
+ }
823
884
  if (requiresActiveWorkspaceCustomModel && context?.created !== false) {
824
- const openRouter = input.model.startsWith(WORKSPACE_OPENROUTER_MODEL_ID_PREFIX);
825
- const upstreamModelId = input.model.slice(
826
- openRouter
827
- ? WORKSPACE_OPENROUTER_MODEL_ID_PREFIX.length
828
- : WORKSPACE_GATEWAY_MODEL_ID_PREFIX.length,
829
- );
830
- const active = openRouter
831
- ? await lockActiveWorkspaceOpenRouterCustomModelForAdmission(tx, {
832
- accountId: input.accountId,
833
- workspaceId: input.workspaceId,
834
- upstreamModelId,
835
- })
836
- : await lockActiveWorkspaceGatewayCustomModelForAdmission(tx, {
837
- accountId: input.accountId,
838
- workspaceId: input.workspaceId,
839
- upstreamModelId,
840
- });
885
+ const reference = {
886
+ scope: input.turnExecutionPolicy.providerId.startsWith("organization-")
887
+ ? ("organization" as const)
888
+ : ("workspace" as const),
889
+ providerKind: input.turnExecutionPolicy.providerId.includes("openrouter")
890
+ ? ("openrouter" as const)
891
+ : ("vercel_gateway" as const),
892
+ upstreamModelId: input.turnExecutionPolicy.upstreamModelId,
893
+ };
894
+ const active = await lockActiveCustomModelForAdmission(tx, {
895
+ accountId: input.accountId,
896
+ workspaceId: input.workspaceId,
897
+ reference,
898
+ });
841
899
  if (!active) {
842
900
  throw new HTTPException(422, {
843
901
  message: `model is not available: ${input.model}`,
844
902
  });
845
903
  }
846
904
  }
905
+ // Reject an already-stale browser draft before the newly inserted
906
+ // shell can commit. The initializer repeats this exact check while
907
+ // consuming the draft after it installs the first runnable unit.
908
+ if (input.consumeNewSessionDraft && context?.created !== false) {
909
+ await setSubjectRlsContext(tx, input.consumeNewSessionDraft.subjectId);
910
+ await assertExactNewSessionDraftInTransaction(tx, {
911
+ workspaceId: input.workspaceId,
912
+ subjectId: input.consumeNewSessionDraft.subjectId,
913
+ expectedRevision: input.consumeNewSessionDraft.expectedRevision,
914
+ expectedSnapshot: input.consumeNewSessionDraft.expectedSnapshot,
915
+ });
916
+ }
917
+ if (preflightTarget?.ok && context?.created !== false) {
918
+ const seeded = await setActiveSandbox(tx, {
919
+ accountId: input.accountId,
920
+ workspaceId: input.workspaceId,
921
+ sessionId,
922
+ targetSandboxId: preflightTarget.targetSandboxId,
923
+ expectedEpoch: 0,
924
+ ...(seedTargetForNewSession?.resourceSubjectId
925
+ ? { subjectId: seedTargetForNewSession.resourceSubjectId }
926
+ : {}),
927
+ workingDir: preflightTarget.workingDir,
928
+ });
929
+ if (!seeded.swapped) {
930
+ throw new HTTPException(422, {
931
+ message: `cannot target sandbox ${seedTargetForNewSession!.sandboxId}: target authority changed during session creation`,
932
+ });
933
+ }
934
+ targetSeededBeforeCreateCommit = true;
935
+ }
847
936
  await input.beforeCreateCommit?.(tx, sessionId);
848
937
  }
849
938
  : undefined;
@@ -882,6 +971,7 @@ export async function createAndStartSessionWithOutcome(input: {
882
971
  policyRole: input.policyRole ?? null,
883
972
  parentSessionId: input.parentSessionId ?? null,
884
973
  createIdempotencyKey: input.createIdempotencyKey,
974
+ selectedInstalledSkillIds: input.selectedInstalledSkillIds ?? [],
885
975
  sandboxGroupId: input.sandboxGroupId ?? null,
886
976
  ...(input.sandboxOs ? { sandboxOs: input.sandboxOs } : {}),
887
977
  mcpServers: input.mcpServers ?? [],
@@ -928,7 +1018,10 @@ export async function createAndStartSessionWithOutcome(input: {
928
1018
  changed: finished.changed,
929
1019
  };
930
1020
  }
931
- const finished = await finishStartSession(input, keyed);
1021
+ const finished = await finishStartSession(
1022
+ targetSeededBeforeCreateCommit ? { ...input, seedTargetSandbox: null } : input,
1023
+ keyed,
1024
+ );
932
1025
  return {
933
1026
  session: finished.session,
934
1027
  outcome: "created",
@@ -989,7 +1082,10 @@ export async function createAndStartSessionWithOutcome(input: {
989
1082
  }
990
1083
  throw error;
991
1084
  }
992
- const finished = await finishStartSession(input, session);
1085
+ const finished = await finishStartSession(
1086
+ targetSeededBeforeCreateCommit ? { ...input, seedTargetSandbox: null } : input,
1087
+ session,
1088
+ );
993
1089
  return {
994
1090
  session: finished.session,
995
1091
  outcome: "created",
@@ -1027,7 +1123,11 @@ async function finishStartSession(
1027
1123
  reasoningEffort: Settings["openaiReasoningEffort"];
1028
1124
  turnExecutionPolicy: TurnExecutionPolicyV1;
1029
1125
  sandboxBackend: Settings["sandboxBackend"];
1030
- variableSets?: Array<{ id: string; name: string; scope: VariableSet["scope"] }>;
1126
+ variableSets?: Array<{
1127
+ id: string;
1128
+ name: string;
1129
+ scope: VariableSet["scope"];
1130
+ }>;
1031
1131
  goal?: GoalSpec | null;
1032
1132
  initialAutomaticTitle?: string | null;
1033
1133
  sessionMcpServers?: SessionMcpServerMetadata[];
@@ -1060,15 +1160,12 @@ async function finishStartSession(
1060
1160
  ): Promise<{ session: CreateSessionResponse; changed: boolean }> {
1061
1161
  // Create-time machine targeting (A-2a): seed the active-sandbox pointer BEFORE
1062
1162
  // the atomic initial turn transaction, so the FIRST turn routes to the chosen
1063
- // machine. swapActiveSandbox does
1163
+ // machine. Home backend and active route are independent: a backend:none
1164
+ // session has no managed home but may still attach a valid Connected Machine.
1165
+ // swapActiveSandbox does
1064
1166
  // the same ownership+liveness validation as the live swap; an invalid/unowned/
1065
1167
  // offline target FAILS the create (422) — never a silent fall-back to the box.
1066
1168
  if (input.seedTargetSandbox) {
1067
- if (session.sandboxBackend === "none") {
1068
- throw new HTTPException(422, {
1069
- message: "cannot target a machine for a session with no sandbox (backend: none)",
1070
- });
1071
- }
1072
1169
  const ctx: FleetContext = {
1073
1170
  accountId: session.accountId,
1074
1171
  workspaceId: session.workspaceId,
@@ -1567,18 +1664,11 @@ export async function postUserMessageTurn(
1567
1664
  if (!reference) {
1568
1665
  throw new Error("workspace custom model reference disappeared");
1569
1666
  }
1570
- const active =
1571
- reference.providerKind === "openrouter"
1572
- ? await lockActiveWorkspaceOpenRouterCustomModelForAdmission(tx, {
1573
- accountId,
1574
- workspaceId,
1575
- upstreamModelId: reference.upstreamModelId,
1576
- })
1577
- : await lockActiveWorkspaceGatewayCustomModelForAdmission(tx, {
1578
- accountId,
1579
- workspaceId,
1580
- upstreamModelId: reference.upstreamModelId,
1581
- });
1667
+ const active = await lockActiveCustomModelForAdmission(tx, {
1668
+ accountId,
1669
+ workspaceId,
1670
+ reference,
1671
+ });
1582
1672
  if (!active) {
1583
1673
  throw new HTTPException(422, {
1584
1674
  message: `model is not available: ${freshWorkspaceCustomModel}`,
@@ -1676,9 +1766,7 @@ async function resolveWorkspaceModelBoundarySettings(
1676
1766
  modelIds: readonly (string | null | undefined)[],
1677
1767
  retainedProductModelId?: string | null,
1678
1768
  ): Promise<Settings> {
1679
- const retainedWorkspaceModel =
1680
- retainedProductModelId?.startsWith(WORKSPACE_GATEWAY_MODEL_ID_PREFIX) === true ||
1681
- retainedProductModelId?.startsWith(WORKSPACE_OPENROUTER_MODEL_ID_PREFIX) === true;
1769
+ const retainedCatalogModel = isCatalogOverlayModel(retainedProductModelId);
1682
1770
  if (deps.catalogSourceSettings) {
1683
1771
  // The adapter already resolved one exact workspace catalog snapshot for
1684
1772
  // this request. Preserve it for fresh selections, but an existing session
@@ -1686,16 +1774,10 @@ async function resolveWorkspaceModelBoundarySettings(
1686
1774
  // intentionally omitted. Re-open only the unoverlaid source for that
1687
1775
  // retention lookup; never feed the synthetic workspace provider back
1688
1776
  // through deployment validation.
1689
- if (!retainedWorkspaceModel) return deps.settings;
1777
+ if (!retainedCatalogModel) return deps.settings;
1690
1778
  }
1691
- const workspaceModelIds = modelIds.filter(
1692
- (modelId): modelId is string =>
1693
- typeof modelId === "string" &&
1694
- (modelId.startsWith(WORKSPACE_GATEWAY_MODEL_ID_PREFIX) ||
1695
- modelId.startsWith(WORKSPACE_OPENROUTER_MODEL_ID_PREFIX)),
1696
- );
1697
1779
  const needsWorkspaceResolution =
1698
- deps.settings.modelCatalogSource === "database" || workspaceModelIds.length > 0;
1780
+ deps.settings.modelCatalogSource === "database" || modelIds.some(isCatalogOverlayModel);
1699
1781
  if (!needsWorkspaceResolution) return deps.settings;
1700
1782
  return (
1701
1783
  await resolveWorkspaceCatalogSettings(deps.db, deps.catalogSourceSettings ?? deps.settings, {
@@ -1859,6 +1941,7 @@ export async function createSessionForRequestWithOutcome(
1859
1941
  ? { activeManagedHumanSubjectId: replayManagedHumanSubjectId }
1860
1942
  : {}),
1861
1943
  createIdempotencyKey: payload.idempotencyKey,
1944
+ selectedInstalledSkillIds: payload.installedSkillIds ?? [],
1862
1945
  ...(payload.requestedSessionId ? { requestedSessionId: payload.requestedSessionId } : {}),
1863
1946
  visibility: effectiveVisibility,
1864
1947
  variableSetIds: payload.variableSetIds ?? [],
@@ -2021,9 +2104,43 @@ export async function createSessionForRequestWithOutcome(
2021
2104
  ? payload.resources
2022
2105
  : (parentSession?.resources ?? payload.resources),
2023
2106
  );
2024
- const skills = hasOwnProperty(rawPayload, "skills")
2107
+ const inheritedOrSubmittedSkills = hasOwnProperty(rawPayload, "skills")
2025
2108
  ? payload.skills
2026
2109
  : (parentSession?.skills ?? payload.skills);
2110
+ const selectedInstalledSkillIds = payload.installedSkillIds ?? [];
2111
+ const selectedInstalledSkills: SessionSkill[] = [];
2112
+ if (selectedInstalledSkillIds.length > 0) {
2113
+ const installedSkills = await listInstalledPortableSkills(db, workspaceId, {
2114
+ includeSessionSelected: true,
2115
+ });
2116
+ const installedById = new Map(installedSkills.map((skill) => [skill.capabilityId, skill]));
2117
+ for (const capabilityId of selectedInstalledSkillIds) {
2118
+ const installed = installedById.get(capabilityId);
2119
+ if (!installed) {
2120
+ throw new HTTPException(422, {
2121
+ message: `Session-selected Skill is not installed in this workspace: ${capabilityId}`,
2122
+ });
2123
+ }
2124
+ if (installed.activationMode !== "session_selected") {
2125
+ throw new HTTPException(422, {
2126
+ message: `Installed Skill does not require explicit session selection: ${capabilityId}`,
2127
+ });
2128
+ }
2129
+ selectedInstalledSkills.push({
2130
+ name: installed.name,
2131
+ description: installed.description,
2132
+ files: installed.files.map((file) => ({ path: file.path, content: file.content })),
2133
+ });
2134
+ }
2135
+ }
2136
+ let skills: SessionSkill[];
2137
+ try {
2138
+ skills = SessionSkills.parse([...inheritedOrSubmittedSkills, ...selectedInstalledSkills]);
2139
+ } catch (error) {
2140
+ throw new HTTPException(422, {
2141
+ message: error instanceof Error ? error.message : "invalid session Skill selection",
2142
+ });
2143
+ }
2027
2144
  const toolsProvided = hasOwnProperty(rawPayload, "tools");
2028
2145
  // Visibility became durable draft state after older clients had already
2029
2146
  // written rows without it. Compare it only when the create request supplied
@@ -2322,7 +2439,10 @@ export async function createSessionForRequestWithOutcome(
2322
2439
  payload.firstPartyMcpTools,
2323
2440
  parentSession ? parentSession.firstPartyMcpTools : undefined,
2324
2441
  workspaceFirstPartyDefaults && !parentSession
2325
- ? { ...deploymentFirstPartyMcpToolPolicy, default: workspaceFirstPartyDefaults }
2442
+ ? {
2443
+ ...deploymentFirstPartyMcpToolPolicy,
2444
+ default: workspaceFirstPartyDefaults,
2445
+ }
2326
2446
  : deploymentFirstPartyMcpToolPolicy,
2327
2447
  );
2328
2448
  const googleDrivePublicationEnabled =
@@ -2398,7 +2518,10 @@ export async function createSessionForRequestWithOutcome(
2398
2518
  let sandboxGroupId: string | null = null;
2399
2519
  let inheritedBackend: Session["sandboxBackend"] | undefined;
2400
2520
  let inheritedSandboxOs: Session["sandboxOs"] | undefined;
2401
- let inheritedActiveTarget: { sandboxId: string; workingDir: string | null } | null = null;
2521
+ let inheritedActiveTarget: {
2522
+ sandboxId: string;
2523
+ workingDir: string | null;
2524
+ } | null = null;
2402
2525
  // ENV-AWARE GROUPING: under the CURRENT mechanics the workspace VariableSet is
2403
2526
  // creation-time box state — the box's manifest env is fixed when it is cold-
2404
2527
  // created, and the SDK's provided-session guard rejects any manifest-env delta
@@ -2707,6 +2830,7 @@ export async function createSessionForRequestWithOutcome(
2707
2830
  ...(xaiProviderAccountAuthoritySnapshot ? { xaiProviderAccountAuthoritySnapshot } : {}),
2708
2831
  parentSessionId,
2709
2832
  createIdempotencyKey: payload.idempotencyKey ?? null,
2833
+ selectedInstalledSkillIds,
2710
2834
  maxNestedAgentDepthOverride: payload.maxNestedAgentDepth ?? null,
2711
2835
  allowNestedAgentDepthIncrease: hasPermission(grant.permissions, "workspace:admin"),
2712
2836
  subjectId: grant.subjectId,
@@ -3158,7 +3282,15 @@ export async function acceptSessionUserMessageWithOutcome(
3158
3282
  ? { schedulePostCommit: deps.schedulePromptPostCommit }
3159
3283
  : {}),
3160
3284
  });
3161
- return { accepted, turn, draft, receipt, routing, interruptionCount, replay };
3285
+ return {
3286
+ accepted,
3287
+ turn,
3288
+ draft,
3289
+ receipt,
3290
+ routing,
3291
+ interruptionCount,
3292
+ replay,
3293
+ };
3162
3294
  } catch (error) {
3163
3295
  if (input.clientEventId && boundaryRequestHash) {
3164
3296
  const replay = await withWorkspaceSubjectSessionActivityRls(
package/src/index.ts CHANGED
@@ -69,12 +69,14 @@ export * from "./billing/limits";
69
69
  // postUserMessageTurn, createAndStartSession, capability/pack/environment/
70
70
  // scheduled-task/workspace-member logic, …).
71
71
  export * from "./domain/capabilities";
72
+ export * from "./domain/host-mcp-authority-source-admission";
72
73
  export * from "./domain/skill-imports";
73
74
  export * from "./domain/environments";
74
75
  export * from "./rigs";
75
76
  export * from "./domain/packs";
76
77
  export * from "./domain/automations";
77
78
  export * from "./domain/pr-review";
79
+ export * from "./domain/product-integration-pack";
78
80
  export * from "./domain/personal-connection-delegations";
79
81
  export * from "./domain/resources";
80
82
  export * from "./domain/github-repository-bindings";