fix(claude-code-cli): resolve SDK executable path and update model IDs

- Add pathToClaudeCodeExecutable to SDK query options, resolving the
  system `claude` binary via `which claude`. Without this, the SDK
  looks for a bundled cli.js that doesn't exist when installed as a
  library dependency.
- Remove env option that was replacing the subprocess environment and
  stripping auth credentials, causing "Not logged in" errors.
- Update model IDs to current versions: claude-opus-4-6 (1M ctx),
  claude-sonnet-4-6 (1M ctx), claude-haiku-4-5 (200K ctx).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lex Christopherson 2026-03-25 12:22:40 -06:00
parent c55d409991
commit e8a7881307
2 changed files with 39 additions and 12 deletions

View file

@ -4,36 +4,39 @@
* Costs are zero because inference is covered by the user's Claude Code
* subscription. The SDK's `result` message still provides token counts
* for display in the TUI.
*
* Context windows and max tokens match the Anthropic API definitions
* in models.generated.ts.
*/
const ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
export const CLAUDE_CODE_MODELS = [
{
id: "claude-opus-4-20250514",
name: "Claude Opus 4 (via Claude Code)",
id: "claude-opus-4-6",
name: "Claude Opus 4.6 (via Claude Code)",
reasoning: true,
input: ["text", "image"] as ("text" | "image")[],
cost: ZERO_COST,
contextWindow: 200_000,
maxTokens: 32_768,
contextWindow: 1_000_000,
maxTokens: 128_000,
},
{
id: "claude-sonnet-4-20250514",
name: "Claude Sonnet 4 (via Claude Code)",
id: "claude-sonnet-4-6",
name: "Claude Sonnet 4.6 (via Claude Code)",
reasoning: true,
input: ["text", "image"] as ("text" | "image")[],
cost: ZERO_COST,
contextWindow: 200_000,
maxTokens: 16_384,
contextWindow: 1_000_000,
maxTokens: 64_000,
},
{
id: "claude-haiku-4-5-20251001",
id: "claude-haiku-4-5",
name: "Claude Haiku 4.5 (via Claude Code)",
reasoning: false,
reasoning: true,
input: ["text", "image"] as ("text" | "image")[],
cost: ZERO_COST,
contextWindow: 200_000,
maxTokens: 8_192,
maxTokens: 64_000,
},
];

View file

@ -16,6 +16,7 @@ import type {
SimpleStreamOptions,
} from "@gsd/pi-ai";
import { EventStream } from "@gsd/pi-ai";
import { execSync } from "node:child_process";
import { PartialMessageBuilder, ZERO_USAGE, mapUsage } from "./partial-builder.js";
import type {
SDKAssistantMessage,
@ -46,6 +47,29 @@ function createAssistantStream(): AssistantMessageEventStream {
) as AssistantMessageEventStream;
}
// ---------------------------------------------------------------------------
// Claude binary resolution
// ---------------------------------------------------------------------------
let cachedClaudePath: string | null = null;
/**
* Resolve the path to the system-installed `claude` binary.
* The SDK defaults to a bundled cli.js which doesn't exist when
* installed as a library we need to point it at the real CLI.
*/
function getClaudePath(): string {
if (cachedClaudePath) return cachedClaudePath;
try {
cachedClaudePath = execSync("which claude", { timeout: 5_000, stdio: "pipe" })
.toString()
.trim();
} catch {
cachedClaudePath = "claude"; // fall back to PATH resolution
}
return cachedClaudePath;
}
// ---------------------------------------------------------------------------
// Prompt extraction
// ---------------------------------------------------------------------------
@ -145,6 +169,7 @@ async function pumpSdkMessages(
const queryResult = sdk.query({
prompt,
options: {
pathToClaudeCodeExecutable: getClaudePath(),
model: modelId,
includePartialMessages: true,
persistSession: false,
@ -154,7 +179,6 @@ async function pumpSdkMessages(
allowDangerouslySkipPermissions: true,
settingSources: ["project"],
systemPrompt: { type: "preset", preset: "claude_code" },
env: { CLAUDE_AGENT_SDK_CLIENT_APP: "gsd" },
betas: modelId.includes("sonnet") ? ["context-1m-2025-08-07"] : [],
},
});