runtime: default LLM verbs to Claude Code, keep Gemini selectable#21
Merged
Merged
Conversation
The in-memory runtime's LLM verbs (summarize, ask, analyze, and the
search fallback) were hardwired to Gemini (geminiCall → r.gemini,
requiring GEMINI_API_KEY). They now default to Claude Code — the `claude`
CLI run as a subprocess, authenticated by the CLI's own local login, no
API key — consistent with the rest of the stack (worker, loom). Gemini
stays fully available, selectable per the user's 'keep GEMINI_API_KEY'
ask.
New (pkg/claude/claudecode.go):
- ClaudeCodeClient: runs `claude -p <prompt> --output-format json` and
returns the result. Same Chat(ctx, prompt) (string, error) shape as
ClaudeClient, so it's a drop-in. No API key.
Runtime (internal/agentscript/runtime.go):
- New llmChatter seam { Chat(ctx, prompt) (string,error) }; Runtime gains
an `llm` field used by verb completions.
- RuntimeConfig.LLMBackend selects the default: "claude-code" (default,
no key) | "gemini" (needs GeminiAPIKey) | "claude" (Anthropic API,
needs ClaudeAPIKey). Empty ⇒ claude-code. Falls back to Claude Code if
a named backend's client isn't available, so verbs always work.
- geminiCall now routes through r.llm (the historical name kept so every
calling verb is unchanged); the raw Gemini client is used when
LLMBackend==gemini (via a geminiChatAdapter mapping GenerateContent →
Chat) or as a last-resort fallback. So 'read >=> summarize' runs on
Claude Code with NO key; '-llm=gemini' + GEMINI_API_KEY still routes
to Gemini.
CLI (cmd/agentscript):
- New -llm flag (claude-code | gemini | claude), default claude-code.
- GEMINI_API_KEY only required for -llm=gemini (the old hard requirement
for -n/-i is relaxed — the default backend needs no key).
- Reads ANTHROPIC_API_KEY (or legacy CLAUDE_API_KEY) for the claude verb
/ claude backend.
scriptmem.MemoryConfig gains LLMBackend, forwarded to the runtime, so a
front end (loom) can pick the memory backend's LLM too; defaults to
claude-code.
Verified: 'read "/tmp/notes.txt" >=> summarize' (no keys) routes to Claude
Code (errors only because this sandbox lacks the `claude` binary —
proving the route); '-llm=gemini' correctly demands GEMINI_API_KEY. The
file-read half needs nothing. Backward compatible: existing Gemini setups
work via -llm=gemini.
CI: vet, gofmt, staticcheck, go test -race ./pkg/..., go build ./... pass.
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.
What
The in-memory runtime's LLM verbs (
summarize,ask,analyze, and thesearchfallback) were hardwired to Gemini (geminiCall → r.gemini, requiringGEMINI_API_KEY). They now default to Claude Code — theclaudeCLI run as a subprocess, authenticated by the CLI's own local login, no API key — consistent with the worker and loom. Gemini stays fully available, selectable (per the 'keep GEMINI_API_KEY' ask).New:
pkg/claude/claudecode.goClaudeCodeClientrunsclaude -p <prompt> --output-format json; sameChat(ctx, prompt)shape asClaudeClient, drop-in, no key.Runtime
llmChatterseam;Runtime.llmused by verb completionsRuntimeConfig.LLMBackend:claude-code(default, no key) |gemini(needs key) |claude(Anthropic API). Empty ⇒ claude-code. Falls back to Claude Code if a named backend's client is unavailable, so verbs always workgeminiCallroutes throughr.llm(name kept so every calling verb is unchanged); raw Gemini used whenLLMBackend==gemini(via a small adapter) or as last-resort fallbackCLI (
cmd/agentscript)-llmflag (claude-code|gemini|claude), defaultclaude-codeGEMINI_API_KEYonly required for-llm=gemini(old hard-n/-irequirement relaxed)ANTHROPIC_API_KEY(or legacyCLAUDE_API_KEY) for the claude backendscriptmem
MemoryConfig.LLMBackendadded + forwarded, so loom's memory execution picks the LLM too; defaults to claude-code.Verified
read "/tmp/notes.txt" >=> summarize(no keys) → routes to Claude Code (errors only because this sandbox lacks theclaudebinary — proving the route; runs on a machine withclaudeinstalled)-llm=gemini→ correctly demandsGEMINI_API_KEYgo vet/gofmt/staticcheckgo test -race ./pkg/...go build ./...Now you can explore in-memory research on Claude Code, no key:
(
searchstill uses the LLM fallback unlessSEARCH_API_KEYis set for real web search.)