fix(coding-agent): bridge isContextOverflow in legacy pi-ai shim
Upstream @earendil-works/pi-ai re-exported isContextOverflow from its package root, but omp's @oh-my-pi/pi-ai barrel forwards only ./error/rate-limit, so the shim's `export * from "@oh-my-pi/pi-ai"` left it off the surface. Plugins importing it (pi-blackhole) tripped Bun's static named-export check during validation, both on disk and through the omp-legacy-pi-bundled: virtual namespace. Audited the upstream root surface rather than fix one symbol at a time: of its runtime exports only isContextOverflow (now under @oh-my-pi/pi-ai/error) and parseJsonWithRepair/parseStreamingJson/ repairJson (relocated to @oh-my-pi/pi-utils) still exist in omp. Bridge exactly that set through the shim and pin it with a regression test that exercises each helper's behavior. Fixes #6859
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### 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)).
|
||||
|
||||
## [17.1.7] - 2026-07-27
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -93,3 +93,21 @@ export * from "@oh-my-pi/pi-ai";
|
||||
export { calculateCost, getBundledModel, getBundledModels, getBundledProviders, modelsAreEqual, Type };
|
||||
export const getModel = getBundledModel;
|
||||
export const getModels = getBundledModels;
|
||||
|
||||
/**
|
||||
* Compatibility re-exports for runtime helpers that upstream
|
||||
* `@earendil-works/pi-ai` exposed from its package root but omp's
|
||||
* `@oh-my-pi/pi-ai` barrel no longer forwards. Each symbol still exists in the
|
||||
* host graph — only its root re-export was dropped — so bridging it here keeps
|
||||
* legacy extensions importing it from the pi-ai root resolving through Bun's
|
||||
* static named-export check (e.g. `omp plugin install pi-blackhole`).
|
||||
*
|
||||
* This is the full set derived from an audit of the upstream root surface: the
|
||||
* error-classification predicate `isContextOverflow` (now under
|
||||
* `@oh-my-pi/pi-ai/error`) and the JSON-repair helpers that omp relocated to
|
||||
* `@oh-my-pi/pi-utils`. Upstream root symbols with no omp equivalent are
|
||||
* intentionally not shimmed — the package has diverged and there is nothing to
|
||||
* forward.
|
||||
*/
|
||||
export { isContextOverflow } from "@oh-my-pi/pi-ai/error";
|
||||
export { parseJsonWithRepair, parseStreamingJson, repairJson } from "@oh-my-pi/pi-utils";
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import type { AssistantMessage } from "@oh-my-pi/pi-ai";
|
||||
import {
|
||||
isContextOverflow,
|
||||
parseJsonWithRepair,
|
||||
parseStreamingJson,
|
||||
repairJson,
|
||||
} from "@oh-my-pi/pi-coding-agent/extensibility/legacy-pi-ai-shim";
|
||||
|
||||
// Issue #6859: pi extensions import runtime helpers from the `@earendil-works/pi-ai`
|
||||
// (aliased to `@oh-my-pi/pi-ai`) package root that omp's barrel no longer forwards.
|
||||
// `isContextOverflow` moved under `@oh-my-pi/pi-ai/error` and the JSON-repair
|
||||
// helpers moved to `@oh-my-pi/pi-utils`, so `export * from "@oh-my-pi/pi-ai"` left
|
||||
// them off the shim surface and a named import tripped Bun's static
|
||||
// "No matching export" check during plugin validation (e.g.
|
||||
// `omp plugin install pi-blackhole`). This pins the bridged root surface so it
|
||||
// cannot silently regress the way #6583 / #6648 did one symbol at a time.
|
||||
function createErrorMessage(errorMessage: string): AssistantMessage {
|
||||
return {
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "" }],
|
||||
api: "anthropic-messages",
|
||||
provider: "anthropic",
|
||||
model: "claude-sonnet-4-5",
|
||||
usage: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
totalTokens: 0,
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
||||
},
|
||||
stopReason: "error",
|
||||
errorMessage,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
describe("legacy pi-ai shim root exports", () => {
|
||||
it("re-exports isContextOverflow with its classification behavior", () => {
|
||||
expect(typeof isContextOverflow).toBe("function");
|
||||
expect(isContextOverflow(createErrorMessage("prompt is too long: 300000 tokens > 200000 maximum"))).toBe(true);
|
||||
expect(isContextOverflow(createErrorMessage("400 Bad Request: invalid API key"))).toBe(false);
|
||||
});
|
||||
|
||||
it("re-exports the JSON-repair helpers that upstream exposed at the pi-ai root", () => {
|
||||
// repairJson escapes a raw control char inside a string so JSON.parse stops throwing.
|
||||
const broken = `{"a": "b${String.fromCharCode(1)}c"}`;
|
||||
expect(() => JSON.parse(broken)).toThrow();
|
||||
expect(JSON.parse(repairJson(broken))).toEqual({ a: "b\u0001c" });
|
||||
// parseJsonWithRepair tolerates trailing commas / unquoted keys.
|
||||
expect(parseJsonWithRepair<{ a: number }>("{a: 1,}")).toEqual({ a: 1 });
|
||||
// parseStreamingJson completes a truncated object at the streaming edge.
|
||||
expect(parseStreamingJson<{ a: number }>('{"a": 1')).toEqual({ a: 1 });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user