diff --git a/src/agents/command/attempt-execution.ts b/src/agents/command/attempt-execution.ts index 5b560aad01bf..571e30dbe22e 100644 --- a/src/agents/command/attempt-execution.ts +++ b/src/agents/command/attempt-execution.ts @@ -6,7 +6,10 @@ import { sanitizeForLog } from "../../../packages/terminal-core/src/ansi.js"; import { formatAcpErrorChain } from "../../acp/runtime/errors.js"; import { normalizeReplyPayload } from "../../auto-reply/reply/normalize-reply.js"; import type { ThinkLevel, VerboseLevel } from "../../auto-reply/thinking.js"; -import { appendSessionTranscriptMessage } from "../../config/sessions/transcript-append.js"; +import { + appendTranscriptMessage, + publishTranscriptUpdate, +} from "../../config/sessions/session-accessor.js"; import { readTailAssistantTextFromSessionTranscript, resolveSessionTranscriptFile, @@ -19,7 +22,6 @@ import { redactSensitiveText } from "../../logging/redact.js"; import { createSubsystemLogger } from "../../logging/subsystem.js"; import type { PluginMetadataSnapshot } from "../../plugins/plugin-metadata-snapshot.types.js"; import { annotateInterSessionPromptText } from "../../sessions/input-provenance.js"; -import { emitSessionTranscriptUpdate } from "../../sessions/transcript-events.js"; import { appendUserTurnTranscriptMessage, type PersistedUserTurnMessage, @@ -244,6 +246,12 @@ async function persistTextTurnTranscript( ...resolveSessionWriteLockOptions(params.config), allowReentrant: true, }); + const transcriptScope = { + sessionFile, + sessionId: params.sessionId, + sessionKey: params.sessionKey, + agentId: params.sessionAgentId, + }; try { const userMessage = params.userMessage; if (userMessage || promptText) { @@ -277,9 +285,7 @@ async function persistTextTurnTranscript( } } if (appendAssistant) { - await appendSessionTranscriptMessage({ - transcriptPath: sessionFile, - sessionId: params.sessionId, + await appendTranscriptMessage(transcriptScope, { cwd: params.sessionCwd, config: params.config, message: { @@ -299,8 +305,7 @@ async function persistTextTurnTranscript( await lock.release(); } - emitSessionTranscriptUpdate({ - sessionFile, + await publishTranscriptUpdate(transcriptScope, { sessionKey: params.sessionKey, agentId: params.sessionAgentId, }); diff --git a/src/config/sessions/transcript.ts b/src/config/sessions/transcript.ts index ae5e1f9bc1a2..4f8c5a405152 100644 --- a/src/config/sessions/transcript.ts +++ b/src/config/sessions/transcript.ts @@ -5,7 +5,6 @@ import type { AgentMessage } from "../../agents/runtime/index.js"; import type { SessionManager } from "../../agents/sessions/session-manager.js"; import { redactTranscriptMessage } from "../../agents/transcript-redact.js"; import { formatErrorMessage } from "../../infra/errors.js"; -import { emitSessionTranscriptUpdate } from "../../sessions/transcript-events.js"; import { extractAssistantVisibleText } from "../../shared/chat-message-content.js"; import type { OpenClawConfig } from "../types.openclaw.js"; import { @@ -14,10 +13,10 @@ import { resolveSessionFilePathOptions, resolveSessionTranscriptPath, } from "./paths.js"; +import { appendTranscriptMessage, publishTranscriptUpdate } from "./session-accessor.js"; import { resolveAndPersistSessionFile } from "./session-file.js"; import { loadSessionStore, resolveSessionStoreEntry } from "./store.js"; import { parseSessionThreadInfo } from "./thread-info.js"; -import { appendSessionTranscriptMessage } from "./transcript-append.js"; import { createSessionTranscriptHeader } from "./transcript-header.js"; import { writeJsonlEntry } from "./transcript-jsonl.js"; import { resolveMirroredTranscriptText } from "./transcript-mirror.js"; @@ -317,6 +316,13 @@ export async function appendExactAssistantMessageToSessionTranscript(params: { ...params.message, ...(explicitIdempotencyKey ? { idempotencyKey: explicitIdempotencyKey } : {}), } as Parameters[0]; + const transcriptScope = { + sessionFile, + sessionId: entry.sessionId, + sessionKey: resolved.normalizedKey, + storePath, + ...(params.agentId ? { agentId: params.agentId } : {}), + }; const { messageId, message: appendedMessage, @@ -329,11 +335,10 @@ export async function appendExactAssistantMessageToSessionTranscript(params: { sessionId: entry.sessionId, cwd: entry.spawnedCwd, }); - return await appendSessionTranscriptMessage({ - transcriptPath: sessionFile, + return await appendTranscriptMessage(transcriptScope, { message, ...(explicitIdempotencyKey ? { idempotencyLookup: "scan" } : {}), - config: params.config, + ...(params.config ? { config: params.config } : {}), }); }, ); @@ -343,8 +348,7 @@ export async function appendExactAssistantMessageToSessionTranscript(params: { switch (params.updateMode ?? "inline") { case "inline": - emitSessionTranscriptUpdate({ - sessionFile, + await publishTranscriptUpdate(transcriptScope, { sessionKey, ...(params.agentId ? { agentId: params.agentId } : {}), message: appendedMessage, @@ -352,8 +356,7 @@ export async function appendExactAssistantMessageToSessionTranscript(params: { }); break; case "file-only": - emitSessionTranscriptUpdate({ - sessionFile, + await publishTranscriptUpdate(transcriptScope, { sessionKey, ...(params.agentId ? { agentId: params.agentId } : {}), }); diff --git a/src/gateway/server-methods/chat-transcript-inject.ts b/src/gateway/server-methods/chat-transcript-inject.ts index c428d78a8db7..fa6f00802897 100644 --- a/src/gateway/server-methods/chat-transcript-inject.ts +++ b/src/gateway/server-methods/chat-transcript-inject.ts @@ -1,8 +1,10 @@ import type { SessionManager } from "../../agents/sessions/session-manager.js"; -import { appendSessionTranscriptMessage } from "../../config/sessions/transcript-append.js"; +import { + appendTranscriptMessage, + publishTranscriptUpdate, +} from "../../config/sessions/session-accessor.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; import { formatErrorMessage } from "../../infra/errors.js"; -import { emitSessionTranscriptUpdate } from "../../sessions/transcript-events.js"; type AppendMessageArg = Parameters[0]; @@ -117,15 +119,18 @@ export async function appendInjectedAssistantMessageToTranscript(params: { }; try { - const { messageId, message: appendedMessage } = await appendSessionTranscriptMessage({ - transcriptPath: params.transcriptPath, + const transcriptScope = { + sessionFile: params.transcriptPath, + sessionKey: params.sessionKey ?? "", + ...(params.agentId ? { agentId: params.agentId } : {}), + }; + const { messageId, message: appendedMessage } = await appendTranscriptMessage(transcriptScope, { message: messageBody, now, useRawWhenLinear: true, - config: params.config, + ...(params.config ? { config: params.config } : {}), }); - emitSessionTranscriptUpdate({ - sessionFile: params.transcriptPath, + await publishTranscriptUpdate(transcriptScope, { ...(params.sessionKey ? { sessionKey: params.sessionKey } : {}), ...(params.agentId ? { agentId: params.agentId } : {}), message: appendedMessage, diff --git a/src/gateway/server-methods/server-methods.test.ts b/src/gateway/server-methods/server-methods.test.ts index 89c99b959a14..0f1b61682896 100644 --- a/src/gateway/server-methods/server-methods.test.ts +++ b/src/gateway/server-methods/server-methods.test.ts @@ -1978,7 +1978,7 @@ describe("gateway chat transcript writes (guardrail)", () => { expect(chatSrc.includes("fs.appendFileSync(transcriptPath")).toBe(false); expect(chatSrc).toContain("appendInjectedAssistantMessageToTranscript("); - expect(helperSrc).toContain("appendSessionTranscriptMessage({"); + expect(helperSrc).toContain("appendTranscriptMessage("); expect(helperSrc).toContain("useRawWhenLinear: true"); expect(helperSrc).not.toContain("SessionManager.open(params.transcriptPath)"); }); diff --git a/src/sessions/user-turn-transcript.ts b/src/sessions/user-turn-transcript.ts index 6c38bff01ba2..514a4db5cf94 100644 --- a/src/sessions/user-turn-transcript.ts +++ b/src/sessions/user-turn-transcript.ts @@ -1,17 +1,20 @@ import path from "node:path"; import { mimeTypeFromFilePath } from "@openclaw/media-core/mime"; import type { AgentMessage } from "../agents/runtime/index.js"; -import { appendSessionTranscriptMessage } from "../config/sessions/transcript-append.js"; +import { + appendTranscriptMessage, + publishTranscriptUpdate, +} from "../config/sessions/session-accessor.js"; +import type { OpenClawConfig } from "../config/types.openclaw.js"; import { applyInputProvenanceToUserMessage, type InputProvenance, normalizeInputProvenance, } from "./input-provenance.js"; -import { emitSessionTranscriptUpdate } from "./transcript-events.js"; // User-turn transcript helpers persist the selected prompt/media as a user // message before or during runtime execution, preserving provenance/idempotency. -type TranscriptAppendConfig = Parameters[0]["config"]; +type TranscriptAppendConfig = OpenClawConfig; type UserTurnSessionEntry = { sessionId: string; @@ -398,13 +401,17 @@ export async function appendUserTurnTranscriptMessage( return undefined; } - const appended = await appendSessionTranscriptMessage({ - transcriptPath: params.transcriptPath, + const transcriptScope = { + sessionFile: params.transcriptPath, + sessionKey: params.sessionKey ?? "", + ...(params.agentId ? { agentId: params.agentId } : {}), ...(params.sessionId ? { sessionId: params.sessionId } : {}), - ...(params.cwd ? { cwd: params.cwd } : {}), - ...(params.config ? { config: params.config } : {}), + }; + const appended = await appendTranscriptMessage(transcriptScope, { message: resolvedMessage, idempotencyLookup: "scan", + ...(params.cwd ? { cwd: params.cwd } : {}), + ...(params.config ? { config: params.config } : {}), prepareMessageAfterIdempotencyCheck: (message) => applyBeforeMessageWriteToUserTurn(message, params), }); @@ -415,8 +422,7 @@ export async function appendUserTurnTranscriptMessage( switch (params.updateMode ?? "inline") { case "inline": if (appended.appended) { - emitSessionTranscriptUpdate({ - sessionFile: params.transcriptPath, + await publishTranscriptUpdate(transcriptScope, { ...(params.sessionKey ? { sessionKey: params.sessionKey } : {}), ...(params.agentId ? { agentId: params.agentId } : {}), message: appended.message,