mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-24 23:32:19 +10:00
feat(agent): omit resume documents from the copied conversation json
This commit is contained in:
@@ -5,7 +5,7 @@ import { fireEvent, render, screen, within } from "@testing-library/react";
|
|||||||
import { beforeAll, describe, expect, it, vi } from "vitest";
|
import { beforeAll, describe, expect, it, vi } from "vitest";
|
||||||
import { i18n } from "@lingui/core";
|
import { i18n } from "@lingui/core";
|
||||||
import { I18nProvider } from "@lingui/react";
|
import { I18nProvider } from "@lingui/react";
|
||||||
import { AskUserQuestion, AssistantMarkdown } from "./agent-chat";
|
import { AskUserQuestion, AssistantMarkdown, withoutResumeDataForExport } from "./agent-chat";
|
||||||
|
|
||||||
describe("AssistantMarkdown", () => {
|
describe("AssistantMarkdown", () => {
|
||||||
it("renders GitHub-style pipe tables as tables", () => {
|
it("renders GitHub-style pipe tables as tables", () => {
|
||||||
@@ -27,6 +27,47 @@ describe("AssistantMarkdown", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("withoutResumeDataForExport", () => {
|
||||||
|
it("strips the resume document from tool outputs but keeps everything else", () => {
|
||||||
|
const messages = [
|
||||||
|
{
|
||||||
|
id: "m1",
|
||||||
|
role: "assistant",
|
||||||
|
parts: [
|
||||||
|
{
|
||||||
|
type: "tool-read_resume",
|
||||||
|
toolCallId: "c1",
|
||||||
|
state: "output-available",
|
||||||
|
input: {},
|
||||||
|
output: { id: "r1", updatedAt: "2026-08-20T00:00:00.000Z", data: { basics: { name: "John" } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tool-apply_resume_patch",
|
||||||
|
toolCallId: "c2",
|
||||||
|
state: "output-available",
|
||||||
|
input: { title: "Edit" },
|
||||||
|
output: { actionId: "a1", changedPaths: ["/basics/name"], resume: { basics: { name: "John" } } },
|
||||||
|
},
|
||||||
|
{ type: "text", text: "Done." },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
] as unknown as UIMessage[];
|
||||||
|
|
||||||
|
const exported = withoutResumeDataForExport(messages);
|
||||||
|
|
||||||
|
const exportedParts = (exported[0]?.parts ?? []) as Array<{ output?: Record<string, unknown> }>;
|
||||||
|
expect(exportedParts[0]?.output?.data).toBe("[resume data omitted]");
|
||||||
|
expect(exportedParts[0]?.output?.updatedAt).toBe("2026-08-20T00:00:00.000Z");
|
||||||
|
expect(exportedParts[1]?.output?.resume).toBe("[resume data omitted]");
|
||||||
|
expect(exportedParts[1]?.output?.changedPaths).toEqual(["/basics/name"]);
|
||||||
|
expect(exported[0]?.parts[2]).toEqual({ type: "text", text: "Done." });
|
||||||
|
|
||||||
|
// The live chat state is never mutated — only the copied structure is redacted.
|
||||||
|
const originalParts = (messages[0]?.parts ?? []) as Array<{ output?: Record<string, unknown> }>;
|
||||||
|
expect(originalParts[0]?.output?.data).toEqual({ basics: { name: "John" } });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const questionPart = {
|
const questionPart = {
|
||||||
type: "tool-ask_user_question",
|
type: "tool-ask_user_question",
|
||||||
toolCallId: "call-1",
|
toolCallId: "call-1",
|
||||||
|
|||||||
@@ -200,6 +200,33 @@ type AgentChatComposerProps = {
|
|||||||
|
|
||||||
const ANSWER_FIELD = "answer";
|
const ANSWER_FIELD = "answer";
|
||||||
|
|
||||||
|
const OMITTED_RESUME_DATA = "[resume data omitted]";
|
||||||
|
|
||||||
|
// "Copy JSON" is for sharing/debugging a conversation; the full resume document embedded in every
|
||||||
|
// read_resume result (`output.data`) and fresh-document patch result (`output.resume`) would make
|
||||||
|
// the export enormous and repetitive. Strip those two payloads; everything else copies verbatim.
|
||||||
|
export function withoutResumeDataForExport(messages: UIMessage[]): UIMessage[] {
|
||||||
|
return messages.map((message) => ({
|
||||||
|
...message,
|
||||||
|
parts: message.parts.map((part) => {
|
||||||
|
if (part.type !== "tool-read_resume" && part.type !== "tool-apply_resume_patch") return part;
|
||||||
|
|
||||||
|
const output = "output" in part && typeof part.output === "object" && part.output ? part.output : null;
|
||||||
|
if (!output) return part;
|
||||||
|
const outputRecord = output as Record<string, unknown>;
|
||||||
|
|
||||||
|
if (part.type === "tool-read_resume" && "data" in outputRecord) {
|
||||||
|
return { ...part, output: { ...outputRecord, data: OMITTED_RESUME_DATA } } as UIMessage["parts"][number];
|
||||||
|
}
|
||||||
|
if (part.type === "tool-apply_resume_patch" && "resume" in outputRecord) {
|
||||||
|
return { ...part, output: { ...outputRecord, resume: OMITTED_RESUME_DATA } } as UIMessage["parts"][number];
|
||||||
|
}
|
||||||
|
|
||||||
|
return part;
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
function toRecord(value: unknown) {
|
function toRecord(value: unknown) {
|
||||||
return typeof value === "object" && value !== null ? (value as Record<string, unknown>) : null;
|
return typeof value === "object" && value !== null ? (value as Record<string, unknown>) : null;
|
||||||
}
|
}
|
||||||
@@ -994,7 +1021,7 @@ export function AgentChat({
|
|||||||
chatStatus: status,
|
chatStatus: status,
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
readOnlyReason,
|
readOnlyReason,
|
||||||
messages,
|
messages: withoutResumeDataForExport(messages),
|
||||||
actions,
|
actions,
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
|
|||||||
Reference in New Issue
Block a user