fix(sessions_spawn): hard-fail invalid model overrides
This commit is contained in:
@@ -223,9 +223,7 @@ describe("subagents", () => {
|
||||
| undefined;
|
||||
const message = params?.message ?? "";
|
||||
const reply =
|
||||
message === "Sub-agent announce step."
|
||||
? "ANNOUNCE_SKIP"
|
||||
: "done";
|
||||
message === "Sub-agent announce step." ? "ANNOUNCE_SKIP" : "done";
|
||||
replyByRunId.set(runId, reply);
|
||||
return {
|
||||
runId,
|
||||
@@ -278,4 +276,35 @@ describe("subagents", () => {
|
||||
model: "claude-haiku-4-5",
|
||||
});
|
||||
});
|
||||
|
||||
it("sessions_spawn fails when model override is invalid", async () => {
|
||||
callGatewayMock.mockReset();
|
||||
const calls: Array<{ method?: string; params?: unknown }> = [];
|
||||
|
||||
callGatewayMock.mockImplementation(async (opts: unknown) => {
|
||||
const request = opts as { method?: string; params?: unknown };
|
||||
calls.push(request);
|
||||
if (request.method === "sessions.patch") {
|
||||
throw new Error("invalid model: bad-model");
|
||||
}
|
||||
return {};
|
||||
});
|
||||
|
||||
const tool = createClawdbotTools({
|
||||
agentSessionKey: "main",
|
||||
agentProvider: "whatsapp",
|
||||
}).find((candidate) => candidate.name === "sessions_spawn");
|
||||
if (!tool) throw new Error("missing sessions_spawn tool");
|
||||
|
||||
const result = await tool.execute("call4", {
|
||||
task: "do thing",
|
||||
timeoutSeconds: 1,
|
||||
model: "bad-model",
|
||||
});
|
||||
expect(result.details).toMatchObject({ status: "error" });
|
||||
expect(
|
||||
String((result.details as { error?: string }).error ?? ""),
|
||||
).toContain("invalid model");
|
||||
expect(calls.some((call) => call.method === "agent")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -220,26 +220,38 @@ export function createSessionsSpawnTool(opts?: {
|
||||
parseAgentSessionKey(requesterInternalKey)?.agentId,
|
||||
);
|
||||
const childSessionKey = `agent:${requesterAgentId}:subagent:${crypto.randomUUID()}`;
|
||||
const patchParams: { key: string; spawnedBy?: string; model?: string } = {
|
||||
key: childSessionKey,
|
||||
};
|
||||
if (opts?.sandboxed === true) {
|
||||
patchParams.spawnedBy = requesterInternalKey;
|
||||
}
|
||||
if (model) {
|
||||
patchParams.model = model;
|
||||
}
|
||||
if (patchParams.spawnedBy || patchParams.model) {
|
||||
try {
|
||||
await callGateway({
|
||||
method: "sessions.patch",
|
||||
params: patchParams,
|
||||
params: { key: childSessionKey, spawnedBy: requesterInternalKey },
|
||||
timeoutMs: 10_000,
|
||||
});
|
||||
} catch {
|
||||
// best-effort; scoping relies on this metadata but spawning still works without it
|
||||
}
|
||||
}
|
||||
if (model) {
|
||||
try {
|
||||
await callGateway({
|
||||
method: "sessions.patch",
|
||||
params: { key: childSessionKey, model },
|
||||
timeoutMs: 10_000,
|
||||
});
|
||||
} catch (err) {
|
||||
const messageText =
|
||||
err instanceof Error
|
||||
? err.message
|
||||
: typeof err === "string"
|
||||
? err
|
||||
: "error";
|
||||
return jsonResult({
|
||||
status: "error",
|
||||
error: messageText,
|
||||
childSessionKey,
|
||||
});
|
||||
}
|
||||
}
|
||||
const childSystemPrompt = buildSubagentSystemPrompt({
|
||||
requesterSessionKey,
|
||||
requesterProvider: opts?.agentProvider,
|
||||
|
||||
Reference in New Issue
Block a user