mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-29 04:25:52 +01:00
fix(runner): select qualified ACP model alias
This commit is contained in:
1 parent
063c14c752
commit
9fed1ae0bf
2 files changed
+40
-10
No files matched your search
@@ -24,7 +24,7 @@ describe("ACPX qualified model verification", () => {
|
||||
expect(setModel).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("selects Claude's canonical model and normalizes its ACP selector", async () => {
|
||||
it("accepts and normalizes Claude's qualified ACP selector", async () => {
|
||||
const setModel = vi.fn(async () => undefined);
|
||||
const getStatus = vi.fn(async () => ({
|
||||
models: {
|
||||
@@ -33,6 +33,34 @@ describe("ACPX qualified model verification", () => {
|
||||
},
|
||||
}));
|
||||
|
||||
await expect(
|
||||
requireVerifiedAcpxModel(
|
||||
{ getStatus, setModel },
|
||||
resolveQualifiedAcpxProfile("claude", "claude-sonnet-5"),
|
||||
),
|
||||
).resolves.toMatchObject({
|
||||
models: {
|
||||
currentModelId: "claude-sonnet-5",
|
||||
availableModelIds: ["default", "claude-sonnet-5", "opus"],
|
||||
},
|
||||
});
|
||||
expect(setModel).not.toHaveBeenCalled();
|
||||
expect(getStatus).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("selects Claude's profile-pinned ACP selector from a stale default", async () => {
|
||||
let selected = false;
|
||||
const setModel = vi.fn(async (model: string) => {
|
||||
expect(model).toBe("sonnet");
|
||||
selected = true;
|
||||
});
|
||||
const getStatus = vi.fn(async () => ({
|
||||
models: {
|
||||
currentModelId: selected ? "sonnet" : "default",
|
||||
availableModelIds: ["default", "sonnet", "opus"],
|
||||
},
|
||||
}));
|
||||
|
||||
await expect(
|
||||
requireVerifiedAcpxModel(
|
||||
{ getStatus, setModel },
|
||||
@@ -45,7 +73,7 @@ describe("ACPX qualified model verification", () => {
|
||||
},
|
||||
});
|
||||
expect(setModel).toHaveBeenCalledTimes(1);
|
||||
expect(setModel).toHaveBeenCalledWith("claude-sonnet-5");
|
||||
expect(setModel).toHaveBeenCalledWith("sonnet");
|
||||
expect(getStatus).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
|
||||
@@ -28,24 +28,26 @@ export async function requireVerifiedAcpxModel(
|
||||
);
|
||||
}
|
||||
const requestedModel = profile.qualificationModel;
|
||||
const providerModel = profile.reportedModelId;
|
||||
let status = await control.getStatus();
|
||||
const mustSelectCanonical =
|
||||
profile.reportedModelId !== requestedModel ||
|
||||
status.models?.currentModelId !== requestedModel;
|
||||
if (mustSelectCanonical) {
|
||||
if (status.models?.currentModelId !== providerModel) {
|
||||
if (!control.setModel) {
|
||||
throw acpxModelVerificationError(
|
||||
"ACPX_MODEL_SELECTION_UNAVAILABLE",
|
||||
"ACPX agent cannot verify its canonical model through ACP config options",
|
||||
"ACPX agent cannot verify its qualified model through ACP config options",
|
||||
);
|
||||
}
|
||||
await control.setModel(requestedModel);
|
||||
// The caller-facing model is already pinned by resolveQualifiedAcpxProfile.
|
||||
// Select the immutable ACP-facing identifier from that same profile: some
|
||||
// providers expose a stable selector (for example Claude's `sonnet`) while
|
||||
// Paperclip publishes the canonical model name after verification.
|
||||
await control.setModel(providerModel);
|
||||
status = await control.getStatus();
|
||||
}
|
||||
if (status.models?.currentModelId !== profile.reportedModelId) {
|
||||
if (status.models?.currentModelId !== providerModel) {
|
||||
throw acpxModelVerificationError(
|
||||
"ACPX_EFFECTIVE_MODEL_MISMATCH",
|
||||
`ACPX effective model mismatch: requested ${requestedModel}, expected ACP selector ${profile.reportedModelId}, received ${status.models?.currentModelId ?? "unverified"}`,
|
||||
`ACPX effective model mismatch: requested ${requestedModel}, expected ACP selector ${providerModel}, received ${status.models?.currentModelId ?? "unverified"}`,
|
||||
);
|
||||
}
|
||||
return normalizeQualifiedModelStatus(status, profile);
|
||||
|
||||
Reference in new issue
Block a user