@diegopetrucci/pi-extensions 0.1.80 → 0.1.81
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/extensions/dirty-repo-guard/index.ts +5 -2
- package/extensions/dirty-repo-guard/package.json +1 -1
- package/extensions/fast/README.md +1 -5
- package/extensions/fast/index.ts +13 -76
- package/extensions/fast/package.json +1 -1
- package/extensions/inline-bash/index.ts +1 -0
- package/extensions/inline-bash/package.json +1 -1
- package/package.json +1 -1
|
@@ -12,9 +12,12 @@ async function checkDirtyRepo(
|
|
|
12
12
|
ctx: ExtensionContext,
|
|
13
13
|
action: string,
|
|
14
14
|
): Promise<{ cancel: boolean } | undefined> {
|
|
15
|
-
const { stdout, code } = await pi.exec("git", ["status", "--porcelain"]
|
|
15
|
+
const { stdout, code, killed } = await pi.exec("git", ["status", "--porcelain"], {
|
|
16
|
+
timeout: 15_000,
|
|
17
|
+
signal: ctx.signal,
|
|
18
|
+
});
|
|
16
19
|
|
|
17
|
-
if (code !== 0) {
|
|
20
|
+
if (killed || code !== 0) {
|
|
18
21
|
return;
|
|
19
22
|
}
|
|
20
23
|
|
|
@@ -34,11 +34,7 @@ For eligible Anthropic Claude models it injects:
|
|
|
34
34
|
}
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
It also
|
|
38
|
-
|
|
39
|
-
```text
|
|
40
|
-
anthropic-beta: fast-mode-2026-02-01
|
|
41
|
-
```
|
|
37
|
+
It also appends the required beta `fast-mode-2026-02-01` to the request's `betas` list, which Pi sends as the `anthropic-beta` header. The extension does not set the `anthropic-beta` header itself, so Pi's own betas are kept.
|
|
42
38
|
|
|
43
39
|
## Eligibility
|
|
44
40
|
|
package/extensions/fast/index.ts
CHANGED
|
@@ -12,9 +12,6 @@ const ANTHROPIC_PROVIDER_ID = "anthropic";
|
|
|
12
12
|
const ANTHROPIC_API_ID = "anthropic-messages";
|
|
13
13
|
const ANTHROPIC_FAST_SPEED = "fast";
|
|
14
14
|
const ANTHROPIC_FAST_BETA = "fast-mode-2026-02-01";
|
|
15
|
-
const CLAUDE_CODE_OAUTH_BETAS = ["claude-code-20250219", "oauth-2025-04-20"];
|
|
16
|
-
const FINE_GRAINED_TOOL_STREAMING_BETA = "fine-grained-tool-streaming-2025-05-14";
|
|
17
|
-
const INTERLEAVED_THINKING_BETA = "interleaved-thinking-2025-05-14";
|
|
18
15
|
const ANTHROPIC_SUPPORTED_MODELS = new Set(["claude-opus-4-8", "claude-opus-5", "claude-opus-5-5"]);
|
|
19
16
|
|
|
20
17
|
const OPENAI_PROVIDER_ID = "openai-codex";
|
|
@@ -79,11 +76,6 @@ type RecursivePartial<T> = {
|
|
|
79
76
|
|
|
80
77
|
type PayloadRecord = Record<string, unknown>;
|
|
81
78
|
|
|
82
|
-
type AnthropicHeaderCompat = {
|
|
83
|
-
forceAdaptiveThinking?: boolean;
|
|
84
|
-
supportsEagerToolInputStreaming?: boolean;
|
|
85
|
-
};
|
|
86
|
-
|
|
87
79
|
type Eligibility = {
|
|
88
80
|
eligible: boolean;
|
|
89
81
|
modelKey: string;
|
|
@@ -368,67 +360,17 @@ function getStatusMessage(ctx: ExtensionContext, state: SessionState): string {
|
|
|
368
360
|
return `Fast mode is ${describeMode(state)}. Current model: ${eligibility.modelKey}.${injected}`;
|
|
369
361
|
}
|
|
370
362
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
if (typeof apiKey === "string") return apiKey.includes("sk-ant-oat");
|
|
383
|
-
} catch {
|
|
384
|
-
// Fall back to the synchronous registry snapshot below.
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
return ctx.model ? ctx.modelRegistry.isUsingOAuth(ctx.model) : false;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
function getAnthropicProviderBetas(ctx: ExtensionContext, hasActiveTools: boolean): string[] {
|
|
391
|
-
const model = ctx.model;
|
|
392
|
-
if (!model) return [];
|
|
393
|
-
const compat = model.compat as AnthropicHeaderCompat | undefined;
|
|
394
|
-
|
|
395
|
-
const betas: string[] = [];
|
|
396
|
-
if (hasActiveTools && compat?.supportsEagerToolInputStreaming === false) {
|
|
397
|
-
betas.push(FINE_GRAINED_TOOL_STREAMING_BETA);
|
|
398
|
-
}
|
|
399
|
-
if (compat?.forceAdaptiveThinking !== true) {
|
|
400
|
-
betas.push(INTERLEAVED_THINKING_BETA);
|
|
401
|
-
}
|
|
402
|
-
return betas;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
async function injectAnthropicFastHeader(
|
|
406
|
-
headers: Record<string, string | null>,
|
|
407
|
-
ctx: ExtensionContext,
|
|
408
|
-
state: SessionState,
|
|
409
|
-
hasActiveTools: boolean,
|
|
410
|
-
): Promise<void> {
|
|
411
|
-
if (state.ultrafast || !isFastEnabled(state)) return;
|
|
412
|
-
const eligibility = getEligibility(ctx, false);
|
|
413
|
-
if (!eligibility.eligible || eligibility.provider !== "anthropic") return;
|
|
414
|
-
|
|
415
|
-
const matchingKeys = Object.keys(headers).filter(
|
|
416
|
-
(name) => name.toLowerCase() === "anthropic-beta",
|
|
417
|
-
);
|
|
418
|
-
const existing = matchingKeys.flatMap((name) => splitBetaHeader(headers[name]));
|
|
419
|
-
const matchingModelEntries = Object.entries(ctx.model?.headers ?? {}).filter(
|
|
420
|
-
([name]) => name.toLowerCase() === "anthropic-beta",
|
|
421
|
-
);
|
|
422
|
-
const modelBetas = matchingModelEntries.flatMap(([, value]) => splitBetaHeader(value));
|
|
423
|
-
const providerBetas = getAnthropicProviderBetas(ctx, hasActiveTools);
|
|
424
|
-
const oauthBetas = (await isAnthropicOAuth(ctx)) ? CLAUDE_CODE_OAUTH_BETAS : [];
|
|
425
|
-
const next = Array.from(
|
|
426
|
-
new Set([...modelBetas, ...existing, ...oauthBetas, ...providerBetas, ANTHROPIC_FAST_BETA]),
|
|
427
|
-
);
|
|
428
|
-
|
|
429
|
-
for (const key of matchingKeys) delete headers[key];
|
|
430
|
-
const outputKey = matchingModelEntries.at(-1)?.[0] ?? "anthropic-beta";
|
|
431
|
-
headers[outputKey] = next.join(",");
|
|
363
|
+
/**
|
|
364
|
+
* Adds the Fast beta to the request's `betas` list instead of rewriting the
|
|
365
|
+
* `anthropic-beta` header. Pi derives the final beta list from the model and
|
|
366
|
+
* request (mid-conversation effort, server-side fallback, inline tools, OAuth,
|
|
367
|
+
* interleaved thinking, ...) and treats an explicit `anthropic-beta` header as
|
|
368
|
+
* the complete list, so setting that header here would drop any beta this
|
|
369
|
+
* extension does not know about.
|
|
370
|
+
*/
|
|
371
|
+
function withAnthropicFastBeta(betas: unknown[] | undefined): unknown[] {
|
|
372
|
+
const existing = betas ?? [];
|
|
373
|
+
return existing.includes(ANTHROPIC_FAST_BETA) ? existing : [...existing, ANTHROPIC_FAST_BETA];
|
|
432
374
|
}
|
|
433
375
|
|
|
434
376
|
function injectUltrafastPayload(
|
|
@@ -461,9 +403,10 @@ function injectFastPayload(
|
|
|
461
403
|
|
|
462
404
|
if (eligibility.provider === "anthropic") {
|
|
463
405
|
if ("speed" in payload) return undefined;
|
|
406
|
+
if (payload.betas !== undefined && !Array.isArray(payload.betas)) return undefined;
|
|
464
407
|
state.lastInjectedAt = Date.now();
|
|
465
408
|
state.lastInjectedModel = eligibility.modelKey;
|
|
466
|
-
return { ...payload, speed: ANTHROPIC_FAST_SPEED };
|
|
409
|
+
return { ...payload, speed: ANTHROPIC_FAST_SPEED, betas: withAnthropicFastBeta(payload.betas) };
|
|
467
410
|
}
|
|
468
411
|
|
|
469
412
|
if ("service_tier" in payload) return undefined;
|
|
@@ -552,12 +495,6 @@ export default function fastExtension(pi: ExtensionAPI) {
|
|
|
552
495
|
updateStatus(ctx, state);
|
|
553
496
|
});
|
|
554
497
|
|
|
555
|
-
pi.on("before_provider_headers", async (event, ctx) => {
|
|
556
|
-
const hasActiveTools =
|
|
557
|
-
typeof pi.getActiveTools === "function" && pi.getActiveTools().length > 0;
|
|
558
|
-
await injectAnthropicFastHeader(event.headers, ctx, getState(ctx), hasActiveTools);
|
|
559
|
-
});
|
|
560
|
-
|
|
561
498
|
pi.on("before_provider_request", (event, ctx) => {
|
|
562
499
|
const state = getState(ctx);
|
|
563
500
|
if (state.ultrafast) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-fast",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "A pi extension that enables Fast mode for supported direct OpenAI API, OpenAI Codex, and Anthropic Claude models based on the currently selected model.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-extensions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.81",
|
|
4
4
|
"description": "A collection of pi extensions and skills for annotation UIs, context management, workflow audits, contrarian review, review-comment triage, notifications, brrr push alerts, safety guards, GitHub research, repo-local knowledge, todos, tool rendering, model/provider helpers, and Xiaohei-style article illustrations.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|