feat(be): route ADK agents through self-hosted Claude gateway via flag - #1
Draft
ccp-manash wants to merge 2 commits into
Draft
feat(be): route ADK agents through self-hosted Claude gateway via flag#1ccp-manash wants to merge 2 commits into
ccp-manash wants to merge 2 commits into
Conversation
Adds the building blocks for routing ADK agents through the
self-hosted claude-internal-gateway (Anthropic Claude proxy)
without modifying any existing agent files.
- src/agent/oak_claude_llm.ts: a custom @google/adk BaseLlm subclass
that translates between ADK's GenAI request/response shape and the
Anthropic Messages API. Uses only @google/adk + native fetch; no
@anthropic-ai/sdk, no litellm, no @google/genai dependency. Handles
text + thinking + tool_use translation in both directions and
normalizes Gemini-flavored function-declaration schemas (uppercase
type enum) into JSON Schema before forwarding to Anthropic.
- src/agent/llmFactory.ts: a tiny factory function getModel({gemini,
claude}) that returns either a Gemini model string or an OakClaude
instance based on the USE_CLAUDE_GATEWAY env var. Single source of
truth for model selection across all agents.
- scripts/try_oak_claude.ts: throwaway smoke test that verifies the
full LlmAgent + OakClaude + tool round-trip works against a local
gateway. Used to validate the migration before touching production
agent files. Can be deleted after the rollout is confirmed stable.
… flag
Switches every LlmAgent's model field from a hardcoded
"gemini-2.5-flash" string to getModel({gemini, claude}).
When USE_CLAUDE_GATEWAY=true the agents will use claude-opus-4-6
through the gateway. When the flag is unset or false, they continue
to use gemini-2.5-flash exactly as before, so this change is fully
backwards-compatible by default.
Touched agents (each is a 2-line diff):
- backerAgent
- campaignCreatorAgent
- commentatorAgent
- financialAgent
- rootAgent
- scoringAgent
.env.example updated with the new USE_CLAUDE_GATEWAY,
OAK_GATEWAY_URL, and OAK_PROXY_TOKEN variables. GEMINI_API_KEY is
kept and still required when the flag is off.
No npm dependencies added; the adapter uses only @google/adk and
native fetch.
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 optional support for routing every ADK agent through a self-hosted
claude-internal-gateway(Anthropic Claude proxy) instead of calling Gemini directly. The change is gated by a single env var (USE_CLAUDE_GATEWAY) so the existing Gemini path remains the default and can be toggled back instantly.Zero new npm dependencies. The adapter uses only
@google/adk(already installed) and Node's built-infetch. No@anthropic-ai/sdk, nolitellm, no@google/genai.Why
How it works
src/agent/oak_claude_llm.ts— a customBaseLlmsubclass (OakClaude) that translates between ADK's GenAI request/response shape and Anthropic's Messages API. Handles text + thinking + tool_use translation and normalizes Gemini-flavored function-declaration schemas (uppercaseOBJECTenum) into JSON Schema before forwarding to Anthropic.src/agent/llmFactory.ts— a tinygetModel({ gemini, claude })factory that returns either a Gemini model string or anOakClaudeinstance based onUSE_CLAUDE_GATEWAY. Single source of truth.All 6 agent files updated to use
getModel({ gemini: \"gemini-2.5-flash\", claude: \"claude-opus-4-6\" })instead of a hardcoded model string. Each diff is exactly 2 lines (1 import + 1 model field).scripts/try_oak_claude.ts— throwaway end-to-end smoke test that wires up anLlmAgentwithOakClaude, runs it throughInMemoryRunneragainst a real ADK tool (getCurrentTime), and verifies the full tool round-trip works. Used to validate the integration before touching production code; can be deleted after rollout is stable.Default behavior
Without setting any new env var, nothing changes. Agents continue to use
gemini-2.5-flashexactly as before. To opt in:```
USE_CLAUDE_GATEWAY=true
OAK_GATEWAY_URL="https://tunnel.cfsprotocol.com\"
OAK_PROXY_TOKEN=""
```
What was tested
End-to-end against a locally-running gateway, in this exact repo:
```
$ USE_CLAUDE_GATEWAY=true OAK_PROXY_TOKEN=... \
OAK_GATEWAY_URL=http://127.0.0.1:8765 \
npx tsx scripts/try_oak_claude.ts
=== STAGE A: minimal LlmAgent + 1 tool via OakClaude ===
[tool_call] name=get_current_time args={}
[tool_result] name=get_current_time response={"time":"2026-04-06T16:44:50.283Z"}
[final_text] The current time is 4:44 PM UTC on April 6, 2026.
STAGE A: ok (tool called, final answer produced)
ALL OK
```
This validates the full agent loop: ADK runtime → custom adapter → gateway → Anthropic → tool_use response → ADK tool execution → tool_result → second LLM call → final text answer.
Test plan
USE_CLAUDE_GATEWAY=false(default) and confirms the existing Gemini path still worksUSE_CLAUDE_GATEWAY=truewithOAK_GATEWAY_URL+OAK_PROXY_TOKEN, runsnpx tsx scripts/try_oak_claude.ts, confirms ALL OKENABLE_AGENTS=true) to confirm a real autonomous loop works on Claudepackage.json/package-lock.json/tsconfig.json(verified by CI / git diff)scripts/try_oak_claude.tsbefore marking PR ready, or keep it as a permanent smoke testThings NOT in this PR
package.json,package-lock.json,tsconfig.json,Dockerfile, or any tool / trigger / database / express code.Known limitations / followups
🤖 Generated with Claude Code