diff --git a/extensions/msteams/src/monitor-handler.feedback-authz.test.ts b/extensions/msteams/src/monitor-handler.feedback-authz.test.ts index 225ec0254c5..b1d9a1173d7 100644 --- a/extensions/msteams/src/monitor-handler.feedback-authz.test.ts +++ b/extensions/msteams/src/monitor-handler.feedback-authz.test.ts @@ -1,4 +1,4 @@ -import { access, mkdtemp, rm } from "node:fs/promises"; +import { mkdtemp, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path"; import { loadSqliteSessionTranscriptEvents } from "openclaw/plugin-sdk/agent-harness-runtime"; @@ -128,10 +128,6 @@ function createFeedbackInvokeContext(params: { } as unknown as MSTeamsTurnContext; } -async function expectFileMissing(filePath: string) { - await expect(access(filePath)).rejects.toMatchObject({ code: "ENOENT" }); -} - function readFeedbackTranscriptMessage(params: { stateDir: string; sessionId: string; @@ -295,7 +291,12 @@ describe("msteams feedback invoke authz", () => { comment: "blocked feedback", }, assertResult: async ({ tmpDir, originalRun }) => { - await expectFileMissing(path.join(tmpDir, "msteams_direct_attacker-aad.jsonl")); + expect( + readFeedbackTranscriptMessage({ + stateDir: tmpDir, + sessionId: "msteams:direct:attacker-aad", + }), + ).toBeUndefined(); expect(feedbackReflectionMockState.runFeedbackReflection).not.toHaveBeenCalled(); expect(originalRun).not.toHaveBeenCalled(); }, @@ -339,7 +340,12 @@ describe("msteams feedback invoke authz", () => { }), ); - await expectFileMissing(path.join(tmpDir, "msteams_group_19_group_thread_tacv2.jsonl")); + expect( + readFeedbackTranscriptMessage({ + stateDir: tmpDir, + sessionId: "msteams:group:19:group@thread.tacv2", + }), + ).toBeUndefined(); expect(feedbackReflectionMockState.runFeedbackReflection).not.toHaveBeenCalled(); expect(originalRun).not.toHaveBeenCalled(); } finally { diff --git a/extensions/msteams/src/monitor-handler.ts b/extensions/msteams/src/monitor-handler.ts index e61afa1646c..8764667c01e 100644 --- a/extensions/msteams/src/monitor-handler.ts +++ b/extensions/msteams/src/monitor-handler.ts @@ -199,8 +199,8 @@ async function handleFeedbackInvoke( const messageId = value.replyToId ?? activity.replyToId ?? "unknown"; const isNegative = reaction === "dislike"; - // Route feedback using the same chat-type logic as normal messages - // so session keys, agent IDs, and transcript paths match. + // Route feedback using the same chat-type logic as normal messages so session + // keys, agent IDs, and SQLite transcript identity match. const convType = normalizeOptionalLowercaseString(activity.conversation?.conversationType); const isDirectMessage = convType === "personal" || (!convType && !activity.conversation?.isGroup); const isChannel = convType === "channel"; diff --git a/src/agents/command/attempt-execution.helpers.ts b/src/agents/command/attempt-execution.helpers.ts index aeacac91db8..ef26a57503f 100644 --- a/src/agents/command/attempt-execution.helpers.ts +++ b/src/agents/command/attempt-execution.helpers.ts @@ -15,8 +15,8 @@ import { readClaudeCliFallbackSeed, } from "../../gateway/cli-session-history.js"; -/** Maximum number of JSONL records to inspect before giving up. */ -const SESSION_FILE_MAX_RECORDS = 500; +/** Maximum number of external Claude CLI JSONL records to inspect before giving up. */ +const CLAUDE_CLI_HISTORY_MAX_RECORDS = 500; const CLAUDE_PROJECTS_RELATIVE_DIR = path.join(".claude", "projects"); function normalizeClaudeCliSessionId(sessionId: string | undefined): string | undefined { @@ -27,7 +27,9 @@ function normalizeClaudeCliSessionId(sessionId: string | undefined): string | un return trimmed; } -async function jsonlFileHasAssistantMessage(filePath: string | undefined): Promise { +async function claudeCliHistoryJsonlHasAssistantMessage( + filePath: string | undefined, +): Promise { if (!filePath) { return false; } @@ -46,7 +48,7 @@ async function jsonlFileHasAssistantMessage(filePath: string | undefined): Promi continue; } recordCount++; - if (recordCount > SESSION_FILE_MAX_RECORDS) { + if (recordCount > CLAUDE_CLI_HISTORY_MAX_RECORDS) { break; } let obj: unknown; @@ -111,7 +113,7 @@ export async function claudeCliSessionTranscriptHasContent(params: { continue; } const candidate = path.join(projectsDir, entry.name, `${sessionId}.jsonl`); - if (await jsonlFileHasAssistantMessage(candidate)) { + if (await claudeCliHistoryJsonlHasAssistantMessage(candidate)) { return true; } } diff --git a/src/agents/pi-embedded-helpers.buildbootstrapcontextfiles.test.ts b/src/agents/pi-embedded-helpers.buildbootstrapcontextfiles.test.ts index b4ca8376143..a9598e2111b 100644 --- a/src/agents/pi-embedded-helpers.buildbootstrapcontextfiles.test.ts +++ b/src/agents/pi-embedded-helpers.buildbootstrapcontextfiles.test.ts @@ -42,7 +42,7 @@ describe("ensureSessionHeader", () => { it("creates the transcript header in SQLite without writing a JSONL file", async () => { const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-header-")); try { - const legacyTranscriptPath = path.join(tempDir, "nested", "session.jsonl"); + const forbiddenJsonlTranscriptPath = path.join(tempDir, "nested", "session.jsonl"); const env = { ...process.env, OPENCLAW_STATE_DIR: path.join(tempDir, "state"), @@ -54,7 +54,7 @@ describe("ensureSessionHeader", () => { env, }); - await expect(fs.access(legacyTranscriptPath)).rejects.toThrow(); + await expect(fs.access(forbiddenJsonlTranscriptPath)).rejects.toThrow(); const events = loadSqliteSessionTranscriptEvents({ agentId: "main", sessionId: "session-1", diff --git a/src/agents/pi-hooks/compaction-safeguard.test.ts b/src/agents/pi-hooks/compaction-safeguard.test.ts index 7df8ca331c0..e1c0d214004 100644 --- a/src/agents/pi-hooks/compaction-safeguard.test.ts +++ b/src/agents/pi-hooks/compaction-safeguard.test.ts @@ -72,7 +72,6 @@ function stubSessionManager(): ExtensionContext["sessionManager"] { getCwd: () => "/stub", getSessionDir: () => "/stub", getSessionId: () => "stub-id", - getSessionFile: () => undefined, getLeafId: () => null, getLeafEntry: () => undefined, getEntry: () => undefined,