mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-23 06:42:15 +10:00
* docs(adr): propose agent AI SDK v7 adoption plan * fix(ai): bind analyzeResume through aiService in service test The test destructured analyzeResume as a named export that does not exist; main was red. * test(agent): keep pure ai helpers real via spread-actual mock factory * feat(agent): add run guards, patch version guard, run wall-clock timeout * feat(agent): validate UI messages at the send boundary * feat(agent): crash-safe draft-row persistence and server-side cancellation * feat(agent): reap stale run claims at boot, on send, and on thread open * feat(agent): fresh-document patch output and tiered context pruning * feat(ai): shared agent tool contracts and message metadata schema * feat(agent): add per-thread review-patches setting with update endpoint * feat(agent): gate resume patches behind hmac-signed tool approval * feat(agent): merge question answers and approval decisions before run claim * feat(agent): approval ui with composed auto-send and fixture-driven tests * feat(agent): usage metadata, tool activity cards, smoother streaming * feat(agent): tool-call repair, input examples, structured step logging * chore(i18n): translate new agent workspace strings across all locales * fix(agent): gate stale-run draft cancellation on winning the claim clear Snapshot streaming drafts before the conditional clear and skip the flip entirely when another reaper or a replacement run already cleared the claim. Also address review nits in eleven locale catalogs. * fix(agent): flip reaped drafts only when their snapshotted state is unchanged * fix(agent): address review findings across run lifecycle, context budget, and approval flow - bind patches to the revision the model read via signed baseUpdatedAt - claim the run before consuming a continuation; recorded-but-unexecuted approvals retry as pending continuations - keep run ownership on stop() until cancellation persists; preserve the claim for the reaper when final persistence fails - estimate tokens without serializing binary attachments (tokenx) and enforce the budget by dropping oldest whole turns - mark crash-recovered patch results as snapshot boundaries; strip /data prefixes at execution time - retry failed continuations without regenerate; mount a single AgentChat; disable response controls on read-only threads; freeze review toggle during runs (client+server) - accumulate usage across continuations and match the SDK's nested usage shape; label-form token strings; reorderable source label; accessible note field; state-neutral web-search label * chore(i18n): translate revised agent strings across all locales * fix(agent): harden baseUpdatedAt validation and address review follow-ups - bundle tokenx in the server runtime dependencies (e2e boot failure) - strict ISO schema for baseUpdatedAt plus loud executor rejection of unparseable values - it-IT source label consistency (Fonte) - prove penultimate-turn retention in the context pruning test * chore(deps): exempt tokenx from knip for the externalized server bundle
53 lines
2.2 KiB
TypeScript
53 lines
2.2 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { buildAgentDraftResumeName, buildUniqueAgentDraftSlug, normalizeAgentResumePatchOperations } from "./resume";
|
|
|
|
describe("agent resume setup helpers", () => {
|
|
it("names duplicated resumes as AI drafts", () => {
|
|
expect(buildAgentDraftResumeName("Senior Product Designer")).toBe("Senior Product Designer - AI Draft");
|
|
expect(buildAgentDraftResumeName("Senior Product Designer - AI Draft")).toBe("Senior Product Designer - AI Draft");
|
|
});
|
|
|
|
it("generates unique AI draft slugs", () => {
|
|
expect(buildUniqueAgentDraftSlug("Senior Product Designer", new Set())).toBe("senior-product-designer-ai-draft");
|
|
expect(buildUniqueAgentDraftSlug("Senior Product Designer", new Set(["senior-product-designer-ai-draft"]))).toBe(
|
|
"senior-product-designer-ai-draft-2",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("normalizeAgentResumePatchOperations", () => {
|
|
it("prefixes shorthand standard section paths without touching custom section paths", () => {
|
|
const result = normalizeAgentResumePatchOperations(
|
|
{
|
|
sections: {
|
|
experience: {},
|
|
education: {},
|
|
},
|
|
},
|
|
[
|
|
{ op: "replace", path: "/experience/items/0/description", value: "Updated" },
|
|
{ op: "copy", from: "/education/items/0", path: "/customSections/0/items/-" },
|
|
],
|
|
);
|
|
|
|
expect(result).toEqual([
|
|
{ op: "replace", path: "/sections/experience/items/0/description", value: "Updated" },
|
|
{ op: "copy", from: "/sections/education/items/0", path: "/customSections/0/items/-" },
|
|
]);
|
|
});
|
|
|
|
it("strips the /data prefix from path and from at execution time", () => {
|
|
const result = normalizeAgentResumePatchOperations({ sections: { experience: {} } }, [
|
|
{ op: "replace", path: "/data/basics/name", value: "Bob" },
|
|
{ op: "move", path: "/data/basics/headline", from: "/data/basics/label" },
|
|
{ op: "replace", path: "/data/experience/items/0/description", value: "Combined with section shortcut" },
|
|
]);
|
|
|
|
expect(result).toEqual([
|
|
{ op: "replace", path: "/basics/name", value: "Bob" },
|
|
{ op: "move", path: "/basics/headline", from: "/basics/label" },
|
|
{ op: "replace", path: "/sections/experience/items/0/description", value: "Combined with section shortcut" },
|
|
]);
|
|
});
|
|
});
|