oira666_pi-limits-wait 0.5.5 → 0.5.6

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 CHANGED
@@ -160,6 +160,7 @@ The extension rereads these files before every LLM call, so changes made during
160
160
 
161
161
  | Variable | Default | Description |
162
162
  |----------|---------|-------------|
163
+ | `PI_LIMITS_WAIT_DISABLE_ALL_WAITING` | `false` | Master kill switch for this extension's error handling, retries, fallbacks, freezing, waiting, notifications, telemetry, and retry summaries. Set to `true` (also accepts `1`, `yes`, `on`) to leave only Anthropic OAuth system-prompt cleaning enabled; requests continue through Pi's normal runtime, including its normal Anthropic headers. This takes precedence over every setting below. |
163
164
  | `PI_LIMITS_WAIT_DEFAULT_WAITING` | `true` | Whether unclassified/unknown provider errors enter the wait-and-retry cycle. Set to `false` (also accepts `0`, `no`, `off`) to surface the error immediately. Rate-limit, overload, authentication, and network retry behavior is unchanged. |
164
165
  | `PI_LIMITS_WAIT_MAX_RETRY` | `999999` | Maximum extension-created retries for an unclassified/unknown provider error. The initial failed request and provider-internal retries do not count. HTTP 400/403 remain eligible. Must be a non-negative integer. |
165
166
  | `PI_LIMITS_WAIT_LIVELINESS_INTERVAL` | `15` | Seconds between liveliness notifications published while waiting in non-interactive (`rpc`/`json`) modes. Must be a non-negative integer; values below 1 second are clamped to 1 second. Ignored in TUI mode. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oira666_pi-limits-wait",
3
- "version": "0.5.5",
3
+ "version": "0.5.6",
4
4
  "description": "Extension for PI that allows to automatically wait for limits to reset and retry the request",
5
5
  "type": "module",
6
6
  "exports": {
package/src/constants.ts CHANGED
@@ -37,6 +37,7 @@ export const DEFAULT_LIVELINESS_INTERVAL_MS = 15 * 1_000; // 15 seconds
37
37
 
38
38
  export const SETTINGS_FILE_NAME = "limits-wait.json";
39
39
  export const FALLBACK_MODELS_KEY = "fallback-models";
40
+ export const DISABLE_ALL_WAITING_ENV_VAR = "PI_LIMITS_WAIT_DISABLE_ALL_WAITING";
40
41
  export const FREEZING_ENV_VAR = "PI_LIMITS_WAIT_FREEZING_ENABLED";
41
42
  export const DEFAULT_WAITING_ENV_VAR = "PI_LIMITS_WAIT_DEFAULT_WAITING";
42
43
  export const MAX_RETRY_ENV_VAR = "PI_LIMITS_WAIT_MAX_RETRY";
package/src/index.ts CHANGED
@@ -3,9 +3,9 @@ import { isInternalSyntheticModel } from "./models.js";
3
3
  import { sanitiseAnthropicPayloadSystem } from "./prompt.js";
4
4
  import { RetrySummaryCoordinator } from "./retry-summary.js";
5
5
  import { loadFallbackSettings } from "./settings.js";
6
- import { loadUnknownErrorRetrySettings } from "./ui.js";
6
+ import { allWaitingDisabled, loadUnknownErrorRetrySettings } from "./ui.js";
7
7
  import { consumeExpectedModelSelection, state } from "./state.js";
8
- import { installModelRuntimeInterception } from "./stream.js";
8
+ import { disableModelRuntimeInterception, installModelRuntimeInterception } from "./stream.js";
9
9
 
10
10
  export { sanitiseAnthropicPayloadSystem, sanitiseSystemPrompt } from "./prompt.js";
11
11
  export {
@@ -46,11 +46,13 @@ export type { LimitsWaitSessionEntryData } from "./retry-summary.js";
46
46
  export {
47
47
  __configureFallbackModelsForTests,
48
48
  __setNonRetryableTuningForTests,
49
+ disableModelRuntimeInterception,
49
50
  installModelRuntimeInterception,
50
51
  streamWithLimitsRetry,
51
52
  streamWithRateLimitRetry,
52
53
  } from "./stream.js";
53
54
  export {
55
+ allWaitingDisabled,
54
56
  clearLivelinessStatus,
55
57
  freezingEnabled,
56
58
  isNonInteractiveHost,
@@ -63,16 +65,24 @@ export {
63
65
  export type { FallbackModel } from "./types.js";
64
66
 
65
67
  export default function (pi: ExtensionAPI) {
68
+ // Current pi-ai inserts the Claude Code identity as the first system block
69
+ // for Anthropic OAuth. Sanitise only that exact payload shape; authentication,
70
+ // identity insertion, Anthropic headers, and all other request composition
71
+ // remain owned by ModelRuntime.
72
+ pi.on("before_provider_request", (event) => sanitiseAnthropicPayloadSystem(event.payload));
73
+
74
+ // Keep prompt sanitisation and the runtime's normal Anthropic header path,
75
+ // but install no retry/error interception or retry-related lifecycle hooks.
76
+ if (allWaitingDisabled()) {
77
+ disableModelRuntimeInterception();
78
+ return;
79
+ }
80
+
66
81
  state.extensionApi = pi;
67
82
  loadUnknownErrorRetrySettings();
68
83
  const retrySummaries = new RetrySummaryCoordinator(pi);
69
84
  const releaseInterception = installModelRuntimeInterception(() => retrySummaries.createStream());
70
85
 
71
- // Current pi-ai inserts the Claude Code identity as the first system block
72
- // for Anthropic OAuth. Sanitise only that exact payload shape; authentication,
73
- // identity insertion and all request composition remain owned by ModelRuntime.
74
- pi.on("before_provider_request", (event) => sanitiseAnthropicPayloadSystem(event.payload));
75
-
76
86
  pi.on("model_select", (event) => {
77
87
  if (consumeExpectedModelSelection(event.model)) return;
78
88
  if (isInternalSyntheticModel(event.model)) return;
package/src/stream.ts CHANGED
@@ -680,6 +680,23 @@ interface InterceptionSlot {
680
680
  }
681
681
  type InterceptablePrototype = ModelRuntime & { [INTERCEPTION_SYMBOL]?: InterceptionSlot };
682
682
 
683
+ /**
684
+ * Deactivate the currently installed retry handler, if any. This is used by
685
+ * the all-waiting kill switch so reloading from an enabled extension instance
686
+ * cannot leave its process-wide interception active.
687
+ */
688
+ export function disableModelRuntimeInterception(): void {
689
+ const prototype = ModelRuntime.prototype as InterceptablePrototype;
690
+ const slot = prototype[INTERCEPTION_SYMBOL];
691
+ if (!slot || prototype.streamSimple !== slot.wrapper) return;
692
+
693
+ const abortOwner = slot.abortOwner;
694
+ slot.owner = undefined;
695
+ slot.abortOwner = undefined;
696
+ slot.handler = undefined;
697
+ abortOwner?.();
698
+ }
699
+
683
700
  /** Install one stable, reload-safe process-wide trampoline. */
684
701
  export function installModelRuntimeInterception(
685
702
  createRetryPeriod?: () => RetryPeriodTracker,
package/src/ui.ts CHANGED
@@ -3,6 +3,7 @@ import {
3
3
  DEFAULT_UNKNOWN_ERROR_MAX_RETRIES,
4
4
  DEFAULT_UNKNOWN_ERROR_RETRY_INTERVAL_MS,
5
5
  DEFAULT_WAITING_ENV_VAR,
6
+ DISABLE_ALL_WAITING_ENV_VAR,
6
7
  FREEZING_ENV_VAR,
7
8
  LIVELINESS_INTERVAL_ENV_VAR,
8
9
  LIVELINESS_STATUS_KEY,
@@ -57,6 +58,10 @@ function envNonNegativeInteger(raw: string | undefined, defaultValue: number, ma
57
58
  return Number.isSafeInteger(value) ? Math.min(value, maximum) : defaultValue;
58
59
  }
59
60
 
61
+ export function allWaitingDisabled(): boolean {
62
+ return envBoolean(process.env[DISABLE_ALL_WAITING_ENV_VAR], false);
63
+ }
64
+
60
65
  export function freezingEnabled(): boolean {
61
66
  return envBoolean(process.env[FREEZING_ENV_VAR], true);
62
67
  }