Skip to content

Commit db72861

Browse files
authored
fix(transcripts): mark delivery mirrors as artifacts (#99855)
* fix(transcripts): mark delivery mirrors as artifacts * fix(transcripts): mark delivery mirrors as artifacts * fix(transcripts): mark delivery mirrors as artifacts
1 parent d9b6d0d commit db72861

8 files changed

Lines changed: 48 additions & 20 deletions

src/agents/embedded-agent-runner.sanitize-session-history.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
Usage,
88
} from "openclaw/plugin-sdk/llm";
99
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
10+
import { OPENCLAW_TRANSCRIPT_ARTIFACT_API } from "../shared/transcript-only-openclaw-assistant.js";
1011
import {
1112
expectOpenAIResponsesStrictSanitizeCall,
1213
loadSanitizeSessionHistoryWithCleanMocks,
@@ -887,7 +888,7 @@ describe("sanitizeSessionHistory", () => {
887888
});
888889
});
889890

890-
it("repairs a message-tool delivery-mirror poisoned OpenAI Responses replay", async () => {
891+
it("repairs a message-tool delivery-mirror poisoned replay", async () => {
891892
const messages: AgentMessage[] = [
892893
makeUserMessage("start"),
893894
makeAssistantMessage(
@@ -905,7 +906,7 @@ describe("sanitizeSessionHistory", () => {
905906
role: "assistant",
906907
provider: "openclaw",
907908
model: "delivery-mirror",
908-
api: "openai-responses",
909+
api: OPENCLAW_TRANSCRIPT_ARTIFACT_API,
909910
content: [{ type: "text", text: "visible reply" }],
910911
stopReason: "stop",
911912
}),

src/agents/embedded-agent-runner/replay-history.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Coverage for normalizing assistant replay content before provider requests.
22
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
33
import { describe, expect, it } from "vitest";
4+
import { OPENCLAW_TRANSCRIPT_ARTIFACT_API } from "../../shared/transcript-only-openclaw-assistant.js";
45
import {
56
INTERNAL_RUNTIME_CONTEXT_BEGIN,
67
INTERNAL_RUNTIME_CONTEXT_END,
@@ -50,7 +51,7 @@ function openclawTranscriptAssistant(model: "delivery-mirror" | "gateway-injecte
5051
return {
5152
role: "assistant",
5253
content: [{ type: "text", text: "channel mirror" }],
53-
api: "openai-responses",
54+
api: OPENCLAW_TRANSCRIPT_ARTIFACT_API,
5455
provider: "openclaw",
5556
model,
5657
usage: {

src/agents/embedded-agent-runner/run/attempt.session-lock.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
withOwnedSessionTranscriptWrites,
1717
} from "../../../config/sessions/transcript-write-context.js";
1818
import { appendExactAssistantMessageToSessionTranscript } from "../../../config/sessions/transcript.js";
19+
import { OPENCLAW_TRANSCRIPT_ARTIFACT_API } from "../../../shared/transcript-only-openclaw-assistant.js";
1920
import { guardSessionManager } from "../../session-tool-result-guard-wrapper.js";
2021
import {
2122
SessionWriteLockStaleError,
@@ -2602,7 +2603,7 @@ describe("embedded attempt session lock lifecycle", () => {
26022603
message: {
26032604
role: "assistant",
26042605
content: [{ type: "text", text: "first-turn delivery" }],
2605-
api: "openai-responses",
2606+
api: OPENCLAW_TRANSCRIPT_ARTIFACT_API,
26062607
provider: "openclaw",
26072608
model: "delivery-mirror",
26082609
usage: {

src/agents/session-file-repair.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import fs from "node:fs/promises";
66
import os from "node:os";
77
import path from "node:path";
88
import { afterEach, describe, expect, it, vi } from "vitest";
9+
import { OPENCLAW_TRANSCRIPT_ARTIFACT_API } from "../shared/transcript-only-openclaw-assistant.js";
910
import { repairSessionFileIfNeeded } from "./session-file-repair.js";
1011

1112
const BLANK_USER_FALLBACK_TEXT = "(continue)";
@@ -832,7 +833,7 @@ describe("repairSessionFileIfNeeded", () => {
832833
role: "assistant",
833834
provider: "openclaw",
834835
model: "delivery-mirror",
835-
api: "openai-responses",
836+
api: OPENCLAW_TRANSCRIPT_ARTIFACT_API,
836837
content: [{ type: "text", text: "Process: `wild-wharf`" }],
837838
stopReason: "stop",
838839
},
@@ -892,7 +893,7 @@ describe("repairSessionFileIfNeeded", () => {
892893
role: "assistant",
893894
provider: "openclaw",
894895
model: "delivery-mirror",
895-
api: "openai-responses",
896+
api: OPENCLAW_TRANSCRIPT_ARTIFACT_API,
896897
content: [{ type: "text", text: "visible reply" }],
897898
stopReason: "stop",
898899
},

src/config/sessions/transcript.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { beforeAll, describe, expect, it, vi } from "vitest";
66
import { repairToolUseResultPairing } from "../../agents/session-transcript-repair.js";
77
import * as transcriptEvents from "../../sessions/transcript-events.js";
88
import type { SessionTranscriptUpdate } from "../../sessions/transcript-events.js";
9+
import { OPENCLAW_TRANSCRIPT_ARTIFACT_API } from "../../shared/transcript-only-openclaw-assistant.js";
910
import { deleteTestEnvValue, setTestEnvValue } from "../../test-utils/env.js";
1011
import { resolveSessionTranscriptPathInDir } from "./paths.js";
1112
import { updateSessionStoreEntry } from "./store.js";
@@ -513,6 +514,7 @@ describe("appendAssistantMessageToSessionTranscript", () => {
513514
const message = event.message as
514515
| {
515516
role?: string;
517+
api?: string;
516518
provider?: string;
517519
model?: string;
518520
content?: unknown;
@@ -522,6 +524,7 @@ describe("appendAssistantMessageToSessionTranscript", () => {
522524
expect(event?.sessionKey).toBe(sessionKey);
523525
expect(event?.messageId).toBeTypeOf("string");
524526
expect(message?.role).toBe("assistant");
527+
expect(message?.api).toBe(OPENCLAW_TRANSCRIPT_ARTIFACT_API);
525528
expect(message?.provider).toBe("openclaw");
526529
expect(message?.model).toBe("delivery-mirror");
527530
expect(message?.content).toEqual([{ type: "text", text: "Hello from delivery mirror!" }]);
@@ -982,6 +985,7 @@ describe("appendAssistantMessageToSessionTranscript", () => {
982985
expect(lines.length).toBe(4);
983986

984987
const messageLine = JSON.parse(lines[3]);
988+
expect(messageLine.message.api).toBe(OPENCLAW_TRANSCRIPT_ARTIFACT_API);
985989
expect(messageLine.message.provider).toBe("openclaw");
986990
expect(messageLine.message.model).toBe("delivery-mirror");
987991
expect(messageLine.message.content[0].text).toBe("Repeated answer");
@@ -1023,6 +1027,7 @@ describe("appendAssistantMessageToSessionTranscript", () => {
10231027
const linesAfterMirror = fs.readFileSync(sessionFile, "utf-8").trim().split("\n");
10241028
expect(linesAfterMirror).toHaveLength(3);
10251029
const mirrorLine = JSON.parse(linesAfterMirror[2]);
1030+
expect(mirrorLine.message.api).toBe(OPENCLAW_TRANSCRIPT_ARTIFACT_API);
10261031
expect(mirrorLine.message.model).toBe("delivery-mirror");
10271032

10281033
await appendSessionTranscriptMessage({

src/config/sessions/transcript.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ import {
99
extractAssistantVisibleText,
1010
extractFirstTextBlock,
1111
} from "../../shared/chat-message-content.js";
12-
import { isTranscriptOnlyOpenClawAssistantModel } from "../../shared/transcript-only-openclaw-assistant.js";
12+
import {
13+
OPENCLAW_DELIVERY_MIRROR_MODEL,
14+
OPENCLAW_TRANSCRIPT_ARTIFACT_API,
15+
OPENCLAW_TRANSCRIPT_ARTIFACT_PROVIDER,
16+
isTranscriptOnlyOpenClawAssistantModel,
17+
} from "../../shared/transcript-only-openclaw-assistant.js";
1318
import type { OpenClawConfig } from "../types.openclaw.js";
1419
import {
1520
resolveDefaultSessionStorePath,
@@ -358,9 +363,9 @@ export async function appendAssistantMessageToSessionTranscript(params: {
358363
message: {
359364
role: "assistant" as const,
360365
content: [{ type: "text", text: mirrorText }],
361-
api: "openai-responses",
362-
provider: "openclaw",
363-
model: "delivery-mirror",
366+
api: OPENCLAW_TRANSCRIPT_ARTIFACT_API,
367+
provider: OPENCLAW_TRANSCRIPT_ARTIFACT_PROVIDER,
368+
model: OPENCLAW_DELIVERY_MIRROR_MODEL,
364369
usage: {
365370
input: 0,
366371
output: 0,
@@ -548,7 +553,10 @@ export async function appendExactAssistantMessageToSessionTranscript(params: {
548553
}
549554

550555
function isRedundantDeliveryMirror(message: SessionTranscriptAssistantMessage): boolean {
551-
return message.provider === "openclaw" && message.model === "delivery-mirror";
556+
return (
557+
message.provider === OPENCLAW_TRANSCRIPT_ARTIFACT_PROVIDER &&
558+
message.model === OPENCLAW_DELIVERY_MIRROR_MODEL
559+
);
552560
}
553561

554562
function isChannelFinalDeliveryMirror(message: SessionTranscriptAssistantMessage): boolean {

src/gateway/sessions-history-http.test.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
emitInternalSessionTranscriptUpdate,
1515
emitSessionTranscriptUpdate,
1616
} from "../sessions/transcript-events.js";
17+
import { OPENCLAW_TRANSCRIPT_ARTIFACT_API } from "../shared/transcript-only-openclaw-assistant.js";
1718
import { testState } from "./test-helpers.runtime-state.js";
1819
import {
1920
connectReq,
@@ -126,11 +127,14 @@ function makeTranscriptAssistantMessage(params: {
126127
function makeDeliveryMirrorAssistantMessage(
127128
params: Parameters<typeof makeTranscriptAssistantMessage>[0],
128129
): AssistantMessage {
129-
return makeTranscriptAssistantMessage({
130-
...params,
131-
provider: "openclaw",
132-
model: "delivery-mirror",
133-
});
130+
return {
131+
...makeTranscriptAssistantMessage({
132+
...params,
133+
provider: "openclaw",
134+
model: "delivery-mirror",
135+
}),
136+
api: OPENCLAW_TRANSCRIPT_ARTIFACT_API,
137+
};
134138
}
135139

136140
async function appendTranscriptMessage(params: {

src/shared/transcript-only-openclaw-assistant.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
// Identifies OpenClaw-authored assistant rows that are transcript bookkeeping,
22
// not provider model output. Some history surfaces keep gateway-injected rows
33
// visible, so use the narrower delivery-mirror predicate when visibility matters.
4+
export const OPENCLAW_TRANSCRIPT_ARTIFACT_API = "openclaw-transcript" as const;
5+
export const OPENCLAW_TRANSCRIPT_ARTIFACT_PROVIDER = "openclaw" as const;
6+
export const OPENCLAW_DELIVERY_MIRROR_MODEL = "delivery-mirror" as const;
7+
export const OPENCLAW_GATEWAY_INJECTED_MODEL = "gateway-injected" as const;
8+
49
const TRANSCRIPT_ONLY_OPENCLAW_ASSISTANT_MODELS = new Set<string>([
5-
"delivery-mirror",
6-
"gateway-injected",
10+
OPENCLAW_DELIVERY_MIRROR_MODEL,
11+
OPENCLAW_GATEWAY_INJECTED_MODEL,
712
]);
813

914
export function isTranscriptOnlyOpenClawAssistantModel(provider: unknown, model: unknown): boolean {
1015
return (
11-
provider === "openclaw" &&
16+
provider === OPENCLAW_TRANSCRIPT_ARTIFACT_PROVIDER &&
1217
typeof model === "string" &&
1318
TRANSCRIPT_ONLY_OPENCLAW_ASSISTANT_MODELS.has(model)
1419
);
@@ -31,6 +36,8 @@ export function isOpenClawDeliveryMirrorAssistantMessage(message: unknown): bool
3136
}
3237
const entry = message as { role?: unknown; provider?: unknown; model?: unknown };
3338
return (
34-
entry.role === "assistant" && entry.provider === "openclaw" && entry.model === "delivery-mirror"
39+
entry.role === "assistant" &&
40+
entry.provider === OPENCLAW_TRANSCRIPT_ARTIFACT_PROVIDER &&
41+
entry.model === OPENCLAW_DELIVERY_MIRROR_MODEL
3542
);
3643
}

0 commit comments

Comments
 (0)