mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-11 05:11:49 +01:00
Revert "fix(runner): name an ACP agent's rejection of an unadvertised model"
This reverts commit 35aff22dd3.
This commit is contained in:
1 parent
35aff22dd3
commit
6b2142eb00
2 files changed
+1
-52
No files matched your search
@@ -2,7 +2,6 @@ import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { resolveQualifiedAcpxProfile } from "./qualified-profiles.js";
|
||||
import { requireVerifiedAcpxModel } from "./model-verification.js";
|
||||
import { acpxSidecarErrorCode } from "../../cli/acpx-sidecar-input.js";
|
||||
|
||||
describe("ACPX requested model verification", () => {
|
||||
it.each(["claude", "codex", "pi", "grok", "cursor", "copilot"] as const)("selects and verifies an unlisted model unchanged with %s", async agent => {
|
||||
@@ -30,33 +29,6 @@ describe("ACPX requested model verification", () => {
|
||||
expect(getStatus).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it.each(["claude", "codex", "pi", "grok", "cursor", "copilot"] as const)("names an ACP rejection of an unadvertised model as an unsupported model with %s", async agent => {
|
||||
const model = "chaos-missing-model-abc12345";
|
||||
// claude-agent-acp 0.73.0 answers session/set_config_option for an unknown model with this
|
||||
// JSON-RPC error; ACPX wraps it as below (live probe, 2026-11-10).
|
||||
const acp = Object.assign(new Error("Internal error"), {
|
||||
code: -32603, data: { details: `Invalid value for config option model: ${model}` },
|
||||
});
|
||||
const wrapped = new Error(`Failed session/set_config_option for model "${model}": Invalid value for config option model: ${model} (ACP -32603, adapter reported "Internal error")`, { cause: acp });
|
||||
const getStatus = vi.fn(async () => ({ models: { currentModelId: "default", availableModelIds: ["default", "opus", "sonnet"] } }));
|
||||
const setModel = vi.fn(async () => { throw wrapped; });
|
||||
const failure = await requireVerifiedAcpxModel({ getStatus, setModel }, resolveQualifiedAcpxProfile(agent, model))
|
||||
.then(() => null, (error: unknown) => error as Error & { code?: unknown; retryable?: unknown });
|
||||
expect(failure).toMatchObject({ code: "ACP_MODEL_UNSUPPORTED", retryable: false });
|
||||
expect(failure?.cause).toBe(wrapped);
|
||||
expect(acpxSidecarErrorCode(failure!)).toBe("ACP_MODEL_UNSUPPORTED");
|
||||
});
|
||||
|
||||
it("keeps a transport failure or an advertised model's rejection unchanged", async () => {
|
||||
const acp = Object.assign(new Error("Internal error"), { code: -32603, data: { details: "busy" } });
|
||||
for (const [rejected, available] of [[new Error("socket closed"), ["default"]], [acp, ["default", "listed-model"]]] as const) {
|
||||
const getStatus = vi.fn(async () => ({ models: { currentModelId: "default", availableModelIds: [...available] } }));
|
||||
const setModel = vi.fn(async () => { throw rejected; });
|
||||
await expect(requireVerifiedAcpxModel({ getStatus, setModel }, resolveQualifiedAcpxProfile("claude", "listed-model")))
|
||||
.rejects.toBe(rejected);
|
||||
}
|
||||
});
|
||||
|
||||
it("accepts an exact model already reported by the provider", async () => {
|
||||
const getStatus = vi.fn(async () => ({
|
||||
models: {
|
||||
|
||||
@@ -38,22 +38,7 @@ export async function requireVerifiedAcpxModel(
|
||||
);
|
||||
}
|
||||
// Catalogs may be incomplete. Let the provider accept or reject the exact ID.
|
||||
try {
|
||||
await control.setModel(providerModel);
|
||||
} catch (error) {
|
||||
// The provider answered the selection of a model it does not advertise with
|
||||
// an ACP error: it rejected that model. Name it as such so the task asks the
|
||||
// user to choose a model. Transport failures and an advertised model's
|
||||
// rejection keep their original error.
|
||||
const advertised = status.models?.availableModelIds ?? [];
|
||||
if (!advertised.includes(providerModel) && acpErrorResponse(error)) {
|
||||
throw Object.assign(
|
||||
new Error(`ACP agent rejected the requested model ${requestedModel}`, { cause: error }),
|
||||
{ code: "ACP_MODEL_UNSUPPORTED", retryable: false },
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
await control.setModel(providerModel);
|
||||
status = await control.getStatus();
|
||||
}
|
||||
if (status.models?.currentModelId !== providerModel) {
|
||||
@@ -65,14 +50,6 @@ export async function requireVerifiedAcpxModel(
|
||||
return normalizeVerifiedModelStatus(status, profile);
|
||||
}
|
||||
|
||||
/** A JSON-RPC error response from the ACP agent, found on the error or its causes. */
|
||||
function acpErrorResponse(error: unknown, depth = 0): boolean {
|
||||
if (!error || typeof error !== "object" || depth > 5) return false;
|
||||
const entry = error as Record<string, unknown>;
|
||||
if (typeof entry.code === "number" && Number.isInteger(entry.code) && typeof entry.message === "string") return true;
|
||||
return ["acp", "cause", "error"].some(key => acpErrorResponse(entry[key], depth + 1));
|
||||
}
|
||||
|
||||
function acpxModelVerificationError(code: string, message: string): Error {
|
||||
return Object.assign(new Error(message), { code });
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user