@inbrowser/model 0.1.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +44 -18
- package/README.md +129 -20
- package/dist/contract.d.ts +104 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +13 -0
- package/dist/contract.js.map +1 -0
- package/dist/engine-client.d.ts +44 -0
- package/dist/engine-client.d.ts.map +1 -0
- package/dist/engine-client.js +136 -0
- package/dist/engine-client.js.map +1 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +20 -10
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts +25 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +46 -8
- package/dist/index.js.map +1 -1
- package/dist/presets.d.ts +10 -0
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +21 -0
- package/dist/presets.js.map +1 -1
- package/dist/providers/anthropic.d.ts +45 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +217 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/claude-cli.d.ts +135 -0
- package/dist/providers/claude-cli.d.ts.map +1 -0
- package/dist/providers/claude-cli.js +270 -0
- package/dist/providers/claude-cli.js.map +1 -0
- package/dist/providers/claude-code.d.ts +188 -0
- package/dist/providers/claude-code.d.ts.map +1 -0
- package/dist/providers/claude-code.js +182 -0
- package/dist/providers/claude-code.js.map +1 -0
- package/dist/providers/gemini.d.ts +32 -0
- package/dist/providers/gemini.d.ts.map +1 -0
- package/dist/providers/gemini.js +441 -0
- package/dist/providers/gemini.js.map +1 -0
- package/dist/providers/llama-server.d.ts +15 -0
- package/dist/providers/llama-server.d.ts.map +1 -0
- package/dist/providers/llama-server.js +51 -0
- package/dist/providers/llama-server.js.map +1 -0
- package/dist/providers/oai-compat.d.ts +113 -0
- package/dist/providers/oai-compat.d.ts.map +1 -0
- package/dist/providers/oai-compat.js +257 -0
- package/dist/providers/oai-compat.js.map +1 -0
- package/dist/providers/ollama.d.ts +15 -0
- package/dist/providers/ollama.d.ts.map +1 -0
- package/dist/providers/ollama.js +51 -0
- package/dist/providers/ollama.js.map +1 -0
- package/dist/providers/openrouter-oauth.d.ts +67 -0
- package/dist/providers/openrouter-oauth.d.ts.map +1 -0
- package/dist/providers/openrouter-oauth.js +84 -0
- package/dist/providers/openrouter-oauth.js.map +1 -0
- package/dist/providers/openrouter.d.ts +16 -0
- package/dist/providers/openrouter.d.ts.map +1 -0
- package/dist/providers/openrouter.js +27 -0
- package/dist/providers/openrouter.js.map +1 -0
- package/dist/providers/requesty.d.ts +16 -0
- package/dist/providers/requesty.d.ts.map +1 -0
- package/dist/providers/requesty.js +27 -0
- package/dist/providers/requesty.js.map +1 -0
- package/dist/providers/types.d.ts +50 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +2 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/sse.d.ts +20 -0
- package/dist/sse.d.ts.map +1 -0
- package/dist/sse.js +47 -0
- package/dist/sse.js.map +1 -0
- package/dist/types.d.ts +2 -13
- package/dist/types.d.ts.map +1 -1
- package/dist/usage.d.ts +6 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +55 -0
- package/dist/usage.js.map +1 -0
- package/dist/with-retry.d.ts +27 -0
- package/dist/with-retry.d.ts.map +1 -0
- package/dist/with-retry.js +55 -0
- package/dist/with-retry.js.map +1 -0
- package/dist/worker.d.ts +1 -1
- package/dist/worker.js +1 -1
- package/package.json +14 -30
- package/dist/adapters/agent.d.ts +0 -19
- package/dist/adapters/agent.d.ts.map +0 -1
- package/dist/adapters/agent.js +0 -96
- package/dist/adapters/agent.js.map +0 -1
- package/dist/adapters/relay.d.ts +0 -17
- package/dist/adapters/relay.d.ts.map +0 -1
- package/dist/adapters/relay.js +0 -90
- package/dist/adapters/relay.js.map +0 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type { ModelClient, ModelMessage } from '../contract.js';
|
|
2
|
+
/**
|
|
3
|
+
* Claude Code CLI provider — spawns `claude -p` (print mode) as a
|
|
4
|
+
* subprocess and adapts its `stream-json` output to `ModelEvent`s.
|
|
5
|
+
*
|
|
6
|
+
* Why: model access through a Claude subscription (the CLI's own
|
|
7
|
+
* login) instead of API-key metering. The caller sends messages and
|
|
8
|
+
* gets a completion back; auth, retries, and the wire protocol are the
|
|
9
|
+
* CLI's problem.
|
|
10
|
+
*
|
|
11
|
+
* ## Semantic differences from a raw model call — READ THIS
|
|
12
|
+
*
|
|
13
|
+
* `claude -p` runs Claude *Code*, an agentic CLI, not the bare
|
|
14
|
+
* Messages API. This provider pins it as close to a pure model call
|
|
15
|
+
* as the CLI allows (flags grounded in `claude --help`, v2.1.172):
|
|
16
|
+
*
|
|
17
|
+
* - `--tools ""` disables all built-in tools (no Bash/Edit/
|
|
18
|
+
* Read…). Re-enable selectively via
|
|
19
|
+
* `ClaudeCliOptions.tools`.
|
|
20
|
+
* - `--strict-mcp-config` with no `--mcp-config` ⇒ zero MCP servers.
|
|
21
|
+
* - `--disable-slash-commands` disables skills.
|
|
22
|
+
* - `--no-session-persistence` nothing written to the session store.
|
|
23
|
+
* - `--system-prompt <s>` when the request carries system messages,
|
|
24
|
+
* they REPLACE Claude Code's default agentic
|
|
25
|
+
* system prompt. With no system message the
|
|
26
|
+
* CLI's default prompt applies.
|
|
27
|
+
*
|
|
28
|
+
* What can NOT be turned off / mapped:
|
|
29
|
+
*
|
|
30
|
+
* - The CLI still injects its own context (current date, user
|
|
31
|
+
* email, memory paths) around the prompt. Responses are "Claude
|
|
32
|
+
* via Claude Code", not raw `/v1/messages`.
|
|
33
|
+
* - There is no `--max-turns` in this CLI version; with all tools
|
|
34
|
+
* disabled the run is effectively single-turn anyway.
|
|
35
|
+
* - Caller-defined tools (`ModelRequest.tools`) have no CLI
|
|
36
|
+
* equivalent — the provider yields an `error` event if any are
|
|
37
|
+
* passed rather than silently dropping them. (`supportsTools` is
|
|
38
|
+
* `false`.)
|
|
39
|
+
* - `temperature` / `topP` / `topK` have no CLI flags and are
|
|
40
|
+
* ignored. `reasoningEffort` maps to `--effort` (`off` is
|
|
41
|
+
* omitted; the CLI has no off level).
|
|
42
|
+
* - Multi-turn histories are flattened into a single transcript
|
|
43
|
+
* prompt (`claude -p` accepts one prompt, piped via stdin). For
|
|
44
|
+
* one-shot user messages the text is passed through verbatim.
|
|
45
|
+
*
|
|
46
|
+
* ## Wire shape
|
|
47
|
+
*
|
|
48
|
+
* `--output-format stream-json --include-partial-messages --verbose`
|
|
49
|
+
* emits NDJSON on stdout. The lines this provider consumes (captured
|
|
50
|
+
* from a real run; see `test/fixtures/claude-cli-stream-json.ndjson`):
|
|
51
|
+
*
|
|
52
|
+
* - `{type:"stream_event", event:{type:"content_block_delta",
|
|
53
|
+
* delta:{type:"text_delta"|"thinking_delta", ...}}}` → incremental
|
|
54
|
+
* `text` / `thinking` chunks.
|
|
55
|
+
* - `{type:"result", subtype:"success", result:"…", usage:{…},
|
|
56
|
+
* total_cost_usd:…}` → terminal `usage` event (input/output/
|
|
57
|
+
* cache-read tokens + real dollar cost). `is_error: true` →
|
|
58
|
+
* `error` event.
|
|
59
|
+
*
|
|
60
|
+
* Everything else (`system`, `assistant` snapshots, `rate_limit_event`,
|
|
61
|
+
* unknown/malformed lines) is skipped.
|
|
62
|
+
*
|
|
63
|
+
* ## Auth
|
|
64
|
+
*
|
|
65
|
+
* If `config.apiKey` is non-empty it is exported as
|
|
66
|
+
* `ANTHROPIC_API_KEY` to the subprocess; otherwise the CLI's own
|
|
67
|
+
* credentials (subscription OAuth / keychain) apply — pass `apiKey: ''`
|
|
68
|
+
* for the common subscription case.
|
|
69
|
+
*
|
|
70
|
+
* ## Subprocess hygiene
|
|
71
|
+
*
|
|
72
|
+
* Spawned with an argv array (never through a shell — no injection
|
|
73
|
+
* surface), prompt piped via stdin (no argv-length limit), stdout
|
|
74
|
+
* parsed incrementally line-by-line (no unbounded buffering), stderr
|
|
75
|
+
* capped at 16 KiB, hard timeout (default 5 min) followed by SIGKILL,
|
|
76
|
+
* `AbortSignal` kills the child, ENOENT and non-zero exits surface as
|
|
77
|
+
* typed `error` events.
|
|
78
|
+
*/
|
|
79
|
+
export interface ClaudeCliOptions {
|
|
80
|
+
/** Path to the executable. Default `'claude'` (resolved via PATH). */
|
|
81
|
+
claudePath?: string;
|
|
82
|
+
/** Hard wall-clock cap; the child is SIGKILLed after this. Default 300_000 ms. */
|
|
83
|
+
timeoutMs?: number;
|
|
84
|
+
/**
|
|
85
|
+
* Working directory for the subprocess. Defaults to `os.tmpdir()` so
|
|
86
|
+
* the CLI doesn't pick up the host project's CLAUDE.md / settings.
|
|
87
|
+
*/
|
|
88
|
+
cwd?: string;
|
|
89
|
+
/**
|
|
90
|
+
* Built-in CLI tools to allow (e.g. `['Read', 'Grep']`), passed to
|
|
91
|
+
* `--tools`. Default `[]` ⇒ `--tools ""` ⇒ all tools disabled —
|
|
92
|
+
* the pure-model configuration.
|
|
93
|
+
*/
|
|
94
|
+
tools?: string[];
|
|
95
|
+
/** Extra argv appended verbatim — escape hatch for new CLI flags. */
|
|
96
|
+
extraArgs?: string[];
|
|
97
|
+
/** Extra environment for the subprocess (merged over `process.env`). */
|
|
98
|
+
env?: Record<string, string | undefined>;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Construction config for the claude-cli provider: the relay-facing
|
|
102
|
+
* `{ apiKey?; model }` plus the CLI-specific `ClaudeCliOptions`.
|
|
103
|
+
*/
|
|
104
|
+
export interface ClaudeCliConfig extends ClaudeCliOptions {
|
|
105
|
+
apiKey?: string;
|
|
106
|
+
model: string;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Flatten relay messages into (system, prompt). A single user message
|
|
110
|
+
* passes through verbatim; anything longer becomes a labeled
|
|
111
|
+
* transcript with an explicit "reply with the next assistant message"
|
|
112
|
+
* framing — `claude -p` takes one prompt, not a message array.
|
|
113
|
+
*/
|
|
114
|
+
export declare function renderPrompt(messages: ModelMessage[]): {
|
|
115
|
+
system: string;
|
|
116
|
+
prompt: string;
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Build a Claude Code CLI `ModelClient`. `claudeCliModelClient({ model })`
|
|
120
|
+
* is the pure-model default; register it like any other provider factory:
|
|
121
|
+
*
|
|
122
|
+
* ```ts
|
|
123
|
+
* const relay = createRelay({
|
|
124
|
+
* store,
|
|
125
|
+
* providers: { 'claude-cli': (c) => claudeCliModelClient(c) },
|
|
126
|
+
* });
|
|
127
|
+
* // client request: { provider: 'claude-cli', model: 'claude-opus-4-8',
|
|
128
|
+
* // messages, tools: [], apiKey: '' }
|
|
129
|
+
* ```
|
|
130
|
+
*
|
|
131
|
+
* Construction values (model, apiKey, CLI options) come in the config;
|
|
132
|
+
* per-call values (messages, reasoning) come in the `ModelRequest`.
|
|
133
|
+
*/
|
|
134
|
+
export declare function claudeCliModelClient(config: ClaudeCliConfig): ModelClient;
|
|
135
|
+
//# sourceMappingURL=claude-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-cli.d.ts","sourceRoot":"","sources":["../../src/providers/claude-cli.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAc,YAAY,EAAgB,MAAM,gBAAgB,CAAC;AAE1F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4EG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kFAAkF;IAClF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,wEAAwE;IACxE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC1C;AAED;;;GAGG;AACH,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAUD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAgCA;AAoBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,GAAG,WAAW,CAqNzE"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
const DEFAULT_TIMEOUT_MS = 300_000;
|
|
2
|
+
const STDERR_CAP = 16 * 1024;
|
|
3
|
+
/** Map the relay's `reasoningEffort` onto `--effort` (no `off` level in the CLI). */
|
|
4
|
+
function toEffortFlag(effort) {
|
|
5
|
+
return effort === 'low' || effort === 'medium' || effort === 'high' ? effort : undefined;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Flatten relay messages into (system, prompt). A single user message
|
|
9
|
+
* passes through verbatim; anything longer becomes a labeled
|
|
10
|
+
* transcript with an explicit "reply with the next assistant message"
|
|
11
|
+
* framing — `claude -p` takes one prompt, not a message array.
|
|
12
|
+
*/
|
|
13
|
+
export function renderPrompt(messages) {
|
|
14
|
+
let system = '';
|
|
15
|
+
const turns = [];
|
|
16
|
+
for (const m of messages) {
|
|
17
|
+
if (m.role === 'system') {
|
|
18
|
+
system += (system ? '\n\n' : '') + (m.text ?? '');
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (m.role === 'user') {
|
|
22
|
+
turns.push({ role: 'User', text: m.text ?? '' });
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (m.role === 'assistant') {
|
|
26
|
+
let text = m.text ?? '';
|
|
27
|
+
for (const c of m.toolCalls ?? []) {
|
|
28
|
+
text += `${text ? '\n' : ''}[called tool ${c.name} with ${JSON.stringify(c.args ?? {})}]`;
|
|
29
|
+
}
|
|
30
|
+
turns.push({ role: 'Assistant', text });
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (m.role === 'tool') {
|
|
34
|
+
turns.push({ role: 'Tool result', text: `${m.name ?? ''}: ${m.resultJson ?? ''}` });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (turns.length === 1 && turns[0]?.role === 'User') {
|
|
38
|
+
return { system, prompt: turns[0].text };
|
|
39
|
+
}
|
|
40
|
+
const transcript = turns.map((t) => `${t.role}: ${t.text}`).join('\n\n');
|
|
41
|
+
return {
|
|
42
|
+
system,
|
|
43
|
+
prompt: `The following is a conversation transcript. Reply with the next Assistant message only — no role label, no commentary.\n\n${transcript}`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Build a Claude Code CLI `ModelClient`. `claudeCliModelClient({ model })`
|
|
48
|
+
* is the pure-model default; register it like any other provider factory:
|
|
49
|
+
*
|
|
50
|
+
* ```ts
|
|
51
|
+
* const relay = createRelay({
|
|
52
|
+
* store,
|
|
53
|
+
* providers: { 'claude-cli': (c) => claudeCliModelClient(c) },
|
|
54
|
+
* });
|
|
55
|
+
* // client request: { provider: 'claude-cli', model: 'claude-opus-4-8',
|
|
56
|
+
* // messages, tools: [], apiKey: '' }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* Construction values (model, apiKey, CLI options) come in the config;
|
|
60
|
+
* per-call values (messages, reasoning) come in the `ModelRequest`.
|
|
61
|
+
*/
|
|
62
|
+
export function claudeCliModelClient(config) {
|
|
63
|
+
const claudePath = config.claudePath ?? 'claude';
|
|
64
|
+
const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
65
|
+
const tools = config.tools ?? [];
|
|
66
|
+
const extraArgs = config.extraArgs ?? [];
|
|
67
|
+
return {
|
|
68
|
+
id: `claude-cli:${config.model}`,
|
|
69
|
+
supportsTools: false,
|
|
70
|
+
async *chat(req, signal) {
|
|
71
|
+
if (signal?.aborted)
|
|
72
|
+
return;
|
|
73
|
+
if (req.tools.length > 0) {
|
|
74
|
+
yield {
|
|
75
|
+
kind: 'error',
|
|
76
|
+
message: 'claude-cli provider does not support caller-defined tools — `claude -p` has no flag to register external tool schemas. Send `tools: []` (or use an API provider for tool calling).',
|
|
77
|
+
};
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const { system, prompt } = renderPrompt(req.messages);
|
|
81
|
+
if (!prompt) {
|
|
82
|
+
yield { kind: 'error', message: 'claude-cli provider: no user message to send.' };
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// Every flag below is grounded in `claude --help` (v2.1.172).
|
|
86
|
+
const args = [
|
|
87
|
+
'-p',
|
|
88
|
+
'--output-format',
|
|
89
|
+
'stream-json',
|
|
90
|
+
'--include-partial-messages',
|
|
91
|
+
'--verbose',
|
|
92
|
+
'--no-session-persistence',
|
|
93
|
+
'--strict-mcp-config',
|
|
94
|
+
'--disable-slash-commands',
|
|
95
|
+
'--tools',
|
|
96
|
+
tools.join(','),
|
|
97
|
+
];
|
|
98
|
+
if (config.model)
|
|
99
|
+
args.push('--model', config.model);
|
|
100
|
+
if (system)
|
|
101
|
+
args.push('--system-prompt', system);
|
|
102
|
+
const effort = toEffortFlag(req.reasoningEffort);
|
|
103
|
+
if (effort)
|
|
104
|
+
args.push('--effort', effort);
|
|
105
|
+
args.push(...extraArgs);
|
|
106
|
+
// Lazy-load the Node-only deps so importing this module is browser-safe
|
|
107
|
+
// (the root barrel re-exports it; the browser never calls chat()).
|
|
108
|
+
const { spawn } = await import('node:child_process');
|
|
109
|
+
const cwd = config.cwd ?? (await import('node:os')).tmpdir();
|
|
110
|
+
let child;
|
|
111
|
+
try {
|
|
112
|
+
child = spawn(claudePath, args, {
|
|
113
|
+
cwd,
|
|
114
|
+
env: {
|
|
115
|
+
...process.env,
|
|
116
|
+
...(config.apiKey ? { ANTHROPIC_API_KEY: config.apiKey } : {}),
|
|
117
|
+
...config.env,
|
|
118
|
+
},
|
|
119
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
123
|
+
yield { kind: 'error', message: e instanceof Error ? e.message : String(e) };
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
let spawnError;
|
|
127
|
+
let timedOut = false;
|
|
128
|
+
let stderr = '';
|
|
129
|
+
child.on('error', (e) => {
|
|
130
|
+
spawnError = e;
|
|
131
|
+
});
|
|
132
|
+
child.stderr?.setEncoding('utf8');
|
|
133
|
+
child.stderr?.on('data', (chunk) => {
|
|
134
|
+
if (stderr.length < STDERR_CAP)
|
|
135
|
+
stderr += chunk.slice(0, STDERR_CAP - stderr.length);
|
|
136
|
+
});
|
|
137
|
+
const exited = new Promise((resolve) => {
|
|
138
|
+
child.on('close', (code) => resolve(code));
|
|
139
|
+
});
|
|
140
|
+
// Also destroy our pipe ends on kill: a grandchild process can
|
|
141
|
+
// inherit the stdout fd and keep the stream open past SIGKILL,
|
|
142
|
+
// which would wedge the read loop.
|
|
143
|
+
const killChild = () => {
|
|
144
|
+
child.kill('SIGKILL');
|
|
145
|
+
child.stdout?.destroy();
|
|
146
|
+
child.stderr?.destroy();
|
|
147
|
+
};
|
|
148
|
+
const timer = setTimeout(() => {
|
|
149
|
+
timedOut = true;
|
|
150
|
+
killChild();
|
|
151
|
+
}, timeoutMs);
|
|
152
|
+
const onAbort = () => killChild();
|
|
153
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
154
|
+
// Pipe the prompt via stdin. Swallow EPIPE — a child that dies
|
|
155
|
+
// before reading stdin is reported through exit-code handling.
|
|
156
|
+
child.stdin?.on('error', () => { });
|
|
157
|
+
child.stdin?.end(prompt);
|
|
158
|
+
let sawText = false;
|
|
159
|
+
let sawResult = false;
|
|
160
|
+
try {
|
|
161
|
+
child.stdout?.setEncoding('utf8');
|
|
162
|
+
let buf = '';
|
|
163
|
+
const lines = async function* () {
|
|
164
|
+
if (!child.stdout)
|
|
165
|
+
return;
|
|
166
|
+
try {
|
|
167
|
+
for await (const chunk of child.stdout) {
|
|
168
|
+
buf += chunk;
|
|
169
|
+
let nl = buf.indexOf('\n');
|
|
170
|
+
while (nl !== -1) {
|
|
171
|
+
yield buf.slice(0, nl);
|
|
172
|
+
buf = buf.slice(nl + 1);
|
|
173
|
+
nl = buf.indexOf('\n');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// stream destroyed by kill/abort — handled after the loop
|
|
179
|
+
}
|
|
180
|
+
if (buf.trim())
|
|
181
|
+
yield buf;
|
|
182
|
+
};
|
|
183
|
+
for await (const rawLine of lines()) {
|
|
184
|
+
const line = rawLine.trim();
|
|
185
|
+
if (!line)
|
|
186
|
+
continue;
|
|
187
|
+
let msg;
|
|
188
|
+
try {
|
|
189
|
+
msg = JSON.parse(line);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
continue; // tolerate non-JSON noise on stdout
|
|
193
|
+
}
|
|
194
|
+
if (msg.type === 'stream_event' && msg.event?.type === 'content_block_delta') {
|
|
195
|
+
const delta = msg.event.delta;
|
|
196
|
+
if (delta?.type === 'text_delta' && typeof delta.text === 'string') {
|
|
197
|
+
sawText = true;
|
|
198
|
+
yield { kind: 'text', text: delta.text };
|
|
199
|
+
}
|
|
200
|
+
else if (delta?.type === 'thinking_delta' && typeof delta.thinking === 'string') {
|
|
201
|
+
yield { kind: 'thinking', text: delta.thinking };
|
|
202
|
+
}
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
if (msg.type === 'result') {
|
|
206
|
+
sawResult = true;
|
|
207
|
+
if (msg.is_error) {
|
|
208
|
+
yield {
|
|
209
|
+
kind: 'error',
|
|
210
|
+
message: `claude -p reported ${msg.subtype ?? 'error'}: ${typeof msg.result === 'string' && msg.result
|
|
211
|
+
? msg.result.slice(0, 400)
|
|
212
|
+
: '(no detail)'}`,
|
|
213
|
+
};
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
// Defensive: if no deltas streamed (e.g. partial messages
|
|
217
|
+
// unavailable), fall back to the terminal result text.
|
|
218
|
+
if (!sawText && typeof msg.result === 'string' && msg.result) {
|
|
219
|
+
yield { kind: 'text', text: msg.result };
|
|
220
|
+
}
|
|
221
|
+
yield {
|
|
222
|
+
kind: 'usage',
|
|
223
|
+
usage: {
|
|
224
|
+
promptTokens: msg.usage?.input_tokens ?? 0,
|
|
225
|
+
outputTokens: msg.usage?.output_tokens ?? 0,
|
|
226
|
+
...(typeof msg.usage?.cache_read_input_tokens === 'number'
|
|
227
|
+
? { cachedTokens: msg.usage.cache_read_input_tokens }
|
|
228
|
+
: {}),
|
|
229
|
+
...(typeof msg.total_cost_usd === 'number' ? { costUsd: msg.total_cost_usd } : {}),
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
return; // result is terminal
|
|
233
|
+
}
|
|
234
|
+
// system / assistant / rate_limit_event / unknown — skipped.
|
|
235
|
+
}
|
|
236
|
+
const exitCode = await exited;
|
|
237
|
+
if (timedOut) {
|
|
238
|
+
yield { kind: 'error', message: `claude -p timed out after ${timeoutMs}ms.` };
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (signal?.aborted)
|
|
242
|
+
return;
|
|
243
|
+
if (spawnError) {
|
|
244
|
+
const hint = spawnError.code === 'ENOENT'
|
|
245
|
+
? `claude CLI not found at '${claudePath}'. Install Claude Code (https://claude.com/claude-code) or set ClaudeCliOptions.claudePath.`
|
|
246
|
+
: `failed to spawn '${claudePath}': ${spawnError.message}`;
|
|
247
|
+
yield { kind: 'error', message: hint };
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (!sawResult) {
|
|
251
|
+
yield {
|
|
252
|
+
kind: 'error',
|
|
253
|
+
message: exitCode !== 0
|
|
254
|
+
? `claude -p exited with code ${exitCode}: ${stderr.trim().slice(0, 400) || '(no stderr)'}`
|
|
255
|
+
: 'claude -p exited without emitting a result event.',
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
finally {
|
|
260
|
+
clearTimeout(timer);
|
|
261
|
+
signal?.removeEventListener('abort', onAbort);
|
|
262
|
+
if (child.exitCode === null && !child.killed)
|
|
263
|
+
child.kill('SIGKILL');
|
|
264
|
+
child.stdout?.destroy();
|
|
265
|
+
child.stderr?.destroy();
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=claude-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-cli.js","sourceRoot":"","sources":["../../src/providers/claude-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import type { ModelClient } from '../contract.js';
|
|
2
|
+
/**
|
|
3
|
+
* Claude Code SDK provider — calls `query()` from
|
|
4
|
+
* `@anthropic-ai/claude-agent-sdk` configured as a bare model call,
|
|
5
|
+
* authenticated against the user's Claude Code login (subscription)
|
|
6
|
+
* rather than an API key.
|
|
7
|
+
*
|
|
8
|
+
* Why this exists, distinct from `anthropicModelClient` and
|
|
9
|
+
* `claude-cli`:
|
|
10
|
+
*
|
|
11
|
+
* - `anthropicModelClient` is the BYOK `/v1/messages` path — per-token
|
|
12
|
+
* billing against an API key.
|
|
13
|
+
* - `claude-cli` shells out to the `claude` CLI subprocess.
|
|
14
|
+
* - this provider talks to the same Agent SDK programmatically and
|
|
15
|
+
* uses the user's subscription credentials. No subprocess, no
|
|
16
|
+
* NDJSON parsing.
|
|
17
|
+
*
|
|
18
|
+
* As of mid-2026 Anthropic confirmed the Agent SDK and `claude -p`
|
|
19
|
+
* still draw from the Claude Pro/Max subscription rate limits when
|
|
20
|
+
* no `ANTHROPIC_API_KEY` is in the environment; the planned move to
|
|
21
|
+
* a separate credit pool was deferred. If `ANTHROPIC_API_KEY` is
|
|
22
|
+
* present, the SDK bills per-token — this provider deletes it from
|
|
23
|
+
* the subprocess env so subscription is the only billing path.
|
|
24
|
+
*
|
|
25
|
+
* ## Bare-model configuration
|
|
26
|
+
*
|
|
27
|
+
* The SDK is Claude Code under the hood; left to its defaults it
|
|
28
|
+
* would run a full coding agent (bash, file edits, MCP servers).
|
|
29
|
+
* This provider pins every option that disables that behavior so it
|
|
30
|
+
* answers like a plain Messages call:
|
|
31
|
+
*
|
|
32
|
+
* - `tools: []` — all built-in tools off.
|
|
33
|
+
* - `systemPrompt: <s>` — string form replaces the default
|
|
34
|
+
* Claude Code prompt. Empty string
|
|
35
|
+
* when the request carries no system
|
|
36
|
+
* message.
|
|
37
|
+
* - `settingSources: []` — no filesystem settings, no CLAUDE.md.
|
|
38
|
+
* - `mcpServers: {}` plus
|
|
39
|
+
* `strictMcpConfig: true` — no MCP discovery from project /
|
|
40
|
+
* plugin / agent-frontmatter sources.
|
|
41
|
+
* - `permissionMode: 'bypassPermissions'` — no interactive prompts;
|
|
42
|
+
* with no tools this is moot but
|
|
43
|
+
* required to suppress the prompt loop.
|
|
44
|
+
* - `includePartialMessages: true` — stream text / thinking deltas
|
|
45
|
+
* as they arrive instead of buffering
|
|
46
|
+
* the whole assistant turn.
|
|
47
|
+
*
|
|
48
|
+
* ## Auth — subscription only
|
|
49
|
+
*
|
|
50
|
+
* The SDK's env precedence is `ANTHROPIC_API_KEY` → `CLAUDE_CODE_OAUTH_TOKEN`
|
|
51
|
+
* → `~/.claude/.credentials.json` (the Claude Code login). This
|
|
52
|
+
* provider removes `ANTHROPIC_API_KEY` from the subprocess env so the
|
|
53
|
+
* subscription path always wins. To pin a specific OAuth token (CI,
|
|
54
|
+
* multi-tenant), pass `oauthToken` to `claudeCodeModelClient` —
|
|
55
|
+
* it is forwarded to the SDK via `CLAUDE_CODE_OAUTH_TOKEN`. Otherwise
|
|
56
|
+
* the host's logged-in subscription is used.
|
|
57
|
+
*
|
|
58
|
+
* `config.apiKey` is **ignored** by this provider.
|
|
59
|
+
*
|
|
60
|
+
* ## Tools, temperature, knobs
|
|
61
|
+
*
|
|
62
|
+
* - Caller-defined tools (`req.tools`) have no parallel in this
|
|
63
|
+
* bare-model setup. Passing any yields a typed `error` event
|
|
64
|
+
* rather than silently dropping them. (`supportsTools` is `false`.)
|
|
65
|
+
* - `temperature` / `topP` / `topK` are not exposed by the SDK in
|
|
66
|
+
* the bare-model configuration and are ignored.
|
|
67
|
+
* - `reasoningEffort` maps to the SDK's `effort` option: `low` /
|
|
68
|
+
* `medium` / `high` pass through; `off` (the relay's sentinel
|
|
69
|
+
* for "do not request reasoning") omits the field so the model's
|
|
70
|
+
* default applies. The SDK also accepts `xhigh` / `max` for
|
|
71
|
+
* newer Opus + Fable models — not exposed yet because the relay
|
|
72
|
+
* layer's `ReasoningEffort` union doesn't include them.
|
|
73
|
+
* - Multi-turn histories are flattened into a single transcript
|
|
74
|
+
* prompt by `renderPrompt` (shared with `claude-cli`). For a
|
|
75
|
+
* one-shot user message the text passes through verbatim.
|
|
76
|
+
*/
|
|
77
|
+
/** Subset of `@anthropic-ai/claude-agent-sdk`'s Options we set. Kept
|
|
78
|
+
* structural so we don't import the SDK at type-check time for HTTP-
|
|
79
|
+
* only consumers. */
|
|
80
|
+
interface SdkOptions {
|
|
81
|
+
model?: string;
|
|
82
|
+
systemPrompt?: string | {
|
|
83
|
+
type: 'preset';
|
|
84
|
+
preset: 'claude_code';
|
|
85
|
+
};
|
|
86
|
+
tools?: string[] | {
|
|
87
|
+
type: 'preset';
|
|
88
|
+
preset: 'claude_code';
|
|
89
|
+
};
|
|
90
|
+
settingSources?: string[];
|
|
91
|
+
mcpServers?: Record<string, unknown>;
|
|
92
|
+
strictMcpConfig?: boolean;
|
|
93
|
+
permissionMode?: 'default' | 'acceptEdits' | 'bypassPermissions' | 'plan';
|
|
94
|
+
includePartialMessages?: boolean;
|
|
95
|
+
/** SDK Options.effort. Wider than the relay's ReasoningEffort —
|
|
96
|
+
* the relay's 'off' is mapped to "omit the field" so the model's
|
|
97
|
+
* default applies; 'xhigh' / 'max' are not exposed by the relay
|
|
98
|
+
* layer yet. */
|
|
99
|
+
effort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
100
|
+
abortController?: AbortController;
|
|
101
|
+
env?: Record<string, string | undefined>;
|
|
102
|
+
}
|
|
103
|
+
/** Subset of the SDK's `SDKMessage` union we consume. */
|
|
104
|
+
interface SdkMessage {
|
|
105
|
+
type: string;
|
|
106
|
+
subtype?: string;
|
|
107
|
+
event?: {
|
|
108
|
+
type?: string;
|
|
109
|
+
delta?: {
|
|
110
|
+
type?: string;
|
|
111
|
+
text?: string;
|
|
112
|
+
thinking?: string;
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
message?: {
|
|
116
|
+
content?: Array<{
|
|
117
|
+
type?: string;
|
|
118
|
+
text?: string;
|
|
119
|
+
thinking?: string;
|
|
120
|
+
}>;
|
|
121
|
+
usage?: {
|
|
122
|
+
input_tokens?: number;
|
|
123
|
+
output_tokens?: number;
|
|
124
|
+
cache_read_input_tokens?: number;
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
usage?: {
|
|
128
|
+
input_tokens?: number;
|
|
129
|
+
output_tokens?: number;
|
|
130
|
+
cache_read_input_tokens?: number;
|
|
131
|
+
};
|
|
132
|
+
result?: string;
|
|
133
|
+
is_error?: boolean;
|
|
134
|
+
}
|
|
135
|
+
/** Minimal shape of the SDK's exported `query` function. */
|
|
136
|
+
type SdkQuery = (params: {
|
|
137
|
+
prompt: string;
|
|
138
|
+
options?: SdkOptions;
|
|
139
|
+
}) => AsyncIterable<SdkMessage>;
|
|
140
|
+
/**
|
|
141
|
+
* Construction config for the claude-code provider: the relay-facing
|
|
142
|
+
* `{ apiKey?; model }` (apiKey ignored) plus the SDK-specific options.
|
|
143
|
+
*/
|
|
144
|
+
export interface ClaudeCodeConfig {
|
|
145
|
+
apiKey?: string;
|
|
146
|
+
model: string;
|
|
147
|
+
/**
|
|
148
|
+
* Explicit OAuth token to use instead of the host's ambient
|
|
149
|
+
* `~/.claude/.credentials.json`. Forwarded to the SDK via
|
|
150
|
+
* `CLAUDE_CODE_OAUTH_TOKEN`. Useful for CI and multi-tenant hosts.
|
|
151
|
+
*/
|
|
152
|
+
oauthToken?: string;
|
|
153
|
+
/**
|
|
154
|
+
* Override SDK module loader. Used in tests to inject a fake
|
|
155
|
+
* `query` without installing the heavy peer dep. Production code
|
|
156
|
+
* leaves this unset — the provider lazy-imports
|
|
157
|
+
* `@anthropic-ai/claude-agent-sdk`.
|
|
158
|
+
*/
|
|
159
|
+
loadSdk?: () => Promise<{
|
|
160
|
+
query: SdkQuery;
|
|
161
|
+
}>;
|
|
162
|
+
/**
|
|
163
|
+
* Extra environment for the SDK subprocess. Merged on top of the
|
|
164
|
+
* provider's computed env. `ANTHROPIC_API_KEY` is always stripped
|
|
165
|
+
* regardless of what you set here — passing it via this slot will
|
|
166
|
+
* not enable per-token billing.
|
|
167
|
+
*/
|
|
168
|
+
env?: Record<string, string | undefined>;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Build a Claude Code SDK `ModelClient`. `claudeCodeModelClient({ model })`
|
|
172
|
+
* with no other options uses the host's ambient subscription credentials:
|
|
173
|
+
*
|
|
174
|
+
* ```ts
|
|
175
|
+
* const relay = createRelay({
|
|
176
|
+
* store,
|
|
177
|
+
* providers: { 'claude-code': (c) => claudeCodeModelClient(c) },
|
|
178
|
+
* });
|
|
179
|
+
* // client request: { provider: 'claude-code', model: 'claude-opus-4-8',
|
|
180
|
+
* // messages, tools: [], apiKey: '' }
|
|
181
|
+
* ```
|
|
182
|
+
*
|
|
183
|
+
* Construction values (model, SDK options) come in the config; per-call
|
|
184
|
+
* values (messages, reasoning) come in the `ModelRequest`.
|
|
185
|
+
*/
|
|
186
|
+
export declare function claudeCodeModelClient(config: ClaudeCodeConfig): ModelClient;
|
|
187
|
+
export {};
|
|
188
|
+
//# sourceMappingURL=claude-code.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../src/providers/claude-code.ts"],"names":[],"mappings":"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"}
|