Files
openclaw/src/agents/pi-embedded-runner/stream-resolution.test.ts
2026-04-04 20:03:15 +09:00

142 lines
4.1 KiB
TypeScript

import { streamSimple } from "@mariozechner/pi-ai";
import { describe, expect, it, vi } from "vitest";
import {
describeEmbeddedAgentStreamStrategy,
resolveEmbeddedAgentApiKey,
resolveEmbeddedAgentStreamFn,
} from "./stream-resolution.js";
describe("describeEmbeddedAgentStreamStrategy", () => {
it("describes provider-owned stream paths explicitly", () => {
expect(
describeEmbeddedAgentStreamStrategy({
currentStreamFn: undefined,
providerStreamFn: vi.fn() as never,
shouldUseWebSocketTransport: false,
model: {
api: "openai-completions",
provider: "ollama",
id: "qwen",
} as never,
}),
).toBe("provider");
});
it("describes default OpenAI fallback shaping", () => {
expect(
describeEmbeddedAgentStreamStrategy({
currentStreamFn: undefined,
shouldUseWebSocketTransport: false,
model: {
api: "openai-responses",
provider: "openai",
id: "gpt-5.4",
} as never,
}),
).toBe("boundary-aware:openai-responses");
});
it("describes default Codex fallback shaping", () => {
expect(
describeEmbeddedAgentStreamStrategy({
currentStreamFn: undefined,
shouldUseWebSocketTransport: false,
model: {
api: "openai-codex-responses",
provider: "openai-codex",
id: "codex-mini-latest",
} as never,
}),
).toBe("boundary-aware:openai-codex-responses");
});
it("keeps custom session streams labeled as custom", () => {
expect(
describeEmbeddedAgentStreamStrategy({
currentStreamFn: vi.fn() as never,
shouldUseWebSocketTransport: false,
model: {
api: "openai-responses",
provider: "openai",
id: "gpt-5.4",
} as never,
}),
).toBe("session-custom");
});
});
describe("resolveEmbeddedAgentStreamFn", () => {
it("prefers the resolved run api key over a later authStorage lookup", async () => {
const authStorage = {
getApiKey: vi.fn(async () => "storage-key"),
};
await expect(
resolveEmbeddedAgentApiKey({
provider: "openai",
resolvedApiKey: "resolved-key",
authStorage,
}),
).resolves.toBe("resolved-key");
expect(authStorage.getApiKey).not.toHaveBeenCalled();
});
it("still routes supported streamSimple fallbacks through boundary-aware transports", () => {
const streamFn = resolveEmbeddedAgentStreamFn({
currentStreamFn: undefined,
shouldUseWebSocketTransport: false,
sessionId: "session-1",
model: {
api: "openai-responses",
provider: "openai",
id: "gpt-5.4",
} as never,
});
expect(streamFn).not.toBe(streamSimple);
});
it("routes Codex responses fallbacks through boundary-aware transports", () => {
const streamFn = resolveEmbeddedAgentStreamFn({
currentStreamFn: undefined,
shouldUseWebSocketTransport: false,
sessionId: "session-1",
model: {
api: "openai-codex-responses",
provider: "openai-codex",
id: "codex-mini-latest",
} as never,
});
expect(streamFn).not.toBe(streamSimple);
});
it("injects the resolved run api key into provider-owned stream functions", async () => {
const providerStreamFn = vi.fn(async (_model, _context, options) => options);
const authStorage = {
getApiKey: vi.fn(async () => "storage-key"),
};
const streamFn = resolveEmbeddedAgentStreamFn({
currentStreamFn: undefined,
providerStreamFn,
shouldUseWebSocketTransport: false,
sessionId: "session-1",
model: {
api: "openai-completions",
provider: "openai",
id: "gpt-5.4",
} as never,
resolvedApiKey: "resolved-key",
authStorage,
});
await expect(
streamFn({ provider: "openai", id: "gpt-5.4" } as never, {} as never, {}),
).resolves.toMatchObject({
apiKey: "resolved-key",
});
expect(authStorage.getApiKey).not.toHaveBeenCalled();
expect(providerStreamFn).toHaveBeenCalledTimes(1);
});
});