Merge PR #6862: fix(coding-agent): bridge isContextOverflow in legacy pi-ai shim (@roboomp)

This commit is contained in:
can1357
2026-07-28 10:59:34 +02:00
3 changed files with 77 additions and 0 deletions
+3
View File
@@ -22,6 +22,9 @@
### Fixed
- Fixed internal Hub peer messages being emitted over ACP as ordinary tool-call updates, which exposed inter-agent coordination text in clients such as Paseo ([#6872](https://github.com/can1357/oh-my-pi/issues/6872)).
### 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
@@ -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 });
});
});