diff --git a/src/agents/pi-embedded-runner/run.overflow-compaction.e2e.test.ts b/src/agents/pi-embedded-runner/run.overflow-compaction.e2e.test.ts index 12df89495..d9ce20b07 100644 --- a/src/agents/pi-embedded-runner/run.overflow-compaction.e2e.test.ts +++ b/src/agents/pi-embedded-runner/run.overflow-compaction.e2e.test.ts @@ -1,91 +1,16 @@ -import { describe, expect, it, vi, beforeEach } from "vitest"; - -vi.mock("./run/attempt.js", () => ({ - runEmbeddedAttempt: vi.fn(), -})); - -vi.mock("./compact.js", () => ({ - compactEmbeddedPiSessionDirect: vi.fn(), -})); - -vi.mock("./model.js", () => ({ - resolveModel: vi.fn(() => ({ - model: { - id: "test-model", - provider: "anthropic", - contextWindow: 200000, - api: "messages", - }, - error: null, - authStorage: { - setRuntimeApiKey: vi.fn(), - }, - modelRegistry: {}, - })), -})); - -vi.mock("../model-auth.js", () => ({ - ensureAuthProfileStore: vi.fn(() => ({})), - getApiKeyForModel: vi.fn(async () => ({ - apiKey: "test-key", - profileId: "test-profile", - source: "test", - })), - resolveAuthProfileOrder: vi.fn(() => []), -})); - -vi.mock("../models-config.js", () => ({ - ensureOpenClawModelsJson: vi.fn(async () => {}), -})); - -vi.mock("../context-window-guard.js", () => ({ - CONTEXT_WINDOW_HARD_MIN_TOKENS: 1000, - CONTEXT_WINDOW_WARN_BELOW_TOKENS: 5000, - evaluateContextWindowGuard: vi.fn(() => ({ - shouldWarn: false, - shouldBlock: false, - tokens: 200000, - source: "model", - })), - resolveContextWindowInfo: vi.fn(() => ({ - tokens: 200000, - source: "model", - })), -})); - -vi.mock("../../process/command-queue.js", () => ({ - enqueueCommandInLane: vi.fn((_lane: string, task: () => unknown) => task()), -})); +import "./run.overflow-compaction.mocks.shared.js"; +import { beforeEach, describe, expect, it, vi } from "vitest"; vi.mock("../../utils.js", () => ({ resolveUserPath: vi.fn((p: string) => p), })); -vi.mock("../../utils/message-channel.js", () => ({ - isMarkdownCapableMessageChannel: vi.fn(() => true), -})); - -vi.mock("../agent-paths.js", () => ({ - resolveOpenClawAgentDir: vi.fn(() => "/tmp/agent-dir"), -})); - vi.mock("../auth-profiles.js", () => ({ markAuthProfileFailure: vi.fn(async () => {}), markAuthProfileGood: vi.fn(async () => {}), markAuthProfileUsed: vi.fn(async () => {}), })); -vi.mock("../defaults.js", () => ({ - DEFAULT_CONTEXT_TOKENS: 200000, - DEFAULT_MODEL: "test-model", - DEFAULT_PROVIDER: "anthropic", -})); - -vi.mock("../failover-error.js", () => ({ - FailoverError: class extends Error {}, - resolveFailoverStatus: vi.fn(), -})); - vi.mock("../usage.js", () => ({ normalizeUsage: vi.fn((usage?: unknown) => usage && typeof usage === "object" ? usage : undefined, @@ -105,43 +30,6 @@ vi.mock("../usage.js", () => ({ hasNonzeroUsage: vi.fn(() => false), })); -vi.mock("./lanes.js", () => ({ - resolveSessionLane: vi.fn(() => "session-lane"), - resolveGlobalLane: vi.fn(() => "global-lane"), -})); - -vi.mock("./logger.js", () => ({ - log: { - debug: vi.fn(), - info: vi.fn(), - warn: vi.fn(), - error: vi.fn(), - isEnabled: vi.fn(() => false), - }, -})); - -vi.mock("./run/payloads.js", () => ({ - buildEmbeddedRunPayloads: vi.fn(() => []), -})); - -vi.mock("./tool-result-truncation.js", () => ({ - truncateOversizedToolResultsInSession: vi.fn(async () => ({ - truncated: false, - truncatedCount: 0, - reason: "no oversized tool results", - })), - sessionLikelyHasOversizedToolResults: vi.fn(() => false), -})); - -vi.mock("./utils.js", () => ({ - describeUnknownError: vi.fn((err: unknown) => { - if (err instanceof Error) { - return err.message; - } - return String(err); - }), -})); - vi.mock("../pi-embedded-helpers.js", async () => { return { isCompactionFailureError: (msg?: string) => { @@ -184,10 +72,10 @@ vi.mock("../pi-embedded-helpers.js", async () => { }; }); -import type { EmbeddedRunAttemptResult } from "./run/types.js"; import { compactEmbeddedPiSessionDirect } from "./compact.js"; import { log } from "./logger.js"; import { runEmbeddedPiAgent } from "./run.js"; +import { makeAttemptResult } from "./run.overflow-compaction.fixture.js"; import { runEmbeddedAttempt } from "./run/attempt.js"; import { sessionLikelyHasOversizedToolResults, @@ -201,27 +89,6 @@ const mockedTruncateOversizedToolResultsInSession = vi.mocked( truncateOversizedToolResultsInSession, ); -function makeAttemptResult( - overrides: Partial = {}, -): EmbeddedRunAttemptResult { - return { - aborted: false, - timedOut: false, - timedOutDuringCompaction: false, - promptError: null, - sessionIdUsed: "test-session", - assistantTexts: ["Hello!"], - toolMetas: [], - lastAssistant: undefined, - messagesSnapshot: [], - didSendViaMessagingTool: false, - messagingToolSentTexts: [], - messagingToolSentTargets: [], - cloudCodeAssistFormatError: false, - ...overrides, - }; -} - const baseParams = { sessionId: "test-session", sessionKey: "test-key", diff --git a/src/agents/pi-embedded-runner/run.overflow-compaction.fixture.ts b/src/agents/pi-embedded-runner/run.overflow-compaction.fixture.ts new file mode 100644 index 000000000..2ba720f2a --- /dev/null +++ b/src/agents/pi-embedded-runner/run.overflow-compaction.fixture.ts @@ -0,0 +1,22 @@ +import type { EmbeddedRunAttemptResult } from "./run/types.js"; + +export function makeAttemptResult( + overrides: Partial = {}, +): EmbeddedRunAttemptResult { + return { + aborted: false, + timedOut: false, + timedOutDuringCompaction: false, + promptError: null, + sessionIdUsed: "test-session", + assistantTexts: ["Hello!"], + toolMetas: [], + lastAssistant: undefined, + messagesSnapshot: [], + didSendViaMessagingTool: false, + messagingToolSentTexts: [], + messagingToolSentTargets: [], + cloudCodeAssistFormatError: false, + ...overrides, + }; +} diff --git a/src/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.ts b/src/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.ts new file mode 100644 index 000000000..407788564 --- /dev/null +++ b/src/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.ts @@ -0,0 +1,114 @@ +import { vi } from "vitest"; + +vi.mock("./run/attempt.js", () => ({ + runEmbeddedAttempt: vi.fn(), +})); + +vi.mock("./compact.js", () => ({ + compactEmbeddedPiSessionDirect: vi.fn(), +})); + +vi.mock("./model.js", () => ({ + resolveModel: vi.fn(() => ({ + model: { + id: "test-model", + provider: "anthropic", + contextWindow: 200000, + api: "messages", + }, + error: null, + authStorage: { + setRuntimeApiKey: vi.fn(), + }, + modelRegistry: {}, + })), +})); + +vi.mock("../model-auth.js", () => ({ + ensureAuthProfileStore: vi.fn(() => ({})), + getApiKeyForModel: vi.fn(async () => ({ + apiKey: "test-key", + profileId: "test-profile", + source: "test", + })), + resolveAuthProfileOrder: vi.fn(() => []), +})); + +vi.mock("../models-config.js", () => ({ + ensureOpenClawModelsJson: vi.fn(async () => {}), +})); + +vi.mock("../context-window-guard.js", () => ({ + CONTEXT_WINDOW_HARD_MIN_TOKENS: 1000, + CONTEXT_WINDOW_WARN_BELOW_TOKENS: 5000, + evaluateContextWindowGuard: vi.fn(() => ({ + shouldWarn: false, + shouldBlock: false, + tokens: 200000, + source: "model", + })), + resolveContextWindowInfo: vi.fn(() => ({ + tokens: 200000, + source: "model", + })), +})); + +vi.mock("../../process/command-queue.js", () => ({ + enqueueCommandInLane: vi.fn((_lane: string, task: () => unknown) => task()), +})); + +vi.mock("../../utils/message-channel.js", () => ({ + isMarkdownCapableMessageChannel: vi.fn(() => true), +})); + +vi.mock("../agent-paths.js", () => ({ + resolveOpenClawAgentDir: vi.fn(() => "/tmp/agent-dir"), +})); + +vi.mock("../defaults.js", () => ({ + DEFAULT_CONTEXT_TOKENS: 200000, + DEFAULT_MODEL: "test-model", + DEFAULT_PROVIDER: "anthropic", +})); + +vi.mock("../failover-error.js", () => ({ + FailoverError: class extends Error {}, + resolveFailoverStatus: vi.fn(), +})); + +vi.mock("./lanes.js", () => ({ + resolveSessionLane: vi.fn(() => "session-lane"), + resolveGlobalLane: vi.fn(() => "global-lane"), +})); + +vi.mock("./logger.js", () => ({ + log: { + debug: vi.fn(), + info: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + isEnabled: vi.fn(() => false), + }, +})); + +vi.mock("./run/payloads.js", () => ({ + buildEmbeddedRunPayloads: vi.fn(() => []), +})); + +vi.mock("./tool-result-truncation.js", () => ({ + truncateOversizedToolResultsInSession: vi.fn(async () => ({ + truncated: false, + truncatedCount: 0, + reason: "no oversized tool results", + })), + sessionLikelyHasOversizedToolResults: vi.fn(() => false), +})); + +vi.mock("./utils.js", () => ({ + describeUnknownError: vi.fn((err: unknown) => { + if (err instanceof Error) { + return err.message; + } + return String(err); + }), +})); diff --git a/src/agents/pi-embedded-runner/run.overflow-compaction.test.ts b/src/agents/pi-embedded-runner/run.overflow-compaction.test.ts index 1a2c29791..ded9da42c 100644 --- a/src/agents/pi-embedded-runner/run.overflow-compaction.test.ts +++ b/src/agents/pi-embedded-runner/run.overflow-compaction.test.ts @@ -1,70 +1,6 @@ +import "./run.overflow-compaction.mocks.shared.js"; import { beforeEach, describe, expect, it, vi } from "vitest"; -vi.mock("./run/attempt.js", () => ({ - runEmbeddedAttempt: vi.fn(), -})); - -vi.mock("./compact.js", () => ({ - compactEmbeddedPiSessionDirect: vi.fn(), -})); - -vi.mock("./model.js", () => ({ - resolveModel: vi.fn(() => ({ - model: { - id: "test-model", - provider: "anthropic", - contextWindow: 200000, - api: "messages", - }, - error: null, - authStorage: { - setRuntimeApiKey: vi.fn(), - }, - modelRegistry: {}, - })), -})); - -vi.mock("../model-auth.js", () => ({ - ensureAuthProfileStore: vi.fn(() => ({})), - getApiKeyForModel: vi.fn(async () => ({ - apiKey: "test-key", - profileId: "test-profile", - source: "test", - })), - resolveAuthProfileOrder: vi.fn(() => []), -})); - -vi.mock("../models-config.js", () => ({ - ensureOpenClawModelsJson: vi.fn(async () => {}), -})); - -vi.mock("../context-window-guard.js", () => ({ - CONTEXT_WINDOW_HARD_MIN_TOKENS: 1000, - CONTEXT_WINDOW_WARN_BELOW_TOKENS: 5000, - evaluateContextWindowGuard: vi.fn(() => ({ - shouldWarn: false, - shouldBlock: false, - tokens: 200000, - source: "model", - })), - resolveContextWindowInfo: vi.fn(() => ({ - tokens: 200000, - source: "model", - })), -})); - -vi.mock("../../process/command-queue.js", () => ({ - enqueueCommandInLane: vi.fn((_lane: string, task: () => unknown) => task()), -})); - -vi.mock("../../utils/message-channel.js", () => ({ - isMarkdownCapableMessageChannel: vi.fn(() => true), -})); - -vi.mock("../agent-paths.js", () => ({ - resolveOpenClawAgentDir: vi.fn(() => "/tmp/agent-dir"), -})); - vi.mock("../auth-profiles.js", () => ({ isProfileInCooldown: vi.fn(() => false), markAuthProfileFailure: vi.fn(async () => {}), @@ -72,17 +8,6 @@ vi.mock("../auth-profiles.js", () => ({ markAuthProfileUsed: vi.fn(async () => {}), })); -vi.mock("../defaults.js", () => ({ - DEFAULT_CONTEXT_TOKENS: 200000, - DEFAULT_MODEL: "test-model", - DEFAULT_PROVIDER: "anthropic", -})); - -vi.mock("../failover-error.js", () => ({ - FailoverError: class extends Error {}, - resolveFailoverStatus: vi.fn(), -})); - vi.mock("../usage.js", () => ({ normalizeUsage: vi.fn((usage?: unknown) => usage && typeof usage === "object" ? usage : undefined, @@ -111,43 +36,6 @@ vi.mock("../workspace-run.js", () => ({ redactRunIdentifier: vi.fn((value?: string) => value ?? ""), })); -vi.mock("./lanes.js", () => ({ - resolveSessionLane: vi.fn(() => "session-lane"), - resolveGlobalLane: vi.fn(() => "global-lane"), -})); - -vi.mock("./logger.js", () => ({ - log: { - debug: vi.fn(), - info: vi.fn(), - warn: vi.fn(), - error: vi.fn(), - isEnabled: vi.fn(() => false), - }, -})); - -vi.mock("./run/payloads.js", () => ({ - buildEmbeddedRunPayloads: vi.fn(() => []), -})); - -vi.mock("./tool-result-truncation.js", () => ({ - truncateOversizedToolResultsInSession: vi.fn(async () => ({ - truncated: false, - truncatedCount: 0, - reason: "no oversized tool results", - })), - sessionLikelyHasOversizedToolResults: vi.fn(() => false), -})); - -vi.mock("./utils.js", () => ({ - describeUnknownError: vi.fn((err: unknown) => { - if (err instanceof Error) { - return err.message; - } - return String(err); - }), -})); - vi.mock("../pi-embedded-helpers.js", () => ({ formatBillingErrorMessage: vi.fn(() => ""), classifyFailoverReason: vi.fn(() => null), @@ -168,35 +56,14 @@ vi.mock("../pi-embedded-helpers.js", () => ({ pickFallbackThinkingLevel: vi.fn(() => null), })); -import type { EmbeddedRunAttemptResult } from "./run/types.js"; import { compactEmbeddedPiSessionDirect } from "./compact.js"; import { runEmbeddedPiAgent } from "./run.js"; +import { makeAttemptResult } from "./run.overflow-compaction.fixture.js"; import { runEmbeddedAttempt } from "./run/attempt.js"; const mockedRunEmbeddedAttempt = vi.mocked(runEmbeddedAttempt); const mockedCompactDirect = vi.mocked(compactEmbeddedPiSessionDirect); -function makeAttemptResult( - overrides: Partial = {}, -): EmbeddedRunAttemptResult { - return { - aborted: false, - timedOut: false, - timedOutDuringCompaction: false, - promptError: null, - sessionIdUsed: "test-session", - assistantTexts: ["Hello!"], - toolMetas: [], - lastAssistant: undefined, - messagesSnapshot: [], - didSendViaMessagingTool: false, - messagingToolSentTexts: [], - messagingToolSentTargets: [], - cloudCodeAssistFormatError: false, - ...overrides, - }; -} - describe("runEmbeddedPiAgent overflow compaction trigger routing", () => { beforeEach(() => { vi.clearAllMocks();