@centerforagenticai/pi-multi-account 0.1.1
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/LICENSE +21 -0
- package/NOTICE +29 -0
- package/README.md +999 -0
- package/config/models/pi-multi-account.v1.json +32 -0
- package/config/subscription-plans.v1.json +122 -0
- package/package.json +76 -0
- package/packages/pi-anthropic-oauth/LICENSE +21 -0
- package/packages/pi-anthropic-oauth/package.json +54 -0
- package/packages/pi-anthropic-oauth/src/auth.ts +396 -0
- package/packages/pi-anthropic-oauth/src/context.ts +116 -0
- package/packages/pi-anthropic-oauth/src/convert.ts +303 -0
- package/packages/pi-anthropic-oauth/src/index.ts +37 -0
- package/packages/pi-anthropic-oauth/src/prompt.ts +137 -0
- package/packages/pi-anthropic-oauth/src/stream.ts +476 -0
- package/packages/pi-antigravity/LICENSE +21 -0
- package/packages/pi-antigravity/package.json +77 -0
- package/packages/pi-antigravity/src/auth/index.ts +14 -0
- package/packages/pi-antigravity/src/auth/oauth.ts +442 -0
- package/packages/pi-antigravity/src/client/client.ts +561 -0
- package/packages/pi-antigravity/src/client/index.ts +1 -0
- package/packages/pi-antigravity/src/context.ts +110 -0
- package/packages/pi-antigravity/src/diagnostics/diagnostics.ts +96 -0
- package/packages/pi-antigravity/src/diagnostics/index.ts +1 -0
- package/packages/pi-antigravity/src/image/image.ts +336 -0
- package/packages/pi-antigravity/src/image/index.ts +1 -0
- package/packages/pi-antigravity/src/index.ts +280 -0
- package/packages/pi-antigravity/src/models/discovery.ts +154 -0
- package/packages/pi-antigravity/src/models/grouping.ts +424 -0
- package/packages/pi-antigravity/src/models/index.ts +3 -0
- package/packages/pi-antigravity/src/models/models.ts +500 -0
- package/packages/pi-antigravity/src/stream/index.ts +1 -0
- package/packages/pi-antigravity/src/stream/stream.ts +1478 -0
- package/packages/pi-antigravity/src/types/enums.ts +42 -0
- package/packages/pi-antigravity/src/types/index.ts +2 -0
- package/packages/pi-antigravity/src/types/types.ts +292 -0
- package/packages/pi-antigravity/src/usage/index.ts +1 -0
- package/packages/pi-antigravity/src/usage/usage.ts +416 -0
- package/packages/pi-antigravity/src/utils/http.ts +91 -0
- package/packages/pi-antigravity/src/utils/index.ts +3 -0
- package/packages/pi-antigravity/src/utils/security.ts +73 -0
- package/packages/pi-antigravity/src/utils/util.ts +132 -0
- package/scripts/multi-account.mjs +44 -0
- package/src/account-labels.ts +223 -0
- package/src/account-plan-assignment.ts +340 -0
- package/src/account-rate-history.ts +372 -0
- package/src/anthropic-adaptive-stream.ts +531 -0
- package/src/anthropic-alias-stream.ts +140 -0
- package/src/anthropic-context-compat.ts +80 -0
- package/src/api-pricing.ts +579 -0
- package/src/bounded-file-lines.ts +97 -0
- package/src/catalog-rebinding.ts +177 -0
- package/src/catalog-registration-probe.ts +111 -0
- package/src/codex-adapter.ts +345 -0
- package/src/codex-model-defaults.ts +785 -0
- package/src/command-completions.ts +404 -0
- package/src/commands.ts +2000 -0
- package/src/compaction.ts +14 -0
- package/src/config.ts +1317 -0
- package/src/continuation.ts +569 -0
- package/src/cooldowns.ts +110 -0
- package/src/cost-digest-store.ts +332 -0
- package/src/cost-digest.ts +1044 -0
- package/src/cost-history.ts +251 -0
- package/src/cost-period-closer.ts +160 -0
- package/src/cost-report-json.ts +318 -0
- package/src/cost-report-reader.ts +368 -0
- package/src/cost-report-render.ts +207 -0
- package/src/cost-report.ts +1104 -0
- package/src/coverage-attestation.ts +397 -0
- package/src/credential-lifecycle.ts +169 -0
- package/src/credential-refresh.ts +248 -0
- package/src/declaration-notice-marker.ts +238 -0
- package/src/diagnostic-store.ts +276 -0
- package/src/diagnostics.ts +309 -0
- package/src/discovery.ts +471 -0
- package/src/duration.ts +13 -0
- package/src/error-classification.ts +256 -0
- package/src/fuzzy.ts +15 -0
- package/src/group-policy.ts +81 -0
- package/src/history-store.ts +897 -0
- package/src/index.ts +5572 -0
- package/src/lifecycle.ts +378 -0
- package/src/logical-dispatch.ts +279 -0
- package/src/logical-model-selector.ts +254 -0
- package/src/logical-model-switcher.ts +430 -0
- package/src/logical-provider-attribution.ts +544 -0
- package/src/logical-provider.ts +1237 -0
- package/src/logical-route-indicator.ts +215 -0
- package/src/machine-lease.ts +445 -0
- package/src/model-support.ts +66 -0
- package/src/models-declaration.ts +1091 -0
- package/src/openai-adapter.ts +117 -0
- package/src/openrouter-budget.ts +304 -0
- package/src/openrouter-fallback.ts +146 -0
- package/src/period-boundaries.ts +376 -0
- package/src/pi-anthropic-oauth.d.ts +6 -0
- package/src/preflight.ts +253 -0
- package/src/pricing-cache.ts +235 -0
- package/src/project-identity.ts +100 -0
- package/src/provider-registration.ts +942 -0
- package/src/rate-formula.ts +163 -0
- package/src/recovery-engine.ts +853 -0
- package/src/recovery-output.ts +837 -0
- package/src/recovery-plan.ts +239 -0
- package/src/report-range.ts +203 -0
- package/src/route-resolver.ts +789 -0
- package/src/routing-config-transaction.ts +232 -0
- package/src/routing.ts +1163 -0
- package/src/runtime-state.ts +630 -0
- package/src/session-account-groups.ts +284 -0
- package/src/session-restore.ts +287 -0
- package/src/shared-usage.ts +1392 -0
- package/src/standalone-cli.ts +720 -0
- package/src/status-view.ts +578 -0
- package/src/subscription-plan-catalog.ts +346 -0
- package/src/tier-model-resolver.ts +46 -0
- package/src/upstream-anthropic.ts +315 -0
- package/src/upstream-antigravity.ts +327 -0
- package/src/usage-fetch.ts +1634 -0
- package/src/usage.ts +1026 -0
- package/src/vendor.ts +87 -0
- package/src/warmer.ts +231 -0
- package/src/watchdog.ts +219 -0
- package/src/window-history.ts +270 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
2
|
+
import type { MessageCreateParamsStreaming } from "@anthropic-ai/sdk/resources/messages.js";
|
|
3
|
+
import {
|
|
4
|
+
type Api,
|
|
5
|
+
type AssistantMessage,
|
|
6
|
+
type AssistantMessageEventStream,
|
|
7
|
+
calculateCost,
|
|
8
|
+
type Context,
|
|
9
|
+
createAssistantMessageEventStream,
|
|
10
|
+
type Model,
|
|
11
|
+
type SimpleStreamOptions,
|
|
12
|
+
type StopReason,
|
|
13
|
+
} from "@earendil-works/pi-ai";
|
|
14
|
+
import { isClaudeOAuthAccessToken, USER_AGENT } from "./auth.js";
|
|
15
|
+
import {
|
|
16
|
+
convertPiMessagesToAnthropic,
|
|
17
|
+
convertPiToolsToAnthropic,
|
|
18
|
+
fromClaudeCodeToolName,
|
|
19
|
+
type IndexedBlock,
|
|
20
|
+
} from "./convert.js";
|
|
21
|
+
import { projectContext } from "./context.js";
|
|
22
|
+
import { buildAnthropicSystemPrompt } from "./prompt.js";
|
|
23
|
+
|
|
24
|
+
const REQUIRED_BETAS = [
|
|
25
|
+
"claude-code-20250219",
|
|
26
|
+
"oauth-2025-04-20",
|
|
27
|
+
// fine-grained-tool-streaming removed: it ships the model's raw, unvalidated
|
|
28
|
+
// tool-input JSON. For large edits full of quotes/newlines the streamed
|
|
29
|
+
// string escaping breaks, so a field (e.g. edit.oldText) swallows the rest of
|
|
30
|
+
// the structure — surfacing as either a hard JSON.parse crash or a wrong-shape
|
|
31
|
+
// schema-validation failure. Default streaming has the server validate/buffer
|
|
32
|
+
// tool JSON, guaranteeing well-formed, correctly-structured input.
|
|
33
|
+
"interleaved-thinking-2025-05-14",
|
|
34
|
+
] as const;
|
|
35
|
+
|
|
36
|
+
function mapStopReason(reason: string | null | undefined): StopReason {
|
|
37
|
+
switch (reason) {
|
|
38
|
+
case "end_turn":
|
|
39
|
+
case "pause_turn":
|
|
40
|
+
case "stop_sequence":
|
|
41
|
+
return "stop";
|
|
42
|
+
case "max_tokens":
|
|
43
|
+
return "length";
|
|
44
|
+
case "tool_use":
|
|
45
|
+
return "toolUse";
|
|
46
|
+
default:
|
|
47
|
+
return "error";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function headersToRecord(headers: Headers): Record<string, string> {
|
|
52
|
+
const record: Record<string, string> = {};
|
|
53
|
+
headers.forEach((value, key) => {
|
|
54
|
+
record[key] = value;
|
|
55
|
+
});
|
|
56
|
+
return record;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function makeDefaultHeaders(
|
|
60
|
+
isOAuth: boolean,
|
|
61
|
+
options?: SimpleStreamOptions,
|
|
62
|
+
): Record<string, string> {
|
|
63
|
+
const headers: Record<string, string> = {
|
|
64
|
+
accept: "application/json",
|
|
65
|
+
"anthropic-dangerous-direct-browser-access": "true",
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
if (isOAuth) {
|
|
69
|
+
headers["anthropic-beta"] = REQUIRED_BETAS.join(",");
|
|
70
|
+
headers["user-agent"] = USER_AGENT;
|
|
71
|
+
headers["x-app"] = "cli";
|
|
72
|
+
} else {
|
|
73
|
+
headers["anthropic-beta"] = ["interleaved-thinking-2025-05-14"].join(",");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (options?.headers) {
|
|
77
|
+
for (const [key, value] of Object.entries(options.headers)) {
|
|
78
|
+
const normalizedKey = key.toLowerCase();
|
|
79
|
+
if (
|
|
80
|
+
isOAuth &&
|
|
81
|
+
(normalizedKey === "x-api-key" || normalizedKey === "authorization")
|
|
82
|
+
) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const existingKey = Object.keys(headers).find(
|
|
86
|
+
(header) => header.toLowerCase() === normalizedKey,
|
|
87
|
+
);
|
|
88
|
+
if (existingKey) delete headers[existingKey];
|
|
89
|
+
if (value !== null) headers[key] = value;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return headers;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function streamAnthropicOAuth(
|
|
97
|
+
model: Model<Api>,
|
|
98
|
+
context: Context,
|
|
99
|
+
options?: SimpleStreamOptions,
|
|
100
|
+
): AssistantMessageEventStream {
|
|
101
|
+
const stream = createAssistantMessageEventStream();
|
|
102
|
+
|
|
103
|
+
void (async () => {
|
|
104
|
+
const output: AssistantMessage = {
|
|
105
|
+
role: "assistant",
|
|
106
|
+
content: [],
|
|
107
|
+
api: model.api,
|
|
108
|
+
provider: model.provider,
|
|
109
|
+
model: model.id,
|
|
110
|
+
usage: {
|
|
111
|
+
input: 0,
|
|
112
|
+
output: 0,
|
|
113
|
+
cacheRead: 0,
|
|
114
|
+
cacheWrite: 0,
|
|
115
|
+
totalTokens: 0,
|
|
116
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
117
|
+
},
|
|
118
|
+
stopReason: "stop",
|
|
119
|
+
timestamp: Date.now(),
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
const apiKey = options?.apiKey;
|
|
124
|
+
if (!apiKey) {
|
|
125
|
+
throw new Error(
|
|
126
|
+
"No Anthropic auth available. Run /login and choose Claude Pro/Max.",
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const isOAuth = isClaudeOAuthAccessToken(apiKey);
|
|
131
|
+
const defaultHeaders = makeDefaultHeaders(isOAuth, options);
|
|
132
|
+
|
|
133
|
+
if (isOAuth) defaultHeaders.authorization = `Bearer ${apiKey}`;
|
|
134
|
+
|
|
135
|
+
const client = new Anthropic({
|
|
136
|
+
baseURL: model.baseUrl,
|
|
137
|
+
apiKey: isOAuth ? null : apiKey,
|
|
138
|
+
authToken: isOAuth ? apiKey : null,
|
|
139
|
+
defaultHeaders,
|
|
140
|
+
dangerouslyAllowBrowser: true,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const maxTokens =
|
|
144
|
+
options?.maxTokens || Math.floor(model.maxTokens / 3);
|
|
145
|
+
const projectedContext = projectContext(context);
|
|
146
|
+
|
|
147
|
+
const params: MessageCreateParamsStreaming = {
|
|
148
|
+
model: model.id,
|
|
149
|
+
messages: convertPiMessagesToAnthropic(
|
|
150
|
+
projectedContext.messages,
|
|
151
|
+
isOAuth,
|
|
152
|
+
model,
|
|
153
|
+
),
|
|
154
|
+
max_tokens: maxTokens,
|
|
155
|
+
stream: true,
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const system = buildAnthropicSystemPrompt(
|
|
159
|
+
projectedContext.systemPrompt,
|
|
160
|
+
isOAuth,
|
|
161
|
+
);
|
|
162
|
+
if (system) params.system = system as never;
|
|
163
|
+
if (projectedContext.tools.length) {
|
|
164
|
+
params.tools = convertPiToolsToAnthropic(
|
|
165
|
+
projectedContext.tools,
|
|
166
|
+
isOAuth,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
if (options?.reasoning && model.reasoning && maxTokens > 1) {
|
|
170
|
+
const defaultBudgets: Record<string, number> = {
|
|
171
|
+
minimal: 1024,
|
|
172
|
+
low: 4096,
|
|
173
|
+
medium: 10240,
|
|
174
|
+
high: 20480,
|
|
175
|
+
xhigh: 32000,
|
|
176
|
+
};
|
|
177
|
+
const customBudget =
|
|
178
|
+
options.thinkingBudgets?.[
|
|
179
|
+
options.reasoning as keyof typeof options.thinkingBudgets
|
|
180
|
+
];
|
|
181
|
+
const requestedBudget =
|
|
182
|
+
customBudget ?? defaultBudgets[options.reasoning] ?? 10240;
|
|
183
|
+
const display = "summarized";
|
|
184
|
+
const forceAdaptive = (
|
|
185
|
+
model.compat as { forceAdaptiveThinking?: boolean } | undefined
|
|
186
|
+
)?.forceAdaptiveThinking;
|
|
187
|
+
const id = model.id.toLowerCase().replace(/\./g, "-");
|
|
188
|
+
const adaptive =
|
|
189
|
+
forceAdaptive === true ||
|
|
190
|
+
(forceAdaptive !== false &&
|
|
191
|
+
(/claude-(?:opus|sonnet|haiku|fable|mythos)-5(?:-|$)/.test(id) ||
|
|
192
|
+
/claude-(?:opus|sonnet|haiku|fable|mythos)-4-(?:[6-9]|\d{2,})(?:-|$)/.test(
|
|
193
|
+
id,
|
|
194
|
+
)));
|
|
195
|
+
|
|
196
|
+
if (adaptive) {
|
|
197
|
+
const mapped = model.thinkingLevelMap?.[options.reasoning];
|
|
198
|
+
const effort =
|
|
199
|
+
typeof mapped === "string"
|
|
200
|
+
? mapped
|
|
201
|
+
: options.reasoning === "minimal" || options.reasoning === "low"
|
|
202
|
+
? "low"
|
|
203
|
+
: options.reasoning === "medium"
|
|
204
|
+
? "medium"
|
|
205
|
+
: options.reasoning === "high"
|
|
206
|
+
? "high"
|
|
207
|
+
: "high";
|
|
208
|
+
params.thinking = { type: "adaptive", display } as never;
|
|
209
|
+
Object.assign(params, { output_config: { effort } });
|
|
210
|
+
} else {
|
|
211
|
+
params.thinking = {
|
|
212
|
+
type: "enabled",
|
|
213
|
+
budget_tokens: Math.min(requestedBudget, maxTokens - 1),
|
|
214
|
+
display,
|
|
215
|
+
} as never;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Raw stream instead of the MessageStream helper: MessageStream
|
|
220
|
+
// accumulates tool_use input and JSON.parses it on content_block_stop,
|
|
221
|
+
// which throws under fine-grained-tool-streaming (input may be invalid
|
|
222
|
+
// mid-flight) and aborts the turn. The raw stream yields the same
|
|
223
|
+
// RawMessageStreamEvents; tool args are already parsed leniently below.
|
|
224
|
+
const { data: anthropicStream, response: httpResponse } =
|
|
225
|
+
await client.messages
|
|
226
|
+
.create(params, {
|
|
227
|
+
signal: options?.signal,
|
|
228
|
+
})
|
|
229
|
+
.withResponse();
|
|
230
|
+
|
|
231
|
+
if (options?.onResponse) {
|
|
232
|
+
try {
|
|
233
|
+
await options.onResponse(
|
|
234
|
+
{
|
|
235
|
+
status: httpResponse.status,
|
|
236
|
+
headers: headersToRecord(httpResponse.headers),
|
|
237
|
+
},
|
|
238
|
+
model,
|
|
239
|
+
);
|
|
240
|
+
} catch {
|
|
241
|
+
// Response hooks are best-effort and should not break streaming.
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
stream.push({ type: "start", partial: output });
|
|
246
|
+
|
|
247
|
+
const blocks = output.content as IndexedBlock[];
|
|
248
|
+
|
|
249
|
+
for await (const event of anthropicStream) {
|
|
250
|
+
if (event.type === "message_start") {
|
|
251
|
+
output.usage.input = event.message.usage.input_tokens || 0;
|
|
252
|
+
output.usage.output = event.message.usage.output_tokens || 0;
|
|
253
|
+
output.usage.cacheRead =
|
|
254
|
+
(event.message.usage as { cache_read_input_tokens?: number })
|
|
255
|
+
.cache_read_input_tokens || 0;
|
|
256
|
+
output.usage.cacheWrite =
|
|
257
|
+
(event.message.usage as { cache_creation_input_tokens?: number })
|
|
258
|
+
.cache_creation_input_tokens || 0;
|
|
259
|
+
output.usage.totalTokens =
|
|
260
|
+
output.usage.input +
|
|
261
|
+
output.usage.output +
|
|
262
|
+
output.usage.cacheRead +
|
|
263
|
+
output.usage.cacheWrite;
|
|
264
|
+
calculateCost(model, output.usage);
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (event.type === "content_block_start") {
|
|
269
|
+
if (event.content_block.type === "text") {
|
|
270
|
+
output.content.push({
|
|
271
|
+
type: "text",
|
|
272
|
+
text: "",
|
|
273
|
+
index: event.index,
|
|
274
|
+
} as IndexedBlock);
|
|
275
|
+
stream.push({
|
|
276
|
+
type: "text_start",
|
|
277
|
+
contentIndex: output.content.length - 1,
|
|
278
|
+
partial: output,
|
|
279
|
+
});
|
|
280
|
+
} else if (event.content_block.type === "thinking") {
|
|
281
|
+
output.content.push({
|
|
282
|
+
type: "thinking",
|
|
283
|
+
thinking: "",
|
|
284
|
+
thinkingSignature: "",
|
|
285
|
+
index: event.index,
|
|
286
|
+
} as IndexedBlock);
|
|
287
|
+
stream.push({
|
|
288
|
+
type: "thinking_start",
|
|
289
|
+
contentIndex: output.content.length - 1,
|
|
290
|
+
partial: output,
|
|
291
|
+
});
|
|
292
|
+
} else if (event.content_block.type === "redacted_thinking") {
|
|
293
|
+
output.content.push({
|
|
294
|
+
type: "thinking",
|
|
295
|
+
thinking: "[Reasoning redacted]",
|
|
296
|
+
thinkingSignature: event.content_block.data,
|
|
297
|
+
redacted: true,
|
|
298
|
+
index: event.index,
|
|
299
|
+
} as IndexedBlock);
|
|
300
|
+
stream.push({
|
|
301
|
+
type: "thinking_start",
|
|
302
|
+
contentIndex: output.content.length - 1,
|
|
303
|
+
partial: output,
|
|
304
|
+
});
|
|
305
|
+
} else if (event.content_block.type === "tool_use") {
|
|
306
|
+
output.content.push({
|
|
307
|
+
type: "toolCall",
|
|
308
|
+
id: event.content_block.id,
|
|
309
|
+
name: isOAuth
|
|
310
|
+
? fromClaudeCodeToolName(
|
|
311
|
+
event.content_block.name,
|
|
312
|
+
projectedContext.tools,
|
|
313
|
+
)
|
|
314
|
+
: event.content_block.name,
|
|
315
|
+
arguments: {},
|
|
316
|
+
partialJson: "",
|
|
317
|
+
index: event.index,
|
|
318
|
+
} as IndexedBlock);
|
|
319
|
+
stream.push({
|
|
320
|
+
type: "toolcall_start",
|
|
321
|
+
contentIndex: output.content.length - 1,
|
|
322
|
+
partial: output,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (event.type === "content_block_delta") {
|
|
329
|
+
const contentIndex = blocks.findIndex(
|
|
330
|
+
(block) => block.index === event.index,
|
|
331
|
+
);
|
|
332
|
+
const block = blocks[contentIndex];
|
|
333
|
+
if (!block) continue;
|
|
334
|
+
|
|
335
|
+
if (event.delta.type === "text_delta" && block.type === "text") {
|
|
336
|
+
block.text += event.delta.text;
|
|
337
|
+
stream.push({
|
|
338
|
+
type: "text_delta",
|
|
339
|
+
contentIndex,
|
|
340
|
+
delta: event.delta.text,
|
|
341
|
+
partial: output,
|
|
342
|
+
});
|
|
343
|
+
} else if (
|
|
344
|
+
event.delta.type === "thinking_delta" &&
|
|
345
|
+
block.type === "thinking"
|
|
346
|
+
) {
|
|
347
|
+
block.thinking += event.delta.thinking;
|
|
348
|
+
stream.push({
|
|
349
|
+
type: "thinking_delta",
|
|
350
|
+
contentIndex,
|
|
351
|
+
delta: event.delta.thinking,
|
|
352
|
+
partial: output,
|
|
353
|
+
});
|
|
354
|
+
} else if (
|
|
355
|
+
event.delta.type === "signature_delta" &&
|
|
356
|
+
block.type === "thinking"
|
|
357
|
+
) {
|
|
358
|
+
block.thinkingSignature =
|
|
359
|
+
(block.thinkingSignature || "") + event.delta.signature;
|
|
360
|
+
} else if (
|
|
361
|
+
event.delta.type === "input_json_delta" &&
|
|
362
|
+
block.type === "toolCall"
|
|
363
|
+
) {
|
|
364
|
+
block.partialJson += event.delta.partial_json;
|
|
365
|
+
try {
|
|
366
|
+
block.arguments = JSON.parse(block.partialJson) as Record<
|
|
367
|
+
string,
|
|
368
|
+
unknown
|
|
369
|
+
>;
|
|
370
|
+
} catch {}
|
|
371
|
+
stream.push({
|
|
372
|
+
type: "toolcall_delta",
|
|
373
|
+
contentIndex,
|
|
374
|
+
delta: event.delta.partial_json,
|
|
375
|
+
partial: output,
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (event.type === "content_block_stop") {
|
|
382
|
+
const contentIndex = blocks.findIndex(
|
|
383
|
+
(block) => block.index === event.index,
|
|
384
|
+
);
|
|
385
|
+
const block = blocks[contentIndex];
|
|
386
|
+
if (!block) continue;
|
|
387
|
+
|
|
388
|
+
delete (block as { index?: number }).index;
|
|
389
|
+
if (block.type === "text") {
|
|
390
|
+
stream.push({
|
|
391
|
+
type: "text_end",
|
|
392
|
+
contentIndex,
|
|
393
|
+
content: block.text,
|
|
394
|
+
partial: output,
|
|
395
|
+
});
|
|
396
|
+
} else if (block.type === "thinking") {
|
|
397
|
+
stream.push({
|
|
398
|
+
type: "thinking_end",
|
|
399
|
+
contentIndex,
|
|
400
|
+
content: block.thinking,
|
|
401
|
+
partial: output,
|
|
402
|
+
});
|
|
403
|
+
} else if (block.type === "toolCall") {
|
|
404
|
+
try {
|
|
405
|
+
block.arguments = JSON.parse(block.partialJson) as Record<
|
|
406
|
+
string,
|
|
407
|
+
unknown
|
|
408
|
+
>;
|
|
409
|
+
} catch {}
|
|
410
|
+
delete (block as { partialJson?: string }).partialJson;
|
|
411
|
+
stream.push({
|
|
412
|
+
type: "toolcall_end",
|
|
413
|
+
contentIndex,
|
|
414
|
+
toolCall: block,
|
|
415
|
+
partial: output,
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (event.type === "message_delta") {
|
|
422
|
+
output.stopReason = mapStopReason(event.delta.stop_reason);
|
|
423
|
+
output.usage.input =
|
|
424
|
+
(event.usage as { input_tokens?: number }).input_tokens ||
|
|
425
|
+
output.usage.input;
|
|
426
|
+
output.usage.output =
|
|
427
|
+
(event.usage as { output_tokens?: number }).output_tokens ||
|
|
428
|
+
output.usage.output;
|
|
429
|
+
output.usage.cacheRead =
|
|
430
|
+
(event.usage as { cache_read_input_tokens?: number })
|
|
431
|
+
.cache_read_input_tokens || 0;
|
|
432
|
+
output.usage.cacheWrite =
|
|
433
|
+
(event.usage as { cache_creation_input_tokens?: number })
|
|
434
|
+
.cache_creation_input_tokens || 0;
|
|
435
|
+
const thinkingTokens = (
|
|
436
|
+
event.usage as {
|
|
437
|
+
output_tokens_details?: { thinking_tokens?: number };
|
|
438
|
+
}
|
|
439
|
+
).output_tokens_details?.thinking_tokens;
|
|
440
|
+
if (thinkingTokens != null) {
|
|
441
|
+
output.usage.reasoning = thinkingTokens;
|
|
442
|
+
}
|
|
443
|
+
output.usage.totalTokens =
|
|
444
|
+
output.usage.input +
|
|
445
|
+
output.usage.output +
|
|
446
|
+
output.usage.cacheRead +
|
|
447
|
+
output.usage.cacheWrite;
|
|
448
|
+
calculateCost(model, output.usage);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if (options?.signal?.aborted) throw new Error("Request aborted");
|
|
453
|
+
stream.push({
|
|
454
|
+
type: "done",
|
|
455
|
+
reason: output.stopReason as "stop" | "length" | "toolUse",
|
|
456
|
+
message: output,
|
|
457
|
+
});
|
|
458
|
+
stream.end();
|
|
459
|
+
} catch (error) {
|
|
460
|
+
for (const block of output.content as Array<{
|
|
461
|
+
index?: number;
|
|
462
|
+
partialJson?: string;
|
|
463
|
+
}>) {
|
|
464
|
+
delete block.index;
|
|
465
|
+
delete block.partialJson;
|
|
466
|
+
}
|
|
467
|
+
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
|
468
|
+
output.errorMessage =
|
|
469
|
+
error instanceof Error ? error.message : String(error);
|
|
470
|
+
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
471
|
+
stream.end();
|
|
472
|
+
}
|
|
473
|
+
})();
|
|
474
|
+
|
|
475
|
+
return stream;
|
|
476
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rahul Arya
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-antigravity",
|
|
3
|
+
"version": "0.7.2-intel.1",
|
|
4
|
+
"description": "Personal Antigravity / Cloud Code Assist provider for Pi Coding Agent",
|
|
5
|
+
"author": "Rahul Arya",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Rahularya01/pi-antigravity.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/Rahularya01/pi-antigravity#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/Rahularya01/pi-antigravity/issues"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"main": "./src/index.ts",
|
|
17
|
+
"keywords": [
|
|
18
|
+
"pi-package",
|
|
19
|
+
"pi-extension",
|
|
20
|
+
"antigravity",
|
|
21
|
+
"google",
|
|
22
|
+
"oauth",
|
|
23
|
+
"provider"
|
|
24
|
+
],
|
|
25
|
+
"files": [
|
|
26
|
+
"LICENSE",
|
|
27
|
+
"README.md",
|
|
28
|
+
"UPSTREAM.json",
|
|
29
|
+
"src",
|
|
30
|
+
"tsconfig.json",
|
|
31
|
+
"UPSTREAM.md",
|
|
32
|
+
"SOURCE_MANIFEST.sha256"
|
|
33
|
+
],
|
|
34
|
+
"packageManager": "bun@1.4.0",
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc -p tsconfig.json --noEmit",
|
|
37
|
+
"prepare": "npm run build",
|
|
38
|
+
"typecheck": "tsc --noEmit",
|
|
39
|
+
"lint": "eslint src",
|
|
40
|
+
"lint:fix": "eslint src --fix",
|
|
41
|
+
"format": "prettier --write .",
|
|
42
|
+
"format:check": "prettier --check .",
|
|
43
|
+
"security-check": "bun scripts/security-check.ts",
|
|
44
|
+
"test": "bun scripts/test-model-routing.ts && bun scripts/test-model-discovery.ts && bun scripts/test-usage-formatter.ts && bun scripts/test-stream-sse.ts && bun scripts/test-stream-header-deadline.ts && bun scripts/test-http-proxy.ts && bun scripts/test-image-gen.ts && bun run test:stream-primary-error && bun run test:usage-abort && bun run test:context-projection",
|
|
45
|
+
"test:stream-primary-error": "bun scripts/test-stream-primary-error.ts",
|
|
46
|
+
"test:usage-abort": "bun scripts/test-usage-abort.ts",
|
|
47
|
+
"smoke:tools": "bun scripts/smoke-tool-schema.ts",
|
|
48
|
+
"smoke:models": "bun scripts/smoke-all-models.mjs",
|
|
49
|
+
"check": "bun run typecheck && bun run lint && bun run format:check && bun run security-check && bun run test",
|
|
50
|
+
"test:context-projection": "bun scripts/test-context-projection.ts",
|
|
51
|
+
"test:context-projection:normalized": "bun scripts/test-context-projection.ts normalized"
|
|
52
|
+
},
|
|
53
|
+
"pi": {
|
|
54
|
+
"extensions": [
|
|
55
|
+
"./src/index.ts"
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
"peerDependencies": {
|
|
59
|
+
"@earendil-works/pi-ai": ">=0.80.0",
|
|
60
|
+
"@earendil-works/pi-coding-agent": ">=0.80.0"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@earendil-works/pi-ai": "^0.84.2",
|
|
64
|
+
"@eslint/js": "^10.0.1",
|
|
65
|
+
"@types/node": "^26.1.1",
|
|
66
|
+
"eslint": "^10.7.0",
|
|
67
|
+
"eslint-config-prettier": "^10.1.8",
|
|
68
|
+
"globals": "^17.7.0",
|
|
69
|
+
"pi-ai-087": "npm:@earendil-works/pi-ai@0.87.1",
|
|
70
|
+
"prettier": "^3.9.5",
|
|
71
|
+
"typescript": "^6.0.3",
|
|
72
|
+
"typescript-eslint": "^8.64.0"
|
|
73
|
+
},
|
|
74
|
+
"dependencies": {
|
|
75
|
+
"undici": "^8.10.0"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export {
|
|
2
|
+
loginAntigravity,
|
|
3
|
+
refreshAntigravityToken,
|
|
4
|
+
getApiKey,
|
|
5
|
+
CLIENT_ID,
|
|
6
|
+
CLIENT_SECRET,
|
|
7
|
+
REDIRECT_URI,
|
|
8
|
+
AUTH_URL,
|
|
9
|
+
TOKEN_URL,
|
|
10
|
+
SCOPES,
|
|
11
|
+
CALLBACK_HOST,
|
|
12
|
+
OAUTH_CALLBACK_TIMEOUT_MS,
|
|
13
|
+
} from "./oauth.js";
|
|
14
|
+
export type { OAuthCredentials, OAuthLoginCallbacks } from "./oauth.js";
|