Merge PR #6848: fix(coding-agent): restore isRetryableAssistantError in legacy pi-ai shim (@roboomp)
This commit is contained in:
@@ -25,6 +25,9 @@
|
||||
### Fixed
|
||||
|
||||
- Fixed `omp plugin install` of legacy pi extensions failing Bun's static named-export validation on `isContextOverflow` (e.g. `pi-blackhole`). The `@oh-my-pi/pi-ai` root barrel dropped upstream `@earendil-works/pi-ai`'s root re-export, so `legacy-pi-ai-shim.ts` (which backs both on-disk and `omp-legacy-pi-bundled:` virtual resolution) never surfaced it. The shim now bridges every upstream-root runtime symbol that still exists in omp — `isContextOverflow` (from `@oh-my-pi/pi-ai/error`) and `parseJsonWithRepair`/`parseStreamingJson`/`repairJson` (from `@oh-my-pi/pi-utils`) ([#6859](https://github.com/can1357/oh-my-pi/issues/6859)).
|
||||
### Fixed
|
||||
|
||||
- Fixed legacy extension plugin validation failing with `Export named 'isRetryableAssistantError' not found in module '.../legacy-pi-ai-shim.ts'` when an extension imports `isRetryableAssistantError` from `@earendil-works/pi-ai` / `@oh-my-pi/pi-ai` (e.g. `@router-for-me/pi-cliproxyapi-provider` >= 1.4.9). Historical pi-ai exports this transient-error classifier from its package root, but OMP's legacy `pi-ai` root shim never bridged it; the shim now ships a compatibility implementation matching the upstream provider-error wording tables. ([#6847](https://github.com/can1357/oh-my-pi/issues/6847))
|
||||
|
||||
## [17.1.7] - 2026-07-27
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* `types.ts` via the `export *` below — pi-ai still exports both as types,
|
||||
* only the runtime `Type` builder and `StringEnum()` helper were removed.
|
||||
*/
|
||||
import type { Api, Model } from "@oh-my-pi/pi-ai";
|
||||
import type { Api, AssistantMessage, Model } from "@oh-my-pi/pi-ai";
|
||||
import type { Effort } from "@oh-my-pi/pi-catalog/effort";
|
||||
import { clampThinkingLevelForModel } from "@oh-my-pi/pi-catalog/model-thinking";
|
||||
import {
|
||||
@@ -80,6 +80,33 @@ export function clampThinkingLevel<TApi extends Api>(model: Model<TApi>, level:
|
||||
return clampThinkingLevelForModel(model, level) ?? "off";
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider-error classification patterns ported verbatim from historical pi-ai
|
||||
* (`@earendil-works/pi-ai` `utils/retry.ts`). Legacy extensions call
|
||||
* {@link isRetryableAssistantError} to decide whether to restart a failed
|
||||
* assistant turn, so the wording tables must match the upstream semantics they
|
||||
* were authored against rather than OMP's own `Error`-based classifiers.
|
||||
*/
|
||||
const NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN =
|
||||
/GoUsageLimitError|FreeUsageLimitError|Monthly usage limit reached|available balance|insufficient_quota|out of budget|quota exceeded|billing/i;
|
||||
const RETRYABLE_PROVIDER_ERROR_PATTERN =
|
||||
/overloaded|rate.?limit|too many requests|429|500|502|503|504|524|service.?unavailable|server.?error|internal.?error|provider.?returned.?error|network.?error|connection.?error|connection.?refused|connection.?lost|other side closed|fetch failed|getaddrinfo|ENOTFOUND|EAI_AGAIN|upstream.?connect|reset before headers|socket hang up|socket connection was closed|timed? out|timeout|terminated|websocket.?closed|websocket.?error|ended without|stream ended before message_stop|stream ended before a terminal response event|http2 request did not get a response|retry delay|you can retry your request|try your request again|please retry your request|ResourceExhausted/i;
|
||||
|
||||
/**
|
||||
* Compatibility implementation of historical pi-ai's `isRetryableAssistantError`.
|
||||
*
|
||||
* Classifies whether a failed assistant message looks like a transient provider
|
||||
* or transport error so legacy extensions can decide if the last assistant turn
|
||||
* should be restarted. Account/quota limits are treated as non-retryable. This
|
||||
* does not implement any retry policy; callers own budget, backoff, and reporting.
|
||||
*/
|
||||
export function isRetryableAssistantError(message: AssistantMessage): boolean {
|
||||
if (message.stopReason !== "error" || !message.errorMessage) return false;
|
||||
const errorMessage = message.errorMessage;
|
||||
if (NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN.test(errorMessage)) return false;
|
||||
return RETRYABLE_PROVIDER_ERROR_PATTERN.test(errorMessage);
|
||||
}
|
||||
|
||||
export * from "@oh-my-pi/pi-ai";
|
||||
/**
|
||||
* Compatibility re-exports for catalog symbols that pi-ai historically exposed
|
||||
|
||||
@@ -220,6 +220,29 @@ describe("legacy-pi @(scope)/pi-ai root `Type` remap (issue #1437)", () => {
|
||||
expect(loaded.schema.safeParse("blue").success).toBe(false);
|
||||
expect(loaded.schema.toJSON?.()?.description).toBe("primary colors");
|
||||
});
|
||||
|
||||
it("exports isRetryableAssistantError for legacy retry classification (issue #6847)", async () => {
|
||||
// `@earendil-works/pi-ai@0.82.x` exports isRetryableAssistantError from its
|
||||
// package root (utils/retry.js). Plugins such as
|
||||
// `@router-for-me/pi-cliproxyapi-provider` (>=1.4.9) import it, so a missing
|
||||
// shim export surfaced as a plain
|
||||
// `Export named 'isRetryableAssistantError' not found` at validation time.
|
||||
const loaded = (await loadLegacyPiModule(
|
||||
await writeFixtureExtension(
|
||||
[
|
||||
'import { isRetryableAssistantError } from "@earendil-works/pi-ai";',
|
||||
'const err = errorMessage => ({ role: "assistant", stopReason: "error", errorMessage });',
|
||||
'export const transient = isRetryableAssistantError(err("upstream connect error"));',
|
||||
'export const quota = isRetryableAssistantError(err("insufficient_quota"));',
|
||||
'export const ok = isRetryableAssistantError({ role: "assistant", stopReason: "stop" });',
|
||||
].join("\n"),
|
||||
),
|
||||
)) as { transient: boolean; quota: boolean; ok: boolean };
|
||||
|
||||
expect(loaded.transient).toBe(true);
|
||||
expect(loaded.quota).toBe(false);
|
||||
expect(loaded.ok).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("legacy pi package root remaps (issue #1474)", () => {
|
||||
|
||||
Reference in New Issue
Block a user