@agent-native/toolkit 0.217.0 → 0.219.0

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 (206) hide show
  1. package/agent-native.eject.json +21 -0
  2. package/dist/app/agent-page/AgentContextTab.d.ts.map +1 -1
  3. package/dist/app/agent-page/AgentContextTab.js +1 -0
  4. package/dist/app/agent-page/AgentContextTab.js.map +1 -1
  5. package/dist/app/agentkit/react/components.d.ts.map +1 -1
  6. package/dist/app/agentkit/react/components.js +1 -1
  7. package/dist/app/agentkit/react/components.js.map +1 -1
  8. package/dist/app/agentkit/react/context.d.ts +4 -1
  9. package/dist/app/agentkit/react/context.d.ts.map +1 -1
  10. package/dist/app/agentkit/react/context.js +3 -1
  11. package/dist/app/agentkit/react/context.js.map +1 -1
  12. package/dist/app/agentkit/react/data-chart-layout.d.ts +30 -0
  13. package/dist/app/agentkit/react/data-chart-layout.d.ts.map +1 -0
  14. package/dist/app/agentkit/react/data-chart-layout.js +2 -0
  15. package/dist/app/agentkit/react/data-chart-layout.js.map +1 -0
  16. package/dist/app/agentkit/react/index.d.ts +1 -0
  17. package/dist/app/agentkit/react/index.d.ts.map +1 -1
  18. package/dist/app/agentkit/react/index.js +1 -0
  19. package/dist/app/agentkit/react/index.js.map +1 -1
  20. package/dist/app/agentkit/react/root.d.ts +3 -1
  21. package/dist/app/agentkit/react/root.d.ts.map +1 -1
  22. package/dist/app/agentkit/react/root.js +2 -2
  23. package/dist/app/agentkit/react/root.js.map +1 -1
  24. package/dist/app/agentkit/react/styles.css +31 -6
  25. package/dist/app/agentkit/react/transcript-layout.d.ts +2 -0
  26. package/dist/app/agentkit/react/transcript-layout.d.ts.map +1 -1
  27. package/dist/app/agentkit/react/transcript-layout.js.map +1 -1
  28. package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
  29. package/dist/app/chat/AgentKitAssistantChat.js +2 -2
  30. package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
  31. package/dist/app/chat/AgentPanel.js +6 -6
  32. package/dist/app/chat/AgentPanel.js.map +1 -1
  33. package/dist/app/chat/MultiTabAssistantChat.d.ts.map +1 -1
  34. package/dist/app/chat/MultiTabAssistantChat.js +53 -95
  35. package/dist/app/chat/MultiTabAssistantChat.js.map +1 -1
  36. package/dist/app/chat/agentkit-chat/action-widget.d.ts.map +1 -1
  37. package/dist/app/chat/agentkit-chat/action-widget.js +4 -1
  38. package/dist/app/chat/agentkit-chat/action-widget.js.map +1 -1
  39. package/dist/app/chat/agentkit-chat/rail.d.ts +1 -1
  40. package/dist/app/chat/agentkit-chat/rail.d.ts.map +1 -1
  41. package/dist/app/chat/agentkit-chat/rail.js +1 -1
  42. package/dist/app/chat/agentkit-chat/rail.js.map +1 -1
  43. package/dist/app/chat/chat/index.d.ts +2 -1
  44. package/dist/app/chat/chat/index.d.ts.map +1 -1
  45. package/dist/app/chat/chat/index.js +1 -1
  46. package/dist/app/chat/chat/index.js.map +1 -1
  47. package/dist/app/chat/chat/surface-types.d.ts +3 -0
  48. package/dist/app/chat/chat/surface-types.d.ts.map +1 -1
  49. package/dist/app/chat/chat/surface-types.js.map +1 -1
  50. package/dist/app/chat/chat/tool-call-display.d.ts +5 -1
  51. package/dist/app/chat/chat/tool-call-display.d.ts.map +1 -1
  52. package/dist/app/chat/chat/tool-call-display.js +6 -4
  53. package/dist/app/chat/chat/tool-call-display.js.map +1 -1
  54. package/dist/app/chat/chat/tool-render-registry.d.ts +4 -0
  55. package/dist/app/chat/chat/tool-render-registry.d.ts.map +1 -1
  56. package/dist/app/chat/chat/tool-render-registry.js.map +1 -1
  57. package/dist/app/chat/chat/widgets/DataChartRenderer.d.ts +3 -1
  58. package/dist/app/chat/chat/widgets/DataChartRenderer.d.ts.map +1 -1
  59. package/dist/app/chat/chat/widgets/DataChartRenderer.js +116 -26
  60. package/dist/app/chat/chat/widgets/DataChartRenderer.js.map +1 -1
  61. package/dist/app/chat/chat/widgets/DataChartWidget.d.ts +3 -1
  62. package/dist/app/chat/chat/widgets/DataChartWidget.d.ts.map +1 -1
  63. package/dist/app/chat/chat/widgets/DataChartWidget.js +21 -2
  64. package/dist/app/chat/chat/widgets/DataChartWidget.js.map +1 -1
  65. package/dist/app/chat/chat/widgets/DataInsightsWidget.d.ts +3 -1
  66. package/dist/app/chat/chat/widgets/DataInsightsWidget.d.ts.map +1 -1
  67. package/dist/app/chat/chat/widgets/DataInsightsWidget.js +2 -2
  68. package/dist/app/chat/chat/widgets/DataInsightsWidget.js.map +1 -1
  69. package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.d.ts +1 -1
  70. package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.d.ts.map +1 -1
  71. package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.js +3 -1
  72. package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.js.map +1 -1
  73. package/dist/app/chat/chat/widgets/builtin-tool-renderers.d.ts.map +1 -1
  74. package/dist/app/chat/chat/widgets/builtin-tool-renderers.js +2 -2
  75. package/dist/app/chat/chat/widgets/builtin-tool-renderers.js.map +1 -1
  76. package/dist/app/chat/chat-first/chat-history.d.ts +13 -2
  77. package/dist/app/chat/chat-first/chat-history.d.ts.map +1 -1
  78. package/dist/app/chat/chat-first/chat-history.js +24 -3
  79. package/dist/app/chat/chat-first/chat-history.js.map +1 -1
  80. package/dist/app/chat/conversation/AgentConversation.d.ts.map +1 -1
  81. package/dist/app/chat/conversation/AgentConversation.js +6 -1
  82. package/dist/app/chat/conversation/AgentConversation.js.map +1 -1
  83. package/dist/app/chat/ownership-history/ChatOwnerAvatar.d.ts +6 -0
  84. package/dist/app/chat/ownership-history/ChatOwnerAvatar.d.ts.map +1 -0
  85. package/dist/app/chat/ownership-history/ChatOwnerAvatar.js +9 -0
  86. package/dist/app/chat/ownership-history/ChatOwnerAvatar.js.map +1 -0
  87. package/dist/app/chat/ownership-history/index.d.ts +11 -0
  88. package/dist/app/chat/ownership-history/index.d.ts.map +1 -0
  89. package/dist/app/chat/ownership-history/index.js +22 -0
  90. package/dist/app/chat/ownership-history/index.js.map +1 -0
  91. package/dist/app/chat/ownership-history/rows.d.ts +27 -0
  92. package/dist/app/chat/ownership-history/rows.d.ts.map +1 -0
  93. package/dist/app/chat/ownership-history/rows.js +101 -0
  94. package/dist/app/chat/ownership-history/rows.js.map +1 -0
  95. package/dist/app/chat/ownership-history/useOwnershipChatHistory.d.ts +52 -0
  96. package/dist/app/chat/ownership-history/useOwnershipChatHistory.d.ts.map +1 -0
  97. package/dist/app/chat/ownership-history/useOwnershipChatHistory.js +497 -0
  98. package/dist/app/chat/ownership-history/useOwnershipChatHistory.js.map +1 -0
  99. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  100. package/dist/app/i18n/catalogs/ar-SA.js +3 -0
  101. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  102. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  103. package/dist/app/i18n/catalogs/de-DE.js +3 -0
  104. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  105. package/dist/app/i18n/catalogs/en-US.d.ts +3 -0
  106. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  107. package/dist/app/i18n/catalogs/en-US.js +3 -0
  108. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  109. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  110. package/dist/app/i18n/catalogs/es-ES.js +3 -0
  111. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  112. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  113. package/dist/app/i18n/catalogs/fr-FR.js +3 -0
  114. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  115. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  116. package/dist/app/i18n/catalogs/hi-IN.js +3 -0
  117. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  118. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  119. package/dist/app/i18n/catalogs/ja-JP.js +3 -0
  120. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  121. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  122. package/dist/app/i18n/catalogs/ko-KR.js +3 -0
  123. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  124. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  125. package/dist/app/i18n/catalogs/pt-BR.js +3 -0
  126. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  127. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  128. package/dist/app/i18n/catalogs/zh-CN.js +3 -0
  129. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  130. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  131. package/dist/app/i18n/catalogs/zh-TW.js +3 -0
  132. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  133. package/dist/app/shared/CommandMenu.d.ts +2 -0
  134. package/dist/app/shared/CommandMenu.d.ts.map +1 -1
  135. package/dist/app/shared/CommandMenu.js +11 -6
  136. package/dist/app/shared/CommandMenu.js.map +1 -1
  137. package/dist/app/sharing/ShareButton.d.ts.map +1 -1
  138. package/dist/app/sharing/ShareButton.js +9 -8
  139. package/dist/app/sharing/ShareButton.js.map +1 -1
  140. package/dist/chat-history/ChatHistoryList.d.ts +16 -3
  141. package/dist/chat-history/ChatHistoryList.d.ts.map +1 -1
  142. package/dist/chat-history/ChatHistoryList.js +25 -15
  143. package/dist/chat-history/ChatHistoryList.js.map +1 -1
  144. package/dist/chat-history.css +109 -9
  145. package/dist/composer/TiptapComposer.js +1 -1
  146. package/dist/composer/TiptapComposer.js.map +1 -1
  147. package/package.json +10 -3
  148. package/src/app/agent-page/AgentContextTab.spec.ts +50 -2
  149. package/src/app/agent-page/AgentContextTab.tsx +1 -0
  150. package/src/app/agentkit/react/components.interaction.spec.tsx +2 -0
  151. package/src/app/agentkit/react/components.spec.tsx +11 -6
  152. package/src/app/agentkit/react/components.tsx +3 -0
  153. package/src/app/agentkit/react/context.tsx +6 -0
  154. package/src/app/agentkit/react/data-chart-layout.ts +25 -0
  155. package/src/app/agentkit/react/index.ts +1 -0
  156. package/src/app/agentkit/react/root.tsx +4 -0
  157. package/src/app/agentkit/react/styles.css +31 -6
  158. package/src/app/agentkit/react/transcript-layout.ts +2 -0
  159. package/src/app/chat/AgentKitAssistantChat.spec.tsx +201 -27
  160. package/src/app/chat/AgentKitAssistantChat.tsx +3 -0
  161. package/src/app/chat/AgentPanel.tsx +8 -8
  162. package/src/app/chat/MultiTabAssistantChat.spec.tsx +270 -3
  163. package/src/app/chat/MultiTabAssistantChat.tsx +81 -158
  164. package/src/app/chat/agentkit-chat/action-widget.spec.tsx +62 -0
  165. package/src/app/chat/agentkit-chat/action-widget.tsx +4 -0
  166. package/src/app/chat/agentkit-chat/rail.ts +11 -0
  167. package/src/app/chat/chat/index.ts +10 -0
  168. package/src/app/chat/chat/surface-types.ts +3 -0
  169. package/src/app/chat/chat/tool-call-display.spec.tsx +29 -0
  170. package/src/app/chat/chat/tool-call-display.tsx +17 -1
  171. package/src/app/chat/chat/tool-render-registry.tsx +5 -0
  172. package/src/app/chat/chat/widgets/DataChartRenderer.spec.tsx +377 -17
  173. package/src/app/chat/chat/widgets/DataChartRenderer.tsx +232 -63
  174. package/src/app/chat/chat/widgets/DataChartWidget.spec.tsx +67 -0
  175. package/src/app/chat/chat/widgets/DataChartWidget.tsx +39 -5
  176. package/src/app/chat/chat/widgets/DataInsightsWidget.tsx +13 -2
  177. package/src/app/chat/chat/widgets/DataWidgetDisplayControls.tsx +6 -4
  178. package/src/app/chat/chat/widgets/builtin-tool-renderers.tsx +5 -1
  179. package/src/app/chat/chat-first/chat-history.spec.tsx +79 -0
  180. package/src/app/chat/chat-first/chat-history.tsx +75 -22
  181. package/src/app/chat/conversation/AgentConversation.spec.tsx +51 -1
  182. package/src/app/chat/conversation/AgentConversation.tsx +11 -2
  183. package/src/app/chat/ownership-history/ChatOwnerAvatar.tsx +27 -0
  184. package/src/app/chat/ownership-history/index.tsx +67 -0
  185. package/src/app/chat/ownership-history/ownership-history.spec.tsx +3146 -0
  186. package/src/app/chat/ownership-history/rows.ts +156 -0
  187. package/src/app/chat/ownership-history/useOwnershipChatHistory.ts +709 -0
  188. package/src/app/i18n/catalogs/ar-SA.ts +3 -0
  189. package/src/app/i18n/catalogs/de-DE.ts +3 -0
  190. package/src/app/i18n/catalogs/en-US.ts +3 -0
  191. package/src/app/i18n/catalogs/es-ES.ts +3 -0
  192. package/src/app/i18n/catalogs/fr-FR.ts +3 -0
  193. package/src/app/i18n/catalogs/hi-IN.ts +3 -0
  194. package/src/app/i18n/catalogs/ja-JP.ts +3 -0
  195. package/src/app/i18n/catalogs/ko-KR.ts +3 -0
  196. package/src/app/i18n/catalogs/pt-BR.ts +3 -0
  197. package/src/app/i18n/catalogs/zh-CN.ts +3 -0
  198. package/src/app/i18n/catalogs/zh-TW.ts +3 -0
  199. package/src/app/shared/CommandMenu.spec.tsx +175 -6
  200. package/src/app/shared/CommandMenu.tsx +24 -7
  201. package/src/app/sharing/ShareButton.tsx +12 -10
  202. package/src/chat-history/ChatHistoryList.spec.tsx +51 -0
  203. package/src/chat-history/ChatHistoryList.tsx +87 -26
  204. package/src/chat-history/ChatHistoryRailSections.spec.tsx +12 -4
  205. package/src/chat-history.css +109 -9
  206. package/src/composer/TiptapComposer.tsx +1 -1
@@ -1,6 +1,7 @@
1
1
  import { useT } from "@agent-native/core/client/i18n";
2
2
  import { IconDatabase } from "@tabler/icons-react";
3
3
 
4
+ import type { AgentChatDataChartLayout } from "../../../agentkit/react/data-chart-layout.js";
4
5
  import type { DataWidgetResult } from "./data-widget-types.js";
5
6
  import { DataChartWidget } from "./DataChartWidget.js";
6
7
  import { DataTableWidget } from "./DataTableWidget.js";
@@ -19,7 +20,13 @@ function SummaryPill({ label, value }: { label: string; value: unknown }) {
19
20
  );
20
21
  }
21
22
 
22
- export function DataInsightsWidget({ result }: { result: DataWidgetResult }) {
23
+ export function DataInsightsWidget({
24
+ result,
25
+ layout,
26
+ }: {
27
+ result: DataWidgetResult;
28
+ layout?: AgentChatDataChartLayout;
29
+ }) {
23
30
  const t = useT();
24
31
  const title =
25
32
  result.display?.title ?? result.title ?? t("agentChat.widget.dataInsights");
@@ -49,7 +56,11 @@ export function DataInsightsWidget({ result }: { result: DataWidgetResult }) {
49
56
  </div>
50
57
  </div>
51
58
  {result.chartSeries ? (
52
- <DataChartWidget chart={result.chartSeries} display={result.display} />
59
+ <DataChartWidget
60
+ chart={result.chartSeries}
61
+ display={result.display}
62
+ layout={layout}
63
+ />
53
64
  ) : null}
54
65
  {result.table ? (
55
66
  <DataTableWidget
@@ -148,7 +148,7 @@ export function DataWidgetDisplayControls({
148
148
  }: {
149
149
  display?: DataWidgetDisplay;
150
150
  chartActions?: DataWidgetChartAction[];
151
- variant?: "primary" | "secondary";
151
+ variant?: "primary" | "secondary" | "quiet";
152
152
  kind?: "chart" | "table";
153
153
  }) {
154
154
  const t = useT();
@@ -219,7 +219,9 @@ export function DataWidgetDisplayControls({
219
219
  className={
220
220
  variant === "secondary"
221
221
  ? "inline-flex max-w-44 items-center gap-1.5 truncate rounded-md border border-border px-2 py-1 text-[11px] font-medium text-foreground no-underline hover:bg-muted hover:no-underline"
222
- : "inline-flex max-w-44 items-center gap-1.5 truncate rounded-md bg-primary px-2 py-1 text-[11px] font-medium text-primary-foreground no-underline hover:bg-primary/90 hover:no-underline"
222
+ : variant === "quiet"
223
+ ? "inline-flex max-w-44 items-center gap-1.5 truncate rounded-sm px-1 py-0.5 text-[11px] font-medium text-muted-foreground no-underline hover:bg-muted hover:text-foreground hover:no-underline"
224
+ : "inline-flex max-w-44 items-center gap-1.5 truncate rounded-md bg-primary px-2 py-1 text-[11px] font-medium text-primary-foreground no-underline hover:bg-primary/90 hover:no-underline"
223
225
  }
224
226
  />
225
227
  ) : null}
@@ -230,7 +232,7 @@ export function DataWidgetDisplayControls({
230
232
  label={item.action.label}
231
233
  icon={item.action.icon}
232
234
  iconOnly
233
- className="inline-flex size-8 shrink-0 items-center justify-center rounded-md border border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
235
+ className={`inline-flex ${variant === "quiet" ? "size-7" : "size-8"} shrink-0 items-center justify-center rounded-md ${variant === "quiet" ? "" : "border border-border"} text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring`}
234
236
  />
235
237
  ))}
236
238
  {overflowActions.length > 0 ? (
@@ -240,7 +242,7 @@ export function DataWidgetDisplayControls({
240
242
  type="button"
241
243
  aria-label={actionsLabel}
242
244
  title={actionsLabel}
243
- className="inline-flex size-8 shrink-0 items-center justify-center rounded-md border border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
245
+ className={`inline-flex ${variant === "quiet" ? "size-7" : "size-8"} shrink-0 items-center justify-center rounded-md ${variant === "quiet" ? "" : "border border-border"} text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring`}
244
246
  >
245
247
  <IconDotsVertical aria-hidden="true" className="size-4" />
246
248
  </button>
@@ -292,6 +292,7 @@ function renderDataWidget(context: ToolRendererContext) {
292
292
  <LazyDataChartWidget
293
293
  chart={result.chartSeries}
294
294
  display={result.display}
295
+ layout={context.dataChartLayout}
295
296
  />
296
297
  </Suspense>
297
298
  );
@@ -299,7 +300,10 @@ function renderDataWidget(context: ToolRendererContext) {
299
300
  if (widget === DATA_INSIGHTS_WIDGET) {
300
301
  return (
301
302
  <Suspense fallback={<BuiltinToolRendererSkeleton />}>
302
- <LazyDataInsightsWidget result={result} />
303
+ <LazyDataInsightsWidget
304
+ result={result}
305
+ layout={context.dataChartLayout}
306
+ />
303
307
  </Suspense>
304
308
  );
305
309
  }
@@ -92,4 +92,83 @@ describe("ChatFirstChatHistory", () => {
92
92
 
93
93
  expect(onOpenChats).toHaveBeenCalledOnce();
94
94
  });
95
+
96
+ it("uses the section rail with independent disclosure and no New chat footer", () => {
97
+ const onSelect = vi.fn();
98
+ const onNewChat = vi.fn();
99
+ act(() => {
100
+ root.render(
101
+ <ChatFirstChatHistory
102
+ sections={[
103
+ {
104
+ id: "shared",
105
+ label: "Shared with you",
106
+ previewCount: 5,
107
+ items: Array.from({ length: 6 }, (_, index) => ({
108
+ id: `shared-${index}`,
109
+ title: `Shared ${index}`,
110
+ readOnly: true,
111
+ ownerAvatar: <span>P</span>,
112
+ ownerLabel: "pat@example.com",
113
+ accessLabel: "Shared directly",
114
+ })),
115
+ },
116
+ ]}
117
+ onSelect={onSelect}
118
+ onNewChat={onNewChat}
119
+ showNewChat={false}
120
+ railLabels={{ newChat: "Start a chat" }}
121
+ />,
122
+ );
123
+ });
124
+ expect(container.querySelectorAll(".an-chat-history-row")).toHaveLength(5);
125
+ expect(container.querySelector(".an-chat-history-rail__footer")).toBeNull();
126
+ expect(
127
+ container.querySelector(".an-chat-history-row__menu-trigger"),
128
+ ).toBeNull();
129
+ expect(
130
+ container.querySelectorAll(".an-chat-history-row__owner-mark"),
131
+ ).toHaveLength(5);
132
+ expect(
133
+ container.querySelector("[data-chat-first-chat-history-header]"),
134
+ ).toBeNull();
135
+ expect(container.textContent).toContain("Shared with you");
136
+ expect(container.textContent).not.toContain("Chats");
137
+ const toggle = container.querySelector<HTMLButtonElement>(
138
+ ".an-chat-history-rail__section-toggle",
139
+ )!;
140
+ expect(toggle.textContent).toBe("Show all");
141
+ act(() => toggle.click());
142
+ expect(container.querySelectorAll(".an-chat-history-row")).toHaveLength(6);
143
+ expect(toggle.textContent).toBe("Show less");
144
+ act(() => {
145
+ container
146
+ .querySelector<HTMLButtonElement>(".an-chat-history-row__button")!
147
+ .click();
148
+ });
149
+ expect(onSelect).toHaveBeenCalledWith("shared-0");
150
+ expect(onNewChat).not.toHaveBeenCalled();
151
+ });
152
+
153
+ it("keeps the required New chat action on the common section footer", () => {
154
+ const onNewChat = vi.fn();
155
+ act(() => {
156
+ root.render(
157
+ <ChatFirstChatHistory
158
+ sections={[{ id: "mine", items: [], emptyLabel: "No owned chats" }]}
159
+ onSelect={() => {}}
160
+ onNewChat={onNewChat}
161
+ railLabels={{ newChat: "Start a chat" }}
162
+ />,
163
+ );
164
+ });
165
+ expect(container.textContent).toContain("No owned chats");
166
+ const buttons = container.querySelectorAll<HTMLButtonElement>(
167
+ ".an-chat-history-rail__new-chat",
168
+ );
169
+ expect(buttons).toHaveLength(1);
170
+ expect(buttons[0].textContent).toBe("Start a chat");
171
+ act(() => buttons[0].click());
172
+ expect(onNewChat).toHaveBeenCalledOnce();
173
+ });
95
174
  });
@@ -1,3 +1,10 @@
1
+ import { useT } from "@agent-native/core/client/i18n";
2
+ import {
3
+ ChatHistoryRail,
4
+ type ChatHistoryRailLabels,
5
+ type ChatHistoryRailProps,
6
+ type ChatHistoryRailSection,
7
+ } from "@agent-native/toolkit/chat-history/ChatHistoryRail";
1
8
  import type { ReactNode } from "react";
2
9
 
3
10
  import {
@@ -6,23 +13,63 @@ import {
6
13
  type ChatHistoryListProps,
7
14
  } from "../chat/ChatHistoryList.js";
8
15
 
9
- export interface ChatFirstChatHistoryProps extends Omit<
16
+ interface ChatFirstChatHistoryItemsProps extends Omit<
10
17
  ChatHistoryListProps,
11
18
  "items" | "sections" | "variant"
12
19
  > {
13
20
  items: ChatHistoryItem[];
21
+ sections?: never;
14
22
  label?: ReactNode;
15
23
  headerAction?: ReactNode;
16
24
  }
17
25
 
26
+ type ChatFirstChatHistorySectionsProps = Omit<
27
+ Extract<ChatHistoryRailProps, { sections: ChatHistoryRailSection[] }>,
28
+ "railLabels" | "renderRail"
29
+ > & {
30
+ railLabels?: Partial<ChatHistoryRailLabels>;
31
+ label?: ReactNode;
32
+ headerAction?: ReactNode;
33
+ };
34
+
35
+ export type ChatFirstChatHistoryProps =
36
+ | ChatFirstChatHistoryItemsProps
37
+ | ChatFirstChatHistorySectionsProps;
38
+
39
+ function SectionedChatHistory({
40
+ railLabels,
41
+ labels,
42
+ ...props
43
+ }: ChatFirstChatHistorySectionsProps) {
44
+ const t = useT();
45
+ return (
46
+ <ChatHistoryRail
47
+ {...props}
48
+ labels={{ copyLink: t("agentChat.history.copyLink"), ...labels }}
49
+ railLabels={{
50
+ newChat: t("agentChat.tabs.newChat"),
51
+ showMore: t("agentChat.history.showAll"),
52
+ showLess: t("agentChat.history.showLess"),
53
+ ...railLabels,
54
+ sections: railLabels?.sections ?? {
55
+ showAll: t("agentChat.history.showAll"),
56
+ showLess: t("agentChat.history.showLess"),
57
+ loadMore: t("agentChat.history.loadMore"),
58
+ loadingMore: t("agentChat.history.loadingMore"),
59
+ retry: t("agentChat.history.retry"),
60
+ },
61
+ }}
62
+ />
63
+ );
64
+ }
65
+
18
66
  export function ChatFirstChatHistory({
19
- items,
20
67
  label = "Chats",
21
68
  headerAction,
22
69
  className,
23
70
  ...props
24
71
  }: ChatFirstChatHistoryProps) {
25
- if (items.length === 0) {
72
+ if (!props.sections && props.items.length === 0) {
26
73
  return (
27
74
  <section
28
75
  data-chat-first-chat-history
@@ -33,30 +80,36 @@ export function ChatFirstChatHistory({
33
80
  );
34
81
  }
35
82
 
83
+ // Sections carry their own labels (My chats, Shared with you), so a sectioned
84
+ // list keeps the header only for its action.
85
+ const showLabel = !props.sections;
36
86
  return (
37
87
  <section
38
88
  data-chat-first-chat-history
39
89
  className={["min-h-0 min-w-0", className].filter(Boolean).join(" ")}
40
90
  >
41
- <div
42
- data-chat-first-chat-history-header
43
- className="group mb-1 flex min-h-6 items-center justify-between gap-2 px-2"
44
- >
45
- <p className="min-w-0 text-[11px] font-medium text-sidebar-foreground/50">
46
- {label}
47
- </p>
48
- {headerAction ? (
49
- <div className="shrink-0 opacity-0 transition-opacity duration-100 group-hover:opacity-100 group-focus-within:opacity-100">
50
- {headerAction}
51
- </div>
52
- ) : null}
53
- </div>
54
- <ChatHistoryList
55
- {...props}
56
- items={items}
57
- variant="rail"
58
- className="min-w-0"
59
- />
91
+ {showLabel || headerAction ? (
92
+ <div
93
+ data-chat-first-chat-history-header
94
+ className="group mb-1 flex min-h-6 items-center justify-between gap-2 px-2"
95
+ >
96
+ {showLabel ? (
97
+ <p className="min-w-0 text-[11px] font-medium text-sidebar-foreground/50">
98
+ {label}
99
+ </p>
100
+ ) : null}
101
+ {headerAction ? (
102
+ <div className="ms-auto shrink-0 opacity-0 transition-opacity duration-100 group-hover:opacity-100 group-focus-within:opacity-100">
103
+ {headerAction}
104
+ </div>
105
+ ) : null}
106
+ </div>
107
+ ) : null}
108
+ {props.sections ? (
109
+ <SectionedChatHistory {...props} className="min-w-0" />
110
+ ) : (
111
+ <ChatHistoryList {...props} variant="rail" className="min-w-0" />
112
+ )}
60
113
  </section>
61
114
  );
62
115
  }
@@ -116,7 +116,9 @@ describe("AgentConversationMessageView", () => {
116
116
  id: "example-renderer",
117
117
  match: "example-tool",
118
118
  Component: ({ context }) => (
119
- <div data-testid="example-renderer">{context.resultText}</div>
119
+ <div data-testid="example-renderer">
120
+ Custom renderer: {context.resultText}
121
+ </div>
120
122
  ),
121
123
  });
122
124
  act(() =>
@@ -144,11 +146,59 @@ describe("AgentConversationMessageView", () => {
144
146
  expect(container.querySelector('[data-testid="example-renderer"]')).toBe(
145
147
  null,
146
148
  );
149
+ expect(container.textContent).not.toContain("Custom renderer:");
150
+ expect(container.querySelector("pre span")?.textContent).toBe(
151
+ "Example Document failed.",
152
+ );
147
153
  expect(
148
154
  container.querySelector("pre span")?.hasAttribute("data-an-mask"),
149
155
  ).toBe(true);
150
156
  });
151
157
 
158
+ it.each([
159
+ ["running", "running"],
160
+ ["activity", "running"],
161
+ ["completed", "completed"],
162
+ ] as const)(
163
+ "passes %s status to conversation custom renderers as %s",
164
+ (state, status) => {
165
+ registerToolRenderer({
166
+ id: "example-status-renderer",
167
+ match: "example-status-tool",
168
+ Component: ({ context }) => (
169
+ <div data-testid="example-tool-status" data-status={context.status} />
170
+ ),
171
+ });
172
+ act(() =>
173
+ root.render(
174
+ <AgentConversationMessageView
175
+ message={{
176
+ id: "message-status",
177
+ role: "assistant",
178
+ parts: [
179
+ {
180
+ id: "tool-status",
181
+ type: "tool",
182
+ tool: {
183
+ id: "tool-status",
184
+ name: "example-status-tool",
185
+ state,
186
+ },
187
+ },
188
+ ],
189
+ }}
190
+ />,
191
+ ),
192
+ );
193
+
194
+ expect(
195
+ container
196
+ .querySelector('[data-testid="example-tool-status"]')
197
+ ?.getAttribute("data-status"),
198
+ ).toBe(status);
199
+ },
200
+ );
201
+
152
202
  it.each(["errored", "completed"] as const)(
153
203
  "blocks only an errored tool's MCP App from replays (%s)",
154
204
  (state) => {
@@ -17,7 +17,10 @@ import ReactMarkdown, { defaultUrlTransform } from "react-markdown";
17
17
  import remarkGfm from "remark-gfm";
18
18
 
19
19
  import { ActionChatUiSurface } from "../chat/action-chat-ui-surface.js";
20
- import { resolveToolRenderer } from "../chat/tool-render-registry.js";
20
+ import {
21
+ resolveToolRenderer,
22
+ type ToolRendererContext,
23
+ } from "../chat/tool-render-registry.js";
21
24
  import {
22
25
  isBuiltinConnectRequiredResult,
23
26
  resolveBuiltinActionChatRenderer,
@@ -407,11 +410,17 @@ function parseJsonObject(value: string | undefined): Record<string, unknown> {
407
410
  function ConversationToolCall({ tool }: { tool: AgentConversationToolCall }) {
408
411
  const t = useT();
409
412
  const resultJson = parseJsonText(tool.result);
410
- const nativeToolContext = {
413
+ const nativeToolContext: ToolRendererContext = {
411
414
  toolName: tool.name,
412
415
  args: tool.args ?? parseJsonObject(tool.input),
413
416
  resultText: tool.result,
414
417
  resultJson: tool.resultJson ?? resultJson,
418
+ status:
419
+ tool.state === "errored"
420
+ ? undefined
421
+ : tool.state === "activity"
422
+ ? "running"
423
+ : tool.state,
415
424
  isRunning: tool.state === "running" || tool.state === "activity",
416
425
  chatUI: tool.chatUI,
417
426
  };
@@ -0,0 +1,27 @@
1
+ import { useAvatarUrl } from "@agent-native/core/client/use-avatar";
2
+ import { emailToColor } from "@agent-native/toolkit/collab-ui";
3
+
4
+ /** The 16px owner mark on a shared chat row: profile photo, else a colored initial. */
5
+ export function ChatOwnerAvatar({
6
+ email,
7
+ label,
8
+ }: {
9
+ email: string;
10
+ label: string;
11
+ }) {
12
+ const avatarUrl = useAvatarUrl(email);
13
+ return (
14
+ <span
15
+ role="img"
16
+ aria-label={label}
17
+ className="an-chat-owner-avatar"
18
+ style={avatarUrl ? undefined : { backgroundColor: emailToColor(email) }}
19
+ >
20
+ {avatarUrl ? (
21
+ <img src={avatarUrl} alt="" className="an-chat-owner-avatar__image" />
22
+ ) : (
23
+ (email.trim().charAt(0) || "?").toUpperCase()
24
+ )}
25
+ </span>
26
+ );
27
+ }
@@ -0,0 +1,67 @@
1
+ import { useT } from "@agent-native/core/client/i18n";
2
+ import {
3
+ ChatHistoryRail,
4
+ type ChatHistoryRailLabels,
5
+ type ChatHistoryRailProps,
6
+ } from "@agent-native/toolkit/chat-history/ChatHistoryRail";
7
+
8
+ import type { UseOwnershipChatHistoryResult } from "./useOwnershipChatHistory.js";
9
+
10
+ export {
11
+ ownDraftRows,
12
+ chatThreadToHistoryItem,
13
+ type OwnDraftRow,
14
+ type OwnDraftRowsOptions,
15
+ type ChatThreadHistoryItemOptions,
16
+ } from "./rows.js";
17
+ export {
18
+ useOwnershipChatHistory,
19
+ type UseOwnershipChatHistoryOptions,
20
+ type UseOwnershipChatHistoryResult,
21
+ type OwnershipChatHistoryMutationKind,
22
+ type OwnershipChatHistorySection,
23
+ type OwnershipChatHistoryListProps,
24
+ } from "./useOwnershipChatHistory.js";
25
+
26
+ export type OwnershipChatHistoryRailProps = Omit<
27
+ ChatHistoryRailProps,
28
+ "items" | "sections" | "railLabels" | "loading" | "error"
29
+ > &
30
+ Pick<UseOwnershipChatHistoryResult, "sections" | "listProps"> & {
31
+ railLabels?: Partial<ChatHistoryRailLabels>;
32
+ loading?: boolean;
33
+ error?: Error | null;
34
+ };
35
+
36
+ export function OwnershipChatHistoryRail({
37
+ sections,
38
+ listProps,
39
+ railLabels,
40
+ labels,
41
+ loading: _loading,
42
+ error: _error,
43
+ ...props
44
+ }: OwnershipChatHistoryRailProps) {
45
+ const t = useT();
46
+ return (
47
+ <ChatHistoryRail
48
+ {...listProps}
49
+ {...props}
50
+ labels={{ copyLink: t("agentChat.history.copyLink"), ...labels }}
51
+ sections={sections}
52
+ railLabels={{
53
+ newChat: t("agentChat.tabs.newChat"),
54
+ showMore: t("agentChat.history.showAll"),
55
+ showLess: t("agentChat.history.showLess"),
56
+ ...railLabels,
57
+ sections: railLabels?.sections ?? {
58
+ showAll: t("agentChat.history.showAll"),
59
+ showLess: t("agentChat.history.showLess"),
60
+ loadMore: t("agentChat.history.loadMore"),
61
+ loadingMore: t("agentChat.history.loadingMore"),
62
+ retry: t("agentChat.history.retry"),
63
+ },
64
+ }}
65
+ />
66
+ );
67
+ }