test(task): stubbed setIrcWakeTurnObserver on executor session fakes

- The IRC wake monitor from PR #7108 calls the observer on every kept-alive
  subagent finalize; fakes across the executor suites predate the method
  and threw during finalization (69 failures).
This commit is contained in:
can1357
2026-07-31 19:41:38 +02:00
parent f564b36086
commit a9573cbf28
11 changed files with 28 additions and 4 deletions
@@ -55,6 +55,7 @@ function createMockSession(
getLastAssistantMessage: () => state.messages[state.messages.length - 1],
abort: async () => {},
dispose: async () => {},
setIrcWakeTurnObserver: () => {},
} as unknown as AgentSession;
}
@@ -146,6 +146,7 @@ function createAsyncSession(
},
dispose: async () => {},
};
session.setIrcWakeTurnObserver = () => {};
harness.session = session as unknown as AgentSession;
return harness;
}
@@ -1,6 +1,7 @@
import { afterEach, expect, it, vi } from "bun:test";
import { AuthStorage } from "@oh-my-pi/pi-ai";
import { ModelRegistry } from "@oh-my-pi/pi-coding-agent/config/model-registry";
import { ExtensionRuntime } from "@oh-my-pi/pi-coding-agent/extensibility/extensions/loader";
import type { CreateAgentSessionResult } from "@oh-my-pi/pi-coding-agent/sdk";
import * as sdkModule from "@oh-my-pi/pi-coding-agent/sdk";
import type { AgentSession, AgentSessionEvent } from "@oh-my-pi/pi-coding-agent/session/agent-session";
@@ -66,16 +67,18 @@ it("overlaps registry refresh with session-file opening and session setup", asyn
getLastAssistantMessage: () => undefined,
abort: async () => {},
dispose: async () => {},
setIrcWakeTurnObserver: () => {},
} as unknown as AgentSession;
vi.spyOn(sdkModule, "createAgentSession").mockImplementation(async () => {
sessionCreationStarted.resolve();
sessionCreated = true;
return {
const result: CreateAgentSessionResult = {
session,
extensionsResult: {},
extensionsResult: { extensions: [], errors: [], runtime: new ExtensionRuntime() },
setToolUIContext: () => {},
eventBus: new EventBus(),
} as unknown as CreateAgentSessionResult;
};
return result;
});
const run = runSubprocess({
@@ -50,6 +50,7 @@ function createMockSession(onPrompt: (params: { emit: (event: AgentSessionEvent)
abort: async () => {},
dispose: async () => {},
};
session.setIrcWakeTurnObserver = () => {};
return session as unknown as AgentSession;
}
@@ -74,6 +74,7 @@ function yieldEmittingSession(
abort: async () => {},
dispose: async () => {},
};
session.setIrcWakeTurnObserver = () => {};
return session as unknown as AgentSession;
}
@@ -196,6 +196,7 @@ function createScriptedSession(
// AgentSession is a concrete class; the executor consumes only this
// structural subset. Deliberate documented test-double escape hatch,
// mirroring test/task/executor-pass-through.test.ts.
session.setIrcWakeTurnObserver = () => {};
return { session: session as unknown as AgentSession, emitted: emittedGate.promise };
}
@@ -63,6 +63,7 @@ function createMockSession(
};
const session: Partial<AgentSession> = {
setIrcWakeTurnObserver: () => {},
state: { messages: [] } as never,
agent: { state: { systemPrompt: ["test"] } } as never,
model: { api: "anthropic-messages" } as never,
@@ -81,6 +81,7 @@ function createMockSession(
dispose: async () => {},
};
session.setIrcWakeTurnObserver = () => {};
return session as unknown as AgentSession;
}
@@ -31,6 +31,7 @@ function createHangingSession(): HangingSessionHandle {
let abortCount = 0;
const { promise: hang, resolve: releaseHang } = Promise.withResolvers<void>();
const session: Partial<AgentSession> = {
setIrcWakeTurnObserver: () => {},
state: { messages: [] } as never,
agent: { state: { systemPrompt: ["test"] } } as never,
extensionRunner: undefined as never,
@@ -121,6 +122,7 @@ describe("runSubprocess wall clock (task.maxRuntimeMs)", () => {
// hang; we only need to assert that NO timeout fires when maxRuntimeMs=0.
const settings = Settings.isolated({ "task.maxRuntimeMs": 0 });
const fastSession: Partial<AgentSession> = {
setIrcWakeTurnObserver: () => {},
state: { messages: [] } as never,
agent: { state: { systemPrompt: ["test"] } } as never,
extensionRunner: undefined as never,
@@ -209,6 +211,7 @@ describe("runSubprocess wall clock (task.maxRuntimeMs)", () => {
const lateDisposed = Promise.withResolvers<void>();
const lateSession = {
dispose: async () => lateDisposed.resolve(),
setIrcWakeTurnObserver: () => {},
} as unknown as AgentSession;
let lateInstall = registry.get("late-generation");
vi.spyOn(sdkModule, "createAgentSession").mockImplementation(async (options = {}) => {
@@ -245,7 +248,10 @@ describe("runSubprocess wall clock (task.maxRuntimeMs)", () => {
const cancelled = await run;
expect(cancelled.aborted).toBe(true);
const replacementSession = { dispose: async () => {} } as unknown as AgentSession;
const replacementSession = {
dispose: async () => {},
setIrcWakeTurnObserver: () => {},
} as unknown as AgentSession;
const replacement = registry.register({
id: "late-generation",
displayName: "replacement B",
@@ -272,6 +278,7 @@ describe("runSubprocess wall clock (task.maxRuntimeMs)", () => {
let listenerRef: ((event: AgentSessionEvent) => void) | undefined;
let abortCount = 0;
const session: Partial<AgentSession> = {
setIrcWakeTurnObserver: () => {},
state: { messages: [] } as never,
agent: { state: { systemPrompt: ["test"] } } as never,
extensionRunner: undefined as never,
@@ -350,6 +357,7 @@ describe("runSubprocess wall clock (task.maxRuntimeMs)", () => {
let abortCount = 0;
let abortCountBeforeYieldExecutionEnd: number | undefined;
const session: Partial<AgentSession> = {
setIrcWakeTurnObserver: () => {},
state: { messages: [] } as never,
agent: { state: { systemPrompt: ["test"] } } as never,
extensionRunner: undefined as never,
@@ -450,6 +458,7 @@ describe("runSubprocess wall clock (task.maxRuntimeMs)", () => {
let abortCountBeforeValidYieldExecutionEnd: number | undefined;
const promptCalls: Array<{ text: string; options?: PromptOptions }> = [];
const session: Partial<AgentSession> = {
setIrcWakeTurnObserver: () => {},
state: { messages: [] } as never,
agent: { state: { systemPrompt: ["test"] } } as never,
extensionRunner: undefined as never,
@@ -580,6 +589,7 @@ describe("runSubprocess wall clock (task.maxRuntimeMs)", () => {
let abortCountBeforeYieldExecutionEnd: number | undefined;
let abortCountAfterFollowingTurn: number | undefined;
const session: Partial<AgentSession> = {
setIrcWakeTurnObserver: () => {},
state: { messages: [] } as never,
agent: { state: { systemPrompt: ["test"] } } as never,
extensionRunner: undefined as never,
@@ -663,6 +673,7 @@ describe("runSubprocess wall clock (task.maxRuntimeMs)", () => {
// executor must surface it on SingleResult.contextTokens.
const settings = Settings.isolated({ "task.maxRuntimeMs": 0 });
const fastSession: Partial<AgentSession> = {
setIrcWakeTurnObserver: () => {},
state: { messages: [] } as never,
agent: { state: { systemPrompt: ["test"] } } as never,
extensionRunner: undefined as never,
@@ -85,6 +85,7 @@ function createYieldingSession(): AgentSession {
getLastAssistantMessage: () => state.messages[state.messages.length - 1],
abort: async () => {},
dispose: async () => {},
setIrcWakeTurnObserver: () => {},
} as unknown as AgentSession;
}
@@ -76,6 +76,7 @@ function createFakeSession(config: FakeSessionConfig = {}): FakeSessionHandle {
if (!config.hang) releaseHang();
const session: Partial<AgentSession> = {
setIrcWakeTurnObserver: () => {},
state: { messages: [] } as never,
agent: { state: { systemPrompt: ["test"] } } as never,
extensionRunner: undefined as never,
@@ -108,6 +109,7 @@ function createFakeSession(config: FakeSessionConfig = {}): FakeSessionHandle {
releaseHang();
},
dispose: async () => {},
setIrcWakeTurnObserver: () => {},
};
return {
session: session as AgentSession,