feat: add a claude-code provider backed by the local Claude Code CLI - #559
Open
Luis Lucio (llucio) wants to merge 1 commit into
Open
feat: add a claude-code provider backed by the local Claude Code CLI#559Luis Lucio (llucio) wants to merge 1 commit into
Luis Lucio (llucio) wants to merge 1 commit into
Conversation
Adds a keyless inference provider for users who cannot provision an Anthropic API key -- notably Claude Team and Enterprise members whose plan does not grant API key creation. It reuses an existing `claude auth login` session, in the same spirit as the `openai-chatgpt` and `copilot` providers, which reuse a ChatGPT and Copilot subscription. Claude Code ships its own agent loop, so the bridge constrains it to a single model turn and keeps execution with DeepAgents: - OpenWiki's tools are exposed through an in-process MCP server, with `alwaysLoad` set so they are not deferred behind ToolSearch (which would consume the turn without producing a tool call). - `canUseTool` captures the resulting tool call and denies it with `interrupt`, handing it back to the OpenWiki agent loop. Nothing is added to `allowedTools`: a bare entry there auto-approves the call and shadows the callback, which is the only interception point. - Claude Code's built-in tools are refused through the same callback *without* interrupting, so the model retries with an OpenWiki tool inside the same turn. `disallowedTools` is a deny-list that cannot stay complete as the CLI gains tools, so it is defense in depth only. - Anthropic credentials are stripped from the spawned process environment. OpenWiki loads `~/.openwiki/.env` into `process.env`, so a previously configured `ANTHROPIC_API_KEY` would otherwise shadow the CLI session and bill the API -- failing outright when that dead key is the reason the user chose this provider. Tool schemas are converted with LangChain's own `toJsonSchema`, which handles Zod v3 and v4 alike; Zod 4's `toJSONSchema` throws on a v3 schema, which would silently degrade a tool to a parameterless one. Objects declaring `additionalProperties: true` stay open, so `openwiki_call_mcp_tool` can still forward arbitrary connector arguments. The Agent SDK accepts only user messages, so prior assistant turns cannot be injected and a session cannot be reconstructed from LangChain's message list. Each generation replays the transcript instead, which keeps the model stateless -- what `_generate` promises, and what makes the checkpointer, summarization middleware, and `--update` resume behave. Rendering is deterministic so the prefix stays byte-stable and Claude Code's prompt cache absorbs most of the repeated cost.
🦋 Changeset detectedLatest commit: 7d6be73 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Collaborator
|
Thanks for the PR Luis Lucio (@llucio)! My biggest concern is just related to ToS. I worked on #278 and we ran it by our anthropic contact internally and were told is was against their ToS. I will double check on this one too to see what they say. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a
claude-codeinference provider that routes model calls through the local Claude Code CLI instead of an Anthropic API key.The motivating case: Claude Team and Enterprise members whose plan does not permit creating API keys currently cannot run OpenWiki at all. This gives them a keyless path, in the same spirit as the existing
openai-chatgptprovider (reuses a ChatGPT login) andcopilotprovider (reuses a Copilot seat viagh).Authentication reuses an existing
claude auth loginsession. OpenWiki never reads, copies, or persists a token — it spawns the CLI through@anthropic-ai/claude-agent-sdkand lets the SDK use whatever session is already there. Nothing is written to~/.openwiki/.env.How the bridge works
Claude Code ships its own agent loop, so the provider constrains it to a single model turn and keeps tool execution with DeepAgents (preserving the virtual filesystem backend, OKF middleware, and translation middleware):
alwaysLoadset so they are not deferred behindToolSearch— which would otherwise consume the turn without producing a tool call.canUseToolcaptures the tool call and denies it withinterrupt, handing it back to the OpenWiki agent loop. Nothing is added toallowedTools: a bare entry there auto-approves the call and shadows the callback, which is the only interception point available.disallowedToolsis a deny-list that cannot stay complete as the CLI gains tools, so it is defense in depth only.~/.openwiki/.envintoprocess.env, so a previously configuredANTHROPIC_API_KEYwould otherwise shadow the CLI session and bill the API — failing outright when that dead key is precisely why the user picked this provider.Schema fidelity
Tool schemas are converted with LangChain's own
toJsonSchema, which handles Zod v3 and v4 alike. Zod 4'sz.toJSONSchemathrows on a v3 schema; converting via atry/catchfallback silently degraded such a tool to a parameterless one, so the model could call it but never correctly. Objects declaringadditionalProperties: trueare kept open (z.looseObject) soopenwiki_call_mcp_toolcan still forward arbitrary connector arguments.Known tradeoff
The Agent SDK accepts only user messages — there is no way to inject prior assistant turns — so a resumable session cannot be reconstructed from LangChain's message list. Each generation replays the transcript instead. That keeps the model stateless, which is what
_generatepromises and what makes the checkpointer, summarization middleware, and--updateresume behave correctly.The cost is speed: a wiki build is slower than the
anthropicprovider and draws on the subscription's rate limits. Rendering is deterministic so the prefix stays byte-stable and Claude Code's prompt cache absorbs most of the repeated cost. The README recommendsanthropicwith an API key for CI. If the SDK later accepts full message histories, this is the natural place to optimize.maxTurnsis set to 6 rather than 1 purely as headroom for a refused built-in before the model retries; capture still interrupts immediately, so a healthy step never reaches it.Testing
test/claude-code-model.test.ts— 13 tests covering JSON-Schema→Zod conversion (required/optional, enums, arrays, nested objects, open vs closed objects), Zod v3 and v4 normalization,bindToolsnon-mutation, credential stripping, the built-in-refusal regression, and turn-ending classification.test/claude-code-provider.test.ts— provider registry wiring, keyless auth, model-id form.test/constants.test.tsupdated:getProvidersForKnownModelIdnow legitimately includesclaude-codefor Claude model ids.Verified end-to-end by generating a full wiki for a real repository (a ~1.4k-file React SPA) with
code --update --print: the run completed, produced a valid OKF bundle (okf_versionon the root index,type/title/descriptionfront matter on concept pages, bare nested indexes), and performed correct incremental reasoning — reading git history and judging which commits left existing pages accurate.pnpm typecheck,pnpm lint:check, andpnpm buildare clean.