diff --git a/src/server/sessions/piSessionService.test.ts b/src/server/sessions/piSessionService.test.ts index 3206b6b..a024650 100644 --- a/src/server/sessions/piSessionService.test.ts +++ b/src/server/sessions/piSessionService.test.ts @@ -125,6 +125,7 @@ function fakeRuntime(sessionId = "session-1", patch: Partial = {}) setSessionName: (name: string) => { session.sessionName = name; }, compact: () => Promise.resolve({ summary: "", tokensBefore: 0 }), getUserMessagesForForking: () => [], + agent: { streamFn: () => { throw new Error("streamFn should not be called in this test"); } }, ...patch, }; const runtime: PiSessionRuntime = { @@ -166,6 +167,23 @@ function emptyArchiveStore(): NonNullable { + it("exposes the session's agent.streamFn for one-off model calls", async () => { + const hub = new CapturingSessionEventHub(); + const streamFn = vi.fn(); + const fake = fakeRuntime("stream-session", { agent: { streamFn } }); + const service = new PiSessionService(hub, { + createAgentRuntime: runtimeCreator(fake.runtime), + sessionManager: sessionGateway([]), + heartbeatIntervalMs: 60_000, + }); + + await service.start("/workspace"); + + expect(fake.session.agent.streamFn).toBe(streamFn); + + await service.dispose(); + }); + it("starts sessions through an injected runtime creator", async () => { const hub = new CapturingSessionEventHub(); const fake = fakeRuntime(); diff --git a/src/server/sessions/piSessionService.ts b/src/server/sessions/piSessionService.ts index dc507f6..e38ffb2 100644 --- a/src/server/sessions/piSessionService.ts +++ b/src/server/sessions/piSessionService.ts @@ -1,5 +1,6 @@ import { open, readFile, writeFile } from "node:fs/promises"; import type { ImageContent } from "@earendil-works/pi-ai"; +import type { StreamFn } from "@earendil-works/pi-agent-core"; import { AuthStorage, createAgentSessionFromServices, @@ -232,6 +233,15 @@ export interface PiAgentSession { setThinkingLevel(level: ClientThinkingLevel): void; cycleThinkingLevel(): ClientThinkingLevel | undefined; setSessionName(name: string): void; + /** + * Narrow re-expression of `AgentSession.agent` (an `@earendil-works/pi-agent-core` + * `Agent`), exposing only `streamFn` — the resolved-auth/headers/retry "call this + * model" function pi's own compaction/branch-summarization code uses internally. + * Lets callers (e.g. session title generation) issue one-off model calls without + * depending on pi-ai's deprecated `/compat` provider registry or leaking the full + * `Agent`/`AgentSession` surface. + */ + agent: { streamFn: StreamFn }; } export interface PiSessionRuntime {