@agent-native/core 0.24.2 → 0.24.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/chat-threads/store.d.ts +6 -2
  2. package/dist/chat-threads/store.d.ts.map +1 -1
  3. package/dist/chat-threads/store.js +20 -6
  4. package/dist/chat-threads/store.js.map +1 -1
  5. package/dist/cli/migrate.d.ts +1 -0
  6. package/dist/cli/migrate.d.ts.map +1 -1
  7. package/dist/cli/migrate.js +137 -5
  8. package/dist/cli/migrate.js.map +1 -1
  9. package/dist/client/use-chat-threads.d.ts +2 -2
  10. package/dist/client/use-chat-threads.d.ts.map +1 -1
  11. package/dist/client/use-chat-threads.js +91 -10
  12. package/dist/client/use-chat-threads.js.map +1 -1
  13. package/dist/client/use-chat-threads.spec.js +225 -0
  14. package/dist/client/use-chat-threads.spec.js.map +1 -1
  15. package/dist/scripts/db/exec.d.ts.map +1 -1
  16. package/dist/scripts/db/exec.js +2 -1
  17. package/dist/scripts/db/exec.js.map +1 -1
  18. package/dist/scripts/db/patch.d.ts.map +1 -1
  19. package/dist/scripts/db/patch.js +2 -1
  20. package/dist/scripts/db/patch.js.map +1 -1
  21. package/dist/scripts/db/safety.d.ts +2 -0
  22. package/dist/scripts/db/safety.d.ts.map +1 -1
  23. package/dist/scripts/db/safety.js +130 -0
  24. package/dist/scripts/db/safety.js.map +1 -1
  25. package/dist/scripts/dev/index.js +1 -1
  26. package/dist/scripts/dev/index.js.map +1 -1
  27. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  28. package/dist/server/agent-chat-plugin.js +33 -7
  29. package/dist/server/agent-chat-plugin.js.map +1 -1
  30. package/docs/content/dispatch.md +2 -2
  31. package/docs/content/faq.md +11 -11
  32. package/docs/content/template-assets.md +23 -1
  33. package/docs/content/template-brain.md +31 -8
  34. package/docs/content/template-clips.md +19 -0
  35. package/docs/content/template-design.md +21 -0
  36. package/docs/content/template-forms.md +19 -0
  37. package/package.json +1 -1
@@ -468,6 +468,231 @@ describe("useChatThreads", () => {
468
468
  });
469
469
  expect(hook.threads.find((thread) => thread.id === "thread-1")?.title).toBe("New title");
470
470
  });
471
+ it("rolls back a failed pin update", async () => {
472
+ const sourceThread = {
473
+ id: "thread-1",
474
+ title: "Pinned candidate",
475
+ preview: "old preview",
476
+ messageCount: 1,
477
+ createdAt: 1,
478
+ updatedAt: 2,
479
+ scope: null,
480
+ pinnedAt: null,
481
+ };
482
+ const fetchMock = vi.fn(async (url, init) => {
483
+ if (url === "/chat/threads" && !init) {
484
+ return jsonResponse({ threads: [sourceThread] });
485
+ }
486
+ if (url === "/chat/threads/thread-1/pin" && init?.method === "POST") {
487
+ return new Response(JSON.stringify({ error: "nope" }), {
488
+ status: 500,
489
+ headers: { "Content-Type": "application/json" },
490
+ });
491
+ }
492
+ throw new Error(`Unexpected fetch: ${url}`);
493
+ });
494
+ vi.stubGlobal("fetch", fetchMock);
495
+ let hook = null;
496
+ function Harness() {
497
+ hook = useChatThreads("/chat", "pin-failure-test", null, {
498
+ autoCreate: false,
499
+ });
500
+ return null;
501
+ }
502
+ await act(async () => {
503
+ root.render(_jsx(Harness, {}));
504
+ });
505
+ await act(async () => {
506
+ await Promise.resolve();
507
+ await Promise.resolve();
508
+ });
509
+ let pinned = true;
510
+ await act(async () => {
511
+ pinned = await hook.pinThread("thread-1", true);
512
+ });
513
+ expect(pinned).toBe(false);
514
+ expect(hook.threads.find((thread) => thread.id === "thread-1")).toMatchObject({
515
+ pinnedAt: null,
516
+ updatedAt: 2,
517
+ });
518
+ });
519
+ it("keeps the active thread when archive fails", async () => {
520
+ window.localStorage.setItem("agent-chat-active-thread:archive-failure-test", "thread-1");
521
+ const sourceThread = {
522
+ id: "thread-1",
523
+ title: "Archive candidate",
524
+ preview: "old preview",
525
+ messageCount: 1,
526
+ createdAt: 1,
527
+ updatedAt: 2,
528
+ scope: null,
529
+ archivedAt: null,
530
+ };
531
+ const fetchMock = vi.fn(async (url, init) => {
532
+ if (url === "/chat/threads" && !init) {
533
+ return jsonResponse({ threads: [sourceThread] });
534
+ }
535
+ if (url === "/chat/threads/thread-1/archive" && init?.method === "POST") {
536
+ return new Response(JSON.stringify({ error: "nope" }), {
537
+ status: 500,
538
+ headers: { "Content-Type": "application/json" },
539
+ });
540
+ }
541
+ throw new Error(`Unexpected fetch: ${url}`);
542
+ });
543
+ vi.stubGlobal("fetch", fetchMock);
544
+ let hook = null;
545
+ function Harness() {
546
+ hook = useChatThreads("/chat", "archive-failure-test", null, {
547
+ autoCreate: false,
548
+ });
549
+ return null;
550
+ }
551
+ await act(async () => {
552
+ root.render(_jsx(Harness, {}));
553
+ });
554
+ await act(async () => {
555
+ await Promise.resolve();
556
+ await Promise.resolve();
557
+ });
558
+ let archived = true;
559
+ await act(async () => {
560
+ archived = await hook.archiveThread("thread-1");
561
+ });
562
+ expect(archived).toBe(false);
563
+ expect(hook.activeThreadId).toBe("thread-1");
564
+ expect(hook.threads.find((thread) => thread.id === "thread-1")).toMatchObject({
565
+ archivedAt: null,
566
+ updatedAt: 2,
567
+ });
568
+ });
569
+ it("keeps server pin metadata when local updatedAt is newer for another reason", async () => {
570
+ let serverThread = {
571
+ id: "thread-1",
572
+ title: "Thread",
573
+ preview: "old preview",
574
+ messageCount: 1,
575
+ createdAt: 1,
576
+ updatedAt: 2,
577
+ scope: null,
578
+ pinnedAt: null,
579
+ };
580
+ const fetchMock = vi.fn(async (url, init) => {
581
+ if (url === "/chat/threads" && !init) {
582
+ return jsonResponse({ threads: [serverThread] });
583
+ }
584
+ if (url === "/chat/threads/thread-1" && init?.method === "PUT") {
585
+ return jsonResponse({ ok: true });
586
+ }
587
+ throw new Error(`Unexpected fetch: ${url}`);
588
+ });
589
+ vi.stubGlobal("fetch", fetchMock);
590
+ let hook = null;
591
+ function Harness() {
592
+ hook = useChatThreads("/chat", "server-pin-merge-test", null, {
593
+ autoCreate: false,
594
+ });
595
+ return null;
596
+ }
597
+ await act(async () => {
598
+ root.render(_jsx(Harness, {}));
599
+ });
600
+ await act(async () => {
601
+ await Promise.resolve();
602
+ await Promise.resolve();
603
+ });
604
+ await act(async () => {
605
+ await hook.saveThreadData("thread-1", {
606
+ threadData: "{}",
607
+ title: "Thread",
608
+ preview: "local send",
609
+ messageCount: 2,
610
+ });
611
+ });
612
+ serverThread = {
613
+ ...serverThread,
614
+ pinnedAt: 123,
615
+ updatedAt: 3,
616
+ };
617
+ await act(async () => {
618
+ hook.refreshThreads();
619
+ await Promise.resolve();
620
+ await Promise.resolve();
621
+ });
622
+ expect(hook.threads.find((thread) => thread.id === "thread-1")).toMatchObject({
623
+ pinnedAt: 123,
624
+ preview: "local send",
625
+ messageCount: 2,
626
+ });
627
+ });
628
+ it("does not restore an archived thread after failed archive if the user moved on", async () => {
629
+ window.localStorage.setItem("agent-chat-active-thread:archive-navigation-test", "thread-1");
630
+ const threads = [
631
+ {
632
+ id: "thread-1",
633
+ title: "Archive candidate",
634
+ preview: "old preview",
635
+ messageCount: 1,
636
+ createdAt: 1,
637
+ updatedAt: 2,
638
+ scope: null,
639
+ archivedAt: null,
640
+ },
641
+ {
642
+ id: "thread-2",
643
+ title: "Next thread",
644
+ preview: "keep me open",
645
+ messageCount: 1,
646
+ createdAt: 3,
647
+ updatedAt: 4,
648
+ scope: null,
649
+ archivedAt: null,
650
+ },
651
+ ];
652
+ let resolveArchive = null;
653
+ const fetchMock = vi.fn(async (url, init) => {
654
+ if (url === "/chat/threads" && !init) {
655
+ return jsonResponse({ threads });
656
+ }
657
+ if (url === "/chat/threads/thread-1/archive" && init?.method === "POST") {
658
+ return new Promise((resolve) => {
659
+ resolveArchive = resolve;
660
+ });
661
+ }
662
+ throw new Error(`Unexpected fetch: ${url}`);
663
+ });
664
+ vi.stubGlobal("fetch", fetchMock);
665
+ let hook = null;
666
+ function Harness() {
667
+ hook = useChatThreads("/chat", "archive-navigation-test", null, {
668
+ autoCreate: false,
669
+ });
670
+ return null;
671
+ }
672
+ await act(async () => {
673
+ root.render(_jsx(Harness, {}));
674
+ });
675
+ await act(async () => {
676
+ await Promise.resolve();
677
+ await Promise.resolve();
678
+ });
679
+ let archivePromise;
680
+ await act(async () => {
681
+ archivePromise = hook.archiveThread("thread-1");
682
+ hook.switchThread("thread-2");
683
+ await Promise.resolve();
684
+ });
685
+ await act(async () => {
686
+ resolveArchive(new Response(JSON.stringify({ error: "nope" }), {
687
+ status: 500,
688
+ headers: { "Content-Type": "application/json" },
689
+ }));
690
+ await archivePromise;
691
+ await Promise.resolve();
692
+ await Promise.resolve();
693
+ });
694
+ expect(hook.activeThreadId).toBe("thread-2");
695
+ });
471
696
  it("preserves a user rename over generated titles and later saves", async () => {
472
697
  const sourceThread = {
473
698
  id: "thread-1",
@@ -1 +1 @@
1
- {"version":3,"file":"use-chat-threads.spec.js","sourceRoot":"","sources":["../../src/client/use-chat-threads.spec.tsx"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment happy-dom\n\nimport React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport {\n useChatThreads,\n type ChatThreadScope,\n type ChatThreadSnapshot,\n type ChatThreadSummary,\n} from \"./use-chat-threads.js\";\n\nfunction jsonResponse(data: unknown) {\n return new Response(JSON.stringify(data), {\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n\ndescribe(\"useChatThreads\", () => {\n let container: HTMLDivElement;\n let root: Root;\n\n beforeEach(() => {\n vi.stubGlobal(\"IS_REACT_ACT_ENVIRONMENT\", true);\n vi.stubGlobal(\"crypto\", { randomUUID: () => \"forked-thread\" });\n window.localStorage.clear();\n container = document.createElement(\"div\");\n document.body.appendChild(container);\n root = createRoot(container);\n });\n\n afterEach(() => {\n act(() => {\n root.unmount();\n });\n container.remove();\n vi.unstubAllGlobals();\n });\n\n it(\"starts fresh when no active thread is saved, even if server history exists\", async () => {\n const oldThread: ChatThreadSummary = {\n id: \"old-project-thread\",\n title: \"Animated charting tool\",\n preview: \"make the chart more playful\",\n messageCount: 2,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [oldThread] });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"analytics-project\");\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(hook!.activeThreadId).toBe(\"forked-thread\");\n expect(hook!.threads.map((thread) => thread.id)).toEqual([\n \"forked-thread\",\n \"old-project-thread\",\n ]);\n });\n\n it(\"keeps a saved active thread when it still exists on the server\", async () => {\n window.localStorage.setItem(\n \"agent-chat-active-thread:analytics-project\",\n \"old-project-thread\",\n );\n const oldThread: ChatThreadSummary = {\n id: \"old-project-thread\",\n title: \"Analytics for Academy\",\n preview: \"show weekly signups\",\n messageCount: 2,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [oldThread] });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"analytics-project\");\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(hook!.activeThreadId).toBe(\"old-project-thread\");\n expect(hook!.threads.map((thread) => thread.id)).toEqual([\n \"old-project-thread\",\n ]);\n });\n\n it(\"can ignore a saved active thread and start fresh immediately\", async () => {\n window.localStorage.setItem(\n \"agent-chat-active-thread:brain\",\n \"old-brain-thread\",\n );\n const oldThread: ChatThreadSummary = {\n id: \"old-brain-thread\",\n title: \"Using the Brain demo corpus\",\n preview: \"what should the demo cite?\",\n messageCount: 2,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [oldThread] });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"brain\", null, {\n restoreActiveThread: false,\n });\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n\n expect(hook!.activeThreadId).toBe(\"forked-thread\");\n\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(hook!.threads.map((thread) => thread.id)).toEqual([\n \"forked-thread\",\n \"old-brain-thread\",\n ]);\n });\n\n it(\"keeps the active general chat visible when entering a scoped surface\", async () => {\n window.localStorage.setItem(\n \"agent-chat-active-thread:forms-app\",\n \"general-thread\",\n );\n const generalThread: ChatThreadSummary = {\n id: \"general-thread\",\n title: \"Create a form\",\n preview: \"make me a form\",\n messageCount: 2,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n };\n const formThread: ChatThreadSummary = {\n id: \"form-thread\",\n title: \"Form edits\",\n preview: \"add another question\",\n messageCount: 2,\n createdAt: 3,\n updatedAt: 4,\n scope: { type: \"form\", id: \"form-1\", label: \"Hackathon\" },\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [generalThread, formThread] });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness({ scope }: { scope?: ChatThreadScope | null }) {\n hook = useChatThreads(\"/chat\", \"forms-app\", scope);\n return null;\n }\n\n await act(async () => {\n root.render(<Harness scope={null} />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(hook!.activeThreadId).toBe(\"general-thread\");\n\n await act(async () => {\n root.render(\n <Harness scope={{ type: \"form\", id: \"form-1\", label: \"Hackathon\" }} />,\n );\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(hook!.activeThreadId).toBe(\"general-thread\");\n expect(\n window.localStorage.getItem(\n \"agent-chat-active-thread:forms-app:scope:form:form-1\",\n ),\n ).toBeNull();\n expect(\n window.localStorage.getItem(\"agent-chat-active-thread:forms-app\"),\n ).toBe(\"general-thread\");\n });\n\n it(\"switches back to the general chat when leaving a scoped thread\", async () => {\n window.localStorage.setItem(\n \"agent-chat-active-thread:forms-app\",\n \"general-thread\",\n );\n window.localStorage.setItem(\n \"agent-chat-active-thread:forms-app:scope:form:form-1\",\n \"form-thread\",\n );\n const generalThread: ChatThreadSummary = {\n id: \"general-thread\",\n title: \"Create a form\",\n preview: \"make me a form\",\n messageCount: 2,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n };\n const formThread: ChatThreadSummary = {\n id: \"form-thread\",\n title: \"Form edits\",\n preview: \"add another question\",\n messageCount: 2,\n createdAt: 3,\n updatedAt: 4,\n scope: { type: \"form\", id: \"form-1\", label: \"Hackathon\" },\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [formThread, generalThread] });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness({ scope }: { scope?: ChatThreadScope | null }) {\n hook = useChatThreads(\"/chat\", \"forms-app\", scope);\n return null;\n }\n\n await act(async () => {\n root.render(\n <Harness scope={{ type: \"form\", id: \"form-1\", label: \"Hackathon\" }} />,\n );\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(hook!.activeThreadId).toBe(\"form-thread\");\n\n await act(async () => {\n root.render(<Harness scope={null} />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(hook!.activeThreadId).toBe(\"general-thread\");\n });\n\n it(\"sends the current client snapshot when forking a thread\", async () => {\n const sourceThread: ChatThreadSummary = {\n id: \"source-thread\",\n title: \"Pipeline\",\n preview: \"make this slide better\",\n messageCount: 2,\n createdAt: 1,\n updatedAt: 2,\n scope: { type: \"dashboard\", id: \"dash-1\", label: \"Pipeline\" },\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [sourceThread] });\n }\n if (url === \"/chat/threads/source-thread/fork\") {\n return jsonResponse({\n ...sourceThread,\n id: \"forked-thread\",\n title: \"Pipeline (fork)\",\n });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"fork-test\");\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n const snapshot: ChatThreadSnapshot = {\n threadData: JSON.stringify({ messages: [{ message: { id: \"m1\" } }] }),\n title: \"Pipeline\",\n preview: \"make this slide better\",\n messageCount: 1,\n };\n\n let forkedId: string | null = null;\n await act(async () => {\n forkedId = await hook!.forkThread(\"source-thread\", snapshot);\n });\n\n expect(forkedId).toBe(\"forked-thread\");\n const forkCall = fetchMock.mock.calls.find(\n ([url]) => url === \"/chat/threads/source-thread/fork\",\n );\n expect(forkCall).toBeDefined();\n expect(JSON.parse(forkCall![1]!.body as string)).toEqual({\n id: \"forked-thread\",\n source: { ...snapshot, scope: sourceThread.scope },\n });\n });\n\n it(\"creates a fork from the client snapshot when the fork endpoint cannot find the source\", async () => {\n const sourceThread: ChatThreadSummary = {\n id: \"source-thread\",\n title: \"Pipeline\",\n preview: \"make this slide better\",\n messageCount: 2,\n createdAt: 1,\n updatedAt: 2,\n scope: { type: \"deck\", id: \"deck-1\", label: \"Pipeline deck\" },\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [sourceThread] });\n }\n if (url === \"/chat/threads/source-thread/fork\") {\n return new Response(JSON.stringify({ error: \"Thread not found\" }), {\n status: 404,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n if (url === \"/chat/threads\" && init?.method === \"POST\") {\n return jsonResponse({\n id: \"forked-thread\",\n title: \"Pipeline (fork)\",\n preview: \"\",\n messageCount: 0,\n createdAt: 3,\n updatedAt: 3,\n scope: sourceThread.scope,\n });\n }\n if (url === \"/chat/threads/forked-thread\" && init?.method === \"PUT\") {\n return jsonResponse({ ok: true });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"fork-test\");\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n const snapshot: ChatThreadSnapshot = {\n threadData: JSON.stringify({ messages: [{ message: { id: \"m1\" } }] }),\n title: \"Pipeline\",\n preview: \"make this slide better\",\n messageCount: 1,\n };\n\n let forkedId: string | null = null;\n await act(async () => {\n forkedId = await hook!.forkThread(\"source-thread\", snapshot);\n });\n\n expect(forkedId).toBe(\"forked-thread\");\n const createCall = fetchMock.mock.calls.find(\n ([url, init]) => url === \"/chat/threads\" && init?.method === \"POST\",\n );\n expect(createCall).toBeDefined();\n expect(JSON.parse(createCall![1]!.body as string)).toEqual({\n id: \"forked-thread\",\n title: \"Pipeline (fork)\",\n scope: sourceThread.scope,\n });\n const saveCall = fetchMock.mock.calls.find(\n ([url, init]) =>\n url === \"/chat/threads/forked-thread\" && init?.method === \"PUT\",\n );\n expect(saveCall).toBeDefined();\n expect(JSON.parse(saveCall![1]!.body as string)).toEqual({\n threadData: snapshot.threadData,\n title: \"Pipeline (fork)\",\n preview: snapshot.preview,\n messageCount: snapshot.messageCount,\n scope: sourceThread.scope,\n });\n });\n\n it(\"keeps generated titles when later thread saves update the preview\", async () => {\n const sourceThread: ChatThreadSummary = {\n id: \"thread-1\",\n title: \"Using the Brain demo data for this example\",\n preview: \"Using the Brain demo data for this example\",\n messageCount: 1,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [sourceThread] });\n }\n if (url === \"/chat/threads/thread-1\" && init?.method === \"PUT\") {\n return jsonResponse({ ok: true });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"title-test\", null, {\n autoCreate: false,\n });\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n await act(async () => {\n await hook!.saveThreadData(\"thread-1\", {\n threadData: \"\",\n title: \"Brain Demo Setup\",\n preview: \"Using the Brain demo data for this example\",\n titleSource: \"generated\",\n });\n });\n\n await act(async () => {\n await hook!.saveThreadData(\"thread-1\", {\n threadData: JSON.stringify({ messages: [] }),\n title: \"Using the Brain demo data for this example\",\n preview: \"What should the demo answer cite?\",\n messageCount: 2,\n });\n });\n\n const saveCalls = fetchMock.mock.calls.filter(\n ([url, init]) =>\n url === \"/chat/threads/thread-1\" && init?.method === \"PUT\",\n );\n expect(JSON.parse(saveCalls[0]![1]!.body as string).title).toBe(\n \"Brain Demo Setup\",\n );\n expect(JSON.parse(saveCalls[1]![1]!.body as string).title).toBe(\n \"Brain Demo Setup\",\n );\n expect(\n hook!.threads.find((thread) => thread.id === \"thread-1\"),\n ).toMatchObject({\n title: \"Brain Demo Setup\",\n preview: \"What should the demo answer cite?\",\n messageCount: 2,\n });\n });\n\n it(\"renames a thread optimistically\", async () => {\n const sourceThread: ChatThreadSummary = {\n id: \"thread-1\",\n title: \"Old title\",\n preview: \"old preview\",\n messageCount: 1,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [sourceThread] });\n }\n if (url === \"/chat/threads/thread-1/rename\" && init?.method === \"POST\") {\n return jsonResponse({ ok: true });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"rename-test\", null, {\n autoCreate: false,\n });\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n await act(async () => {\n await hook!.renameThread(\"thread-1\", \" New title \");\n });\n\n expect(JSON.parse(fetchMock.mock.calls[1]![1]!.body as string)).toEqual({\n title: \"New title\",\n });\n expect(\n hook!.threads.find((thread) => thread.id === \"thread-1\")?.title,\n ).toBe(\"New title\");\n });\n\n it(\"preserves a user rename over generated titles and later saves\", async () => {\n const sourceThread: ChatThreadSummary = {\n id: \"thread-1\",\n title: \"Old title\",\n preview: \"old preview\",\n messageCount: 1,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n };\n let resolveGenerate:\n | ((response: Response | PromiseLike<Response>) => void)\n | null = null;\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [sourceThread] });\n }\n if (url === \"/chat/generate-title\" && init?.method === \"POST\") {\n return new Promise<Response>((resolve) => {\n resolveGenerate = resolve;\n });\n }\n if (url === \"/chat/threads/thread-1/rename\" && init?.method === \"POST\") {\n return jsonResponse({ ok: true });\n }\n if (url === \"/chat/threads/thread-1\" && init?.method === \"PUT\") {\n return jsonResponse({ ok: true });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"rename-generated-test\", null, {\n autoCreate: false,\n });\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n const generatedTitlePromise = hook!.generateTitle(\n \"thread-1\",\n \"Please summarize this chat\",\n );\n\n await act(async () => {\n await hook!.renameThread(\"thread-1\", \"User title\");\n });\n await act(async () => {\n resolveGenerate!(jsonResponse({ title: \"Generated title\" }));\n await generatedTitlePromise;\n });\n await act(async () => {\n await hook!.saveThreadData(\"thread-1\", {\n threadData: \"\",\n title: \"Generated title\",\n preview: \"Please summarize this chat\",\n titleSource: \"generated\",\n });\n });\n\n const saveCall = fetchMock.mock.calls.find(\n ([url, init]) =>\n url === \"/chat/threads/thread-1\" && init?.method === \"PUT\",\n );\n expect(JSON.parse(saveCall![1]!.body as string).title).toBe(\"User title\");\n expect(\n hook!.threads.find((thread) => thread.id === \"thread-1\")?.title,\n ).toBe(\"User title\");\n });\n});\n"]}
1
+ {"version":3,"file":"use-chat-threads.spec.js","sourceRoot":"","sources":["../../src/client/use-chat-threads.spec.tsx"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment happy-dom\n\nimport React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport {\n useChatThreads,\n type ChatThreadScope,\n type ChatThreadSnapshot,\n type ChatThreadSummary,\n} from \"./use-chat-threads.js\";\n\nfunction jsonResponse(data: unknown) {\n return new Response(JSON.stringify(data), {\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n\ndescribe(\"useChatThreads\", () => {\n let container: HTMLDivElement;\n let root: Root;\n\n beforeEach(() => {\n vi.stubGlobal(\"IS_REACT_ACT_ENVIRONMENT\", true);\n vi.stubGlobal(\"crypto\", { randomUUID: () => \"forked-thread\" });\n window.localStorage.clear();\n container = document.createElement(\"div\");\n document.body.appendChild(container);\n root = createRoot(container);\n });\n\n afterEach(() => {\n act(() => {\n root.unmount();\n });\n container.remove();\n vi.unstubAllGlobals();\n });\n\n it(\"starts fresh when no active thread is saved, even if server history exists\", async () => {\n const oldThread: ChatThreadSummary = {\n id: \"old-project-thread\",\n title: \"Animated charting tool\",\n preview: \"make the chart more playful\",\n messageCount: 2,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [oldThread] });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"analytics-project\");\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(hook!.activeThreadId).toBe(\"forked-thread\");\n expect(hook!.threads.map((thread) => thread.id)).toEqual([\n \"forked-thread\",\n \"old-project-thread\",\n ]);\n });\n\n it(\"keeps a saved active thread when it still exists on the server\", async () => {\n window.localStorage.setItem(\n \"agent-chat-active-thread:analytics-project\",\n \"old-project-thread\",\n );\n const oldThread: ChatThreadSummary = {\n id: \"old-project-thread\",\n title: \"Analytics for Academy\",\n preview: \"show weekly signups\",\n messageCount: 2,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [oldThread] });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"analytics-project\");\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(hook!.activeThreadId).toBe(\"old-project-thread\");\n expect(hook!.threads.map((thread) => thread.id)).toEqual([\n \"old-project-thread\",\n ]);\n });\n\n it(\"can ignore a saved active thread and start fresh immediately\", async () => {\n window.localStorage.setItem(\n \"agent-chat-active-thread:brain\",\n \"old-brain-thread\",\n );\n const oldThread: ChatThreadSummary = {\n id: \"old-brain-thread\",\n title: \"Using the Brain demo corpus\",\n preview: \"what should the demo cite?\",\n messageCount: 2,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [oldThread] });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"brain\", null, {\n restoreActiveThread: false,\n });\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n\n expect(hook!.activeThreadId).toBe(\"forked-thread\");\n\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(hook!.threads.map((thread) => thread.id)).toEqual([\n \"forked-thread\",\n \"old-brain-thread\",\n ]);\n });\n\n it(\"keeps the active general chat visible when entering a scoped surface\", async () => {\n window.localStorage.setItem(\n \"agent-chat-active-thread:forms-app\",\n \"general-thread\",\n );\n const generalThread: ChatThreadSummary = {\n id: \"general-thread\",\n title: \"Create a form\",\n preview: \"make me a form\",\n messageCount: 2,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n };\n const formThread: ChatThreadSummary = {\n id: \"form-thread\",\n title: \"Form edits\",\n preview: \"add another question\",\n messageCount: 2,\n createdAt: 3,\n updatedAt: 4,\n scope: { type: \"form\", id: \"form-1\", label: \"Hackathon\" },\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [generalThread, formThread] });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness({ scope }: { scope?: ChatThreadScope | null }) {\n hook = useChatThreads(\"/chat\", \"forms-app\", scope);\n return null;\n }\n\n await act(async () => {\n root.render(<Harness scope={null} />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(hook!.activeThreadId).toBe(\"general-thread\");\n\n await act(async () => {\n root.render(\n <Harness scope={{ type: \"form\", id: \"form-1\", label: \"Hackathon\" }} />,\n );\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(hook!.activeThreadId).toBe(\"general-thread\");\n expect(\n window.localStorage.getItem(\n \"agent-chat-active-thread:forms-app:scope:form:form-1\",\n ),\n ).toBeNull();\n expect(\n window.localStorage.getItem(\"agent-chat-active-thread:forms-app\"),\n ).toBe(\"general-thread\");\n });\n\n it(\"switches back to the general chat when leaving a scoped thread\", async () => {\n window.localStorage.setItem(\n \"agent-chat-active-thread:forms-app\",\n \"general-thread\",\n );\n window.localStorage.setItem(\n \"agent-chat-active-thread:forms-app:scope:form:form-1\",\n \"form-thread\",\n );\n const generalThread: ChatThreadSummary = {\n id: \"general-thread\",\n title: \"Create a form\",\n preview: \"make me a form\",\n messageCount: 2,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n };\n const formThread: ChatThreadSummary = {\n id: \"form-thread\",\n title: \"Form edits\",\n preview: \"add another question\",\n messageCount: 2,\n createdAt: 3,\n updatedAt: 4,\n scope: { type: \"form\", id: \"form-1\", label: \"Hackathon\" },\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [formThread, generalThread] });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness({ scope }: { scope?: ChatThreadScope | null }) {\n hook = useChatThreads(\"/chat\", \"forms-app\", scope);\n return null;\n }\n\n await act(async () => {\n root.render(\n <Harness scope={{ type: \"form\", id: \"form-1\", label: \"Hackathon\" }} />,\n );\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(hook!.activeThreadId).toBe(\"form-thread\");\n\n await act(async () => {\n root.render(<Harness scope={null} />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(hook!.activeThreadId).toBe(\"general-thread\");\n });\n\n it(\"sends the current client snapshot when forking a thread\", async () => {\n const sourceThread: ChatThreadSummary = {\n id: \"source-thread\",\n title: \"Pipeline\",\n preview: \"make this slide better\",\n messageCount: 2,\n createdAt: 1,\n updatedAt: 2,\n scope: { type: \"dashboard\", id: \"dash-1\", label: \"Pipeline\" },\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [sourceThread] });\n }\n if (url === \"/chat/threads/source-thread/fork\") {\n return jsonResponse({\n ...sourceThread,\n id: \"forked-thread\",\n title: \"Pipeline (fork)\",\n });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"fork-test\");\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n const snapshot: ChatThreadSnapshot = {\n threadData: JSON.stringify({ messages: [{ message: { id: \"m1\" } }] }),\n title: \"Pipeline\",\n preview: \"make this slide better\",\n messageCount: 1,\n };\n\n let forkedId: string | null = null;\n await act(async () => {\n forkedId = await hook!.forkThread(\"source-thread\", snapshot);\n });\n\n expect(forkedId).toBe(\"forked-thread\");\n const forkCall = fetchMock.mock.calls.find(\n ([url]) => url === \"/chat/threads/source-thread/fork\",\n );\n expect(forkCall).toBeDefined();\n expect(JSON.parse(forkCall![1]!.body as string)).toEqual({\n id: \"forked-thread\",\n source: { ...snapshot, scope: sourceThread.scope },\n });\n });\n\n it(\"creates a fork from the client snapshot when the fork endpoint cannot find the source\", async () => {\n const sourceThread: ChatThreadSummary = {\n id: \"source-thread\",\n title: \"Pipeline\",\n preview: \"make this slide better\",\n messageCount: 2,\n createdAt: 1,\n updatedAt: 2,\n scope: { type: \"deck\", id: \"deck-1\", label: \"Pipeline deck\" },\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [sourceThread] });\n }\n if (url === \"/chat/threads/source-thread/fork\") {\n return new Response(JSON.stringify({ error: \"Thread not found\" }), {\n status: 404,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n if (url === \"/chat/threads\" && init?.method === \"POST\") {\n return jsonResponse({\n id: \"forked-thread\",\n title: \"Pipeline (fork)\",\n preview: \"\",\n messageCount: 0,\n createdAt: 3,\n updatedAt: 3,\n scope: sourceThread.scope,\n });\n }\n if (url === \"/chat/threads/forked-thread\" && init?.method === \"PUT\") {\n return jsonResponse({ ok: true });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"fork-test\");\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n const snapshot: ChatThreadSnapshot = {\n threadData: JSON.stringify({ messages: [{ message: { id: \"m1\" } }] }),\n title: \"Pipeline\",\n preview: \"make this slide better\",\n messageCount: 1,\n };\n\n let forkedId: string | null = null;\n await act(async () => {\n forkedId = await hook!.forkThread(\"source-thread\", snapshot);\n });\n\n expect(forkedId).toBe(\"forked-thread\");\n const createCall = fetchMock.mock.calls.find(\n ([url, init]) => url === \"/chat/threads\" && init?.method === \"POST\",\n );\n expect(createCall).toBeDefined();\n expect(JSON.parse(createCall![1]!.body as string)).toEqual({\n id: \"forked-thread\",\n title: \"Pipeline (fork)\",\n scope: sourceThread.scope,\n });\n const saveCall = fetchMock.mock.calls.find(\n ([url, init]) =>\n url === \"/chat/threads/forked-thread\" && init?.method === \"PUT\",\n );\n expect(saveCall).toBeDefined();\n expect(JSON.parse(saveCall![1]!.body as string)).toEqual({\n threadData: snapshot.threadData,\n title: \"Pipeline (fork)\",\n preview: snapshot.preview,\n messageCount: snapshot.messageCount,\n scope: sourceThread.scope,\n });\n });\n\n it(\"keeps generated titles when later thread saves update the preview\", async () => {\n const sourceThread: ChatThreadSummary = {\n id: \"thread-1\",\n title: \"Using the Brain demo data for this example\",\n preview: \"Using the Brain demo data for this example\",\n messageCount: 1,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [sourceThread] });\n }\n if (url === \"/chat/threads/thread-1\" && init?.method === \"PUT\") {\n return jsonResponse({ ok: true });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"title-test\", null, {\n autoCreate: false,\n });\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n await act(async () => {\n await hook!.saveThreadData(\"thread-1\", {\n threadData: \"\",\n title: \"Brain Demo Setup\",\n preview: \"Using the Brain demo data for this example\",\n titleSource: \"generated\",\n });\n });\n\n await act(async () => {\n await hook!.saveThreadData(\"thread-1\", {\n threadData: JSON.stringify({ messages: [] }),\n title: \"Using the Brain demo data for this example\",\n preview: \"What should the demo answer cite?\",\n messageCount: 2,\n });\n });\n\n const saveCalls = fetchMock.mock.calls.filter(\n ([url, init]) =>\n url === \"/chat/threads/thread-1\" && init?.method === \"PUT\",\n );\n expect(JSON.parse(saveCalls[0]![1]!.body as string).title).toBe(\n \"Brain Demo Setup\",\n );\n expect(JSON.parse(saveCalls[1]![1]!.body as string).title).toBe(\n \"Brain Demo Setup\",\n );\n expect(\n hook!.threads.find((thread) => thread.id === \"thread-1\"),\n ).toMatchObject({\n title: \"Brain Demo Setup\",\n preview: \"What should the demo answer cite?\",\n messageCount: 2,\n });\n });\n\n it(\"renames a thread optimistically\", async () => {\n const sourceThread: ChatThreadSummary = {\n id: \"thread-1\",\n title: \"Old title\",\n preview: \"old preview\",\n messageCount: 1,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [sourceThread] });\n }\n if (url === \"/chat/threads/thread-1/rename\" && init?.method === \"POST\") {\n return jsonResponse({ ok: true });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"rename-test\", null, {\n autoCreate: false,\n });\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n await act(async () => {\n await hook!.renameThread(\"thread-1\", \" New title \");\n });\n\n expect(JSON.parse(fetchMock.mock.calls[1]![1]!.body as string)).toEqual({\n title: \"New title\",\n });\n expect(\n hook!.threads.find((thread) => thread.id === \"thread-1\")?.title,\n ).toBe(\"New title\");\n });\n\n it(\"rolls back a failed pin update\", async () => {\n const sourceThread: ChatThreadSummary = {\n id: \"thread-1\",\n title: \"Pinned candidate\",\n preview: \"old preview\",\n messageCount: 1,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n pinnedAt: null,\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [sourceThread] });\n }\n if (url === \"/chat/threads/thread-1/pin\" && init?.method === \"POST\") {\n return new Response(JSON.stringify({ error: \"nope\" }), {\n status: 500,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"pin-failure-test\", null, {\n autoCreate: false,\n });\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n let pinned = true;\n await act(async () => {\n pinned = await hook!.pinThread(\"thread-1\", true);\n });\n\n expect(pinned).toBe(false);\n expect(\n hook!.threads.find((thread) => thread.id === \"thread-1\"),\n ).toMatchObject({\n pinnedAt: null,\n updatedAt: 2,\n });\n });\n\n it(\"keeps the active thread when archive fails\", async () => {\n window.localStorage.setItem(\n \"agent-chat-active-thread:archive-failure-test\",\n \"thread-1\",\n );\n const sourceThread: ChatThreadSummary = {\n id: \"thread-1\",\n title: \"Archive candidate\",\n preview: \"old preview\",\n messageCount: 1,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n archivedAt: null,\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [sourceThread] });\n }\n if (url === \"/chat/threads/thread-1/archive\" && init?.method === \"POST\") {\n return new Response(JSON.stringify({ error: \"nope\" }), {\n status: 500,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"archive-failure-test\", null, {\n autoCreate: false,\n });\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n let archived = true;\n await act(async () => {\n archived = await hook!.archiveThread(\"thread-1\");\n });\n\n expect(archived).toBe(false);\n expect(hook!.activeThreadId).toBe(\"thread-1\");\n expect(\n hook!.threads.find((thread) => thread.id === \"thread-1\"),\n ).toMatchObject({\n archivedAt: null,\n updatedAt: 2,\n });\n });\n\n it(\"keeps server pin metadata when local updatedAt is newer for another reason\", async () => {\n let serverThread: ChatThreadSummary = {\n id: \"thread-1\",\n title: \"Thread\",\n preview: \"old preview\",\n messageCount: 1,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n pinnedAt: null,\n };\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [serverThread] });\n }\n if (url === \"/chat/threads/thread-1\" && init?.method === \"PUT\") {\n return jsonResponse({ ok: true });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"server-pin-merge-test\", null, {\n autoCreate: false,\n });\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n await act(async () => {\n await hook!.saveThreadData(\"thread-1\", {\n threadData: \"{}\",\n title: \"Thread\",\n preview: \"local send\",\n messageCount: 2,\n });\n });\n\n serverThread = {\n ...serverThread,\n pinnedAt: 123,\n updatedAt: 3,\n };\n await act(async () => {\n hook!.refreshThreads();\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(\n hook!.threads.find((thread) => thread.id === \"thread-1\"),\n ).toMatchObject({\n pinnedAt: 123,\n preview: \"local send\",\n messageCount: 2,\n });\n });\n\n it(\"does not restore an archived thread after failed archive if the user moved on\", async () => {\n window.localStorage.setItem(\n \"agent-chat-active-thread:archive-navigation-test\",\n \"thread-1\",\n );\n const threads: ChatThreadSummary[] = [\n {\n id: \"thread-1\",\n title: \"Archive candidate\",\n preview: \"old preview\",\n messageCount: 1,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n archivedAt: null,\n },\n {\n id: \"thread-2\",\n title: \"Next thread\",\n preview: \"keep me open\",\n messageCount: 1,\n createdAt: 3,\n updatedAt: 4,\n scope: null,\n archivedAt: null,\n },\n ];\n let resolveArchive:\n | ((response: Response | PromiseLike<Response>) => void)\n | null = null;\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads });\n }\n if (url === \"/chat/threads/thread-1/archive\" && init?.method === \"POST\") {\n return new Promise<Response>((resolve) => {\n resolveArchive = resolve;\n });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"archive-navigation-test\", null, {\n autoCreate: false,\n });\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n let archivePromise: Promise<boolean>;\n await act(async () => {\n archivePromise = hook!.archiveThread(\"thread-1\");\n hook!.switchThread(\"thread-2\");\n await Promise.resolve();\n });\n await act(async () => {\n resolveArchive!(\n new Response(JSON.stringify({ error: \"nope\" }), {\n status: 500,\n headers: { \"Content-Type\": \"application/json\" },\n }),\n );\n await archivePromise!;\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(hook!.activeThreadId).toBe(\"thread-2\");\n });\n\n it(\"preserves a user rename over generated titles and later saves\", async () => {\n const sourceThread: ChatThreadSummary = {\n id: \"thread-1\",\n title: \"Old title\",\n preview: \"old preview\",\n messageCount: 1,\n createdAt: 1,\n updatedAt: 2,\n scope: null,\n };\n let resolveGenerate:\n | ((response: Response | PromiseLike<Response>) => void)\n | null = null;\n const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {\n if (url === \"/chat/threads\" && !init) {\n return jsonResponse({ threads: [sourceThread] });\n }\n if (url === \"/chat/generate-title\" && init?.method === \"POST\") {\n return new Promise<Response>((resolve) => {\n resolveGenerate = resolve;\n });\n }\n if (url === \"/chat/threads/thread-1/rename\" && init?.method === \"POST\") {\n return jsonResponse({ ok: true });\n }\n if (url === \"/chat/threads/thread-1\" && init?.method === \"PUT\") {\n return jsonResponse({ ok: true });\n }\n throw new Error(`Unexpected fetch: ${url}`);\n });\n vi.stubGlobal(\"fetch\", fetchMock);\n\n let hook: ReturnType<typeof useChatThreads> | null = null;\n function Harness() {\n hook = useChatThreads(\"/chat\", \"rename-generated-test\", null, {\n autoCreate: false,\n });\n return null;\n }\n\n await act(async () => {\n root.render(<Harness />);\n });\n await act(async () => {\n await Promise.resolve();\n await Promise.resolve();\n });\n\n const generatedTitlePromise = hook!.generateTitle(\n \"thread-1\",\n \"Please summarize this chat\",\n );\n\n await act(async () => {\n await hook!.renameThread(\"thread-1\", \"User title\");\n });\n await act(async () => {\n resolveGenerate!(jsonResponse({ title: \"Generated title\" }));\n await generatedTitlePromise;\n });\n await act(async () => {\n await hook!.saveThreadData(\"thread-1\", {\n threadData: \"\",\n title: \"Generated title\",\n preview: \"Please summarize this chat\",\n titleSource: \"generated\",\n });\n });\n\n const saveCall = fetchMock.mock.calls.find(\n ([url, init]) =>\n url === \"/chat/threads/thread-1\" && init?.method === \"PUT\",\n );\n expect(JSON.parse(saveCall![1]!.body as string).title).toBe(\"User title\");\n expect(\n hook!.threads.find((thread) => thread.id === \"thread-1\")?.title,\n ).toBe(\"User title\");\n });\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../../src/scripts/db/exec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAmlBH,wBAA8B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAyJlE"}
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../../src/scripts/db/exec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAulBH,wBAA8B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAyJlE"}
@@ -17,7 +17,7 @@ import path from "path";
17
17
  import { getDatabaseUrl } from "../../db/client.js";
18
18
  import { parseArgs, fail } from "../utils.js";
19
19
  import { buildScopingPostgres, buildScopingSqlite, } from "./scoping.js";
20
- import { assertNoSensitiveFrameworkTables } from "./safety.js";
20
+ import { assertNoRawDbAccessControlWrite, assertNoSensitiveFrameworkTables, } from "./safety.js";
21
21
  import { createSqliteScriptClient } from "./sqlite-client.js";
22
22
  function isPostgresUrl(url) {
23
23
  return url.startsWith("postgres://") || url.startsWith("postgresql://");
@@ -160,6 +160,7 @@ function validateWriteSql(sql, index) {
160
160
  `Dangerous operations like DROP, ATTACH, VACUUM, DETACH, CREATE, and ALTER are blocked.`);
161
161
  }
162
162
  assertNoSensitiveFrameworkTables(normalized, "write");
163
+ assertNoRawDbAccessControlWrite(normalized);
163
164
  return normalized;
164
165
  }
165
166
  function convertQuestionMarksToPostgresParams(sql) {