pi-anthropic-oauth 0.1.8 → 0.1.9
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 +26 -0
- package/package.json +1 -1
- package/src/auth.ts +0 -1
- package/src/index.ts +45 -51
- package/src/stream.ts +7 -3
package/README.md
CHANGED
|
@@ -27,10 +27,36 @@ Claude Pro/Max
|
|
|
27
27
|
|
|
28
28
|
## Notes
|
|
29
29
|
|
|
30
|
+
- uses Pi's built-in Anthropic model list
|
|
30
31
|
- sends Claude Code-like OAuth headers
|
|
31
32
|
- rewrites Pi system identity where needed
|
|
32
33
|
- auto-creates `~/.Claude Code` → `~/.pi` symlink
|
|
33
34
|
|
|
35
|
+
## Custom models
|
|
36
|
+
|
|
37
|
+
To add another Anthropic model, create `~/.pi/agent/models.json`:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"providers": {
|
|
42
|
+
"anthropic": {
|
|
43
|
+
"baseUrl": "https://api.anthropic.com",
|
|
44
|
+
"apiKey": "REQUIRED_BY_PI_FOR_CUSTOM_MODELS",
|
|
45
|
+
"api": "anthropic-messages",
|
|
46
|
+
"models": [
|
|
47
|
+
{
|
|
48
|
+
"id": "your-model-id",
|
|
49
|
+
"name": "Your Model Name"
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
> [!NOTE]
|
|
58
|
+
> Pi requires `baseUrl`, `apiKey`, and `api` when defining custom models in `models.json`. With this extension, requests normally authenticate through Claude Pro/Max OAuth after `/login anthropic`, so `apiKey` is present to satisfy Pi's config requirements and does not need to be a valid Anthropic API key.
|
|
59
|
+
|
|
34
60
|
## License
|
|
35
61
|
|
|
36
62
|
MIT
|
package/package.json
CHANGED
package/src/auth.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,58 +1,27 @@
|
|
|
1
1
|
import { existsSync, symlinkSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import
|
|
4
|
+
import {
|
|
5
|
+
AuthStorage,
|
|
6
|
+
ModelRegistry,
|
|
7
|
+
type ExtensionAPI,
|
|
8
|
+
type ProviderConfig,
|
|
9
|
+
} from "@mariozechner/pi-coding-agent";
|
|
5
10
|
import type { OAuthCredentials } from "@mariozechner/pi-ai";
|
|
6
11
|
import { loginAnthropic, refreshAnthropicToken } from "./auth.js";
|
|
7
12
|
import { streamAnthropicOAuth } from "./stream.js";
|
|
8
13
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
id: "claude-opus-4-6",
|
|
21
|
-
name: "Claude Opus 4.6",
|
|
22
|
-
reasoning: true,
|
|
23
|
-
input: ["text", "image"] as ("text" | "image")[],
|
|
24
|
-
cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
|
|
25
|
-
contextWindow: 1000000,
|
|
26
|
-
maxTokens: 128000,
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
id: "claude-sonnet-4-6",
|
|
30
|
-
name: "Claude Sonnet 4.6",
|
|
31
|
-
reasoning: true,
|
|
32
|
-
input: ["text", "image"] as ("text" | "image")[],
|
|
33
|
-
cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
|
|
34
|
-
contextWindow: 1000000,
|
|
35
|
-
maxTokens: 64000,
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
id: "claude-haiku-4-5",
|
|
39
|
-
name: "Claude Haiku 4.5",
|
|
40
|
-
reasoning: true,
|
|
41
|
-
input: ["text", "image"] as ("text" | "image")[],
|
|
42
|
-
cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 },
|
|
43
|
-
contextWindow: 200000,
|
|
44
|
-
maxTokens: 64000,
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
id: "claude-opus-4-5-20251101",
|
|
48
|
-
name: "Claude Opus 4.5",
|
|
49
|
-
reasoning: true,
|
|
50
|
-
input: ["text", "image"] as ("text" | "image")[],
|
|
51
|
-
cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
|
|
52
|
-
contextWindow: 200000,
|
|
53
|
-
maxTokens: 64000,
|
|
54
|
-
}
|
|
55
|
-
];
|
|
14
|
+
const DEFAULT_OPUS_4_7: NonNullable<ProviderConfig["models"]>[number] = {
|
|
15
|
+
id: "claude-opus-4-7",
|
|
16
|
+
name: "Claude Opus 4.7",
|
|
17
|
+
api: "anthropic-messages",
|
|
18
|
+
reasoning: true,
|
|
19
|
+
input: ["text", "image"],
|
|
20
|
+
cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
|
|
21
|
+
contextWindow: 1000000,
|
|
22
|
+
maxTokens: 128000,
|
|
23
|
+
compat: undefined,
|
|
24
|
+
};
|
|
56
25
|
|
|
57
26
|
function ensureClaudeCodeSymlink() {
|
|
58
27
|
const target = join(homedir(), ".pi");
|
|
@@ -64,13 +33,38 @@ function ensureClaudeCodeSymlink() {
|
|
|
64
33
|
}
|
|
65
34
|
}
|
|
66
35
|
|
|
36
|
+
function getAnthropicModels(): NonNullable<ProviderConfig["models"]> {
|
|
37
|
+
const modelRegistry = ModelRegistry.create(AuthStorage.inMemory());
|
|
38
|
+
const models: NonNullable<ProviderConfig["models"]> = modelRegistry
|
|
39
|
+
.getAll()
|
|
40
|
+
.filter((model) => model.provider === "anthropic")
|
|
41
|
+
.map((model) => ({
|
|
42
|
+
id: model.id,
|
|
43
|
+
name: model.name,
|
|
44
|
+
api: model.api ?? "anthropic-messages",
|
|
45
|
+
reasoning: model.reasoning,
|
|
46
|
+
input: model.input,
|
|
47
|
+
cost: model.cost,
|
|
48
|
+
contextWindow: model.contextWindow,
|
|
49
|
+
maxTokens: model.maxTokens,
|
|
50
|
+
compat: model.compat,
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
if (!models.some((model) => model.id === DEFAULT_OPUS_4_7.id)) {
|
|
54
|
+
models.push(DEFAULT_OPUS_4_7);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return models;
|
|
58
|
+
}
|
|
59
|
+
|
|
67
60
|
export default function (pi: ExtensionAPI) {
|
|
68
61
|
ensureClaudeCodeSymlink();
|
|
62
|
+
const models = getAnthropicModels();
|
|
63
|
+
|
|
69
64
|
pi.registerProvider("anthropic", {
|
|
70
65
|
baseUrl: "https://api.anthropic.com",
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
models: [...MODELS],
|
|
66
|
+
api: "anthropic-messages",
|
|
67
|
+
models,
|
|
74
68
|
oauth: {
|
|
75
69
|
name: "Claude Pro/Max",
|
|
76
70
|
usesCallbackServer: true,
|
package/src/stream.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
type SimpleStreamOptions,
|
|
12
12
|
type StopReason,
|
|
13
13
|
} from "@mariozechner/pi-ai";
|
|
14
|
-
import { USER_AGENT } from "./auth.js";
|
|
14
|
+
import { isClaudeOAuthAccessToken, USER_AGENT } from "./auth.js";
|
|
15
15
|
import {
|
|
16
16
|
convertPiMessagesToAnthropic,
|
|
17
17
|
convertPiToolsToAnthropic,
|
|
@@ -105,8 +105,12 @@ export function streamAnthropicOAuth(
|
|
|
105
105
|
};
|
|
106
106
|
|
|
107
107
|
try {
|
|
108
|
-
const apiKey = options?.apiKey
|
|
109
|
-
|
|
108
|
+
const apiKey = options?.apiKey;
|
|
109
|
+
if (!apiKey) {
|
|
110
|
+
throw new Error("No Anthropic auth available. Run /login anthropic.");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const isOAuth = isClaudeOAuthAccessToken(apiKey);
|
|
110
114
|
const defaultHeaders = makeDefaultHeaders(isOAuth, options);
|
|
111
115
|
|
|
112
116
|
if (isOAuth) defaultHeaders.authorization = `Bearer ${apiKey}`;
|