oira666_pi-limits-wait 0.4.2 → 0.4.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.ts +22 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oira666_pi-limits-wait",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
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
  "license": "MIT",
package/src/index.ts CHANGED
@@ -115,6 +115,16 @@ function formatModel(model: Pick<Model<Api>, "provider" | "id">): string {
115
115
  return `${model.provider}/${model.id}`;
116
116
  }
117
117
 
118
+ function isInternalSyntheticModel(model: Pick<Model<Api>, "provider" | "id">): boolean {
119
+ return model.provider.startsWith("pi-") || model.id.startsWith("synthetic-");
120
+ }
121
+
122
+ function isFallbackEligibleModel(model: Model<Api>): boolean {
123
+ if (isInternalSyntheticModel(model)) return false;
124
+ const key = modelKey(model);
125
+ return primaryModel ? key === modelKey(primaryModel) || fallbackModels.some((entry) => modelKey(entry.model) === key) : true;
126
+ }
127
+
118
128
  function isThinkingLevel(value: unknown): value is ThinkingLevel {
119
129
  return ["off", "minimal", "low", "medium", "high", "xhigh"].includes(String(value));
120
130
  }
@@ -677,7 +687,8 @@ export function streamWithLimitsRetry(
677
687
 
678
688
  void (async () => {
679
689
  let committed = false;
680
- let attempt: FallbackModel = initialAttempt(model);
690
+ const allowFallback = fallbackEnabled() && isFallbackEligibleModel(model);
691
+ let attempt: FallbackModel = allowFallback ? initialAttempt(model) : { model, reasoningEffort: primaryThinkingLevel };
681
692
 
682
693
  const flush = (buffer: AssistantMessageEvent[]) => {
683
694
  for (const event of buffer) output.push(event);
@@ -693,7 +704,7 @@ export function streamWithLimitsRetry(
693
704
 
694
705
  try {
695
706
  try {
696
- const attemptOptions = fallbackEnabled()
707
+ const attemptOptions = allowFallback
697
708
  ? await optionsForModel(model, attempt, options)
698
709
  : options;
699
710
  const attemptDelegate = attempt.model.api === model.api
@@ -709,7 +720,7 @@ export function streamWithLimitsRetry(
709
720
  retryable = !options?.signal?.aborted ? getRetryableError(errMsg) : undefined;
710
721
  if (retryable) break;
711
722
 
712
- if (fallbackEnabled()) {
723
+ if (allowFallback) {
713
724
  nonRetryableError = { message: errMsg, event };
714
725
  break;
715
726
  }
@@ -732,7 +743,7 @@ export function streamWithLimitsRetry(
732
743
  }
733
744
 
734
745
  // First non-start, non-error event means this attempt is real.
735
- if (fallbackEnabled()) await switchPiModel(attempt);
746
+ if (allowFallback) await switchPiModel(attempt);
736
747
  if (buffer.length > 0) {
737
748
  flush(buffer);
738
749
  } else {
@@ -758,7 +769,7 @@ export function streamWithLimitsRetry(
758
769
  const errMsg = err instanceof Error ? err.message : String(err);
759
770
  retryable = !options?.signal?.aborted ? getRetryableError(errMsg) : undefined;
760
771
  if (!retryable) {
761
- if (fallbackEnabled() && !options?.signal?.aborted) {
772
+ if (allowFallback && !options?.signal?.aborted) {
762
773
  nonRetryableError = { message: errMsg };
763
774
  } else {
764
775
  if (!committed) {
@@ -788,7 +799,7 @@ export function streamWithLimitsRetry(
788
799
  }
789
800
 
790
801
  if (nonRetryableError) {
791
- if (fallbackEnabled() && !committed) {
802
+ if (allowFallback && !committed) {
792
803
  rememberNonRetryableFailure(attempt.model, nonRetryableError.message);
793
804
  const next = nextAvailableCandidate(attempt.model);
794
805
  if (next) {
@@ -843,7 +854,7 @@ export function streamWithLimitsRetry(
843
854
  return;
844
855
  }
845
856
 
846
- if (fallbackEnabled()) {
857
+ if (allowFallback) {
847
858
  rememberRateLimit(attempt.model, retryable);
848
859
  const next = nextAvailableCandidate(attempt.model);
849
860
  if (next) {
@@ -918,22 +929,23 @@ export default function (pi: ExtensionAPI) {
918
929
  suppressNextModelSelect = false;
919
930
  return;
920
931
  }
932
+ if (isInternalSyntheticModel(event.model)) return;
921
933
  primaryModel = event.model;
922
934
  primaryThinkingLevel = pi.getThinkingLevel();
923
935
  });
924
936
 
925
937
  pi.on("before_agent_start", (event, ctx) => {
926
938
  sharedCtx = ctx;
927
- primaryModel ??= ctx.model;
939
+ if (!primaryModel && ctx.model && !isInternalSyntheticModel(ctx.model)) primaryModel = ctx.model;
928
940
  primaryThinkingLevel ??= pi.getThinkingLevel();
929
941
  loadFallbackSettings(ctx);
930
942
 
931
943
  // Some extensions may register providers after this extension loads. Wrap
932
944
  // any APIs that exist by the time an agent starts too.
933
945
  for (const model of ctx.modelRegistry.getAll()) {
934
- registerWrappedApi(pi, model.api);
946
+ if (!isInternalSyntheticModel(model)) registerWrappedApi(pi, model.api);
935
947
  }
936
- if (ctx.model) registerWrappedApi(pi, ctx.model.api);
948
+ if (ctx.model && !isInternalSyntheticModel(ctx.model)) registerWrappedApi(pi, ctx.model.api);
937
949
 
938
950
  // Anthropic subscription/OAuth requests identify as Claude Code, not Pi.
939
951
  // Check the session-wide Anthropic OAuth configuration rather than only the