fix(manager): allow session provider switches (#240)
This commit is contained in:
+2
-3
@@ -685,9 +685,8 @@ export function assertSessionBoundary(existing: SessionRecord, input: CreateRunI
|
||||
if (existing.tenantId !== input.tenantId || existing.projectId !== input.projectId) {
|
||||
throw new AgentRunError("tenant-policy-denied", "sessionRef cannot be reused across tenant or project boundary", { httpStatus: 403, details: { sessionId: existing.sessionId, valuesPrinted: false } });
|
||||
}
|
||||
if (existing.backendProfile !== input.backendProfile) {
|
||||
throw new AgentRunError("schema-invalid", "sessionRef cannot be reused across backendProfile boundary", { httpStatus: 400, details: { sessionId: existing.sessionId, existingBackendProfile: existing.backendProfile, requestedBackendProfile: input.backendProfile, valuesPrinted: false } });
|
||||
}
|
||||
// backendProfile is run-scoped, not session/PVC-scoped. A HWLAB session must be
|
||||
// able to switch providers without losing its session storage or workspace.
|
||||
}
|
||||
|
||||
export function statusFromTerminal(terminalStatus: TerminalStatus): RunRecord["status"] {
|
||||
|
||||
@@ -45,9 +45,9 @@ console.log(JSON.stringify({ apiVersion: manifest.apiVersion, kind: manifest.kin
|
||||
await assertEventContractAndCompletedSemantics(client, context, server.baseUrl);
|
||||
await assertRunnerJobStatus(client, context);
|
||||
assertThreadResumeStandard(context);
|
||||
await assertSessionProfileIsolation(client, context);
|
||||
await assertSessionProfileSwitchAllowed(client, context);
|
||||
await assertResourceBundleFailure(client, context, server.baseUrl);
|
||||
return { name: "hwlab-baseline-contract", tests: ["event-contract", "result-completed-terminal-only", "bounded-output-summary", "runner-job-status", "thread-resume-standard", "backend-preflight-redacted", "session-profile-isolation", "resource-bundle-failure-kind"] };
|
||||
return { name: "hwlab-baseline-contract", tests: ["event-contract", "result-completed-terminal-only", "bounded-output-summary", "runner-job-status", "thread-resume-standard", "backend-preflight-redacted", "session-profile-switch", "resource-bundle-failure-kind"] };
|
||||
} finally {
|
||||
await new Promise<void>((resolve) => server.server.close(() => resolve()));
|
||||
}
|
||||
@@ -166,13 +166,13 @@ function assertThreadResumeStandard(context: SelfTestContext): void {
|
||||
assert.equal(backendTurnOptions({ ...run, sessionRef: { sessionId: "selftest-thread-standard-session" } }, command).threadId, undefined);
|
||||
}
|
||||
|
||||
async function assertSessionProfileIsolation(client: ManagerClient, context: SelfTestContext): Promise<void> {
|
||||
async function assertSessionProfileSwitchAllowed(client: ManagerClient, context: SelfTestContext): Promise<void> {
|
||||
const first = await client.post("/api/v1/runs", runPayload(context, "codex", "selftest-profile-boundary-session")) as { id: string };
|
||||
await client.patch(`/api/v1/runs/${first.id}/status`, { terminalStatus: "completed", failureKind: null, failureMessage: null, threadId: "thread_codex_profile_boundary", turnId: "turn_profile_boundary" });
|
||||
await assert.rejects(
|
||||
() => client.post("/api/v1/runs", runPayload(context, "deepseek", "selftest-profile-boundary-session")),
|
||||
(error) => error instanceof Error && error.message.includes("backendProfile boundary"),
|
||||
);
|
||||
const second = await client.post("/api/v1/runs", runPayload(context, "deepseek", "selftest-profile-boundary-session")) as { id: string; backendProfile?: string; sessionRef?: { sessionId?: string } };
|
||||
assert.ok(second.id);
|
||||
assert.equal(second.backendProfile, "deepseek");
|
||||
assert.equal(second.sessionRef?.sessionId, "selftest-profile-boundary-session");
|
||||
}
|
||||
|
||||
async function assertResourceBundleFailure(client: ManagerClient, context: SelfTestContext, managerUrl: string): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user