@xtruder/opencode-claude-max-plugin 0.1.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/README.md +99 -0
- package/build/agent-index.d.ts +24 -0
- package/build/agent-index.d.ts.map +1 -0
- package/build/agent-index.js +294 -0
- package/build/agent-model.d.ts +34 -0
- package/build/agent-model.d.ts.map +1 -0
- package/build/agent-test.d.ts +2 -0
- package/build/agent-test.d.ts.map +1 -0
- package/build/credentials.d.ts +21 -0
- package/build/credentials.d.ts.map +1 -0
- package/build/index.d.ts +66 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +881 -0
- package/build/model.d.ts +19 -0
- package/build/model.d.ts.map +1 -0
- package/build/prompt.d.ts +11 -0
- package/build/prompt.d.ts.map +1 -0
- package/build/stream.d.ts +6 -0
- package/build/stream.d.ts.map +1 -0
- package/build/tool-names.d.ts +24 -0
- package/build/tool-names.d.ts.map +1 -0
- package/build/tools.d.ts +8 -0
- package/build/tools.d.ts.map +1 -0
- package/build/usage-cli.d.ts +3 -0
- package/build/usage-cli.d.ts.map +1 -0
- package/build/usage-cli.js +139 -0
- package/build/usage.d.ts +28 -0
- package/build/usage.d.ts.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# @xtruder/opencode-claude-max-plugin
|
|
2
|
+
|
|
3
|
+
An [OpenCode](https://opencode.ai/) plugin that enables Claude Pro/Max subscription access via the official [`@anthropic-ai/sdk`](https://github.com/anthropics/anthropic-sdk-typescript), using OAuth credentials from Claude Code (`~/.claude/.credentials.json`).
|
|
4
|
+
|
|
5
|
+
## Why?
|
|
6
|
+
|
|
7
|
+
- **Use your Claude subscription** — Automatically reads OAuth credentials from Claude Code, no separate API key needed
|
|
8
|
+
- **Matches Claude Code exactly** — Same headers, billing, tool names, and request format as Claude Code CLI
|
|
9
|
+
- **Prompt caching** — 98% of input tokens served from cache (system prompt + tools cached globally)
|
|
10
|
+
- **All Claude models** — Opus 4.6, Sonnet 4.6, Sonnet 4.5, Haiku 4.5, and more
|
|
11
|
+
- **Extended thinking** — Full reasoning support with signature passthrough
|
|
12
|
+
- **Usage tracking** — Built-in `/usage` command shows subscription utilization
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @xtruder/opencode-claude-max-plugin
|
|
18
|
+
# or
|
|
19
|
+
bun add @xtruder/opencode-claude-max-plugin
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### With OpenCode
|
|
25
|
+
|
|
26
|
+
Add to `.opencode/opencode.json`. If you have Claude Code credentials (`~/.claude/.credentials.json`), no environment variable is needed:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"provider": {
|
|
31
|
+
"anthropic-sdk": {
|
|
32
|
+
"npm": "@xtruder/opencode-claude-max-plugin",
|
|
33
|
+
"name": "Anthropic SDK",
|
|
34
|
+
"models": {
|
|
35
|
+
"claude-sonnet-4-6": { "name": "Claude Sonnet 4.6", "reasoning": true, "tool_call": true },
|
|
36
|
+
"claude-opus-4-6": { "name": "Claude Opus 4.6", "reasoning": true, "tool_call": true },
|
|
37
|
+
"claude-haiku-4-5-20251001": { "name": "Claude Haiku 4.5", "tool_call": true }
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### With Vercel AI SDK
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { createAnthropicSDK } from "@xtruder/opencode-claude-max-plugin";
|
|
48
|
+
import { streamText, generateText } from "ai";
|
|
49
|
+
|
|
50
|
+
// Uses ~/.claude/.credentials.json automatically
|
|
51
|
+
const provider = createAnthropicSDK();
|
|
52
|
+
const model = provider.languageModel("claude-sonnet-4-6");
|
|
53
|
+
|
|
54
|
+
const result = streamText({ model, prompt: "Hello!" });
|
|
55
|
+
for await (const chunk of result.textStream) {
|
|
56
|
+
process.stdout.write(chunk);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Authentication
|
|
61
|
+
|
|
62
|
+
Credentials are resolved in order:
|
|
63
|
+
|
|
64
|
+
1. **`apiKey` option** or **`ANTHROPIC_API_KEY` env var**
|
|
65
|
+
2. **Claude Code credentials** — auto-read from `~/.claude/.credentials.json`
|
|
66
|
+
|
|
67
|
+
For Claude Code credentials, log in via `claude` CLI first.
|
|
68
|
+
|
|
69
|
+
## Context Window Limits
|
|
70
|
+
|
|
71
|
+
| Model | Max Context (subscription, no Extra usage) |
|
|
72
|
+
|---|---|
|
|
73
|
+
| Opus 4.6 | ~615K+ tokens (native 1M) |
|
|
74
|
+
| Sonnet 4.6 | ~120K tokens (429 above, needs Extra usage) |
|
|
75
|
+
| Haiku 4.5 | 200K tokens (hard limit) |
|
|
76
|
+
|
|
77
|
+
## Features
|
|
78
|
+
|
|
79
|
+
- Streaming and non-streaming completions
|
|
80
|
+
- Tool/function calling with Claude Code tool name mapping
|
|
81
|
+
- Extended thinking with signature passthrough
|
|
82
|
+
- Prompt caching (98% cache hit rate with full tool set)
|
|
83
|
+
- Subscription rate limit detection with clear error messages
|
|
84
|
+
- `/usage` command for subscription utilization tracking
|
|
85
|
+
- MCP tool name remapping (OpenCode → Claude Code format)
|
|
86
|
+
|
|
87
|
+
## Development
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
bun install
|
|
91
|
+
bun run build
|
|
92
|
+
bun run test # 17 integration tests
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
See [RESEARCH.md](RESEARCH.md) for detailed reverse-engineering findings.
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
MIT
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { LanguageModelV2 } from "@ai-sdk/provider";
|
|
2
|
+
export interface AgentSDKProviderOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Provider name for logging. Defaults to "anthropic-agent-sdk".
|
|
5
|
+
*/
|
|
6
|
+
name?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Any additional options (passed through by OpenCode).
|
|
9
|
+
*/
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
export interface AgentSDKProvider {
|
|
13
|
+
languageModel(modelId: string): LanguageModelV2;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Create an Anthropic Agent SDK provider for use with OpenCode / Vercel AI SDK.
|
|
17
|
+
*
|
|
18
|
+
* Uses @anthropic-ai/claude-agent-sdk which handles authentication via
|
|
19
|
+
* Claude Code's built-in OAuth flow — no API keys or billing headers needed.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createAgentSDK(options?: AgentSDKProviderOptions): AgentSDKProvider;
|
|
22
|
+
export default createAgentSDK;
|
|
23
|
+
export { AgentSDKModel } from "./agent-model.js";
|
|
24
|
+
//# sourceMappingURL=agent-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-index.d.ts","sourceRoot":"","sources":["../src/agent-index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAEvD,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb;;OAEG;IACH,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAAA;CAChD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,OAAO,GAAE,uBAA4B,GACpC,gBAAgB,CAQlB;AAED,eAAe,cAAc,CAAA;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
// src/agent-model.ts
|
|
2
|
+
import {
|
|
3
|
+
unstable_v2_createSession
|
|
4
|
+
} from "@anthropic-ai/claude-agent-sdk";
|
|
5
|
+
function mapFinishReason(reason) {
|
|
6
|
+
switch (reason) {
|
|
7
|
+
case "end_turn":
|
|
8
|
+
return "stop";
|
|
9
|
+
case "stop_sequence":
|
|
10
|
+
return "stop";
|
|
11
|
+
case "max_tokens":
|
|
12
|
+
return "length";
|
|
13
|
+
case "tool_use":
|
|
14
|
+
return "tool-calls";
|
|
15
|
+
default:
|
|
16
|
+
return "unknown";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function extractSystem(prompt) {
|
|
20
|
+
const parts = [];
|
|
21
|
+
for (const msg of prompt) {
|
|
22
|
+
if (msg.role === "system")
|
|
23
|
+
parts.push(msg.content);
|
|
24
|
+
}
|
|
25
|
+
return parts.length > 0 ? parts.join(`
|
|
26
|
+
|
|
27
|
+
`) : undefined;
|
|
28
|
+
}
|
|
29
|
+
function extractMessages(prompt) {
|
|
30
|
+
return prompt.filter((m) => m.role !== "system");
|
|
31
|
+
}
|
|
32
|
+
function formatLastMessage(msg) {
|
|
33
|
+
if (msg.role === "user") {
|
|
34
|
+
return msg.content.map((p) => {
|
|
35
|
+
if (p.type === "text")
|
|
36
|
+
return p.text;
|
|
37
|
+
return "";
|
|
38
|
+
}).filter(Boolean).join(`
|
|
39
|
+
`);
|
|
40
|
+
}
|
|
41
|
+
if (msg.role === "tool") {
|
|
42
|
+
return msg.content.map((p) => {
|
|
43
|
+
const output = p.output;
|
|
44
|
+
if (output.type === "text" || output.type === "error-text")
|
|
45
|
+
return output.value;
|
|
46
|
+
if (output.type === "json" || output.type === "error-json")
|
|
47
|
+
return JSON.stringify(output.value);
|
|
48
|
+
return String(output.value);
|
|
49
|
+
}).join(`
|
|
50
|
+
`);
|
|
51
|
+
}
|
|
52
|
+
return "";
|
|
53
|
+
}
|
|
54
|
+
function convertAgentStream(stream, modelId) {
|
|
55
|
+
let idCounter = 0;
|
|
56
|
+
return new ReadableStream({
|
|
57
|
+
async start(controller) {
|
|
58
|
+
try {
|
|
59
|
+
let emittedMetadata = false;
|
|
60
|
+
let firstAssistantTurnDone = false;
|
|
61
|
+
for await (const msg of stream) {
|
|
62
|
+
if (firstAssistantTurnDone) {
|
|
63
|
+
if (msg.type === "result")
|
|
64
|
+
break;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (msg.type === "assistant") {
|
|
68
|
+
const message = msg.message;
|
|
69
|
+
const content = message.content ?? [];
|
|
70
|
+
if (!emittedMetadata && message.id) {
|
|
71
|
+
emittedMetadata = true;
|
|
72
|
+
controller.enqueue({
|
|
73
|
+
type: "response-metadata",
|
|
74
|
+
id: message.id,
|
|
75
|
+
modelId: message.model ?? modelId,
|
|
76
|
+
timestamp: new Date
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
for (const block of content) {
|
|
80
|
+
if (block.type === "text") {
|
|
81
|
+
const id = `block-${idCounter++}`;
|
|
82
|
+
controller.enqueue({ type: "text-start", id });
|
|
83
|
+
controller.enqueue({ type: "text-delta", id, delta: block.text });
|
|
84
|
+
controller.enqueue({ type: "text-end", id });
|
|
85
|
+
} else if (block.type === "thinking") {
|
|
86
|
+
const id = `block-${idCounter++}`;
|
|
87
|
+
controller.enqueue({ type: "reasoning-start", id });
|
|
88
|
+
controller.enqueue({ type: "reasoning-delta", id, delta: block.thinking });
|
|
89
|
+
controller.enqueue({ type: "reasoning-end", id });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (msg.type === "result") {
|
|
94
|
+
const result = msg;
|
|
95
|
+
controller.enqueue({
|
|
96
|
+
type: "finish",
|
|
97
|
+
finishReason: mapFinishReason(result.stop_reason),
|
|
98
|
+
usage: {
|
|
99
|
+
inputTokens: result.usage?.input_tokens ?? 0,
|
|
100
|
+
outputTokens: result.usage?.output_tokens ?? 0,
|
|
101
|
+
totalTokens: (result.usage?.input_tokens ?? 0) + (result.usage?.output_tokens ?? 0)
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
firstAssistantTurnDone = true;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} catch (error) {
|
|
109
|
+
controller.enqueue({ type: "error", error });
|
|
110
|
+
} finally {
|
|
111
|
+
controller.close();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
class AgentSDKModel {
|
|
118
|
+
providerName;
|
|
119
|
+
specificationVersion = "v2";
|
|
120
|
+
provider;
|
|
121
|
+
modelId;
|
|
122
|
+
supportedUrls = {};
|
|
123
|
+
session = null;
|
|
124
|
+
processedMessageCount = 0;
|
|
125
|
+
lastSystemPrompt = undefined;
|
|
126
|
+
constructor(modelId, providerName) {
|
|
127
|
+
this.providerName = providerName;
|
|
128
|
+
this.modelId = modelId;
|
|
129
|
+
this.provider = providerName;
|
|
130
|
+
}
|
|
131
|
+
needsNewSession(system, messages) {
|
|
132
|
+
if (!this.session)
|
|
133
|
+
return true;
|
|
134
|
+
if (system !== this.lastSystemPrompt)
|
|
135
|
+
return true;
|
|
136
|
+
if (messages.length < this.processedMessageCount)
|
|
137
|
+
return true;
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
createSession(system, tools) {
|
|
141
|
+
const opts = {
|
|
142
|
+
model: this.modelId,
|
|
143
|
+
maxTurns: 100,
|
|
144
|
+
includePartialMessages: true,
|
|
145
|
+
permissionMode: "bypassPermissions",
|
|
146
|
+
allowDangerouslySkipPermissions: true,
|
|
147
|
+
persistSession: false,
|
|
148
|
+
systemPrompt: system ?? "You are a helpful assistant.",
|
|
149
|
+
tools: []
|
|
150
|
+
};
|
|
151
|
+
return unstable_v2_createSession(opts);
|
|
152
|
+
}
|
|
153
|
+
async doStream(options) {
|
|
154
|
+
const system = extractSystem(options.prompt);
|
|
155
|
+
const messages = extractMessages(options.prompt);
|
|
156
|
+
const warnings = [];
|
|
157
|
+
if (this.needsNewSession(system, messages)) {
|
|
158
|
+
if (this.session) {
|
|
159
|
+
try {
|
|
160
|
+
this.session.close();
|
|
161
|
+
} catch {}
|
|
162
|
+
}
|
|
163
|
+
this.session = this.createSession(system, options.tools);
|
|
164
|
+
this.lastSystemPrompt = system;
|
|
165
|
+
this.processedMessageCount = 0;
|
|
166
|
+
}
|
|
167
|
+
let messageToSend;
|
|
168
|
+
if (this.processedMessageCount === 0) {
|
|
169
|
+
const firstUser = messages.find((m) => m.role === "user");
|
|
170
|
+
if (firstUser) {
|
|
171
|
+
messageToSend = formatLastMessage(firstUser);
|
|
172
|
+
this.processedMessageCount = messages.indexOf(firstUser) + 1;
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
const newMessages = messages.slice(this.processedMessageCount);
|
|
176
|
+
const toolMsg = newMessages.find((m) => m.role === "tool");
|
|
177
|
+
if (toolMsg) {
|
|
178
|
+
messageToSend = formatLastMessage(toolMsg);
|
|
179
|
+
} else {
|
|
180
|
+
const userMsg = [...newMessages].reverse().find((m) => m.role === "user");
|
|
181
|
+
if (userMsg) {
|
|
182
|
+
messageToSend = formatLastMessage(userMsg);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
this.processedMessageCount = messages.length;
|
|
186
|
+
}
|
|
187
|
+
if (!messageToSend) {
|
|
188
|
+
messageToSend = "Continue.";
|
|
189
|
+
}
|
|
190
|
+
await this.session.send(messageToSend);
|
|
191
|
+
const stream = convertAgentStream(this.session.stream(), this.modelId);
|
|
192
|
+
const wrappedStream = new ReadableStream({
|
|
193
|
+
async start(controller) {
|
|
194
|
+
controller.enqueue({ type: "stream-start", warnings });
|
|
195
|
+
const reader = stream.getReader();
|
|
196
|
+
try {
|
|
197
|
+
while (true) {
|
|
198
|
+
const { done, value } = await reader.read();
|
|
199
|
+
if (done)
|
|
200
|
+
break;
|
|
201
|
+
controller.enqueue(value);
|
|
202
|
+
}
|
|
203
|
+
} finally {
|
|
204
|
+
reader.releaseLock();
|
|
205
|
+
controller.close();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
return {
|
|
210
|
+
stream: wrappedStream,
|
|
211
|
+
request: { body: messageToSend }
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
async doGenerate(options) {
|
|
215
|
+
const result = await this.doStream(options);
|
|
216
|
+
const reader = result.stream.getReader();
|
|
217
|
+
const content = [];
|
|
218
|
+
let finishReason = "unknown";
|
|
219
|
+
let usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
220
|
+
let responseId = "";
|
|
221
|
+
let responseModel = this.modelId;
|
|
222
|
+
let currentText = "";
|
|
223
|
+
while (true) {
|
|
224
|
+
const { done, value } = await reader.read();
|
|
225
|
+
if (done)
|
|
226
|
+
break;
|
|
227
|
+
switch (value.type) {
|
|
228
|
+
case "text-delta":
|
|
229
|
+
currentText += value.delta ?? "";
|
|
230
|
+
break;
|
|
231
|
+
case "text-end":
|
|
232
|
+
if (currentText) {
|
|
233
|
+
content.push({ type: "text", text: currentText });
|
|
234
|
+
currentText = "";
|
|
235
|
+
}
|
|
236
|
+
break;
|
|
237
|
+
case "tool-call":
|
|
238
|
+
content.push({
|
|
239
|
+
type: "tool-call",
|
|
240
|
+
toolCallId: value.toolCallId,
|
|
241
|
+
toolName: value.toolName,
|
|
242
|
+
input: value.input
|
|
243
|
+
});
|
|
244
|
+
break;
|
|
245
|
+
case "finish":
|
|
246
|
+
finishReason = value.finishReason;
|
|
247
|
+
usage = value.usage ?? usage;
|
|
248
|
+
break;
|
|
249
|
+
case "response-metadata":
|
|
250
|
+
responseId = value.id ?? "";
|
|
251
|
+
responseModel = value.modelId ?? this.modelId;
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (currentText) {
|
|
256
|
+
content.push({ type: "text", text: currentText });
|
|
257
|
+
}
|
|
258
|
+
return {
|
|
259
|
+
content,
|
|
260
|
+
finishReason,
|
|
261
|
+
usage,
|
|
262
|
+
response: {
|
|
263
|
+
id: responseId,
|
|
264
|
+
modelId: responseModel,
|
|
265
|
+
timestamp: new Date
|
|
266
|
+
},
|
|
267
|
+
warnings: []
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
close() {
|
|
271
|
+
if (this.session) {
|
|
272
|
+
try {
|
|
273
|
+
this.session.close();
|
|
274
|
+
} catch {}
|
|
275
|
+
this.session = null;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// src/agent-index.ts
|
|
281
|
+
function createAgentSDK(options = {}) {
|
|
282
|
+
const { name = "anthropic-agent-sdk", ...rest } = options;
|
|
283
|
+
return {
|
|
284
|
+
languageModel(modelId) {
|
|
285
|
+
return new AgentSDKModel(modelId, name);
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
var agent_index_default = createAgentSDK;
|
|
290
|
+
export {
|
|
291
|
+
agent_index_default as default,
|
|
292
|
+
createAgentSDK,
|
|
293
|
+
AgentSDKModel
|
|
294
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { LanguageModelV2, LanguageModelV2CallOptions } from "@ai-sdk/provider";
|
|
2
|
+
type DoStreamResult = Awaited<ReturnType<LanguageModelV2["doStream"]>>;
|
|
3
|
+
type DoGenerateResult = Awaited<ReturnType<LanguageModelV2["doGenerate"]>>;
|
|
4
|
+
export declare class AgentSDKModel implements LanguageModelV2 {
|
|
5
|
+
private providerName;
|
|
6
|
+
readonly specificationVersion: "v2";
|
|
7
|
+
readonly provider: string;
|
|
8
|
+
readonly modelId: string;
|
|
9
|
+
readonly supportedUrls: Record<string, RegExp[]>;
|
|
10
|
+
private session;
|
|
11
|
+
private processedMessageCount;
|
|
12
|
+
private lastSystemPrompt;
|
|
13
|
+
constructor(modelId: string, providerName: string);
|
|
14
|
+
/**
|
|
15
|
+
* Determine if we need a new session based on the prompt.
|
|
16
|
+
* A new session is needed when:
|
|
17
|
+
* - No session exists
|
|
18
|
+
* - System prompt changed
|
|
19
|
+
* - Message count decreased (new conversation)
|
|
20
|
+
*
|
|
21
|
+
* The session is REUSED across doStream() calls for the same conversation
|
|
22
|
+
* (tool result continuations and multi-turn).
|
|
23
|
+
*/
|
|
24
|
+
private needsNewSession;
|
|
25
|
+
private createSession;
|
|
26
|
+
doStream(options: LanguageModelV2CallOptions): Promise<DoStreamResult>;
|
|
27
|
+
doGenerate(options: LanguageModelV2CallOptions): Promise<DoGenerateResult>;
|
|
28
|
+
/**
|
|
29
|
+
* Close the session and clean up resources.
|
|
30
|
+
*/
|
|
31
|
+
close(): void;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=agent-model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-model.d.ts","sourceRoot":"","sources":["../src/agent-model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,0BAA0B,EAO3B,MAAM,kBAAkB,CAAA;AAMzB,KAAK,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;AACtE,KAAK,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;AAqJ1E,qBAAa,aAAc,YAAW,eAAe;IAajD,OAAO,CAAC,YAAY;IAZtB,QAAQ,CAAC,oBAAoB,EAAG,IAAI,CAAS;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAK;IAErD,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,qBAAqB,CAAI;IACjC,OAAO,CAAC,gBAAgB,CAAgC;gBAItD,OAAO,EAAE,MAAM,EACP,YAAY,EAAE,MAAM;IAM9B;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,aAAa;IAoBf,QAAQ,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,cAAc,CAAC;IA2EtE,UAAU,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA+DhF;;OAEG;IACH,KAAK;CAMN"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-test.d.ts","sourceRoot":"","sources":["../src/agent-test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface ClaudeOAuthCredentials {
|
|
2
|
+
accessToken: string;
|
|
3
|
+
refreshToken: string;
|
|
4
|
+
expiresAt: number;
|
|
5
|
+
scopes: string[];
|
|
6
|
+
subscriptionType: string | null;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Default path to Claude Code credentials file.
|
|
10
|
+
*/
|
|
11
|
+
export declare function getCredentialsPath(): string;
|
|
12
|
+
/**
|
|
13
|
+
* Read OAuth credentials from Claude Code's credentials file.
|
|
14
|
+
* Returns null if the file doesn't exist or can't be parsed.
|
|
15
|
+
*/
|
|
16
|
+
export declare function readClaudeCredentials(path?: string): ClaudeOAuthCredentials | null;
|
|
17
|
+
/**
|
|
18
|
+
* Check if credentials are expired (with 5 minute buffer).
|
|
19
|
+
*/
|
|
20
|
+
export declare function isExpired(creds: ClaudeOAuthCredentials): boolean;
|
|
21
|
+
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;CAChC;AAMD;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,CAAC,EAAE,MAAM,GACZ,sBAAsB,GAAG,IAAI,CAa/B;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAGhE"}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { LanguageModelV2 } from "@ai-sdk/provider";
|
|
2
|
+
/**
|
|
3
|
+
* Beta flags that Claude Code sends on every OAuth request.
|
|
4
|
+
* Order and exact values must match what Claude Code sends.
|
|
5
|
+
*/
|
|
6
|
+
export declare const OAUTH_BETAS: string[];
|
|
7
|
+
/**
|
|
8
|
+
* Beta flag that enables 1M context window. Only sent when model ID
|
|
9
|
+
* includes [1m] suffix — e.g. "claude-sonnet-4-6[1m]".
|
|
10
|
+
* Claude Code checks: /\[1m\]/i.test(modelId) before including this.
|
|
11
|
+
*/
|
|
12
|
+
export declare const CONTEXT_1M_BETA = "context-1m-2025-08-07";
|
|
13
|
+
/**
|
|
14
|
+
* Beta flags for regular API key auth (no OAuth).
|
|
15
|
+
*/
|
|
16
|
+
export declare const API_KEY_BETAS: string[];
|
|
17
|
+
export interface AnthropicSDKProviderOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Anthropic API key. Defaults to ANTHROPIC_API_KEY env var.
|
|
20
|
+
*/
|
|
21
|
+
apiKey?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Custom base URL for the Anthropic API.
|
|
24
|
+
*/
|
|
25
|
+
baseURL?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Additional default headers to send with requests.
|
|
28
|
+
*/
|
|
29
|
+
headers?: Record<string, string>;
|
|
30
|
+
/**
|
|
31
|
+
* Custom fetch implementation.
|
|
32
|
+
*/
|
|
33
|
+
fetch?: typeof globalThis.fetch;
|
|
34
|
+
/**
|
|
35
|
+
* Provider name for logging. Set automatically by OpenCode.
|
|
36
|
+
*/
|
|
37
|
+
name?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Path to Claude Code credentials file.
|
|
40
|
+
* Defaults to ~/.claude/.credentials.json.
|
|
41
|
+
*/
|
|
42
|
+
credentialsPath?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Any additional options (passed through by OpenCode).
|
|
45
|
+
*/
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
}
|
|
48
|
+
export interface AnthropicSDKProvider {
|
|
49
|
+
/**
|
|
50
|
+
* Get a language model by model ID.
|
|
51
|
+
*/
|
|
52
|
+
languageModel(modelId: string): LanguageModelV2;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Create an Anthropic SDK provider for use with OpenCode / Vercel AI SDK.
|
|
56
|
+
*
|
|
57
|
+
* When using OAuth credentials from Claude Code, requests are made to
|
|
58
|
+
* look identical to Claude Code CLI requests — same headers, user-agent,
|
|
59
|
+
* beta flags, billing system block, and body structure.
|
|
60
|
+
*/
|
|
61
|
+
export declare function createAnthropicSDK(options?: AnthropicSDKProviderOptions): AnthropicSDKProvider;
|
|
62
|
+
export default createAnthropicSDK;
|
|
63
|
+
export { AnthropicSDKModel } from "./model.js";
|
|
64
|
+
export type { ConvertedPrompt } from "./prompt.js";
|
|
65
|
+
export { readClaudeCredentials, isExpired, getCredentialsPath, type ClaudeOAuthCredentials, } from "./credentials.js";
|
|
66
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAQvD;;;GAGG;AACH,eAAO,MAAM,WAAW,UAOvB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,0BAA0B,CAAA;AAEtD;;GAEG;AACH,eAAO,MAAM,aAAa,UAGzB,CAAA;AAED,MAAM,WAAW,2BAA2B;IAC1C;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEhC;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;IAE/B;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IAExB;;OAEG;IACH,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAAA;CAChD;AAgCD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,GAAE,2BAAgC,GACxC,oBAAoB,CA8FtB;AAGD,eAAe,kBAAkB,CAAA;AAGjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC9C,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,EACL,qBAAqB,EACrB,SAAS,EACT,kBAAkB,EAClB,KAAK,sBAAsB,GAC5B,MAAM,kBAAkB,CAAA"}
|