diff --git a/apps/worker/src/sandbox-server/lib/harnesses/__tests__/opencode-server.test.ts b/apps/worker/src/sandbox-server/lib/harnesses/__tests__/opencode-server.test.ts index 2bba62fa8..b92fadec4 100644 --- a/apps/worker/src/sandbox-server/lib/harnesses/__tests__/opencode-server.test.ts +++ b/apps/worker/src/sandbox-server/lib/harnesses/__tests__/opencode-server.test.ts @@ -3366,6 +3366,59 @@ describe('OpenCodeServerHarness', () => { } }); + it('preserves actionable links in readable provider errors', async () => { + const { client, harness } = createHarness(); + const persistedEnvelopes: AcpPersistedEnvelope[] = []; + + harness.subscribeRuntimePersistedEnvelope((envelope) => + persistedEnvelopes.push(envelope), + ); + + try { + await connectHarness(harness, client); + expect( + harness.sendCommand({ + commandName: TaskCommandName.StartNewTask, + data: { text: 'Start work.', visibleInTranscript: true }, + }), + ).toBe(true); + await vi.waitFor(() => { + expect(client.promptAsync).toHaveBeenCalledTimes(1); + }); + + await client.emit({ + type: 'session.error', + properties: { + sessionID: 'ses_1', + error: { + name: 'APIError', + data: { + message: + 'This model requires explicit region opt in: https://provider.example/settings/region', + statusCode: 403, + isRetryable: false, + responseBody: '{"type":"error","error":{"type":"RegionError"}}', + }, + }, + }, + }); + + const errorMessage = persistedEnvelopes.find( + (envelope) => + envelope.eventType === ACP_ENVELOPE_EVENT_TYPES.AssistantMessage && + String(envelope.payload.text ?? '').includes( + 'The provider returned an error', + ), + ); + + expect(String(errorMessage?.payload.text)).toBe( + 'The provider returned an error: This model requires explicit region opt in: https://provider.example/settings/region', + ); + } finally { + harness.dispose(); + } + }); + it('does not persist credential-shaped provider headers', async () => { const { client, harness } = createHarness(); const persistedEnvelopes: AcpPersistedEnvelope[] = []; diff --git a/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/harness.ts b/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/harness.ts index 6ef9b863b..9aa7d265e 100644 --- a/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/harness.ts +++ b/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/harness.ts @@ -1055,7 +1055,7 @@ function isOpenCodeMessageAbortedError(error: unknown): boolean { const MAX_RESOLVED_USER_INPUT_REQUEST_IDS = 256; const MAX_PROVIDER_ERROR_SUMMARY_CHARS = 500; const UNSAFE_PROVIDER_ERROR_SUMMARY_PATTERN = - /\r|\n|https?:\/\/|\b(?:headers?|response[_ -]?body|stack|traceback)\b|\b(?:[a-z][a-z0-9-]*-[a-z0-9-]+|authorization|cookie|host|user-agent)\s*:\s*\S+/i; + /\r|\n|\b(?:headers?|response[_ -]?body|stack|traceback)\b|\b(?:[a-z][a-z0-9-]*-[a-z0-9-]+|authorization|cookie|host|user-agent)\s*:\s*\S+/i; function isJsonProviderErrorMessage(message: string): boolean { if (!message.startsWith('{') && !message.startsWith('[')) {