fix: adapt the bridge to omp 18.4.8 host differences
Validate / validate (push) Successful in 9m53s

- resolve the agent dir through the host getAgentDir() (registered by the composition root) instead of sniffing execPath/argv
- synthesize agent_settled from the first terminal agent_end on omp
- read the live model through ctx.models.current() and prefer it over the stored model on omp
- adapt omp Settings (reloadFromDisk, global enabledModels) at the SDK boundary and drop scoped-model persistence on omp
This commit is contained in:
evandrodevbr committed 2026-10-01 10:07:47 -03:00
1 parent 52c9fbeaf3
commit 2aefc7ef5a
12 files changed
+232 -55

No files matched your search

+35
View File
@@ -560,3 +560,38 @@ test("Lifecycle helpers register pi hooks and delegate to handlers", async () =>
"agent-end",
]);
});
test("Terminal agent_end synthesizes agent_settled only for hosts that never emit it", async () => {
const cases = [
{ settle: true, event: { messages: [] }, expected: ["agent-end", "agent-settled"] },
{ settle: true, event: { messages: [], willContinue: true }, expected: ["agent-end"] },
{ settle: false, event: { messages: [] }, expected: ["agent-end"] },
];
for (const { settle, event, expected } of cases) {
const harness = createLifecycleApiHarness();
const events: string[] = [];
registerTelegramLifecycleHooks(harness.api, {
settleOnTerminalAgentEnd: settle,
onSessionStart: async () => {},
onSessionShutdown: async () => {},
onBeforeAgentStart: () => undefined,
onModelSelect: () => {},
onAgentStart: async () => {},
onToolExecutionStart: () => {},
onToolExecutionEnd: () => {},
onMessageStart: async () => {},
onMessageUpdate: async () => {},
onAgentEnd: async () => {
events.push("agent-end");
},
onAgentSettled: () => {
events.push("agent-settled");
},
});
await getRequiredLifecycleHandler(harness.handlers, "agent_end")(
event,
createLifecycleContext(),
);
assert.deepEqual(events, expected, JSON.stringify({ settle, event }));
}
});
+12
View File
@@ -83,6 +83,18 @@ test("Current model store prefers explicit Telegram model over context fallback"
assert.equal(store.get({ model: fallback }), fallback);
});
test("Current model store follows the live context model on hosts without model_select", () => {
const stale = { provider: "stale", id: "a", name: "Stale" };
const live = { provider: "live", id: "b", name: "Live" };
const store = createCurrentModelStore<{ model?: typeof live }, typeof live>(
(ctx) => ctx.model,
true,
);
store.set(stale);
assert.equal(store.get({ model: live }), live);
assert.equal(store.get({ model: undefined }), stale);
});
test("Current model runtime combines store fallback and status updates", () => {
const fallback = { provider: "fallback", id: "f", name: "Fallback" };
const selected = { provider: "selected", id: "s", name: "Selected" };
+18 -26
View File
@@ -10,6 +10,7 @@ import test from "node:test";
import {
resolveAgentDir,
setHostAgentDirResolver,
resolveTelegramConfigPath,
resolveTelegramLocksPath,
resolveTelegramTempDir,
@@ -29,41 +30,32 @@ test("Diagnostics use the resolved agent root and profile suffix", () => {
});
await test("resolveAgentDir", async (t) => {
await t.test("returns PI_CODING_AGENT_DIR when env is set", () => {
t.afterEach(() => setHostAgentDirResolver(undefined));
await t.test("PI_CODING_AGENT_DIR wins over the host directory", () => {
setHostAgentDirResolver(() => {
throw new Error("host directory must not be consulted");
});
assert.equal(
resolveAgentDir({
env: { PI_CODING_AGENT_DIR: "/custom/agent/dir" },
execPath: "/usr/bin/omp",
argv: ["omp"],
}),
resolveAgentDir({ env: { PI_CODING_AGENT_DIR: "/custom/agent/dir" } }),
resolve("/custom/agent/dir"),
);
});
await t.test("returns ~/.omp/agent for OMP-compatible runtimes", () => {
assert.equal(
resolveAgentDir({ env: {}, execPath: "/home/user/.local/bin/omp" }),
join(homedir(), ".omp", "agent"),
);
assert.equal(
resolveAgentDir({
env: {},
execPath: "/usr/bin/node",
argv: ["node", "omp"],
}),
join(homedir(), ".omp", "agent"),
);
});
await t.test(
"returns ~/.pi/agent as fallback when no env and no OMP runtime",
"uses the registered host runtime directory when env is unset",
() => {
assert.equal(
resolveAgentDir({ env: {}, execPath: "/usr/bin/node", argv: ["node"] }),
join(homedir(), ".pi", "agent"),
);
setHostAgentDirResolver(() => "/home/user/.omp/agent");
assert.equal(resolveAgentDir({ env: {} }), "/home/user/.omp/agent");
},
);
await t.test("falls back to ~/.pi/agent when no host is registered", () => {
assert.equal(
resolveAgentDir({ env: {} }),
join(homedir(), ".pi", "agent"),
);
});
});
await test("resolveTelegramConfigPath", () => {
+12
View File
@@ -157,3 +157,15 @@ test("Pi context helpers expose model, idle, pending-message, and compact adapte
assert.equal(hasExtensionContextPendingMessages(ctx), false);
assert.deepEqual(events, ["compact", "complete"]);
});
test("Pi context model prefers omp's live models facade over a frozen ctx.model", () => {
const frozen = { provider: "fake", id: "fake-1" };
const live = { provider: "fake", id: "fake-2" };
const ompCtx = {
model: frozen,
models: { current: () => live },
} as unknown as ExtensionContext;
const piCtx = { model: frozen } as unknown as ExtensionContext;
assert.equal(getExtensionContextModel(ompCtx), live);
assert.equal(getExtensionContextModel(piCtx), frozen);
});