Skip to content

Commit 7f3096f

Browse files
authored
Merge pull request #73 from TraderAlice/dev
Unify AI providers: Agent SDK OAuth + remove Claude Code CLI
2 parents a9a0e34 + 7aafd2e commit 7f3096f

18 files changed

Lines changed: 284 additions & 415 deletions

File tree

CLAUDE.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,8 @@ src/
3232
│ ├── media-store.ts # Media file persistence
3333
│ └── types.ts # Plugin, EngineContext interfaces
3434
├── ai-providers/
35-
│ ├── claude-code/ # Claude Code CLI subprocess
3635
│ ├── vercel-ai-sdk/ # Vercel AI SDK ToolLoopAgent
37-
│ └── agent-sdk/ # Agent SDK (@anthropic-ai/claude-agent-sdk)
36+
│ └── agent-sdk/ # Claude backend (@anthropic-ai/claude-agent-sdk, supports OAuth + API key)
3837
├── domain/
3938
│ ├── market-data/ # Structured data layer (typebb in-process + OpenBB API remote)
4039
│ ├── trading/ # Unified multi-account trading, guard pipeline, git-like commits
@@ -72,10 +71,9 @@ Two layers (Engine was removed):
7271

7372
1. **AgentCenter** (`core/agent-center.ts`) — top-level orchestration. Manages sessions, compaction, and routes calls through GenerateRouter. Exposes `ask()` (stateless) and `askWithSession()` (with history).
7473

75-
2. **GenerateRouter** (`core/ai-provider-manager.ts`) — reads `ai-provider.json` on each call, resolves to active provider. Three backends:
76-
- Claude Code CLI (`inputKind: 'text'`)
77-
- Vercel AI SDK (`inputKind: 'messages'`)
78-
- Agent SDK (`inputKind: 'text'`)
74+
2. **GenerateRouter** (`core/ai-provider-manager.ts`) — reads `ai-provider.json` on each call, resolves to active provider. Two backends:
75+
- Agent SDK (`inputKind: 'text'`) — Claude via @anthropic-ai/claude-agent-sdk, tools via in-process MCP
76+
- Vercel AI SDK (`inputKind: 'messages'`) — direct API calls, tools via Vercel tool system
7977

8078
**AIProvider interface**: `ask(prompt)` for one-shot, `generate(input, opts)` for streaming `ProviderEvent` (tool_use / tool_result / text / done). Optional `compact()` for provider-native compaction.
8179

README.md

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Your one-person Wall Street. Alice is an AI trading agent that gives you your ow
2323
2424
## Features
2525

26-
- **Multi-provider AI** — switch between Claude Code CLI, Vercel AI SDK, and Agent SDK at runtime, no restart needed
26+
- **Multi-provider AI** — switch between Claude (via Agent SDK with OAuth or API key) and Vercel AI SDK at runtime, no restart needed
2727
- **Unified Trading Account (UTA)** — each trading account is a self-contained entity that owns its broker connection, git-like operation history, and guard pipeline. AI interacts with UTAs, never with brokers directly. All order types use IBKR's type system (`@traderalice/ibkr`) as the single source of truth, with Alpaca and CCXT adapting to it
2828
- **Trading-as-Git** — stage orders, commit with a message, push to execute. Every commit gets an 8-char hash. Full history reviewable via `tradingLog` / `tradingShow`
2929
- **Guard pipeline** — pre-execution safety checks (max position size, cooldown, symbol whitelist) that run inside each UTA before orders reach the broker
@@ -39,7 +39,7 @@ Your one-person Wall Street. Alice is an AI trading agent that gives you your ow
3939

4040
## Key Concepts
4141

42-
**Provider** — The AI backend that powers Alice. Claude Code (subprocess), Vercel AI SDK (in-process), or Agent SDK (`@anthropic-ai/claude-agent-sdk`). Switchable at runtime via `ai-provider.json`.
42+
**Provider** — The AI backend that powers Alice. Claude (via `@anthropic-ai/claude-agent-sdk`, supports OAuth login or API key) or Vercel AI SDK (direct API calls to Anthropic, OpenAI, Google). Switchable at runtime via `ai-provider.json`.
4343

4444
**Extension** — A self-contained tool package registered in ToolCenter. Each extension owns its tools, state, and persistence. Examples: trading, brain, analysis-kit.
4545

@@ -64,9 +64,8 @@ Your one-person Wall Street. Alice is an AI trading agent that gives you your ow
6464
```mermaid
6565
graph LR
6666
subgraph Providers
67-
CC[Claude Code CLI]
67+
AS[Claude / Agent SDK]
6868
VS[Vercel AI SDK]
69-
AS[Agent SDK]
7069
end
7170
7271
subgraph Core
@@ -102,12 +101,12 @@ graph LR
102101
MCP[MCP Server]
103102
end
104103
105-
CC --> PR
106-
VS --> PR
107104
AS --> PR
105+
VS --> PR
108106
PR --> AC
109107
AC --> S
110108
TC -->|Vercel tools| VS
109+
TC -->|in-process MCP| AS
111110
TC -->|MCP tools| MCP
112111
OBB --> AK
113112
OBB --> NC
@@ -128,7 +127,7 @@ graph LR
128127
MCP --> AC
129128
```
130129

131-
**Providers** — interchangeable AI backends. Claude Code spawns `claude -p` as a subprocess; Vercel AI SDK runs a `ToolLoopAgent` in-process; Agent SDK uses `@anthropic-ai/claude-agent-sdk`. `ProviderRouter` reads `ai-provider.json` on each call to select the active backend at runtime.
130+
**Providers** — interchangeable AI backends. Claude (Agent SDK) uses `@anthropic-ai/claude-agent-sdk` with tools delivered via in-process MCP — supports Claude Pro/Max OAuth login or API key. Vercel AI SDK runs a `ToolLoopAgent` in-process with direct API calls. `ProviderRouter` reads `ai-provider.json` on each call to select the active backend at runtime.
132131

133132
**Core**`AgentCenter` is the top-level orchestration center that routes all calls (both stateless and session-aware) through `ProviderRouter`. `ToolCenter` is a centralized tool registry — extensions register tools there, and it exports them in Vercel AI SDK and MCP formats. `EventLog` provides persistent append-only event storage (JSONL) with real-time subscriptions and crash recovery. `ConnectorCenter` tracks which channel the user last spoke through.
134133

@@ -149,7 +148,7 @@ pnpm install && pnpm build
149148
pnpm dev
150149
```
151150

152-
Open [localhost:3002](http://localhost:3002) and start chatting. No API keys or config needed — the default setup uses Claude Code as the AI backend with your existing login.
151+
Open [localhost:3002](http://localhost:3002) and start chatting. No API keys or config needed — the default setup uses your local Claude Code login (Claude Pro/Max subscription).
153152

154153
```bash
155154
pnpm dev # start backend (port 3002) with watch mode
@@ -164,16 +163,15 @@ pnpm test # run tests
164163

165164
All config lives in `data/config/` as JSON files with Zod validation. Missing files fall back to sensible defaults. You can edit these files directly or use the Web UI.
166165

167-
**AI Provider** — The default provider is Claude Code (`claude -p` subprocess). To use the [Vercel AI SDK](https://sdk.vercel.ai/docs) instead (Anthropic, OpenAI, Google, etc.), switch `ai-provider.json` to `vercel-ai-sdk` and add your API key to `api-keys.json`. A third option, Agent SDK (`@anthropic-ai/claude-agent-sdk`), is also available via `agent-sdk`.
166+
**AI Provider** — The default provider is Claude (Agent SDK), which uses your local Claude Code login — no API key needed. To use the [Vercel AI SDK](https://sdk.vercel.ai/docs) instead (Anthropic, OpenAI, Google, etc.), switch `ai-provider.json` to `vercel-ai-sdk` and add your API key. Both can be switched at runtime via the Web UI.
168167

169168
**Trading** — Unified Trading Account (UTA) architecture. Define platforms in `platforms.json` (CCXT exchanges, Alpaca), then create accounts in `accounts.json` referencing a platform. Each account becomes a UTA with its own git history and guard config. Legacy `crypto.json` and `securities.json` are still supported.
170169

171170
| File | Purpose |
172171
|------|---------|
173172
| `engine.json` | Trading pairs, tick interval, timeframe |
174173
| `agent.json` | Max agent steps, evolution mode toggle, Claude Code tool permissions |
175-
| `ai-provider.json` | Active AI provider (`claude-code`, `vercel-ai-sdk`, or `agent-sdk`), switchable at runtime |
176-
| `api-keys.json` | AI provider API keys (Anthropic, OpenAI, Google) — only needed for Vercel AI SDK mode |
174+
| `ai-provider.json` | Active AI provider (`agent-sdk` or `vercel-ai-sdk`), login method, switchable at runtime |
177175
| `platforms.json` | Trading platform definitions (CCXT exchanges, Alpaca) |
178176
| `accounts.json` | Trading account credentials and guard config, references platforms |
179177
| `crypto.json` | CCXT exchange config + API keys, allowed symbols, guards |
@@ -218,9 +216,8 @@ src/
218216
media-store.ts # Media file persistence
219217
types.ts # Plugin, EngineContext interfaces
220218
ai-providers/
221-
claude-code/ # Claude Code CLI subprocess wrapper
222219
vercel-ai-sdk/ # Vercel AI SDK ToolLoopAgent wrapper
223-
agent-sdk/ # Agent SDK (@anthropic-ai/claude-agent-sdk) wrapper
220+
agent-sdk/ # Claude backend (@anthropic-ai/claude-agent-sdk, OAuth + API key)
224221
extension/
225222
analysis-kit/ # Indicator calculator and market data tools
226223
equity/ # Equity fundamentals and data adapter

src/ai-providers/agent-sdk/query.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { query as sdkQuery } from '@anthropic-ai/claude-agent-sdk'
99
import type { McpSdkServerConfigWithInstance } from '@anthropic-ai/claude-agent-sdk'
1010
import { pino } from 'pino'
1111
import type { ContentBlock } from '../../core/session.js'
12+
1213
import { readAIProviderConfig } from '../../core/config.js'
1314

1415
const logger = pino({
@@ -37,6 +38,7 @@ export interface AgentSdkOverride {
3738
model?: string
3839
apiKey?: string
3940
baseUrl?: string
41+
loginMethod?: 'api-key' | 'claudeai'
4042
}
4143

4244
export interface AgentSdkMessage {
@@ -115,12 +117,20 @@ export async function askAgentSdk(
115117
const finalAllowed = allowedTools.length > 0 ? allowedTools : modeAllowed
116118
const finalDisallowed = [...disallowedTools, ...modeDisallowed]
117119

118-
// Build env with API key injection
120+
// Build env with authentication
119121
const aiConfig = await readAIProviderConfig()
120-
const apiKey = override?.apiKey ?? aiConfig.apiKeys.anthropic
121-
const baseUrl = override?.baseUrl ?? aiConfig.baseUrl
122+
const loginMethod = override?.loginMethod ?? aiConfig.loginMethod ?? 'api-key'
123+
const isOAuthMode = loginMethod === 'claudeai'
124+
122125
const env: Record<string, string | undefined> = { ...process.env }
123-
if (apiKey) env.ANTHROPIC_API_KEY = apiKey
126+
if (isOAuthMode) {
127+
// Force OAuth by removing any inherited API key
128+
delete env.ANTHROPIC_API_KEY
129+
} else {
130+
const apiKey = override?.apiKey ?? aiConfig.apiKeys.anthropic
131+
if (apiKey) env.ANTHROPIC_API_KEY = apiKey
132+
}
133+
const baseUrl = override?.baseUrl ?? aiConfig.baseUrl
124134
if (baseUrl) env.ANTHROPIC_BASE_URL = baseUrl
125135

126136
// MCP servers
@@ -148,6 +158,7 @@ export async function askAgentSdk(
148158
permissionMode: 'bypassPermissions',
149159
allowDangerouslySkipPermissions: true,
150160
persistSession: false,
161+
...(loginMethod === 'claudeai' ? { forceLoginMethod: 'claudeai' as const } : {}),
151162
},
152163
})) {
153164
// assistant message — extract tool_use + text blocks

src/ai-providers/claude-code/claude-code-provider.ts

Lines changed: 0 additions & 81 deletions
This file was deleted.

src/ai-providers/claude-code/index.ts

Lines changed: 0 additions & 3 deletions
This file was deleted.

0 commit comments

Comments
 (0)