Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 4 additions & 1 deletion apps/server/src/provider/ClaudeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ function claudeAuthStatus(
// Amazon Bedrock initializes far slower than first-party auth: the SDK boots the Bedrock
// backend and runs the `awsAuthRefresh` credential hook before returning account info.
const CAPABILITIES_PROBE_TIMEOUT_MS = 25_000;
// The native Claude CLI can take several seconds just to answer `--version` on Windows,
// so the shared 4 s probe deadline reported a healthy install as failing on a busy machine.
const CLAUDE_VERSION_CHECK_TIMEOUT_MS = 20_000;

export const CLAUDE_CAPABILITIES_PROBE_SETTING_SOURCES = [
"user",
Expand Down Expand Up @@ -507,7 +510,7 @@ export const checkClaudeProviderStatus = Effect.fn("checkClaudeProviderStatus")(
["--version"],
resolvedEnvironment,
cwd,
).pipe(Effect.timeoutOption(DEFAULT_TIMEOUT_MS), Effect.result);
).pipe(Effect.timeoutOption(CLAUDE_VERSION_CHECK_TIMEOUT_MS), Effect.result);

if (Result.isFailure(versionProbe)) {
const error = versionProbe.failure;
Expand Down
47 changes: 47 additions & 0 deletions apps/server/src/provider/ProviderRegistry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3121,6 +3121,53 @@ it.layer(
),
);

it.effect("waits for a healthy claude CLI that is slow to answer --version", () =>
Effect.gen(function* () {
const statusFiber = yield* checkClaudeProviderStatus(
defaultClaudeSettings,
claudeCapabilities(),
).pipe(
Effect.provide(
Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make((command) => {
const joined = (command as unknown as { args: ReadonlyArray<string> }).args.join(
" ",
);
if (joined !== "--version") throw new Error(`Unexpected args: ${joined}`);
// The native CLI can take several seconds to start on a busy Windows host.
const answer = Effect.sleep("19 seconds");
return Effect.succeed(
ChildProcessSpawner.makeHandle({
pid: ChildProcessSpawner.ProcessId(1),
exitCode: answer.pipe(Effect.as(ChildProcessSpawner.ExitCode(0))),
isRunning: Effect.succeed(true),
kill: () => Effect.void,
unref: Effect.succeed(Effect.void),
stdin: Sink.drain,
stdout: Stream.fromEffect(answer.pipe(Effect.as(encoder.encode("1.0.0
")))),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
stderr: Stream.empty,
all: Stream.empty,
getInputFd: () => Sink.drain,
getOutputFd: () => Stream.empty,
}),
);
}),
),
),
Effect.forkChild,
);
for (let second = 0; second < 20; second++) {
yield* Effect.yieldNow;
yield* TestClock.adjust("1 second");
}
const status = yield* Fiber.join(statusFiber);
assert.strictEqual(status.status, "ready");
assert.strictEqual(status.version, "1.0.0");
}),
);

it.effect("returns ready and labels Bedrock-backed Claude as authenticated", () =>
Effect.gen(function* () {
// Bedrock authenticates via external AWS credentials, so the SDK init
Expand Down
Loading