From 222b2d7c3c6174ee31a17fbc0668acf5f1dc5e08 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 14 Feb 2026 18:37:15 +0000 Subject: [PATCH] refactor(test): trim pi-embedded-runner e2e scaffolding --- ...ner.applygoogleturnorderingfix.e2e.test.ts | 98 +--------------- ...unner.buildembeddedsandboxinfo.e2e.test.ts | 101 +---------------- ...ner.createsystempromptoverride.e2e.test.ts | 100 +--------------- ...ck-provider-default-per-dm-not.e2e.test.ts | 98 +--------------- ...efined-sessionkey-is-undefined.e2e.test.ts | 98 +--------------- ...edded-runner.limithistoryturns.e2e.test.ts | 107 ++---------------- ...-runner.resolvesessionagentids.e2e.test.ts | 102 +---------------- ...-embedded-runner.splitsdktools.e2e.test.ts | 100 +--------------- 8 files changed, 24 insertions(+), 780 deletions(-) diff --git a/src/agents/pi-embedded-runner.applygoogleturnorderingfix.e2e.test.ts b/src/agents/pi-embedded-runner.applygoogleturnorderingfix.e2e.test.ts index 0ca26b54672..8194b167223 100644 --- a/src/agents/pi-embedded-runner.applygoogleturnorderingfix.e2e.test.ts +++ b/src/agents/pi-embedded-runner.applygoogleturnorderingfix.e2e.test.ts @@ -1,105 +1,8 @@ import type { AgentMessage } from "@mariozechner/pi-agent-core"; import { SessionManager } from "@mariozechner/pi-coding-agent"; -import fs from "node:fs/promises"; import { describe, expect, it, vi } from "vitest"; -import type { OpenClawConfig } from "../config/config.js"; -import { ensureOpenClawModelsJson } from "./models-config.js"; import { applyGoogleTurnOrderingFix } from "./pi-embedded-runner.js"; -vi.mock("@mariozechner/pi-ai", async () => { - const actual = await vi.importActual("@mariozechner/pi-ai"); - return { - ...actual, - streamSimple: (model: { api: string; provider: string; id: string }) => { - if (model.id === "mock-error") { - throw new Error("boom"); - } - const stream = new actual.AssistantMessageEventStream(); - queueMicrotask(() => { - stream.push({ - type: "done", - reason: "stop", - message: { - role: "assistant", - content: [{ type: "text", text: "ok" }], - stopReason: "stop", - api: model.api, - provider: model.provider, - model: model.id, - usage: { - input: 1, - output: 1, - cacheRead: 0, - cacheWrite: 0, - totalTokens: 2, - cost: { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - total: 0, - }, - }, - timestamp: Date.now(), - }, - }); - }); - return stream; - }, - }; -}); - -const _makeOpenAiConfig = (modelIds: string[]) => - ({ - models: { - providers: { - openai: { - api: "openai-responses", - apiKey: "sk-test", - baseUrl: "https://example.com", - models: modelIds.map((id) => ({ - id, - name: `Mock ${id}`, - reasoning: false, - input: ["text"], - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - contextWindow: 16_000, - maxTokens: 2048, - })), - }, - }, - }, - }) satisfies OpenClawConfig; - -const _ensureModels = (cfg: OpenClawConfig, agentDir: string) => - ensureOpenClawModelsJson(cfg, agentDir) as unknown; - -const _textFromContent = (content: unknown) => { - if (typeof content === "string") { - return content; - } - if (Array.isArray(content) && content[0]?.type === "text") { - return (content[0] as { text?: string }).text; - } - return undefined; -}; - -const _readSessionMessages = async (sessionFile: string) => { - const raw = await fs.readFile(sessionFile, "utf-8"); - return raw - .split(/\r?\n/) - .filter(Boolean) - .map( - (line) => - JSON.parse(line) as { - type?: string; - message?: { role?: string; content?: unknown }; - }, - ) - .filter((entry) => entry.type === "message") - .map((entry) => entry.message as { role?: string; content?: unknown }); -}; - describe("applyGoogleTurnOrderingFix", () => { const makeAssistantFirst = () => [ @@ -141,6 +44,7 @@ describe("applyGoogleTurnOrderingFix", () => { }); expect(warn).toHaveBeenCalledTimes(1); }); + it("skips non-Google models", () => { const sessionManager = SessionManager.inMemory(); const warn = vi.fn(); diff --git a/src/agents/pi-embedded-runner.buildembeddedsandboxinfo.e2e.test.ts b/src/agents/pi-embedded-runner.buildembeddedsandboxinfo.e2e.test.ts index f5a29ec8eba..38431f14cf3 100644 --- a/src/agents/pi-embedded-runner.buildembeddedsandboxinfo.e2e.test.ts +++ b/src/agents/pi-embedded-runner.buildembeddedsandboxinfo.e2e.test.ts @@ -1,108 +1,12 @@ -import fs from "node:fs/promises"; -import { describe, expect, it, vi } from "vitest"; -import type { OpenClawConfig } from "../config/config.js"; +import { describe, expect, it } from "vitest"; import type { SandboxContext } from "./sandbox.js"; -import { ensureOpenClawModelsJson } from "./models-config.js"; import { buildEmbeddedSandboxInfo } from "./pi-embedded-runner.js"; -vi.mock("@mariozechner/pi-ai", async () => { - const actual = await vi.importActual("@mariozechner/pi-ai"); - return { - ...actual, - streamSimple: (model: { api: string; provider: string; id: string }) => { - if (model.id === "mock-error") { - throw new Error("boom"); - } - const stream = new actual.AssistantMessageEventStream(); - queueMicrotask(() => { - stream.push({ - type: "done", - reason: "stop", - message: { - role: "assistant", - content: [{ type: "text", text: "ok" }], - stopReason: "stop", - api: model.api, - provider: model.provider, - model: model.id, - usage: { - input: 1, - output: 1, - cacheRead: 0, - cacheWrite: 0, - totalTokens: 2, - cost: { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - total: 0, - }, - }, - timestamp: Date.now(), - }, - }); - }); - return stream; - }, - }; -}); - -const _makeOpenAiConfig = (modelIds: string[]) => - ({ - models: { - providers: { - openai: { - api: "openai-responses", - apiKey: "sk-test", - baseUrl: "https://example.com", - models: modelIds.map((id) => ({ - id, - name: `Mock ${id}`, - reasoning: false, - input: ["text"], - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - contextWindow: 16_000, - maxTokens: 2048, - })), - }, - }, - }, - }) satisfies OpenClawConfig; - -const _ensureModels = (cfg: OpenClawConfig, agentDir: string) => - ensureOpenClawModelsJson(cfg, agentDir) as unknown; - -const _textFromContent = (content: unknown) => { - if (typeof content === "string") { - return content; - } - if (Array.isArray(content) && content[0]?.type === "text") { - return (content[0] as { text?: string }).text; - } - return undefined; -}; - -const _readSessionMessages = async (sessionFile: string) => { - const raw = await fs.readFile(sessionFile, "utf-8"); - return raw - .split(/\r?\n/) - .filter(Boolean) - .map( - (line) => - JSON.parse(line) as { - type?: string; - message?: { role?: string; content?: unknown }; - }, - ) - .filter((entry) => entry.type === "message") - .map((entry) => entry.message as { role?: string; content?: unknown }); -}; - describe("buildEmbeddedSandboxInfo", () => { it("returns undefined when sandbox is missing", () => { expect(buildEmbeddedSandboxInfo()).toBeUndefined(); }); + it("maps sandbox context into prompt info", () => { const sandbox = { enabled: true, @@ -145,6 +49,7 @@ describe("buildEmbeddedSandboxInfo", () => { hostBrowserAllowed: true, }); }); + it("includes elevated info when allowed", () => { const sandbox = { enabled: true, diff --git a/src/agents/pi-embedded-runner.createsystempromptoverride.e2e.test.ts b/src/agents/pi-embedded-runner.createsystempromptoverride.e2e.test.ts index 99eb77c032c..439ba9148a0 100644 --- a/src/agents/pi-embedded-runner.createsystempromptoverride.e2e.test.ts +++ b/src/agents/pi-embedded-runner.createsystempromptoverride.e2e.test.ts @@ -1,108 +1,12 @@ -import fs from "node:fs/promises"; -import { describe, expect, it, vi } from "vitest"; -import type { OpenClawConfig } from "../config/config.js"; -import { ensureOpenClawModelsJson } from "./models-config.js"; +import { describe, expect, it } from "vitest"; import { createSystemPromptOverride } from "./pi-embedded-runner.js"; -vi.mock("@mariozechner/pi-ai", async () => { - const actual = await vi.importActual("@mariozechner/pi-ai"); - return { - ...actual, - streamSimple: (model: { api: string; provider: string; id: string }) => { - if (model.id === "mock-error") { - throw new Error("boom"); - } - const stream = new actual.AssistantMessageEventStream(); - queueMicrotask(() => { - stream.push({ - type: "done", - reason: "stop", - message: { - role: "assistant", - content: [{ type: "text", text: "ok" }], - stopReason: "stop", - api: model.api, - provider: model.provider, - model: model.id, - usage: { - input: 1, - output: 1, - cacheRead: 0, - cacheWrite: 0, - totalTokens: 2, - cost: { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - total: 0, - }, - }, - timestamp: Date.now(), - }, - }); - }); - return stream; - }, - }; -}); - -const _makeOpenAiConfig = (modelIds: string[]) => - ({ - models: { - providers: { - openai: { - api: "openai-responses", - apiKey: "sk-test", - baseUrl: "https://example.com", - models: modelIds.map((id) => ({ - id, - name: `Mock ${id}`, - reasoning: false, - input: ["text"], - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - contextWindow: 16_000, - maxTokens: 2048, - })), - }, - }, - }, - }) satisfies OpenClawConfig; - -const _ensureModels = (cfg: OpenClawConfig, agentDir: string) => - ensureOpenClawModelsJson(cfg, agentDir) as unknown; - -const _textFromContent = (content: unknown) => { - if (typeof content === "string") { - return content; - } - if (Array.isArray(content) && content[0]?.type === "text") { - return (content[0] as { text?: string }).text; - } - return undefined; -}; - -const _readSessionMessages = async (sessionFile: string) => { - const raw = await fs.readFile(sessionFile, "utf-8"); - return raw - .split(/\r?\n/) - .filter(Boolean) - .map( - (line) => - JSON.parse(line) as { - type?: string; - message?: { role?: string; content?: unknown }; - }, - ) - .filter((entry) => entry.type === "message") - .map((entry) => entry.message as { role?: string; content?: unknown }); -}; - describe("createSystemPromptOverride", () => { it("returns the override prompt trimmed", () => { const override = createSystemPromptOverride("OVERRIDE"); expect(override()).toBe("OVERRIDE"); }); + it("returns an empty string for blank overrides", () => { const override = createSystemPromptOverride(" \n "); expect(override()).toBe(""); diff --git a/src/agents/pi-embedded-runner.get-dm-history-limit-from-session-key.falls-back-provider-default-per-dm-not.e2e.test.ts b/src/agents/pi-embedded-runner.get-dm-history-limit-from-session-key.falls-back-provider-default-per-dm-not.e2e.test.ts index f2f74cdd054..9402a9d39a1 100644 --- a/src/agents/pi-embedded-runner.get-dm-history-limit-from-session-key.falls-back-provider-default-per-dm-not.e2e.test.ts +++ b/src/agents/pi-embedded-runner.get-dm-history-limit-from-session-key.falls-back-provider-default-per-dm-not.e2e.test.ts @@ -1,103 +1,7 @@ -import fs from "node:fs/promises"; -import { describe, expect, it, vi } from "vitest"; +import { describe, expect, it } from "vitest"; import type { OpenClawConfig } from "../config/config.js"; -import { ensureOpenClawModelsJson } from "./models-config.js"; import { getDmHistoryLimitFromSessionKey } from "./pi-embedded-runner.js"; -vi.mock("@mariozechner/pi-ai", async () => { - const actual = await vi.importActual("@mariozechner/pi-ai"); - return { - ...actual, - streamSimple: (model: { api: string; provider: string; id: string }) => { - if (model.id === "mock-error") { - throw new Error("boom"); - } - const stream = new actual.AssistantMessageEventStream(); - queueMicrotask(() => { - stream.push({ - type: "done", - reason: "stop", - message: { - role: "assistant", - content: [{ type: "text", text: "ok" }], - stopReason: "stop", - api: model.api, - provider: model.provider, - model: model.id, - usage: { - input: 1, - output: 1, - cacheRead: 0, - cacheWrite: 0, - totalTokens: 2, - cost: { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - total: 0, - }, - }, - timestamp: Date.now(), - }, - }); - }); - return stream; - }, - }; -}); - -const _makeOpenAiConfig = (modelIds: string[]) => - ({ - models: { - providers: { - openai: { - api: "openai-responses", - apiKey: "sk-test", - baseUrl: "https://example.com", - models: modelIds.map((id) => ({ - id, - name: `Mock ${id}`, - reasoning: false, - input: ["text"], - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - contextWindow: 16_000, - maxTokens: 2048, - })), - }, - }, - }, - }) satisfies OpenClawConfig; - -const _ensureModels = (cfg: OpenClawConfig, agentDir: string) => - ensureOpenClawModelsJson(cfg, agentDir); - -const _textFromContent = (content: unknown) => { - if (typeof content === "string") { - return content; - } - if (Array.isArray(content) && content[0]?.type === "text") { - return (content[0] as { text?: string }).text; - } - return undefined; -}; - -const _readSessionMessages = async (sessionFile: string) => { - const raw = await fs.readFile(sessionFile, "utf-8"); - return raw - .split(/\r?\n/) - .filter(Boolean) - .map( - (line) => - JSON.parse(line) as { - type?: string; - message?: { role?: string; content?: unknown }; - }, - ) - .filter((entry) => entry.type === "message") - .map((entry) => entry.message as { role?: string; content?: unknown }); -}; - describe("getDmHistoryLimitFromSessionKey", () => { it("falls back to provider default when per-DM not set", () => { const config = { diff --git a/src/agents/pi-embedded-runner.get-dm-history-limit-from-session-key.returns-undefined-sessionkey-is-undefined.e2e.test.ts b/src/agents/pi-embedded-runner.get-dm-history-limit-from-session-key.returns-undefined-sessionkey-is-undefined.e2e.test.ts index b685f88d499..b5b1017b540 100644 --- a/src/agents/pi-embedded-runner.get-dm-history-limit-from-session-key.returns-undefined-sessionkey-is-undefined.e2e.test.ts +++ b/src/agents/pi-embedded-runner.get-dm-history-limit-from-session-key.returns-undefined-sessionkey-is-undefined.e2e.test.ts @@ -1,103 +1,7 @@ -import fs from "node:fs/promises"; -import { describe, expect, it, vi } from "vitest"; +import { describe, expect, it } from "vitest"; import type { OpenClawConfig } from "../config/config.js"; -import { ensureOpenClawModelsJson } from "./models-config.js"; import { getDmHistoryLimitFromSessionKey } from "./pi-embedded-runner.js"; -vi.mock("@mariozechner/pi-ai", async () => { - const actual = await vi.importActual("@mariozechner/pi-ai"); - return { - ...actual, - streamSimple: (model: { api: string; provider: string; id: string }) => { - if (model.id === "mock-error") { - throw new Error("boom"); - } - const stream = new actual.AssistantMessageEventStream(); - queueMicrotask(() => { - stream.push({ - type: "done", - reason: "stop", - message: { - role: "assistant", - content: [{ type: "text", text: "ok" }], - stopReason: "stop", - api: model.api, - provider: model.provider, - model: model.id, - usage: { - input: 1, - output: 1, - cacheRead: 0, - cacheWrite: 0, - totalTokens: 2, - cost: { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - total: 0, - }, - }, - timestamp: Date.now(), - }, - }); - }); - return stream; - }, - }; -}); - -const _makeOpenAiConfig = (modelIds: string[]) => - ({ - models: { - providers: { - openai: { - api: "openai-responses", - apiKey: "sk-test", - baseUrl: "https://example.com", - models: modelIds.map((id) => ({ - id, - name: `Mock ${id}`, - reasoning: false, - input: ["text"], - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - contextWindow: 16_000, - maxTokens: 2048, - })), - }, - }, - }, - }) satisfies OpenClawConfig; - -const _ensureModels = (cfg: OpenClawConfig, agentDir: string) => - ensureOpenClawModelsJson(cfg, agentDir) as unknown; - -const _textFromContent = (content: unknown) => { - if (typeof content === "string") { - return content; - } - if (Array.isArray(content) && content[0]?.type === "text") { - return (content[0] as { text?: string }).text; - } - return undefined; -}; - -const _readSessionMessages = async (sessionFile: string) => { - const raw = await fs.readFile(sessionFile, "utf-8"); - return raw - .split(/\r?\n/) - .filter(Boolean) - .map( - (line) => - JSON.parse(line) as { - type?: string; - message?: { role?: string; content?: unknown }; - }, - ) - .filter((entry) => entry.type === "message") - .map((entry) => entry.message as { role?: string; content?: unknown }); -}; - describe("getDmHistoryLimitFromSessionKey", () => { it("returns undefined when sessionKey is undefined", () => { expect(getDmHistoryLimitFromSessionKey(undefined, {})).toBeUndefined(); diff --git a/src/agents/pi-embedded-runner.limithistoryturns.e2e.test.ts b/src/agents/pi-embedded-runner.limithistoryturns.e2e.test.ts index c5ce7979471..37fd3f09ec2 100644 --- a/src/agents/pi-embedded-runner.limithistoryturns.e2e.test.ts +++ b/src/agents/pi-embedded-runner.limithistoryturns.e2e.test.ts @@ -1,104 +1,7 @@ import type { AgentMessage } from "@mariozechner/pi-agent-core"; -import fs from "node:fs/promises"; -import { describe, expect, it, vi } from "vitest"; -import type { OpenClawConfig } from "../config/config.js"; -import { ensureOpenClawModelsJson } from "./models-config.js"; +import { describe, expect, it } from "vitest"; import { limitHistoryTurns } from "./pi-embedded-runner.js"; -vi.mock("@mariozechner/pi-ai", async () => { - const actual = await vi.importActual("@mariozechner/pi-ai"); - return { - ...actual, - streamSimple: (model: { api: string; provider: string; id: string }) => { - if (model.id === "mock-error") { - throw new Error("boom"); - } - const stream = new actual.AssistantMessageEventStream(); - queueMicrotask(() => { - stream.push({ - type: "done", - reason: "stop", - message: { - role: "assistant", - content: [{ type: "text", text: "ok" }], - stopReason: "stop", - api: model.api, - provider: model.provider, - model: model.id, - usage: { - input: 1, - output: 1, - cacheRead: 0, - cacheWrite: 0, - totalTokens: 2, - cost: { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - total: 0, - }, - }, - timestamp: Date.now(), - }, - }); - }); - return stream; - }, - }; -}); - -const _makeOpenAiConfig = (modelIds: string[]) => - ({ - models: { - providers: { - openai: { - api: "openai-responses", - apiKey: "sk-test", - baseUrl: "https://example.com", - models: modelIds.map((id) => ({ - id, - name: `Mock ${id}`, - reasoning: false, - input: ["text"], - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - contextWindow: 16_000, - maxTokens: 2048, - })), - }, - }, - }, - }) satisfies OpenClawConfig; - -const _ensureModels = (cfg: OpenClawConfig, agentDir: string) => - ensureOpenClawModelsJson(cfg, agentDir) as unknown; - -const _textFromContent = (content: unknown) => { - if (typeof content === "string") { - return content; - } - if (Array.isArray(content) && content[0]?.type === "text") { - return (content[0] as { text?: string }).text; - } - return undefined; -}; - -const _readSessionMessages = async (sessionFile: string) => { - const raw = await fs.readFile(sessionFile, "utf-8"); - return raw - .split(/\r?\n/) - .filter(Boolean) - .map( - (line) => - JSON.parse(line) as { - type?: string; - message?: { role?: string; content?: unknown }; - }, - ) - .filter((entry) => entry.type === "message") - .map((entry) => entry.message as { role?: string; content?: unknown }); -}; - describe("limitHistoryTurns", () => { const makeMessages = (roles: ("user" | "assistant")[]): AgentMessage[] => roles.map((role, i) => ({ @@ -110,27 +13,33 @@ describe("limitHistoryTurns", () => { const messages = makeMessages(["user", "assistant", "user", "assistant"]); expect(limitHistoryTurns(messages, undefined)).toBe(messages); }); + it("returns all messages when limit is 0", () => { const messages = makeMessages(["user", "assistant", "user", "assistant"]); expect(limitHistoryTurns(messages, 0)).toBe(messages); }); + it("returns all messages when limit is negative", () => { const messages = makeMessages(["user", "assistant", "user", "assistant"]); expect(limitHistoryTurns(messages, -1)).toBe(messages); }); + it("returns empty array when messages is empty", () => { expect(limitHistoryTurns([], 5)).toEqual([]); }); + it("keeps all messages when fewer user turns than limit", () => { const messages = makeMessages(["user", "assistant", "user", "assistant"]); expect(limitHistoryTurns(messages, 10)).toBe(messages); }); + it("limits to last N user turns", () => { const messages = makeMessages(["user", "assistant", "user", "assistant", "user", "assistant"]); const limited = limitHistoryTurns(messages, 2); expect(limited.length).toBe(4); expect(limited[0].content).toEqual([{ type: "text", text: "message 2" }]); }); + it("handles single user turn limit", () => { const messages = makeMessages(["user", "assistant", "user", "assistant", "user", "assistant"]); const limited = limitHistoryTurns(messages, 1); @@ -138,6 +47,7 @@ describe("limitHistoryTurns", () => { expect(limited[0].content).toEqual([{ type: "text", text: "message 4" }]); expect(limited[1].content).toEqual([{ type: "text", text: "message 5" }]); }); + it("handles messages with multiple assistant responses per user turn", () => { const messages = makeMessages(["user", "assistant", "assistant", "user", "assistant"]); const limited = limitHistoryTurns(messages, 1); @@ -145,6 +55,7 @@ describe("limitHistoryTurns", () => { expect(limited[0].role).toBe("user"); expect(limited[1].role).toBe("assistant"); }); + it("preserves message content integrity", () => { const messages: AgentMessage[] = [ { role: "user", content: [{ type: "text", text: "first" }] }, diff --git a/src/agents/pi-embedded-runner.resolvesessionagentids.e2e.test.ts b/src/agents/pi-embedded-runner.resolvesessionagentids.e2e.test.ts index 8151e086757..931ec280949 100644 --- a/src/agents/pi-embedded-runner.resolvesessionagentids.e2e.test.ts +++ b/src/agents/pi-embedded-runner.resolvesessionagentids.e2e.test.ts @@ -1,102 +1,6 @@ -import fs from "node:fs/promises"; -import { describe, expect, it, vi } from "vitest"; +import { describe, expect, it } from "vitest"; import type { OpenClawConfig } from "../config/config.js"; import { resolveSessionAgentIds } from "./agent-scope.js"; -import { ensureOpenClawModelsJson } from "./models-config.js"; - -vi.mock("@mariozechner/pi-ai", async () => { - const actual = await vi.importActual("@mariozechner/pi-ai"); - return { - ...actual, - streamSimple: (model: { api: string; provider: string; id: string }) => { - if (model.id === "mock-error") { - throw new Error("boom"); - } - const stream = new actual.AssistantMessageEventStream(); - queueMicrotask(() => { - stream.push({ - type: "done", - reason: "stop", - message: { - role: "assistant", - content: [{ type: "text", text: "ok" }], - stopReason: "stop", - api: model.api, - provider: model.provider, - model: model.id, - usage: { - input: 1, - output: 1, - cacheRead: 0, - cacheWrite: 0, - totalTokens: 2, - cost: { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - total: 0, - }, - }, - timestamp: Date.now(), - }, - }); - }); - return stream; - }, - }; -}); - -const _makeOpenAiConfig = (modelIds: string[]) => - ({ - models: { - providers: { - openai: { - api: "openai-responses", - apiKey: "sk-test", - baseUrl: "https://example.com", - models: modelIds.map((id) => ({ - id, - name: `Mock ${id}`, - reasoning: false, - input: ["text"], - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - contextWindow: 16_000, - maxTokens: 2048, - })), - }, - }, - }, - }) satisfies OpenClawConfig; - -const _ensureModels = (cfg: OpenClawConfig, agentDir: string) => - ensureOpenClawModelsJson(cfg, agentDir) as unknown; - -const _textFromContent = (content: unknown) => { - if (typeof content === "string") { - return content; - } - if (Array.isArray(content) && content[0]?.type === "text") { - return (content[0] as { text?: string }).text; - } - return undefined; -}; - -const _readSessionMessages = async (sessionFile: string) => { - const raw = await fs.readFile(sessionFile, "utf-8"); - return raw - .split(/\r?\n/) - .filter(Boolean) - .map( - (line) => - JSON.parse(line) as { - type?: string; - message?: { role?: string; content?: unknown }; - }, - ) - .filter((entry) => entry.type === "message") - .map((entry) => entry.message as { role?: string; content?: unknown }); -}; describe("resolveSessionAgentIds", () => { const cfg = { @@ -112,6 +16,7 @@ describe("resolveSessionAgentIds", () => { expect(defaultAgentId).toBe("beta"); expect(sessionAgentId).toBe("beta"); }); + it("falls back to the configured default when sessionKey is non-agent", () => { const { sessionAgentId } = resolveSessionAgentIds({ sessionKey: "telegram:slash:123", @@ -119,6 +24,7 @@ describe("resolveSessionAgentIds", () => { }); expect(sessionAgentId).toBe("beta"); }); + it("falls back to the configured default for global sessions", () => { const { sessionAgentId } = resolveSessionAgentIds({ sessionKey: "global", @@ -126,6 +32,7 @@ describe("resolveSessionAgentIds", () => { }); expect(sessionAgentId).toBe("beta"); }); + it("keeps the agent id for provider-qualified agent sessions", () => { const { sessionAgentId } = resolveSessionAgentIds({ sessionKey: "agent:beta:slack:channel:c1", @@ -133,6 +40,7 @@ describe("resolveSessionAgentIds", () => { }); expect(sessionAgentId).toBe("beta"); }); + it("uses the agent id from agent session keys", () => { const { sessionAgentId } = resolveSessionAgentIds({ sessionKey: "agent:main:main", diff --git a/src/agents/pi-embedded-runner.splitsdktools.e2e.test.ts b/src/agents/pi-embedded-runner.splitsdktools.e2e.test.ts index 258d10b683c..6195e3b812d 100644 --- a/src/agents/pi-embedded-runner.splitsdktools.e2e.test.ts +++ b/src/agents/pi-embedded-runner.splitsdktools.e2e.test.ts @@ -1,104 +1,7 @@ import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core"; -import fs from "node:fs/promises"; -import { describe, expect, it, vi } from "vitest"; -import type { OpenClawConfig } from "../config/config.js"; -import { ensureOpenClawModelsJson } from "./models-config.js"; +import { describe, expect, it } from "vitest"; import { splitSdkTools } from "./pi-embedded-runner.js"; -vi.mock("@mariozechner/pi-ai", async () => { - const actual = await vi.importActual("@mariozechner/pi-ai"); - return { - ...actual, - streamSimple: (model: { api: string; provider: string; id: string }) => { - if (model.id === "mock-error") { - throw new Error("boom"); - } - const stream = new actual.AssistantMessageEventStream(); - queueMicrotask(() => { - stream.push({ - type: "done", - reason: "stop", - message: { - role: "assistant", - content: [{ type: "text", text: "ok" }], - stopReason: "stop", - api: model.api, - provider: model.provider, - model: model.id, - usage: { - input: 1, - output: 1, - cacheRead: 0, - cacheWrite: 0, - totalTokens: 2, - cost: { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - total: 0, - }, - }, - timestamp: Date.now(), - }, - }); - }); - return stream; - }, - }; -}); - -const _makeOpenAiConfig = (modelIds: string[]) => - ({ - models: { - providers: { - openai: { - api: "openai-responses", - apiKey: "sk-test", - baseUrl: "https://example.com", - models: modelIds.map((id) => ({ - id, - name: `Mock ${id}`, - reasoning: false, - input: ["text"], - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - contextWindow: 16_000, - maxTokens: 2048, - })), - }, - }, - }, - }) satisfies OpenClawConfig; - -const _ensureModels = (cfg: OpenClawConfig, agentDir: string) => - ensureOpenClawModelsJson(cfg, agentDir) as unknown; - -const _textFromContent = (content: unknown) => { - if (typeof content === "string") { - return content; - } - if (Array.isArray(content) && content[0]?.type === "text") { - return (content[0] as { text?: string }).text; - } - return undefined; -}; - -const _readSessionMessages = async (sessionFile: string) => { - const raw = await fs.readFile(sessionFile, "utf-8"); - return raw - .split(/\r?\n/) - .filter(Boolean) - .map( - (line) => - JSON.parse(line) as { - type?: string; - message?: { role?: string; content?: unknown }; - }, - ) - .filter((entry) => entry.type === "message") - .map((entry) => entry.message as { role?: string; content?: unknown }); -}; - function createStubTool(name: string): AgentTool { return { name, @@ -132,6 +35,7 @@ describe("splitSdkTools", () => { "browser", ]); }); + it("routes all tools to customTools even when not sandboxed", () => { const { builtInTools, customTools } = splitSdkTools({ tools,