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) {
|
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 } });
|
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) {
|
// backendProfile is run-scoped, not session/PVC-scoped. A HWLAB session must be
|
||||||
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 } });
|
// able to switch providers without losing its session storage or workspace.
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function statusFromTerminal(terminalStatus: TerminalStatus): RunRecord["status"] {
|
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 assertEventContractAndCompletedSemantics(client, context, server.baseUrl);
|
||||||
await assertRunnerJobStatus(client, context);
|
await assertRunnerJobStatus(client, context);
|
||||||
assertThreadResumeStandard(context);
|
assertThreadResumeStandard(context);
|
||||||
await assertSessionProfileIsolation(client, context);
|
await assertSessionProfileSwitchAllowed(client, context);
|
||||||
await assertResourceBundleFailure(client, context, server.baseUrl);
|
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 {
|
} finally {
|
||||||
await new Promise<void>((resolve) => server.server.close(() => resolve()));
|
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);
|
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 };
|
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 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(
|
const second = await client.post("/api/v1/runs", runPayload(context, "deepseek", "selftest-profile-boundary-session")) as { id: string; backendProfile?: string; sessionRef?: { sessionId?: string } };
|
||||||
() => client.post("/api/v1/runs", runPayload(context, "deepseek", "selftest-profile-boundary-session")),
|
assert.ok(second.id);
|
||||||
(error) => error instanceof Error && error.message.includes("backendProfile boundary"),
|
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> {
|
async function assertResourceBundleFailure(client: ManagerClient, context: SelfTestContext, managerUrl: string): Promise<void> {
|
||||||
|
|||||||
Reference in New Issue
Block a user