





















@@ -313,6 +313,11 @@ describe("normalizeMessagesForLlmBoundary", () => {
313313'Conversation info (untrusted metadata):\n```json\n{"channel":"telegram"}\n```\n\nPlain historical ask',
314314timestamp: 1,
315315},
316+{
317+role: "assistant",
318+content: [{ type: "text", text: "Historical answer" }],
319+timestamp: 2,
320+},
316321];
317322318323const output = normalizeMessagesForLlmBoundary(
@@ -322,6 +327,73 @@ describe("normalizeMessagesForLlmBoundary", () => {
322327expect(output[0]?.content).toBe("Plain historical ask");
323328});
324329330+it("preserves inbound metadata on the current user turn", () => {
331+const historicalEnvelope =
332+'Conversation info (untrusted metadata):\n```json\n{"channel":"discord"}\n```\n\nOld ask';
333+const currentEnvelope =
334+'Conversation info (untrusted metadata):\n```json\n{"channel":"discord","has_reply_context":true}\n```\n\nReply target of current user message (untrusted, for context):\n```json\n{"body":"quoted status body"}\n```\n\nCurrent ask';
335+const input = [
336+{
337+role: "user",
338+content: [{ type: "text", text: historicalEnvelope }],
339+timestamp: 1,
340+},
341+{
342+role: "assistant",
343+content: [{ type: "text", text: "Historical answer" }],
344+timestamp: 2,
345+},
346+{
347+role: "user",
348+content: [{ type: "text", text: currentEnvelope }],
349+timestamp: 3,
350+},
351+];
352+353+const output = normalizeMessagesForLlmBoundary(
354+input as Parameters<typeof normalizeMessagesForLlmBoundary>[0],
355+) as unknown as Array<{ content?: Array<{ text?: string }> }>;
356+357+expect(output[0]?.content?.[0]?.text).toBe("Old ask");
358+expect(output[2]?.content?.[0]?.text).toContain(
359+"Reply target of current user message (untrusted, for context):",
360+);
361+expect(output[2]?.content?.[0]?.text).toContain("quoted status body");
362+});
363+364+it("preserves current user inbound metadata through tool-result continuation", () => {
365+const currentEnvelope =
366+'Conversation info (untrusted metadata):\n```json\n{"channel":"discord","has_reply_context":true}\n```\n\nReply target of current user message (untrusted, for context):\n```json\n{"body":"quoted status body"}\n```\n\nCurrent ask';
367+const input = [
368+{
369+role: "user",
370+content: [{ type: "text", text: currentEnvelope }],
371+timestamp: 1,
372+},
373+{
374+role: "assistant",
375+content: [{ type: "toolCall", id: "call_1", name: "read", arguments: {} }],
376+timestamp: 2,
377+},
378+{
379+role: "toolResult",
380+toolCallId: "call_1",
381+toolName: "read",
382+content: [{ type: "text", text: "tool output" }],
383+timestamp: 3,
384+},
385+];
386+387+const output = normalizeMessagesForLlmBoundary(
388+input as Parameters<typeof normalizeMessagesForLlmBoundary>[0],
389+) as unknown as Array<{ content?: Array<{ text?: string }> }>;
390+391+expect(output[0]?.content?.[0]?.text).toContain(
392+"Reply target of current user message (untrusted, for context):",
393+);
394+expect(output[0]?.content?.[0]?.text).toContain("quoted status body");
395+});
396+325397it("strips tool result details before provider conversion", () => {
326398const input = [
327399{
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。