From dfe923d6e54096b9f7fe9ecedc481be69c141c31 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Mon, 2 Nov 2026 19:31:20 +0000 Subject: [PATCH 1/2] test(provider-core): reproduce #29534 ACP auth-required session failure hides sign-in guidance The failing test reproduces #29534: a provider session that fails to open because the ACP agent answers -32000 "Authentication required" gets no curated message, so the thread shows the wrapper text with the internal provider session id instead of telling the user to sign in. Co-Authored-By: Claude Opus 5.5 --- .../provider-core/src/server/failure.test.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/provider-core/src/server/failure.test.ts b/packages/provider-core/src/server/failure.test.ts index 84cc14dc2e594..68380b357beab 100644 --- a/packages/provider-core/src/server/failure.test.ts +++ b/packages/provider-core/src/server/failure.test.ts @@ -139,6 +139,29 @@ it("names how the provider process exited and the stage it failed in, without it ); }); +it("tells the user to sign in when an ACP agent rejects the session as unauthenticated", () => { + const providerSessionId = ProviderSessionId.make("provider-session:private-id"); + const sessionOpenFailure = { + _tag: "ProviderSessionOpenError", + providerSessionId, + cause: new ProviderAdapter.ProviderAdapterOpenSessionError({ + driver: ProviderDriverKind.make("acpRegistry"), + providerSessionId, + cause: Cause.fail({ + _tag: "AcpRequestError", + code: -32000, + errorMessage: "Authentication required", + }), + }), + }; + + const known = knownProviderFailureMessage(sessionOpenFailure); + assert.isDefined(known, "an ACP auth-required failure should have a curated message"); + assert.match(known ?? "", /sign(ed)?[ -]?in|log(ged)?[ -]?in/iu); + assert.notInclude(known ?? "", providerSessionId); + assert.equal(makeProviderFailure({ cause: Cause.fail(sessionOpenFailure) }).message, known); +}); + it("keeps unrecognized reasons and provider text out of category messages", () => { for (const cause of [ "Private launch command", From 5dd873362a734a87757533a0a967b7a8497faa54 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Mon, 2 Nov 2026 19:38:36 +0000 Subject: [PATCH 2/2] fix(provider-core): ACP auth-required failures tell the user to sign in When an ACP agent rejected a session or turn with the auth_required error (code -32000), the curated failure walk did not recognise it, so the thread showed the wrapper "Failed to open acpRegistry provider session ." with an internal id and no recovery step. The walk now maps an AcpRequestError with code -32000, which the ACP schema reserves for "Authentication required", to a fixed T3 message that names how to sign in and to retry. The agent's own text stays hidden, as for the other curated causes. Co-Authored-By: Claude Opus 5.5 --- ...cpRegistryReplayFixtures.integration.test.ts | 17 ++++++----------- packages/provider-core/src/server/failure.ts | 8 ++++++++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/apps/server/src/orchestration-v2/testkit/AcpRegistryReplayFixtures.integration.test.ts b/apps/server/src/orchestration-v2/testkit/AcpRegistryReplayFixtures.integration.test.ts index e0a9a233bfd9e..805f4ad2d10db 100644 --- a/apps/server/src/orchestration-v2/testkit/AcpRegistryReplayFixtures.integration.test.ts +++ b/apps/server/src/orchestration-v2/testkit/AcpRegistryReplayFixtures.integration.test.ts @@ -182,17 +182,12 @@ describe("ACP registry replay fixtures", () => { const errors = projection.turnItems.filter((item) => item.type === "error"); assert.lengthOf(errors, 1); assert.equal(errors[0]?.failure.class, "provider_error"); - if (testCase.code === -32602) { - assert.equal( - errors[0]?.failure.message, - 'The agent did not accept the model "replay-model-b". Choose another model for this provider, then retry.', - ); - } else { - assert.match( - errors[0]?.failure.message ?? "", - /^Failed to open acpRegistry provider session \S+\.$/u, - ); - } + assert.equal( + errors[0]?.failure.message, + testCase.code === -32602 + ? 'The agent did not accept the model "replay-model-b". Choose another model for this provider, then retry.' + : "The provider needs you to sign in. Sign in from its provider settings or with its own CLI or app, then retry the turn.", + ); }).pipe( Effect.provide( layerProviderReplay(scenario, AcpRegistryOrchestratorReplayHarness, { diff --git a/packages/provider-core/src/server/failure.ts b/packages/provider-core/src/server/failure.ts index 9bdebc55d373b..e430dbaef4be0 100644 --- a/packages/provider-core/src/server/failure.ts +++ b/packages/provider-core/src/server/failure.ts @@ -118,6 +118,14 @@ function curatedCauseMessages(cause: unknown): { category: categoryMessage(), }; } + // ACP reserves -32000 for auth_required; the agent's own text is not shown. + case "AcpRequestError": + if ((cause as Record).code !== -32000) break; + return { + known: + "The provider needs you to sign in. Sign in from its provider settings or with its own CLI or app, then retry the turn.", + category: categoryMessage(), + }; case "ContextHandoffDeliveryUncertainError": return { known: