

























@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
22import path from "node:path";
33import type { AgentMessage } from "@mariozechner/pi-agent-core";
44import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5+import type { OpenClawConfig } from "../../../config/types.js";
56import { buildMemorySystemPromptAddition } from "../../../context-engine/delegate.js";
67import {
78clearMemoryPluginState,
@@ -29,6 +30,7 @@ import {
2930buildEmbeddedSubscriptionParams,
3031cleanupEmbeddedAttemptResources,
3132} from "./attempt.subscription-cleanup.js";
33+import type { MidTurnPrecheckRequest } from "./midturn-precheck.js";
32343335const hoisted = getHoisted();
3436const embeddedSessionId = "embedded-session";
@@ -37,6 +39,11 @@ const seedMessage = { role: "user", content: "seed", timestamp: 1 } as AgentMess
3739const doneMessage = { role: "assistant", content: "done", timestamp: 2 } as unknown as AgentMessage;
3840type AfterTurnPromptCacheCall = { runtimeContext?: { promptCache?: Record<string, unknown> } };
3941type TrajectoryEvent = { type?: string; data?: Record<string, unknown> };
42+type ToolResultGuardInstallParams = {
43+midTurnPrecheck?: {
44+onMidTurnPrecheck?: (request: MidTurnPrecheckRequest) => void;
45+};
46+};
40474148function createTestContextEngine(params: Partial<AttemptContextEngine>): AttemptContextEngine {
4249return {
@@ -770,3 +777,95 @@ describe("runEmbeddedAttempt context engine sessionKey forwarding", () => {
770777});
771778});
772779});
780+781+describe("runEmbeddedAttempt context engine mid-turn precheck integration", () => {
782+const sessionKey = "agent:main:guildchat:channel:midturn-precheck";
783+const tempPaths: string[] = [];
784+785+beforeEach(() => {
786+resetEmbeddedAttemptHarness();
787+clearMemoryPluginState();
788+});
789+790+afterEach(async () => {
791+await cleanupTempPaths(tempPaths);
792+clearMemoryPluginState();
793+vi.restoreAllMocks();
794+});
795+796+it("keeps mid-turn precheck out of the context-engine-owned compaction hook", async () => {
797+await createContextEngineAttemptRunner({
798+contextEngine: {
799+ ...createContextEngineBootstrapAndAssemble(),
800+info: { ownsCompaction: true },
801+},
802+ sessionKey,
803+ tempPaths,
804+attemptOverrides: {
805+config: {
806+agents: {
807+defaults: {
808+compaction: {
809+mode: "safeguard",
810+midTurnPrecheck: { enabled: true },
811+},
812+},
813+},
814+} as OpenClawConfig,
815+},
816+});
817+818+expect(hoisted.installContextEngineLoopHookMock).toHaveBeenCalledWith(
819+expect.not.objectContaining({ midTurnPrecheck: expect.anything() }),
820+);
821+});
822+823+it("recovers when Pi persists the mid-turn precheck as an assistant error", async () => {
824+hoisted.installToolResultContextGuardMock.mockImplementation((...args: unknown[]) => {
825+const params = args[0] as ToolResultGuardInstallParams;
826+params.midTurnPrecheck?.onMidTurnPrecheck?.({
827+route: "compact_only",
828+estimatedPromptTokens: 9000,
829+promptBudgetBeforeReserve: 7000,
830+overflowTokens: 2000,
831+toolResultReducibleChars: 0,
832+effectiveReserveTokens: 1000,
833+});
834+return () => {};
835+});
836+837+const syntheticPiError = {
838+role: "assistant",
839+content: [{ type: "text", text: "" }],
840+stopReason: "error",
841+errorMessage: "Context overflow: prompt too large for the model (mid-turn precheck).",
842+timestamp: 3,
843+} as unknown as AgentMessage;
844+845+const result = await createContextEngineAttemptRunner({
846+contextEngine: createContextEngineBootstrapAndAssemble(),
847+ sessionKey,
848+ tempPaths,
849+attemptOverrides: {
850+config: {
851+agents: {
852+defaults: {
853+compaction: {
854+mode: "safeguard",
855+midTurnPrecheck: { enabled: true },
856+},
857+},
858+},
859+} as OpenClawConfig,
860+},
861+sessionMessages: [seedMessage],
862+sessionPrompt: async (session) => {
863+session.messages = [...session.messages, syntheticPiError];
864+},
865+});
866+867+expect(result.promptErrorSource).toBe("precheck");
868+expect(result.preflightRecovery).toEqual({ route: "compact_only" });
869+expect(result.messagesSnapshot).toEqual([seedMessage]);
870+});
871+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。