Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion apps/server/src/orchestration-v2/ProviderTurnStartService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,14 @@ const isProviderTurnStartError = Schema.is(ProviderTurnStartError);

/**
* Claude refuses these before it reads the prompt: replacing a process running background work,
* or launch arguments whose appended system prompt cannot be read.
* launch arguments whose appended system prompt cannot be read, or MCP registration that never
* answers while the query opens.
*/
const PROMPT_REFUSAL_TAGS = [
"ClaudeBackgroundWorkBlocksQueryReplacementError",
"ClaudeAppendSystemPromptFileError",
"ClaudeAppendSystemPromptMissingValueError",
"ClaudeMcpRegistrationTimeoutError",
] as const;

const refusedBeforePrompt = (error: unknown): boolean =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import * as SqlClient from "effect/sql/SqlClient";
import * as SqlitePersistence from "../../persistence/Sqlite.ts";
import { CommandPolicyCapabilityUnsupportedError } from "../CommandPolicy.ts";
import {
ClaudeAgentSdkQueryRunnerError,
ClaudeAppendSystemPromptFileError,
ClaudeBackgroundWorkBlocksQueryReplacementError,
ClaudeProviderCapabilitiesV2,
Expand Down Expand Up @@ -404,6 +405,12 @@ const waitForIdle = Effect.fn("ProviderSwitchTest.waitForIdle")(function* (
return idle;
});

// Same tag as the adapter's unexported error raised when Claude never answers setMcpServers.
class ClaudeMcpRegistrationTimeoutError extends Schema.TaggedError<ClaudeMcpRegistrationTimeoutError>()(
"ClaudeMcpRegistrationTimeoutError",
{},
) {}

describe("orchestration v2 provider switching", () => {
it.live.each([
"compact-native",
Expand Down Expand Up @@ -1311,6 +1318,13 @@ describe("orchestration v2 provider switching", () => {
it.live.each([
["background work", new ClaudeBackgroundWorkBlocksQueryReplacementError()],
["an unreadable append file", new ClaudeAppendSystemPromptFileError({ path: "missing.md" })],
[
"an MCP registration timeout",
new ClaudeAgentSdkQueryRunnerError({
method: "setMcpServers",
cause: new ClaudeMcpRegistrationTimeoutError(),
}),
],
] as const)("keeps the native session after turns refused for %s", ([, refusalCause]) =>
Effect.scoped(
Effect.gen(function* () {
Expand Down
Loading