@agent-native/toolkit 0.218.0 → 0.220.0-nightly-20261023183804

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 (59) hide show
  1. package/dist/app/agentkit/react/styles.css +13 -6
  2. package/dist/app/chat/AgentKitAssistantChat.d.ts +2 -0
  3. package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
  4. package/dist/app/chat/AgentKitAssistantChat.js +11 -3
  5. package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
  6. package/dist/app/chat/AgentPanel.js +6 -6
  7. package/dist/app/chat/AgentPanel.js.map +1 -1
  8. package/dist/app/chat/MultiTabAssistantChat.d.ts.map +1 -1
  9. package/dist/app/chat/MultiTabAssistantChat.js +5 -3
  10. package/dist/app/chat/MultiTabAssistantChat.js.map +1 -1
  11. package/dist/app/chat/agentkit-chat/action-widget.d.ts.map +1 -1
  12. package/dist/app/chat/agentkit-chat/action-widget.js +1 -0
  13. package/dist/app/chat/agentkit-chat/action-widget.js.map +1 -1
  14. package/dist/app/chat/chat/surface-types.d.ts +2 -0
  15. package/dist/app/chat/chat/surface-types.d.ts.map +1 -1
  16. package/dist/app/chat/chat/surface-types.js.map +1 -1
  17. package/dist/app/chat/chat/tool-call-display.d.ts +3 -1
  18. package/dist/app/chat/chat/tool-call-display.d.ts.map +1 -1
  19. package/dist/app/chat/chat/tool-call-display.js +5 -4
  20. package/dist/app/chat/chat/tool-call-display.js.map +1 -1
  21. package/dist/app/chat/chat/tool-render-registry.d.ts +2 -0
  22. package/dist/app/chat/chat/tool-render-registry.d.ts.map +1 -1
  23. package/dist/app/chat/chat/tool-render-registry.js.map +1 -1
  24. package/dist/app/chat/conversation/AgentConversation.d.ts.map +1 -1
  25. package/dist/app/chat/conversation/AgentConversation.js +6 -1
  26. package/dist/app/chat/conversation/AgentConversation.js.map +1 -1
  27. package/dist/app/shared/CommandMenu.d.ts +2 -0
  28. package/dist/app/shared/CommandMenu.d.ts.map +1 -1
  29. package/dist/app/shared/CommandMenu.js +11 -6
  30. package/dist/app/shared/CommandMenu.js.map +1 -1
  31. package/dist/composer/ComposerContextMenu.d.ts.map +1 -1
  32. package/dist/composer/ComposerContextMenu.js +27 -2
  33. package/dist/composer/ComposerContextMenu.js.map +1 -1
  34. package/dist/composer/ComposerPlusMenu.d.ts.map +1 -1
  35. package/dist/composer/ComposerPlusMenu.js +50 -4
  36. package/dist/composer/ComposerPlusMenu.js.map +1 -1
  37. package/dist/composer/TiptapComposer.js +1 -1
  38. package/dist/composer/TiptapComposer.js.map +1 -1
  39. package/package.json +4 -4
  40. package/src/app/agentkit/react/components.spec.tsx +7 -5
  41. package/src/app/agentkit/react/styles.css +13 -6
  42. package/src/app/chat/AgentKitAssistantChat.spec.tsx +258 -27
  43. package/src/app/chat/AgentKitAssistantChat.tsx +15 -2
  44. package/src/app/chat/AgentPanel.tsx +8 -8
  45. package/src/app/chat/MultiTabAssistantChat.spec.tsx +17 -0
  46. package/src/app/chat/MultiTabAssistantChat.tsx +7 -2
  47. package/src/app/chat/agentkit-chat/action-widget.spec.tsx +62 -0
  48. package/src/app/chat/agentkit-chat/action-widget.tsx +1 -0
  49. package/src/app/chat/chat/surface-types.ts +2 -0
  50. package/src/app/chat/chat/tool-call-display.tsx +10 -1
  51. package/src/app/chat/chat/tool-render-registry.tsx +2 -0
  52. package/src/app/chat/conversation/AgentConversation.spec.tsx +51 -1
  53. package/src/app/chat/conversation/AgentConversation.tsx +11 -2
  54. package/src/app/shared/CommandMenu.spec.tsx +175 -6
  55. package/src/app/shared/CommandMenu.tsx +24 -7
  56. package/src/composer/ComposerContextMenu.tsx +32 -3
  57. package/src/composer/ComposerPlusMenu.parity.spec.tsx +96 -2
  58. package/src/composer/ComposerPlusMenu.tsx +48 -4
  59. package/src/composer/TiptapComposer.tsx +1 -1
@@ -71,7 +71,10 @@ afterEach(() => {
71
71
  async function settle() {
72
72
  await new Promise((resolve) => setTimeout(resolve, 0));
73
73
  }
74
- async function mount(props: Partial<PromptComposerProps> = {}) {
74
+ async function mount(
75
+ props: Partial<PromptComposerProps> = {},
76
+ settleAfterRender = true,
77
+ ) {
75
78
  const composerRef = React.createRef<TiptapComposerHandle>();
76
79
  const onSubmit = vi.fn();
77
80
  await act(async () => {
@@ -92,7 +95,7 @@ async function mount(props: Partial<PromptComposerProps> = {}) {
92
95
  />
93
96
  </ComposerRuntimeAdaptersProvider>,
94
97
  );
95
- await settle();
98
+ if (settleAfterRender) await settle();
96
99
  });
97
100
  return { composerRef, onSubmit };
98
101
  }
@@ -722,4 +725,95 @@ describe("shared default action preservation", () => {
722
725
  expect(document.querySelector('[role="status"]')).toBeNull();
723
726
  expect(item("Upload skill file")).toBeDefined();
724
727
  });
728
+
729
+ it("resumes skill-file review after the native picker dismisses the menu", async () => {
730
+ await mount();
731
+ await open();
732
+ await choose("Create Skill");
733
+ await choose("Upload skill file");
734
+
735
+ await act(async () => {
736
+ await new Promise((resolve) => setTimeout(resolve, 120));
737
+ });
738
+
739
+ const input = container.querySelector<HTMLInputElement>(
740
+ 'input[accept=".md,text/markdown"]',
741
+ )!;
742
+ const file = new File(["# Test skill\nDo the test."], "Test Skill.md", {
743
+ type: "text/markdown",
744
+ });
745
+ Object.defineProperty(input, "files", {
746
+ configurable: true,
747
+ value: [file],
748
+ });
749
+ await act(async () => {
750
+ input.dispatchEvent(new Event("change", { bubbles: true }));
751
+ await settle();
752
+ });
753
+
754
+ const form = document.querySelector<HTMLFormElement>("[role=menu] form");
755
+ expect(form).not.toBeNull();
756
+ expect(form?.textContent).toContain(
757
+ "Review the content from Test Skill.md before saving.",
758
+ );
759
+ expect(form?.querySelector("textarea")?.value).toBe(
760
+ "# Test skill\nDo the test.",
761
+ );
762
+ });
763
+
764
+ it("restores the skill submenu when the native picker is canceled", async () => {
765
+ await mount();
766
+ await open();
767
+ await choose("Create Skill");
768
+ await choose("Upload skill file");
769
+
770
+ await act(async () => {
771
+ await new Promise((resolve) => setTimeout(resolve, 120));
772
+ });
773
+
774
+ const input = container.querySelector<HTMLInputElement>(
775
+ 'input[accept=".md,text/markdown"]',
776
+ )!;
777
+ await act(async () => {
778
+ input.dispatchEvent(new Event("cancel"));
779
+ await settle();
780
+ });
781
+
782
+ expect(labels()).toContain("Upload skill file");
783
+ });
784
+
785
+ it("does not resume the skill page if the composer is disabled", async () => {
786
+ await mount();
787
+ await open();
788
+ await choose("Create Skill");
789
+ await choose("Upload skill file");
790
+
791
+ const input = container.querySelector<HTMLInputElement>(
792
+ 'input[accept=".md,text/markdown"]',
793
+ )!;
794
+ vi.useFakeTimers();
795
+ try {
796
+ const scheduledTimeouts = vi.spyOn(globalThis, "setTimeout");
797
+ const clearedTimeouts = vi.spyOn(globalThis, "clearTimeout");
798
+ const timersBeforeCancel = vi.getTimerCount();
799
+ const timeoutCallIndex = scheduledTimeouts.mock.calls.length;
800
+ act(() => input.dispatchEvent(new Event("cancel")));
801
+ expect(vi.getTimerCount()).toBe(timersBeforeCancel + 1);
802
+ const resumeTimer =
803
+ scheduledTimeouts.mock.results[timeoutCallIndex]?.value;
804
+ expect(resumeTimer).toBeDefined();
805
+
806
+ await mount({ disabled: true }, false);
807
+ expect(clearedTimeouts).toHaveBeenCalledWith(resumeTimer);
808
+
809
+ await act(async () => {
810
+ await vi.advanceTimersByTimeAsync(0);
811
+ });
812
+
813
+ expect(document.querySelector("[role=menu] form")).toBeNull();
814
+ expect(labels()).not.toContain("Upload skill file");
815
+ } finally {
816
+ vi.useRealTimers();
817
+ }
818
+ });
725
819
  });
@@ -92,6 +92,9 @@ export function useComposerDefaultActions({
92
92
  const [view, setView] = useState<View>("menu");
93
93
  const skillFileInputRef = useRef<HTMLInputElement>(null);
94
94
  const skillControls = useRef<ComposerContextPageControls | null>(null);
95
+ const skillFilePickerOpen = useRef(false);
96
+ const skillPageDismissedWhilePickerOpen = useRef(false);
97
+ const skillResumeTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
95
98
  const skillEpoch = useRef(0);
96
99
  const skillRequest = useRef<AbortController | null>(null);
97
100
  const skillCloseTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
@@ -104,13 +107,48 @@ export function useComposerDefaultActions({
104
107
  } | null>(null);
105
108
  const [skillUploadBusy, setSkillUploadBusy] = useState(false);
106
109
  const formId = useId();
107
- const cancelSkillWork = useCallback(() => {
110
+ const invalidateSkillWork = useCallback(() => {
108
111
  skillEpoch.current++;
109
112
  skillRequest.current?.abort();
110
113
  skillRequest.current = null;
111
114
  if (skillCloseTimer.current !== null) clearTimeout(skillCloseTimer.current);
112
115
  skillCloseTimer.current = null;
113
116
  }, []);
117
+ const cancelSkillWork = useCallback(() => {
118
+ skillFilePickerOpen.current = false;
119
+ skillPageDismissedWhilePickerOpen.current = false;
120
+ if (skillResumeTimer.current !== null)
121
+ clearTimeout(skillResumeTimer.current);
122
+ skillResumeTimer.current = null;
123
+ invalidateSkillWork();
124
+ }, [invalidateSkillWork]);
125
+ const finishSkillFilePicker = useCallback(() => {
126
+ skillFilePickerOpen.current = false;
127
+ if (!skillPageDismissedWhilePickerOpen.current) return;
128
+ skillPageDismissedWhilePickerOpen.current = false;
129
+ if (skillResumeTimer.current !== null)
130
+ clearTimeout(skillResumeTimer.current);
131
+ skillResumeTimer.current = setTimeout(() => {
132
+ skillResumeTimer.current = null;
133
+ skillControls.current?.onResume();
134
+ }, 0);
135
+ }, []);
136
+ const dismissSkillPage = useCallback(() => {
137
+ if (skillFilePickerOpen.current) {
138
+ skillPageDismissedWhilePickerOpen.current = true;
139
+ return;
140
+ }
141
+ cancelSkillWork();
142
+ }, [cancelSkillWork]);
143
+ useEffect(() => {
144
+ const input = skillFileInputRef.current;
145
+ input?.addEventListener("cancel", finishSkillFilePicker);
146
+ return () => {
147
+ input?.removeEventListener("cancel", finishSkillFilePicker);
148
+ if (skillResumeTimer.current !== null)
149
+ clearTimeout(skillResumeTimer.current);
150
+ };
151
+ }, [finishSkillFilePicker]);
114
152
  useEffect(() => cancelSkillWork, [cancelSkillWork, adapters.resolvePath]);
115
153
  useEffect(() => {
116
154
  if (!disabled) return;
@@ -128,7 +166,7 @@ export function useComposerDefaultActions({
128
166
  setSkillUploadBusy(false);
129
167
  };
130
168
  const handleSkillFileSelected = async (file: File) => {
131
- cancelSkillWork();
169
+ invalidateSkillWork();
132
170
  const epoch = skillEpoch.current;
133
171
  setSkillUploadStatus(null);
134
172
  try {
@@ -298,7 +336,7 @@ export function useComposerDefaultActions({
298
336
  }),
299
337
  ],
300
338
  onSelect: resetSkillUpload,
301
- onDismiss: cancelSkillWork,
339
+ onDismiss: dismissSkillPage,
302
340
  render: (controls) => {
303
341
  skillControls.current = controls;
304
342
  return view === "menu" ? (
@@ -317,7 +355,12 @@ export function useComposerDefaultActions({
317
355
  <DropdownMenuItem
318
356
  onSelect={(event) => {
319
357
  event.preventDefault();
320
- skillFileInputRef.current?.click();
358
+ const input = skillFileInputRef.current;
359
+ if (!input) return;
360
+ skillPageDismissedWhilePickerOpen.current = false;
361
+ skillFilePickerOpen.current = true;
362
+ controls.onClose({ restoreFocus: false });
363
+ input.click();
321
364
  }}
322
365
  >
323
366
  {t("agentChat.composer.skill.uploadFile", {
@@ -451,6 +494,7 @@ export function useComposerDefaultActions({
451
494
  onChange={(event) => {
452
495
  const file = event.target.files?.[0];
453
496
  event.target.value = "";
497
+ finishSkillFilePicker();
454
498
  if (file) void handleSkillFileSelected(file);
455
499
  }}
456
500
  />
@@ -2207,7 +2207,7 @@ function ModelSelector({
2207
2207
  ? `. Agent: ${selectedAgentLabel}`
2208
2208
  : ""
2209
2209
  }`}
2210
- className="agent-composer-model-button flex min-w-0 max-w-none shrink-0 items-center gap-1 rounded-md px-2 py-1 text-[12px] font-medium text-muted-foreground hover:bg-accent/50 hover:text-foreground"
2210
+ className="agent-composer-model-button flex min-w-0 max-w-none shrink items-center gap-1 overflow-hidden rounded-md px-2 py-1 text-[12px] font-medium text-muted-foreground hover:bg-accent/50 hover:text-foreground"
2211
2211
  >
2212
2212
  <span className="min-w-0 truncate">
2213
2213
  {selectedAgentOption?.icon ? (