Compare commits

...
Author SHA1 Message Date
paseo-bot[bot] 26dd2c5a90 fix(claude): allow Auto mode on hosted providers
Claude Code supports Auto mode on Bedrock and Vertex, but Paseo removed it from the catalog and rejected explicit selections before reaching Claude Code. Remove that obsolete eligibility gate while preserving the existing default modes and SDK error handling.
2026-10-14 19:16:38 +02:00
3 changed files with 62 additions and 87 deletions
@@ -0,0 +1,54 @@
import { expect, test } from "vitest";
import { createTestLogger } from "../../../../test-utils/test-logger.js";
import { ClaudeAgentClient } from "./agent.js";
const hostedEnvironments = [
{ transport: "Bedrock", env: { CLAUDE_CODE_USE_BEDROCK: "1" } },
{ transport: "Vertex", env: { CLAUDE_CODE_USE_VERTEX: "true" } },
];
test.each(hostedEnvironments)(
"offers Auto mode on $transport while preserving its default mode",
async ({ env }) => {
const client = new ClaudeAgentClient({
logger: createTestLogger(),
runtimeSettings: { env },
resolveVersion: async () => "2.1.263",
discoverModels: async () => [],
});
const catalog = await client.fetchCatalog({ cwd: process.cwd() });
expect(catalog.modes?.map((mode) => mode.id)).toContain("auto");
expect(catalog.defaultModeId).toBe("default");
},
);
test.each(hostedEnvironments)(
"passes an explicit Auto selection on $transport to Claude Code",
async ({ env }) => {
const sdkError = new Error("Claude Code rejected this request");
let requestedMode: string | undefined;
let requestedEnv: NodeJS.ProcessEnv | undefined;
const client = new ClaudeAgentClient({
logger: createTestLogger(),
runtimeSettings: { env },
resolveBinary: async () => "/test/claude",
queryFactory: ({ options }) => {
requestedMode = options.permissionMode;
requestedEnv = options.env;
throw sdkError;
},
});
const session = await client.createSession({ provider: "claude", cwd: process.cwd() });
try {
await expect(session.setMode("auto")).rejects.toBe(sdkError);
expect(requestedMode).toBe("auto");
expect(requestedEnv).toMatchObject(env);
} finally {
await session.close();
}
},
);
@@ -201,23 +201,6 @@ test("exposes and applies auto permission mode", async () => {
}
});
test("rejects auto mode when Claude Code uses Bedrock", async () => {
const previousBedrock = process.env.CLAUDE_CODE_USE_BEDROCK;
process.env.CLAUDE_CODE_USE_BEDROCK = "1";
const session = await createSession();
try {
await expect(session.setMode("auto")).rejects.toThrow(
"Claude Auto mode requires the Anthropic API and is not supported when Claude Code uses Bedrock",
);
expect(sdkQueryFactory).not.toHaveBeenCalled();
} finally {
restoreEnvValue("CLAUDE_CODE_USE_BEDROCK", previousBedrock);
await session.close();
}
});
test.each([
{ env: {}, expected: "auto" },
{ env: { CLAUDE_CODE_USE_BEDROCK: "1" }, expected: "default" },
@@ -293,40 +276,6 @@ test("allows launch env to disable inherited Bedrock transport for auto mode", a
}
});
test("fails an auto mode turn when Claude Code uses Vertex", async () => {
const previousVertex = process.env.CLAUDE_CODE_USE_VERTEX;
process.env.CLAUDE_CODE_USE_VERTEX = "true";
sdkQueryFactory.mockImplementation(() => {
throw new Error("query should not start");
});
const client = new ClaudeAgentClient({
logger: createTestLogger(),
queryFactory: sdkQueryFactory,
resolveBinary: async () => "/test/claude/bin",
});
const session = await client.createSession({
provider: "claude",
cwd: process.cwd(),
modeId: "auto",
});
try {
const events = await collectUntilTerminal(streamSession(session, "hello"));
const failure = events.find(
(event): event is Extract<AgentStreamEvent, { type: "turn_failed" }> =>
event.type === "turn_failed",
);
expect(failure?.error).toContain(
"Claude Auto mode requires the Anthropic API and is not supported when Claude Code uses Vertex",
);
expect(sdkQueryFactory).not.toHaveBeenCalled();
} finally {
restoreEnvValue("CLAUDE_CODE_USE_VERTEX", previousVertex);
await session.close();
}
});
test("switches an auto mode session to another mode when Claude Code uses Bedrock", async () => {
const previousBedrock = process.env.CLAUDE_CODE_USE_BEDROCK;
process.env.CLAUDE_CODE_USE_BEDROCK = "1";
@@ -947,37 +947,11 @@ function isTruthyEnvValue(value: string | undefined): boolean {
);
}
function claudeAutoModeUnavailableOn(env: NodeJS.ProcessEnv): "Bedrock" | "Vertex" | null {
if (isTruthyEnvValue(env.CLAUDE_CODE_USE_BEDROCK)) {
return "Bedrock";
}
if (isTruthyEnvValue(env.CLAUDE_CODE_USE_VERTEX)) {
return "Vertex";
}
return null;
}
function assertClaudeModeCanRun(mode: PermissionMode, env: NodeJS.ProcessEnv): void {
if (mode !== "auto") {
return;
}
const transport = claudeAutoModeUnavailableOn(env);
if (transport === null) {
return;
}
throw new Error(
`Claude Auto mode requires the Anthropic API and is not supported when Claude Code uses ${transport}. Select another permission mode or unset the ${transport === "Bedrock" ? "CLAUDE_CODE_USE_BEDROCK" : "CLAUDE_CODE_USE_VERTEX"} environment variable.`,
);
}
function claudeModeCatalog(env: NodeJS.ProcessEnv): {
modes: AgentMode[];
defaultModeId: PermissionMode;
} {
if (claudeAutoModeUnavailableOn(env)) {
return { modes: DEFAULT_MODES.filter((mode) => mode.id !== "auto"), defaultModeId: "default" };
}
return { modes: DEFAULT_MODES, defaultModeId: "auto" };
function claudeDefaultMode(env: NodeJS.ProcessEnv): PermissionMode {
return isTruthyEnvValue(env.CLAUDE_CODE_USE_BEDROCK) ||
isTruthyEnvValue(env.CLAUDE_CODE_USE_VERTEX)
? "default"
: "auto";
}
function coerceSessionMetadata(metadata: AgentMetadata | undefined): Partial<AgentSessionConfig> {
@@ -1642,15 +1616,15 @@ export class ClaudeAgentClient implements AgentClient {
discoveredModelIds,
),
);
const modeCatalog = claudeModeCatalog(env);
return {
models,
...modeCatalog,
modes: DEFAULT_MODES,
defaultModeId: claudeDefaultMode(env),
};
}
async resolveDefaultModeId({ env: launchEnv }: ResolveAgentDefaultModeInput): Promise<string> {
return claudeModeCatalog(this.buildProviderEnv(launchEnv)).defaultModeId;
return claudeDefaultMode(this.buildProviderEnv(launchEnv));
}
private buildProviderEnv(launchEnv?: Record<string, string>): NodeJS.ProcessEnv {
@@ -2540,7 +2514,6 @@ class ClaudeAgentSession implements AgentSession {
}
const normalized = isPermissionMode(modeId) ? modeId : "default";
assertClaudeModeCanRun(normalized, this.harnessEnvironment);
const previousMode = this.currentMode;
const launchesQuery = !this.query || this.queryRestartNeeded;
const activeQuery = await this.ensureQuery(normalized);
@@ -3424,7 +3397,6 @@ class ClaudeAgentSession implements AgentSession {
);
const settingsOptions = this.buildSettingsOptions(providerOptions, { ultracode });
const sdkEnv = this.harnessEnvironment;
assertClaudeModeCanRun(permissionMode, sdkEnv);
const claudeBinary = await this.resolveBinary();
this.logger.debug(