@opengeni/core 2.2.0-canary.0 → 2.4.0-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.
- package/dist/application/session-tenancy.d.ts +1 -1
- package/dist/dependencies.d.ts +38 -0
- package/dist/domain/insights.d.ts +15 -0
- package/dist/domain/remember.d.ts +4 -1
- package/dist/domain/sessions.d.ts +4 -3
- package/dist/index.js +280 -239
- package/dist/index.js.map +1 -1
- package/dist/rigs/provider-images.d.ts +1 -1
- package/package.json +10 -10
- package/src/access/index.ts +1 -0
- package/src/application/new-session-drafts.ts +24 -10
- package/src/application/session-tenancy.ts +98 -5
- package/src/dependencies.ts +35 -0
- package/src/domain/insights.ts +112 -162
- package/src/domain/organization-membership-lifecycle.ts +2 -1
- package/src/domain/packs.ts +10 -8
- package/src/domain/remember.ts +37 -15
- package/src/domain/sessions.ts +49 -44
- package/src/rigs/index.ts +4 -5
- package/src/rigs/provider-images.ts +2 -3
- package/src/sandbox/runtime-settings.ts +11 -11
package/src/domain/packs.ts
CHANGED
|
@@ -535,13 +535,15 @@ async function resolvePackRig(
|
|
|
535
535
|
image: null,
|
|
536
536
|
};
|
|
537
537
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
538
|
+
// Explicit Rig images are disabled: a selected Rig always composes on the
|
|
539
|
+
// deployment platform base. Historical image values remain stored but are
|
|
540
|
+
// neither effective runtime truth nor a valid v2 Pack compatibility target.
|
|
541
|
+
const image = null;
|
|
542
|
+
const status = pack.sandboxImage
|
|
543
|
+
? "mismatch"
|
|
544
|
+
: pack.rig?.requireVerified && rig.activeVersionHealth?.checkHealth !== "passing"
|
|
545
|
+
? "unverified"
|
|
546
|
+
: "ready";
|
|
545
547
|
return {
|
|
546
548
|
required,
|
|
547
549
|
status,
|
|
@@ -561,7 +563,7 @@ function packRigBlocker(rig: PackRigResolution, legacyImage: string | null): str
|
|
|
561
563
|
return "Verify the selected compute environment before installing this Pack";
|
|
562
564
|
}
|
|
563
565
|
if (legacyImage) {
|
|
564
|
-
return `
|
|
566
|
+
return `This Pack requires the retired explicit sandbox image ${legacyImage}; Rig-bound Packs currently must use the deployment-managed platform sandbox`;
|
|
565
567
|
}
|
|
566
568
|
return "The selected compute environment does not satisfy this Pack's requirement";
|
|
567
569
|
}
|
package/src/domain/remember.ts
CHANGED
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
getWorkspaceInstructionPolicyBaseline,
|
|
28
28
|
getWorkspaceKnowledgeChangeProposalSummary,
|
|
29
29
|
getWorkspaceKnowledgeClaimInitiatingHuman,
|
|
30
|
+
materializeConfirmedRememberKnowledgeMemory,
|
|
30
31
|
nestedPostgresSqlState,
|
|
31
32
|
rebaselineWorkspaceInstructionPolicyKnowledgeProposal,
|
|
32
33
|
} from "@opengeni/db";
|
|
@@ -101,6 +102,7 @@ export type RememberRouterOptions = {
|
|
|
101
102
|
rebaselineProposal?: typeof rebaselineWorkspaceInstructionPolicyKnowledgeProposal;
|
|
102
103
|
activateHumanConfirmed?: typeof activateHumanConfirmedLearningDecision;
|
|
103
104
|
confirmKnowledgeClaim?: typeof confirmRememberKnowledgeClaim;
|
|
105
|
+
materializeKnowledgeMemory?: typeof materializeConfirmedRememberKnowledgeMemory;
|
|
104
106
|
proposalSummary?: typeof getWorkspaceKnowledgeChangeProposalSummary;
|
|
105
107
|
claimInitiatingHuman?: typeof getWorkspaceKnowledgeClaimInitiatingHuman;
|
|
106
108
|
instructionPolicyBaseline?: typeof getWorkspaceInstructionPolicyBaseline;
|
|
@@ -283,6 +285,8 @@ function activationSummary(receipt: GovernedLearningActivationReceipt) {
|
|
|
283
285
|
* and the result is either an immediate activation (automatic policy), a
|
|
284
286
|
* proposal for the human Knowledge review lifecycle, or a durable proposal that
|
|
285
287
|
* still needs one bound human confirmation through `request_human_input`.
|
|
288
|
+
* A confirmed Knowledge claim is then materialized as a keyword-searchable
|
|
289
|
+
* Memory record from its exact approved Task-note text.
|
|
286
290
|
*/
|
|
287
291
|
export function createRememberRouter(options: RememberRouterOptions): {
|
|
288
292
|
remember: (input: { attempt: unknown; request: unknown }) => Promise<RememberReceiptType>;
|
|
@@ -297,6 +301,8 @@ export function createRememberRouter(options: RememberRouterOptions): {
|
|
|
297
301
|
const activateHumanConfirmed =
|
|
298
302
|
options.activateHumanConfirmed ?? activateHumanConfirmedLearningDecision;
|
|
299
303
|
const confirmKnowledgeClaim = options.confirmKnowledgeClaim ?? confirmRememberKnowledgeClaim;
|
|
304
|
+
const materializeKnowledgeMemory =
|
|
305
|
+
options.materializeKnowledgeMemory ?? materializeConfirmedRememberKnowledgeMemory;
|
|
300
306
|
const proposalSummary = options.proposalSummary ?? getWorkspaceKnowledgeChangeProposalSummary;
|
|
301
307
|
const claimInitiatingHuman =
|
|
302
308
|
options.claimInitiatingHuman ?? getWorkspaceKnowledgeClaimInitiatingHuman;
|
|
@@ -362,7 +368,11 @@ export function createRememberRouter(options: RememberRouterOptions): {
|
|
|
362
368
|
scope: request.scope,
|
|
363
369
|
};
|
|
364
370
|
if (route.decision === "blocked" || route.write === null) {
|
|
365
|
-
return RememberReceipt.parse({
|
|
371
|
+
return RememberReceipt.parse({
|
|
372
|
+
...base,
|
|
373
|
+
status: "blocked",
|
|
374
|
+
reason: "learning_policy_off",
|
|
375
|
+
});
|
|
366
376
|
}
|
|
367
377
|
if (route.write.knowledgeChangeProposalId === null) {
|
|
368
378
|
// Knowledge is owned by the human review lifecycle: the same one-click
|
|
@@ -424,19 +434,30 @@ export function createRememberRouter(options: RememberRouterOptions): {
|
|
|
424
434
|
if (!initiatingHuman) {
|
|
425
435
|
throw new RememberError("proposal_unavailable", "The remember claim is not available");
|
|
426
436
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
437
|
+
// Approval and Memory materialization are one outer transaction. The
|
|
438
|
+
// nested RLS helpers use savepoints, so a failed Memory write rolls the
|
|
439
|
+
// approval back instead of leaving an approved but unretrievable claim.
|
|
440
|
+
const { receipt, materialization } = await options.db.transaction(async (tx) => {
|
|
441
|
+
const transaction = tx as unknown as Database;
|
|
442
|
+
const activationReceipt = await confirmKnowledgeClaim(transaction, {
|
|
443
|
+
caller: {
|
|
444
|
+
workspaceId: attempt.workspaceId,
|
|
445
|
+
subjectId: initiatingHuman,
|
|
446
|
+
sessionId: attempt.sessionId,
|
|
447
|
+
turnId: attempt.turnId,
|
|
448
|
+
executionGeneration: attempt.executionGeneration,
|
|
449
|
+
},
|
|
450
|
+
request: {
|
|
451
|
+
operationId: request.operationId,
|
|
452
|
+
claimId: request.claimId,
|
|
453
|
+
humanInputRequestId: request.humanInputRequestId,
|
|
454
|
+
},
|
|
455
|
+
});
|
|
456
|
+
const materializedMemory = await materializeKnowledgeMemory(
|
|
457
|
+
transaction,
|
|
458
|
+
activationReceipt,
|
|
459
|
+
);
|
|
460
|
+
return { receipt: activationReceipt, materialization: materializedMemory };
|
|
440
461
|
});
|
|
441
462
|
return RememberConfirmReceipt.parse({
|
|
442
463
|
status: "activated",
|
|
@@ -448,10 +469,11 @@ export function createRememberRouter(options: RememberRouterOptions): {
|
|
|
448
469
|
destination: "knowledge",
|
|
449
470
|
receiptId: receipt.id,
|
|
450
471
|
claimId: receipt.claimId,
|
|
472
|
+
memoryId: materialization.memoryId,
|
|
451
473
|
approvalReviewId: receipt.approvalReviewId,
|
|
452
474
|
effectiveAt: receipt.createdAt,
|
|
453
475
|
authorityKind: "human_confirmed",
|
|
454
|
-
undo: "
|
|
476
|
+
undo: "memory_management",
|
|
455
477
|
},
|
|
456
478
|
});
|
|
457
479
|
}
|
package/src/domain/sessions.ts
CHANGED
|
@@ -54,6 +54,7 @@ import {
|
|
|
54
54
|
type TurnInitiator,
|
|
55
55
|
type TurnInitiatorContext,
|
|
56
56
|
type TurnExecutionPolicyV1,
|
|
57
|
+
type VariableSet,
|
|
57
58
|
type XaiProviderAccountAuthoritySnapshotV1,
|
|
58
59
|
} from "@opengeni/contracts";
|
|
59
60
|
import {
|
|
@@ -65,7 +66,7 @@ import {
|
|
|
65
66
|
getChannel,
|
|
66
67
|
getRig,
|
|
67
68
|
getWorkspaceDefaultRigId,
|
|
68
|
-
|
|
69
|
+
listDistinctVariableSetSelectionsInGroup,
|
|
69
70
|
listDistinctRigVersionIdsInGroup,
|
|
70
71
|
getSandbox,
|
|
71
72
|
getSession,
|
|
@@ -87,7 +88,7 @@ import {
|
|
|
87
88
|
requireSession,
|
|
88
89
|
submitHumanPromptInTransaction,
|
|
89
90
|
appendSessionEventsWithLockedSessionUpdate,
|
|
90
|
-
|
|
91
|
+
updateSessionTitleWithEvent,
|
|
91
92
|
withWorkspaceSubjectSessionActivityRls,
|
|
92
93
|
type CreateSessionMcpServerInput,
|
|
93
94
|
type Database,
|
|
@@ -107,7 +108,6 @@ import {
|
|
|
107
108
|
type NewSessionDraftSnapshot,
|
|
108
109
|
} from "@opengeni/db";
|
|
109
110
|
import {
|
|
110
|
-
appendAndPublishEvents,
|
|
111
111
|
publishDurableSessionEvents,
|
|
112
112
|
publishDurableWorkspaceControlEvent,
|
|
113
113
|
type EventBus,
|
|
@@ -640,8 +640,9 @@ export async function createAndStartSessionWithOutcome(input: {
|
|
|
640
640
|
createdBy?: TurnInitiator;
|
|
641
641
|
createdByContext?: TurnInitiatorContext;
|
|
642
642
|
createdByActor?: Extract<SessionCommandActor, { type: "agent_attempt" }> | null;
|
|
643
|
-
// Names/ids only;
|
|
644
|
-
|
|
643
|
+
// Ordered low-to-high precedence. Names/ids only; session.created never
|
|
644
|
+
// carries variable values.
|
|
645
|
+
variableSets?: Array<{ id: string; name: string; scope: VariableSet["scope"] }>;
|
|
645
646
|
// The rig + frozen active rig version resolved at create (M3). Both null ⇒ a
|
|
646
647
|
// rig-less session (byte-for-byte today's behavior). Frozen here so a later
|
|
647
648
|
// rig promote never moves an existing session's version.
|
|
@@ -760,7 +761,8 @@ export async function createAndStartSessionWithOutcome(input: {
|
|
|
760
761
|
reasoningEffort: input.reasoningEffort,
|
|
761
762
|
latencyMode: input.latencyMode ?? "standard",
|
|
762
763
|
sandboxBackend: input.sandboxBackend,
|
|
763
|
-
|
|
764
|
+
variableSetIds: input.variableSets?.map((variableSet) => variableSet.id) ?? [],
|
|
765
|
+
variableSetId: input.variableSets?.at(-1)?.id ?? null,
|
|
764
766
|
rigId: input.rigId ?? null,
|
|
765
767
|
rigVersionId: input.rigVersionId ?? null,
|
|
766
768
|
channelId: input.channelId ?? null,
|
|
@@ -831,7 +833,8 @@ export async function createAndStartSessionWithOutcome(input: {
|
|
|
831
833
|
reasoningEffort: input.reasoningEffort,
|
|
832
834
|
latencyMode: input.latencyMode ?? "standard",
|
|
833
835
|
sandboxBackend: input.sandboxBackend,
|
|
834
|
-
|
|
836
|
+
variableSetIds: input.variableSets?.map((variableSet) => variableSet.id) ?? [],
|
|
837
|
+
variableSetId: input.variableSets?.at(-1)?.id ?? null,
|
|
835
838
|
rigId: input.rigId ?? null,
|
|
836
839
|
rigVersionId: input.rigVersionId ?? null,
|
|
837
840
|
channelId: input.channelId ?? null,
|
|
@@ -900,7 +903,7 @@ async function finishStartSession(
|
|
|
900
903
|
reasoningEffort: Settings["openaiReasoningEffort"];
|
|
901
904
|
turnExecutionPolicy: TurnExecutionPolicyV1;
|
|
902
905
|
sandboxBackend: Settings["sandboxBackend"];
|
|
903
|
-
|
|
906
|
+
variableSets?: Array<{ id: string; name: string; scope: VariableSet["scope"] }>;
|
|
904
907
|
goal?: GoalSpec | null;
|
|
905
908
|
sessionMcpServers?: SessionMcpServerMetadata[];
|
|
906
909
|
seedTargetSandbox?: {
|
|
@@ -978,10 +981,13 @@ async function finishStartSession(
|
|
|
978
981
|
turnExecutionPolicy: input.turnExecutionPolicy,
|
|
979
982
|
createdEventPayload: {
|
|
980
983
|
toolPolicy: input.toolPolicy,
|
|
981
|
-
...(input.
|
|
984
|
+
...(input.variableSets?.length
|
|
982
985
|
? {
|
|
983
|
-
|
|
984
|
-
|
|
986
|
+
variableSetIds: input.variableSets.map((variableSet) => variableSet.id),
|
|
987
|
+
variableSets: input.variableSets,
|
|
988
|
+
// Legacy highest-precedence aliases.
|
|
989
|
+
variableSetId: input.variableSets.at(-1)!.id,
|
|
990
|
+
variableSetName: input.variableSets.at(-1)!.name,
|
|
985
991
|
}
|
|
986
992
|
: {}),
|
|
987
993
|
...(input.sessionMcpServers?.length ? { mcpServers: input.sessionMcpServers } : {}),
|
|
@@ -1719,17 +1725,15 @@ export async function createSessionForRequestWithOutcome(
|
|
|
1719
1725
|
});
|
|
1720
1726
|
}
|
|
1721
1727
|
await validateFileResources(db, grant.accountId, workspaceId, grant.subjectId, resources);
|
|
1722
|
-
//
|
|
1723
|
-
//
|
|
1724
|
-
//
|
|
1725
|
-
const
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
)
|
|
1732
|
-
: null;
|
|
1728
|
+
// Every selected Variable Set is independently authorized. Scope does not
|
|
1729
|
+
// affect precedence: explicit order is low-to-high and later sets win name
|
|
1730
|
+
// collisions.
|
|
1731
|
+
const variableSets: VariableSet[] = [];
|
|
1732
|
+
for (const variableSetId of payload.variableSetIds ?? []) {
|
|
1733
|
+
variableSets.push(
|
|
1734
|
+
await validateVariableSetAttachment({ settings, db }, grant, workspaceId, variableSetId),
|
|
1735
|
+
);
|
|
1736
|
+
}
|
|
1733
1737
|
// RIG BINDING (M3). Resolve the rig this session rides — a UUID binds that
|
|
1734
1738
|
// rig, null explicitly opts out, and omission inherits the workspace default
|
|
1735
1739
|
// (workspaces.default_rig_id) — then FREEZE both the rig id and its currently-
|
|
@@ -1827,7 +1831,12 @@ export async function createSessionForRequestWithOutcome(
|
|
|
1827
1831
|
...(payload.sandboxBackend ? { sandboxBackend: payload.sandboxBackend } : {}),
|
|
1828
1832
|
...(payload.targetSandboxId ? { targetSandboxId: payload.targetSandboxId } : {}),
|
|
1829
1833
|
...(payload.workingDir ? { workingDir: payload.workingDir } : {}),
|
|
1830
|
-
...(
|
|
1834
|
+
...(variableSets.length
|
|
1835
|
+
? {
|
|
1836
|
+
variableSetIds: variableSets.map((variableSet) => variableSet.id),
|
|
1837
|
+
variableSetId: variableSets.at(-1)!.id,
|
|
1838
|
+
}
|
|
1839
|
+
: {}),
|
|
1831
1840
|
...(payload.rigId ? { rigId: payload.rigId } : {}),
|
|
1832
1841
|
...(payload.goal ? { goal: payload.goal } : {}),
|
|
1833
1842
|
...(payload.firstPartyMcpPermissions
|
|
@@ -2041,9 +2050,9 @@ export async function createSessionForRequestWithOutcome(
|
|
|
2041
2050
|
// provided-session attach — no shared box state exists to conflict, and
|
|
2042
2051
|
// env-differing spawns from such parents shared safely before the env-aware
|
|
2043
2052
|
// check. They keep sharing (and keep inheriting "none").
|
|
2044
|
-
const
|
|
2045
|
-
const
|
|
2046
|
-
|
|
2053
|
+
const requestedVariableSetIds = variableSets.map((variableSet) => variableSet.id);
|
|
2054
|
+
const variableSetsMatchGroup = (memberVariableSetIds: readonly string[]): boolean =>
|
|
2055
|
+
stableJson(memberVariableSetIds) === stableJson(requestedVariableSetIds);
|
|
2047
2056
|
// RIG-AWARE GROUPING (M3), the exact sibling of the env-aware gate above: the
|
|
2048
2057
|
// box's rig-baked setup/tooling is fixed at cold-create, so a session joining a
|
|
2049
2058
|
// shared box must ride the SAME frozen rig_version_id. A mismatch is a genuine
|
|
@@ -2067,8 +2076,7 @@ export async function createSessionForRequestWithOutcome(
|
|
|
2067
2076
|
}
|
|
2068
2077
|
const parent = parentSession;
|
|
2069
2078
|
const parentBoxed = parent.sandboxBackend !== "none";
|
|
2070
|
-
const variableSetMismatch =
|
|
2071
|
-
parentBoxed && !variableSetMatchesGroup(parent.variableSetId ?? null);
|
|
2079
|
+
const variableSetMismatch = parentBoxed && !variableSetsMatchGroup(parent.variableSetIds);
|
|
2072
2080
|
let rigMismatch = parentBoxed && !rigVersionMatchesGroup(parent.rigVersionId ?? null);
|
|
2073
2081
|
if (parentBoxed && !rigMismatch) {
|
|
2074
2082
|
const memberRigVersionIds = await listDistinctRigVersionIdsInGroup(
|
|
@@ -2113,14 +2121,14 @@ export async function createSessionForRequestWithOutcome(
|
|
|
2113
2121
|
// the join verdict nondeterministic. Post-env-aware groups are homogeneous
|
|
2114
2122
|
// (both join paths enforce equality), so this reads one distinct value in
|
|
2115
2123
|
// the common case; a mixed legacy group deterministically rejects.
|
|
2116
|
-
const
|
|
2124
|
+
const memberVariableSetSelections = await listDistinctVariableSetSelectionsInGroup(
|
|
2117
2125
|
db,
|
|
2118
2126
|
workspaceId,
|
|
2119
2127
|
sandboxChoice.groupId,
|
|
2120
2128
|
);
|
|
2121
2129
|
if (
|
|
2122
|
-
!
|
|
2123
|
-
|
|
2130
|
+
!memberVariableSetSelections.every((memberVariableSetIds) =>
|
|
2131
|
+
variableSetsMatchGroup(memberVariableSetIds),
|
|
2124
2132
|
)
|
|
2125
2133
|
) {
|
|
2126
2134
|
throw new HTTPException(422, {
|
|
@@ -2263,7 +2271,11 @@ export async function createSessionForRequestWithOutcome(
|
|
|
2263
2271
|
...(creationInitiator.initiator ? { createdBy: creationInitiator.initiator } : {}),
|
|
2264
2272
|
...(creationInitiator.context ? { createdByContext: creationInitiator.context } : {}),
|
|
2265
2273
|
createdByActor: creationInitiator.actor ?? null,
|
|
2266
|
-
|
|
2274
|
+
variableSets: variableSets.map((variableSet) => ({
|
|
2275
|
+
id: variableSet.id,
|
|
2276
|
+
name: variableSet.name,
|
|
2277
|
+
scope: variableSet.scope,
|
|
2278
|
+
})),
|
|
2267
2279
|
// Frozen rig binding (M3): both null for a rig-less session (today's path).
|
|
2268
2280
|
rigId: frozenRigId,
|
|
2269
2281
|
rigVersionId: frozenRigVersionId,
|
|
@@ -2663,25 +2675,18 @@ export async function updateSessionTitle(
|
|
|
2663
2675
|
surface: "core",
|
|
2664
2676
|
});
|
|
2665
2677
|
const workspaceId = grant.workspaceId;
|
|
2666
|
-
const result = await
|
|
2678
|
+
const result = await updateSessionTitleWithEvent(db, {
|
|
2667
2679
|
workspaceId,
|
|
2668
2680
|
sessionId,
|
|
2669
2681
|
title,
|
|
2670
2682
|
source,
|
|
2671
2683
|
});
|
|
2672
|
-
if (result.
|
|
2673
|
-
await
|
|
2674
|
-
{
|
|
2675
|
-
type: "session.title_set",
|
|
2676
|
-
payload: {
|
|
2677
|
-
title: result.title ?? title,
|
|
2678
|
-
source,
|
|
2679
|
-
},
|
|
2680
|
-
},
|
|
2681
|
-
]);
|
|
2684
|
+
if (result.events.length > 0) {
|
|
2685
|
+
await publishDurableSessionEvents(bus, workspaceId, sessionId, result.events);
|
|
2682
2686
|
}
|
|
2683
2687
|
return {
|
|
2684
|
-
|
|
2688
|
+
updated: result.updated,
|
|
2689
|
+
title: result.title,
|
|
2685
2690
|
relatedSessionAccess: authorization?.relatedSessionAccess ?? "root",
|
|
2686
2691
|
};
|
|
2687
2692
|
}
|
package/src/rigs/index.ts
CHANGED
|
@@ -252,7 +252,7 @@ export async function createRigForApi(
|
|
|
252
252
|
description: payload.description ?? null,
|
|
253
253
|
createdBy,
|
|
254
254
|
initialVersion: {
|
|
255
|
-
image:
|
|
255
|
+
image: null,
|
|
256
256
|
setupScript: payload.setupScript ?? null,
|
|
257
257
|
checks: payload.checks,
|
|
258
258
|
credentialHooks: payload.credentialHooks,
|
|
@@ -452,7 +452,7 @@ export async function promoteSetupAppendChange(
|
|
|
452
452
|
});
|
|
453
453
|
}
|
|
454
454
|
const nextDefinition = {
|
|
455
|
-
image:
|
|
455
|
+
image: null,
|
|
456
456
|
setupScript: appendRigSetupCommand(base.setupScript, payload.command),
|
|
457
457
|
checks: base.checks,
|
|
458
458
|
credentialHooks: base.credentialHooks,
|
|
@@ -526,7 +526,6 @@ export async function promoteVerifiedDefinitionEditChangeForApi(
|
|
|
526
526
|
throw new HTTPException(404, { message: "base rig version not found" });
|
|
527
527
|
}
|
|
528
528
|
const payload = change.payload as {
|
|
529
|
-
image?: unknown;
|
|
530
529
|
setupScript?: unknown;
|
|
531
530
|
checks?: unknown;
|
|
532
531
|
credentialHooks?: unknown;
|
|
@@ -534,7 +533,7 @@ export async function promoteVerifiedDefinitionEditChangeForApi(
|
|
|
534
533
|
changelog?: unknown;
|
|
535
534
|
};
|
|
536
535
|
const nextDefinition = {
|
|
537
|
-
image:
|
|
536
|
+
image: null,
|
|
538
537
|
setupScript:
|
|
539
538
|
payload.setupScript === undefined ? base.setupScript : (payload.setupScript as string | null),
|
|
540
539
|
checks: Array.isArray(payload.checks) ? (payload.checks as RigVersion["checks"]) : base.checks,
|
|
@@ -606,7 +605,7 @@ export async function createRigVersionForApi(
|
|
|
606
605
|
rig.workspaceId,
|
|
607
606
|
rig.id,
|
|
608
607
|
{
|
|
609
|
-
image:
|
|
608
|
+
image: null,
|
|
610
609
|
setupScript: payload.setupScript === undefined ? base.setupScript : payload.setupScript,
|
|
611
610
|
checks: payload.checks ?? base.checks,
|
|
612
611
|
credentialHooks: payload.credentialHooks ?? base.credentialHooks,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
|
|
12
12
|
export type RigProviderImageDefinition = Pick<
|
|
13
13
|
RigVersion,
|
|
14
|
-
"
|
|
14
|
+
"setupScript" | "checks" | "credentialHooks" | "defaultVariableSetIds"
|
|
15
15
|
>;
|
|
16
16
|
|
|
17
17
|
function sha256(value: string): string {
|
|
@@ -42,10 +42,9 @@ export function rigProviderImageContentHash(input: {
|
|
|
42
42
|
}): string {
|
|
43
43
|
return sha256(
|
|
44
44
|
stableJson({
|
|
45
|
-
version:
|
|
45
|
+
version: 2,
|
|
46
46
|
backend: input.backend,
|
|
47
47
|
sourceImage: input.sourceImage,
|
|
48
|
-
image: input.definition.image,
|
|
49
48
|
setupScript: input.definition.setupScript,
|
|
50
49
|
checks: input.definition.checks,
|
|
51
50
|
credentialHooks: input.definition.credentialHooks,
|
|
@@ -83,13 +83,11 @@ export function settingsWithPackSandboxImage(
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
export function settingsWithRigImage(settings: Settings, rigImage: string | null): Settings {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
modalImageId: undefined,
|
|
92
|
-
};
|
|
86
|
+
// Explicit Rig image overrides are intentionally inert. Preserve this helper
|
|
87
|
+
// as a compatibility seam for callers and historical rows while ensuring the
|
|
88
|
+
// deployment-owned platform image remains authoritative.
|
|
89
|
+
void rigImage;
|
|
90
|
+
return settings;
|
|
93
91
|
}
|
|
94
92
|
|
|
95
93
|
export function rigProviderImageSourceImage(
|
|
@@ -250,10 +248,12 @@ export async function resolveSessionSandboxRuntime(
|
|
|
250
248
|
throw new Error(`Frozen rig version ${session.rigVersionId} is unavailable`);
|
|
251
249
|
}
|
|
252
250
|
const legacy = legacySandboxRuntimeFromPacks(packs);
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
251
|
+
// A Rig is always a setup/check layer over the deployment-owned platform
|
|
252
|
+
// sandbox. Legacy pre-v2 Pack image compatibility remains available only to
|
|
253
|
+
// rig-less sessions; it cannot replace the base beneath a Rig.
|
|
254
|
+
const logicalSettings = rigVersion
|
|
255
|
+
? settings
|
|
256
|
+
: settingsWithPackSandboxImage(settings, legacy.sandboxImage, legacy.sandboxProviderImages);
|
|
257
257
|
return {
|
|
258
258
|
settings: {
|
|
259
259
|
...logicalSettings,
|