pi-anthropic-oauth 0.1.1 → 0.1.3
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 +1 -0
- package/package.json +1 -1
- package/src/convert.ts +22 -12
- package/src/index.ts +14 -0
- package/src/stream.ts +9 -4
package/README.md
CHANGED
package/package.json
CHANGED
package/src/convert.ts
CHANGED
|
@@ -54,6 +54,24 @@ export function convertPiMessagesToAnthropic(
|
|
|
54
54
|
isOAuth: boolean,
|
|
55
55
|
): MessageParam[] {
|
|
56
56
|
const params: MessageParam[] = [];
|
|
57
|
+
const toolIdMap = new Map<string, string>();
|
|
58
|
+
const usedToolIds = new Set<string>();
|
|
59
|
+
|
|
60
|
+
const getAnthropicToolId = (id: string): string => {
|
|
61
|
+
const existing = toolIdMap.get(id);
|
|
62
|
+
if (existing) return existing;
|
|
63
|
+
|
|
64
|
+
let base = sanitizeSurrogates(id).replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
65
|
+
if (!base) base = "tool";
|
|
66
|
+
let candidate = base;
|
|
67
|
+
let suffix = 1;
|
|
68
|
+
while (usedToolIds.has(candidate)) {
|
|
69
|
+
candidate = `${base}_${suffix++}`;
|
|
70
|
+
}
|
|
71
|
+
usedToolIds.add(candidate);
|
|
72
|
+
toolIdMap.set(id, candidate);
|
|
73
|
+
return candidate;
|
|
74
|
+
};
|
|
57
75
|
|
|
58
76
|
for (let i = 0; i < messages.length; i++) {
|
|
59
77
|
const message = messages[i];
|
|
@@ -81,19 +99,11 @@ export function convertPiMessagesToAnthropic(
|
|
|
81
99
|
if (block.type === "text" && block.text.trim()) {
|
|
82
100
|
blocks.push({ type: "text", text: sanitizeSurrogates(block.text) });
|
|
83
101
|
} else if (block.type === "thinking" && block.thinking.trim()) {
|
|
84
|
-
|
|
85
|
-
blocks.push({
|
|
86
|
-
type: "thinking" as never,
|
|
87
|
-
thinking: sanitizeSurrogates(block.thinking),
|
|
88
|
-
signature: block.thinkingSignature,
|
|
89
|
-
});
|
|
90
|
-
} else {
|
|
91
|
-
blocks.push({ type: "text", text: sanitizeSurrogates(block.thinking) });
|
|
92
|
-
}
|
|
102
|
+
blocks.push({ type: "text", text: sanitizeSurrogates(block.thinking) });
|
|
93
103
|
} else if (block.type === "toolCall") {
|
|
94
104
|
blocks.push({
|
|
95
105
|
type: "tool_use",
|
|
96
|
-
id: block.id,
|
|
106
|
+
id: getAnthropicToolId(block.id),
|
|
97
107
|
name: isOAuth ? toClaudeCodeToolName(block.name) : block.name,
|
|
98
108
|
input: block.arguments,
|
|
99
109
|
});
|
|
@@ -107,7 +117,7 @@ export function convertPiMessagesToAnthropic(
|
|
|
107
117
|
const toolResults = [
|
|
108
118
|
{
|
|
109
119
|
type: "tool_result" as const,
|
|
110
|
-
tool_use_id: message.toolCallId,
|
|
120
|
+
tool_use_id: getAnthropicToolId(message.toolCallId),
|
|
111
121
|
content: convertToolResultContentToAnthropic(message.content),
|
|
112
122
|
is_error: message.isError,
|
|
113
123
|
},
|
|
@@ -118,7 +128,7 @@ export function convertPiMessagesToAnthropic(
|
|
|
118
128
|
const nextMessage = messages[j] as ToolResultMessage;
|
|
119
129
|
toolResults.push({
|
|
120
130
|
type: "tool_result" as const,
|
|
121
|
-
tool_use_id: nextMessage.toolCallId,
|
|
131
|
+
tool_use_id: getAnthropicToolId(nextMessage.toolCallId),
|
|
122
132
|
content: convertToolResultContentToAnthropic(nextMessage.content),
|
|
123
133
|
is_error: nextMessage.isError,
|
|
124
134
|
});
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { existsSync, symlinkSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
1
4
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
2
5
|
import { loginAnthropic, refreshAnthropicToken } from "./auth.js";
|
|
3
6
|
import { streamAnthropicOAuth } from "./stream.js";
|
|
@@ -32,7 +35,18 @@ const MODELS = [
|
|
|
32
35
|
},
|
|
33
36
|
];
|
|
34
37
|
|
|
38
|
+
function ensureClaudeCodeSymlink() {
|
|
39
|
+
const target = join(homedir(), ".pi");
|
|
40
|
+
const link = join(homedir(), ".Claude Code");
|
|
41
|
+
if (existsSync(target) && !existsSync(link)) {
|
|
42
|
+
try {
|
|
43
|
+
symlinkSync(target, link);
|
|
44
|
+
} catch {}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
35
48
|
export default function (pi: ExtensionAPI) {
|
|
49
|
+
ensureClaudeCodeSymlink();
|
|
36
50
|
pi.registerProvider("anthropic", {
|
|
37
51
|
baseUrl: "https://api.anthropic.com",
|
|
38
52
|
apiKey: "ANTHROPIC_MAX_API_KEY",
|
package/src/stream.ts
CHANGED
|
@@ -111,10 +111,13 @@ export function streamAnthropicOAuth(
|
|
|
111
111
|
dangerouslyAllowBrowser: true,
|
|
112
112
|
});
|
|
113
113
|
|
|
114
|
+
const maxTokens =
|
|
115
|
+
options?.maxTokens || Math.floor(model.maxTokens / 3);
|
|
116
|
+
|
|
114
117
|
const params: MessageCreateParamsStreaming = {
|
|
115
118
|
model: model.id,
|
|
116
119
|
messages: convertPiMessagesToAnthropic(context.messages, isOAuth),
|
|
117
|
-
max_tokens:
|
|
120
|
+
max_tokens: maxTokens,
|
|
118
121
|
stream: true,
|
|
119
122
|
};
|
|
120
123
|
|
|
@@ -123,7 +126,7 @@ export function streamAnthropicOAuth(
|
|
|
123
126
|
if (context.tools?.length)
|
|
124
127
|
params.tools = convertPiToolsToAnthropic(context.tools, isOAuth);
|
|
125
128
|
|
|
126
|
-
if (options?.reasoning && model.reasoning) {
|
|
129
|
+
if (options?.reasoning && model.reasoning && maxTokens > 1) {
|
|
127
130
|
const defaultBudgets: Record<string, number> = {
|
|
128
131
|
minimal: 1024,
|
|
129
132
|
low: 4096,
|
|
@@ -135,10 +138,12 @@ export function streamAnthropicOAuth(
|
|
|
135
138
|
options.thinkingBudgets?.[
|
|
136
139
|
options.reasoning as keyof typeof options.thinkingBudgets
|
|
137
140
|
];
|
|
141
|
+
const requestedBudget =
|
|
142
|
+
customBudget ?? defaultBudgets[options.reasoning] ?? 10240;
|
|
143
|
+
|
|
138
144
|
params.thinking = {
|
|
139
145
|
type: "enabled",
|
|
140
|
-
budget_tokens:
|
|
141
|
-
customBudget ?? defaultBudgets[options.reasoning] ?? 10240,
|
|
146
|
+
budget_tokens: Math.min(requestedBudget, maxTokens - 1),
|
|
142
147
|
};
|
|
143
148
|
}
|
|
144
149
|
|