mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 15:30:47 +00:00
fix(sessions): dedupe redundant delivery mirrors
This commit is contained in:
@@ -118,6 +118,52 @@ describe("appendAssistantMessageToSessionTranscript", () => {
|
||||
expect(messageLine.message.content[0].text).toBe("Hello from delivery mirror!");
|
||||
});
|
||||
|
||||
it("does not append a duplicate delivery mirror when the latest assistant message already matches", async () => {
|
||||
writeTranscriptStore();
|
||||
|
||||
const exactResult = await appendExactAssistantMessageToSessionTranscript({
|
||||
sessionKey,
|
||||
storePath: fixture.storePath(),
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "Hello from Codex!" }],
|
||||
api: "openai-responses",
|
||||
provider: "codex",
|
||||
model: "gpt-5.4",
|
||||
usage: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
totalTokens: 0,
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
||||
},
|
||||
stopReason: "stop",
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
});
|
||||
|
||||
expect(exactResult.ok).toBe(true);
|
||||
|
||||
const mirrorResult = await appendAssistantMessageToSessionTranscript({
|
||||
sessionKey,
|
||||
text: "Hello from Codex!",
|
||||
storePath: fixture.storePath(),
|
||||
});
|
||||
|
||||
expect(mirrorResult.ok).toBe(true);
|
||||
if (exactResult.ok && mirrorResult.ok) {
|
||||
expect(mirrorResult.messageId).toBe(exactResult.messageId);
|
||||
const lines = fs.readFileSync(mirrorResult.sessionFile, "utf-8").trim().split("\n");
|
||||
expect(lines.length).toBe(2);
|
||||
|
||||
const messageLine = JSON.parse(lines[1]);
|
||||
expect(messageLine.message.provider).toBe("codex");
|
||||
expect(messageLine.message.model).toBe("gpt-5.4");
|
||||
expect(messageLine.message.content[0].text).toBe("Hello from Codex!");
|
||||
}
|
||||
});
|
||||
|
||||
it("finds session entry using normalized (lowercased) key", async () => {
|
||||
const storeKey = "agent:main:bluebubbles:direct:+15551234567";
|
||||
const store = {
|
||||
|
||||
@@ -201,6 +201,13 @@ export async function appendExactAssistantMessageToSessionTranscript(params: {
|
||||
return { ok: true, sessionFile, messageId: existingMessageId };
|
||||
}
|
||||
|
||||
const latestEquivalentAssistantId = isRedundantDeliveryMirror(params.message)
|
||||
? await findLatestEquivalentAssistantMessageId(sessionFile, params.message)
|
||||
: undefined;
|
||||
if (latestEquivalentAssistantId) {
|
||||
return { ok: true, sessionFile, messageId: latestEquivalentAssistantId };
|
||||
}
|
||||
|
||||
const message = {
|
||||
...params.message,
|
||||
...(explicitIdempotencyKey ? { idempotencyKey: explicitIdempotencyKey } : {}),
|
||||
@@ -252,3 +259,73 @@ async function transcriptHasIdempotencyKey(
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function isRedundantDeliveryMirror(message: SessionTranscriptAssistantMessage): boolean {
|
||||
return message.provider === "openclaw" && message.model === "delivery-mirror";
|
||||
}
|
||||
|
||||
function extractAssistantMessageText(message: SessionTranscriptAssistantMessage): string | null {
|
||||
if (typeof message.text === "string" && message.text.trim()) {
|
||||
return message.text.trim();
|
||||
}
|
||||
if (!Array.isArray(message.content)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const parts = message.content
|
||||
.filter(
|
||||
(
|
||||
part,
|
||||
): part is {
|
||||
type: "text";
|
||||
text: string;
|
||||
} => part.type === "text" && typeof part.text === "string" && part.text.trim().length > 0,
|
||||
)
|
||||
.map((part) => part.text.trim());
|
||||
|
||||
return parts.length > 0 ? parts.join("\n").trim() : null;
|
||||
}
|
||||
|
||||
async function findLatestEquivalentAssistantMessageId(
|
||||
transcriptPath: string,
|
||||
message: SessionTranscriptAssistantMessage,
|
||||
): Promise<string | undefined> {
|
||||
const expectedText = extractAssistantMessageText(message);
|
||||
if (!expectedText) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
const raw = await fs.promises.readFile(transcriptPath, "utf-8");
|
||||
const lines = raw.split(/\r?\n/);
|
||||
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
||||
const line = lines[index];
|
||||
if (!line.trim()) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
const parsed = JSON.parse(line) as {
|
||||
id?: unknown;
|
||||
message?: SessionTranscriptAssistantMessage;
|
||||
};
|
||||
const candidate = parsed.message;
|
||||
if (!candidate || candidate.role !== "assistant") {
|
||||
continue;
|
||||
}
|
||||
const candidateText = extractAssistantMessageText(candidate);
|
||||
if (candidateText !== expectedText) {
|
||||
continue;
|
||||
}
|
||||
if (typeof parsed.id === "string" && parsed.id) {
|
||||
return parsed.id;
|
||||
}
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user