mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-08-28 08:35:57 +00:00
82 lines
4.1 KiB
TypeScript
82 lines
4.1 KiB
TypeScript
/**
|
|
* isolated-provider.e2e.test.ts — reachability guard for PR #152 (issue #151).
|
|
*
|
|
* PR #152 fixes isolated subagents dropping extension-registered custom providers
|
|
* on Pi >= 0.80.8 (the `modelRegistry` → `modelRuntime` migration). agent-runner
|
|
* forwards the parent's runtime, read off the ModelRegistry facade as
|
|
* `ctx.modelRegistry.runtime` via `as unknown as { runtime }`.
|
|
*
|
|
* That forwarding is already guarded by the unit test in test/agent-runner.test.ts
|
|
* ("passes the parent model runtime …") — but against a MOCK whose `.runtime` is
|
|
* hand-set. The mock cannot catch the one thing that would silently break the fix:
|
|
* `.runtime` is a `private readonly` field on the real ModelRegistry, absent from
|
|
* the public type AND the package exports. If a future Pi renames it, makes it a
|
|
* true #private, or moves the module, the cast quietly yields `undefined`, the fix
|
|
* omits `modelRuntime`, and the bug returns with no failing test.
|
|
*
|
|
* This test closes exactly that gap and nothing else: it asserts the real facade
|
|
* exposes a runtime-reachable `.runtime` that IS the runtime it wraps. It is not a
|
|
* guard for the forwarding itself (that's the unit test's job) — a fuller e2e that
|
|
* drives real `runAgent` end-to-end is tracked as a follow-up.
|
|
*
|
|
* VERSION GATE: `.runtime` only exists in the post-migration facade world (Pi >=
|
|
* 0.80.8, where `ModelRuntime` is first exported). The repo's dev dependency is
|
|
* pinned post-migration, so this runs by default — but it stays gated because CI
|
|
* also runs the suite against the peer-range floor (see .github/workflows/ci.yml),
|
|
* where Pi predates the migration. There we DYNAMICALLY import Pi and skip
|
|
* cleanly; a static `import { ModelRuntime }` would be a link-time error.
|
|
*/
|
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { afterAll, describe, expect, it } from "vitest";
|
|
|
|
// Dynamic, so this file LOADS on pre-migration Pi (a static `import { ModelRuntime }`
|
|
// would be a link-time error there — 0.80.6 doesn't export it).
|
|
const pi = (await import("@earendil-works/pi-coding-agent")) as Record<string, unknown>;
|
|
const ModelRuntime = pi.ModelRuntime as
|
|
| { create(opts?: Record<string, unknown>): Promise<ModelRuntimeLike> }
|
|
| undefined;
|
|
|
|
// The migration is exactly "ModelRuntime now exists". Absent ⇒ pre-0.80.8 ⇒ there
|
|
// is no `.runtime` facade to guard.
|
|
const MIGRATED = typeof ModelRuntime?.create === "function";
|
|
const RT = ModelRuntime as { create(opts?: Record<string, unknown>): Promise<ModelRuntimeLike> };
|
|
|
|
// The one method the reach scenario needs; `.runtime` itself is private (reached below).
|
|
interface ModelRuntimeLike {
|
|
registerProvider(id: string, config: Record<string, unknown>): void;
|
|
}
|
|
|
|
const tmpDirs: string[] = [];
|
|
afterAll(() => {
|
|
for (const d of tmpDirs.splice(0)) rmSync(d, { recursive: true, force: true });
|
|
});
|
|
|
|
describe.skipIf(!MIGRATED)("PR #152 reach: real ModelRegistry exposes .runtime (Pi >= 0.80.8)", () => {
|
|
it("ctx.modelRegistry.runtime is reachable and IS the runtime it wraps", async () => {
|
|
// A real, configured runtime — as an extension leaves it after registerProvider.
|
|
const dir = mkdtempSync(join(tmpdir(), "iso-prov-"));
|
|
tmpDirs.push(dir);
|
|
const runtime = await RT.create({
|
|
authPath: join(dir, "auth.json"),
|
|
modelsPath: join(dir, "models.json"),
|
|
allowModelNetwork: false,
|
|
});
|
|
|
|
// `.runtime` is private and not in the package exports — reach the compiled
|
|
// class by file path, exactly the field the patch's cast depends on. If Pi
|
|
// moves/renames/#privates it, THIS line fails loudly instead of the fix
|
|
// silently no-op'ing back to the #151 bug.
|
|
const indexUrl = import.meta.resolve("@earendil-works/pi-coding-agent");
|
|
const mrUrl = indexUrl.replace(/index\.js$/, "core/model-registry.js");
|
|
const { ModelRegistry } = (await import(mrUrl)) as {
|
|
ModelRegistry: new (rt: ModelRuntimeLike) => { runtime?: unknown };
|
|
};
|
|
|
|
const facade = new ModelRegistry(runtime);
|
|
// This is the exact expression agent-runner reads (`ctx.modelRegistry.runtime`).
|
|
expect((facade as { runtime?: unknown }).runtime).toBe(runtime);
|
|
});
|
|
});
|