refactor: streamline reply tag parsing

This commit is contained in:
Peter Steinberger
2026-01-09 17:14:36 +01:00
parent cef13aa705
commit d372fac9c6
3 changed files with 66 additions and 20 deletions

View File

@@ -249,6 +249,42 @@ describe("directive behavior", () => {
});
});
it("strips reply tags with whitespace and maps reply_to_current to MessageSid", async () => {
await withTempHome(async (home) => {
vi.mocked(runEmbeddedPiAgent).mockResolvedValue({
payloads: [{ text: "hello [[ reply_to_current ]]" }],
meta: {
durationMs: 5,
agentMeta: { sessionId: "s", provider: "p", model: "m" },
},
});
const res = await getReplyFromConfig(
{
Body: "ping",
From: "+1004",
To: "+2000",
MessageSid: "msg-123",
},
{},
{
agents: {
defaults: {
model: "anthropic/claude-opus-4-5",
workspace: path.join(home, "clawd"),
},
},
whatsapp: { allowFrom: ["*"] },
session: { store: path.join(home, "sessions.json") },
},
);
const payload = Array.isArray(res) ? res[0] : res;
expect(payload?.text).toBe("hello");
expect(payload?.replyToId).toBe("msg-123");
});
});
it("prefers explicit reply_to id over reply_to_current", async () => {
await withTempHome(async (home) => {
vi.mocked(runEmbeddedPiAgent).mockResolvedValue({

View File

@@ -1,3 +1,13 @@
const REPLY_TAG_RE =
/\[\[\s*(?:reply_to_current|reply_to\s*:\s*([^\]\n]+))\s*\]\]/gi;
function normalizeReplyText(text: string) {
return text
.replace(/[ \t]+/g, " ")
.replace(/[ \t]*\n[ \t]*/g, "\n")
.trim();
}
export function extractReplyToTag(
text?: string,
currentMessageId?: string,
@@ -7,29 +17,28 @@ export function extractReplyToTag(
hasTag: boolean;
} {
if (!text) return { cleaned: "", hasTag: false };
let cleaned = text;
let replyToId: string | undefined;
let sawCurrent = false;
let lastExplicitId: string | undefined;
let hasTag = false;
const currentMatch = cleaned.match(/\[\[\s*reply_to_current\s*\]\]/i);
if (currentMatch) {
cleaned = cleaned.replace(/\[\[\s*reply_to_current\s*\]\]/gi, " ");
hasTag = true;
if (currentMessageId?.trim()) {
replyToId = currentMessageId.trim();
}
}
const cleaned = normalizeReplyText(
text.replace(REPLY_TAG_RE, (_full, idRaw: string | undefined) => {
hasTag = true;
if (idRaw === undefined) {
sawCurrent = true;
return " ";
}
const idMatch = cleaned.match(/\[\[\s*reply_to\s*:\s*([^\]\n]+)\s*\]\]/i);
if (idMatch?.[1]) {
cleaned = cleaned.replace(/\[\[\s*reply_to\s*:\s*[^\]\n]+\s*\]\]/gi, " ");
replyToId = idMatch[1].trim();
hasTag = true;
}
const id = idRaw.trim();
if (id) lastExplicitId = id;
return " ";
}),
);
const replyToId =
lastExplicitId ??
(sawCurrent ? currentMessageId?.trim() || undefined : undefined);
cleaned = cleaned
.replace(/[ \t]+/g, " ")
.replace(/[ \t]*\n[ \t]*/g, "\n")
.trim();
return { cleaned, replyToId, hasTag };
}