pi-anthropic-oauth 0.1.16 → 0.2.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 +7 -2
- package/package.json +5 -5
- package/src/index.ts +0 -37
- package/src/stream.ts +5 -12
package/README.md
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
Use Claude Pro/Max in Pi with browser OAuth.
|
|
6
6
|
|
|
7
|
+
> [!IMPORTANT]
|
|
8
|
+
> This release requires Pi 0.80.8 or later in the 0.80.x release line.
|
|
9
|
+
|
|
7
10
|
## Features
|
|
8
11
|
|
|
9
12
|
- Claude Pro/Max login from `/login`
|
|
@@ -11,7 +14,7 @@ Use Claude Pro/Max in Pi with browser OAuth.
|
|
|
11
14
|
- Claude Code-compatible OAuth headers and prompt shaping
|
|
12
15
|
- No Anthropic API key needed
|
|
13
16
|
- Uses Pi's Anthropic model registry
|
|
14
|
-
- Adds Claude Opus 4.8 by default
|
|
17
|
+
- Adds Claude Opus 4.8 and Claude Fable 5 by default
|
|
15
18
|
- Auto-creates `~/.Claude Code` → `~/.pi` symlink when missing
|
|
16
19
|
|
|
17
20
|
## Quick start
|
|
@@ -34,6 +37,8 @@ Claude Pro/Max
|
|
|
34
37
|
|
|
35
38
|
Complete the browser login. After login, select an Anthropic model in Pi.
|
|
36
39
|
|
|
40
|
+
When the extension is active, `/login` includes `Claude Pro/Max` and Anthropic models show `(sub)` after OAuth login.
|
|
41
|
+
|
|
37
42
|
Update with:
|
|
38
43
|
|
|
39
44
|
```bash
|
|
@@ -96,7 +101,7 @@ To add another Anthropic model, create `~/.pi/agent/models.json`:
|
|
|
96
101
|
```
|
|
97
102
|
|
|
98
103
|
> [!NOTE]
|
|
99
|
-
>
|
|
104
|
+
> Opus 4.8 and Fable 5 are included in Pi's built-in Anthropic model catalog.
|
|
100
105
|
>
|
|
101
106
|
> 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`, so `apiKey` is only a placeholder to satisfy Pi's config requirements and does not need to be a valid Anthropic API key.
|
|
102
107
|
>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-anthropic-oauth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Claude Pro/Max OAuth extension for Pi",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,12 +38,12 @@
|
|
|
38
38
|
"@anthropic-ai/sdk": "^0.52.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"@earendil-works/pi-ai": "
|
|
42
|
-
"@earendil-works/pi-coding-agent": "
|
|
41
|
+
"@earendil-works/pi-ai": "^0.80.8",
|
|
42
|
+
"@earendil-works/pi-coding-agent": "^0.80.8"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@earendil-works/pi-ai": "^0.
|
|
46
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
45
|
+
"@earendil-works/pi-ai": "^0.80.8",
|
|
46
|
+
"@earendil-works/pi-coding-agent": "^0.80.8",
|
|
47
47
|
"typescript": "^5.9.3"
|
|
48
48
|
}
|
|
49
49
|
}
|
package/src/index.ts
CHANGED
|
@@ -2,8 +2,6 @@ import { existsSync, symlinkSync } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import {
|
|
5
|
-
AuthStorage,
|
|
6
|
-
ModelRegistry,
|
|
7
5
|
type ExtensionAPI,
|
|
8
6
|
type ProviderConfig,
|
|
9
7
|
} from "@earendil-works/pi-coding-agent";
|
|
@@ -11,19 +9,6 @@ import type { OAuthCredentials } from "@earendil-works/pi-ai";
|
|
|
11
9
|
import { loginAnthropic, refreshAnthropicToken } from "./auth.js";
|
|
12
10
|
import { streamAnthropicOAuth } from "./stream.js";
|
|
13
11
|
|
|
14
|
-
const DEFAULT_OPUS_4_8: NonNullable<ProviderConfig["models"]>[number] = {
|
|
15
|
-
id: "claude-opus-4-8",
|
|
16
|
-
name: "Claude Opus 4.8",
|
|
17
|
-
api: "anthropic-messages",
|
|
18
|
-
reasoning: true,
|
|
19
|
-
thinkingLevelMap: { xhigh: "xhigh" },
|
|
20
|
-
input: ["text", "image"],
|
|
21
|
-
cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
|
|
22
|
-
contextWindow: 1000000,
|
|
23
|
-
maxTokens: 128000,
|
|
24
|
-
compat: undefined,
|
|
25
|
-
};
|
|
26
|
-
|
|
27
12
|
function ensureClaudeCodeSymlink() {
|
|
28
13
|
const target = join(homedir(), ".pi");
|
|
29
14
|
const link = join(homedir(), ".Claude Code");
|
|
@@ -34,34 +19,12 @@ function ensureClaudeCodeSymlink() {
|
|
|
34
19
|
}
|
|
35
20
|
}
|
|
36
21
|
|
|
37
|
-
function getAnthropicModels(): NonNullable<ProviderConfig["models"]> {
|
|
38
|
-
const modelRegistry = ModelRegistry.create(AuthStorage.inMemory());
|
|
39
|
-
const models: NonNullable<ProviderConfig["models"]> = modelRegistry
|
|
40
|
-
.getAll()
|
|
41
|
-
.filter((model) => model.provider === "anthropic")
|
|
42
|
-
// Spread the full registry model so every field (thinkingLevelMap,
|
|
43
|
-
// baseUrl, headers, compat, and anything added in future) propagates
|
|
44
|
-
// automatically instead of being silently dropped by a hand-picked list.
|
|
45
|
-
.map((model) => ({
|
|
46
|
-
...model,
|
|
47
|
-
api: model.api ?? "anthropic-messages",
|
|
48
|
-
}));
|
|
49
|
-
|
|
50
|
-
if (!models.some((model) => model.id === DEFAULT_OPUS_4_8.id)) {
|
|
51
|
-
models.push(DEFAULT_OPUS_4_8);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return models;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
22
|
export default function (pi: ExtensionAPI) {
|
|
58
23
|
ensureClaudeCodeSymlink();
|
|
59
|
-
const models = getAnthropicModels();
|
|
60
24
|
|
|
61
25
|
pi.registerProvider("anthropic", {
|
|
62
26
|
baseUrl: "https://api.anthropic.com",
|
|
63
27
|
api: "anthropic-messages",
|
|
64
|
-
models,
|
|
65
28
|
oauth: {
|
|
66
29
|
name: "Claude Pro/Max",
|
|
67
30
|
usesCallbackServer: true,
|
package/src/stream.ts
CHANGED
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
type Model,
|
|
11
11
|
type SimpleStreamOptions,
|
|
12
12
|
type StopReason,
|
|
13
|
-
streamSimpleAnthropic,
|
|
14
13
|
} from "@earendil-works/pi-ai";
|
|
15
14
|
import { isClaudeOAuthAccessToken, USER_AGENT } from "./auth.js";
|
|
16
15
|
import {
|
|
@@ -82,7 +81,11 @@ function makeDefaultHeaders(
|
|
|
82
81
|
) {
|
|
83
82
|
continue;
|
|
84
83
|
}
|
|
85
|
-
|
|
84
|
+
const existingKey = Object.keys(headers).find(
|
|
85
|
+
(header) => header.toLowerCase() === normalizedKey,
|
|
86
|
+
);
|
|
87
|
+
if (existingKey) delete headers[existingKey];
|
|
88
|
+
if (value !== null) headers[key] = value;
|
|
86
89
|
}
|
|
87
90
|
}
|
|
88
91
|
|
|
@@ -94,16 +97,6 @@ export function streamAnthropicOAuth(
|
|
|
94
97
|
context: Context,
|
|
95
98
|
options?: SimpleStreamOptions,
|
|
96
99
|
): AssistantMessageEventStream {
|
|
97
|
-
// pi-ai keys streamSimple by `api`, so this runs for every anthropic-messages
|
|
98
|
-
// model (copilot, openrouter, …). Delegate non-anthropic providers.
|
|
99
|
-
if (model.provider !== "anthropic") {
|
|
100
|
-
return streamSimpleAnthropic(
|
|
101
|
-
model as Model<"anthropic-messages">,
|
|
102
|
-
context,
|
|
103
|
-
options,
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
100
|
const stream = createAssistantMessageEventStream();
|
|
108
101
|
|
|
109
102
|
void (async () => {
|