- 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:
1 parent
52c9fbeaf3
commit
2aefc7ef5a
12 files changed
+232
-55
No files matched your search
@@ -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 }));
|
||||
}
|
||||
});
|
||||
@@ -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
@@ -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", () => {
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
Reference in new issue
Block a user