fix(sessions): dedupe redundant delivery mirrors

This commit is contained in:
Andy
2026-04-15 20:32:00 +09:00
committed by Peter Steinberger
parent 86f108401b
commit e95efa4373
2 changed files with 123 additions and 0 deletions

View File

@@ -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 = {

View File

@@ -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;
}