@agent-native/toolkit 0.221.0-same-host-mcp-20261027-20261027081850 → 0.221.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 (259) hide show
  1. package/agent-native.eject.json +16 -1
  2. package/dist/app/agentkit/react/components.d.ts +5 -3
  3. package/dist/app/agentkit/react/components.d.ts.map +1 -1
  4. package/dist/app/agentkit/react/components.js +103 -42
  5. package/dist/app/agentkit/react/components.js.map +1 -1
  6. package/dist/app/agentkit/react/styles.css +93 -65
  7. package/dist/app/agentkit/react/voice-transcripts.d.ts +22 -1
  8. package/dist/app/agentkit/react/voice-transcripts.d.ts.map +1 -1
  9. package/dist/app/agentkit/react/voice-transcripts.js +209 -8
  10. package/dist/app/agentkit/react/voice-transcripts.js.map +1 -1
  11. package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
  12. package/dist/app/chat/AgentKitAssistantChat.js +55 -40
  13. package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
  14. package/dist/app/chat/agentkit-chat/guided-questions.d.ts +1 -0
  15. package/dist/app/chat/agentkit-chat/guided-questions.d.ts.map +1 -1
  16. package/dist/app/chat/agentkit-chat/guided-questions.js +18 -6
  17. package/dist/app/chat/agentkit-chat/guided-questions.js.map +1 -1
  18. package/dist/app/chat/agentkit-chat/index.d.ts +1 -1
  19. package/dist/app/chat/agentkit-chat/index.d.ts.map +1 -1
  20. package/dist/app/chat/agentkit-chat/index.js +1 -1
  21. package/dist/app/chat/agentkit-chat/index.js.map +1 -1
  22. package/dist/app/chat/chat/run-recovery.d.ts.map +1 -1
  23. package/dist/app/chat/chat/run-recovery.js +5 -1
  24. package/dist/app/chat/chat/run-recovery.js.map +1 -1
  25. package/dist/app/chat/composer/runtime-adapters.d.ts.map +1 -1
  26. package/dist/app/chat/composer/runtime-adapters.js +2 -0
  27. package/dist/app/chat/composer/runtime-adapters.js.map +1 -1
  28. package/dist/app/chat/reply-connection-suggestion.d.ts +29 -0
  29. package/dist/app/chat/reply-connection-suggestion.d.ts.map +1 -0
  30. package/dist/app/chat/reply-connection-suggestion.js +42 -0
  31. package/dist/app/chat/reply-connection-suggestion.js.map +1 -0
  32. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  33. package/dist/app/i18n/catalogs/ar-SA.js +7 -0
  34. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  35. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  36. package/dist/app/i18n/catalogs/de-DE.js +7 -0
  37. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  38. package/dist/app/i18n/catalogs/en-US.d.ts +7 -0
  39. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  40. package/dist/app/i18n/catalogs/en-US.js +7 -0
  41. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  42. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  43. package/dist/app/i18n/catalogs/es-ES.js +7 -0
  44. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  45. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  46. package/dist/app/i18n/catalogs/fr-FR.js +7 -0
  47. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  48. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  49. package/dist/app/i18n/catalogs/hi-IN.js +7 -0
  50. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  51. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  52. package/dist/app/i18n/catalogs/ja-JP.js +7 -0
  53. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  54. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  55. package/dist/app/i18n/catalogs/ko-KR.js +7 -0
  56. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  57. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  58. package/dist/app/i18n/catalogs/pt-BR.js +7 -0
  59. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  60. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  61. package/dist/app/i18n/catalogs/zh-CN.js +7 -0
  62. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  63. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  64. package/dist/app/i18n/catalogs/zh-TW.js +7 -0
  65. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  66. package/dist/app/mcp-approval/McpApprovalReview.d.ts +25 -0
  67. package/dist/app/mcp-approval/McpApprovalReview.d.ts.map +1 -0
  68. package/dist/app/mcp-approval/McpApprovalReview.js +342 -0
  69. package/dist/app/mcp-approval/McpApprovalReview.js.map +1 -0
  70. package/dist/app/onboarding/FirstRunOnboarding.d.ts.map +1 -1
  71. package/dist/app/onboarding/FirstRunOnboarding.js +299 -71
  72. package/dist/app/onboarding/FirstRunOnboarding.js.map +1 -1
  73. package/dist/app/onboarding/GettingStartedCard.js +1 -1
  74. package/dist/app/onboarding/GettingStartedCard.js.map +1 -1
  75. package/dist/app/onboarding/first-run-builder-credits-flag.d.ts +2 -0
  76. package/dist/app/onboarding/first-run-builder-credits-flag.d.ts.map +1 -0
  77. package/dist/app/onboarding/first-run-builder-credits-flag.js +8 -0
  78. package/dist/app/onboarding/first-run-builder-credits-flag.js.map +1 -0
  79. package/dist/app/providers/AppProviders.d.ts.map +1 -1
  80. package/dist/app/providers/AppProviders.js +14 -1
  81. package/dist/app/providers/AppProviders.js.map +1 -1
  82. package/dist/app/resources/McpConnectionSuggestion.d.ts +2 -4
  83. package/dist/app/resources/McpConnectionSuggestion.d.ts.map +1 -1
  84. package/dist/app/resources/McpConnectionSuggestion.js +59 -36
  85. package/dist/app/resources/McpConnectionSuggestion.js.map +1 -1
  86. package/dist/app/settings/account/PreferencesSettings.d.ts.map +1 -1
  87. package/dist/app/settings/account/PreferencesSettings.js +14 -1
  88. package/dist/app/settings/account/PreferencesSettings.js.map +1 -1
  89. package/dist/app/settings/account/ThemeFamilySettings.js +2 -2
  90. package/dist/app/settings/account/ThemeFamilySettings.js.map +1 -1
  91. package/dist/app/settings/account/search-entries.d.ts +1 -0
  92. package/dist/app/settings/account/search-entries.d.ts.map +1 -1
  93. package/dist/app/settings/account/search-entries.js +5 -0
  94. package/dist/app/settings/account/search-entries.js.map +1 -1
  95. package/dist/app/settings/shell/SettingsShell.d.ts.map +1 -1
  96. package/dist/app/settings/shell/SettingsShell.js +26 -2
  97. package/dist/app/settings/shell/SettingsShell.js.map +1 -1
  98. package/dist/app/shared/AppShellSkeleton.d.ts.map +1 -1
  99. package/dist/app/shared/AppShellSkeleton.js +4 -10
  100. package/dist/app/shared/AppShellSkeleton.js.map +1 -1
  101. package/dist/app/shared/EnvironmentBadge.d.ts +2 -1
  102. package/dist/app/shared/EnvironmentBadge.d.ts.map +1 -1
  103. package/dist/app/shared/EnvironmentBadge.js +2 -3
  104. package/dist/app/shared/EnvironmentBadge.js.map +1 -1
  105. package/dist/app/shared/is-builder-io-employee.d.ts +8 -0
  106. package/dist/app/shared/is-builder-io-employee.d.ts.map +1 -0
  107. package/dist/app/shared/is-builder-io-employee.js +10 -0
  108. package/dist/app/shared/is-builder-io-employee.js.map +1 -0
  109. package/dist/app/styles/agent-conversation.css +30 -17
  110. package/dist/app/styles/theme-families.css +22 -5
  111. package/dist/app/styles/tokens/agent-kit.css +3 -3
  112. package/dist/composer/PromptComposer.d.ts +15 -3
  113. package/dist/composer/PromptComposer.d.ts.map +1 -1
  114. package/dist/composer/PromptComposer.js +74 -16
  115. package/dist/composer/PromptComposer.js.map +1 -1
  116. package/dist/composer/RealtimeVoiceMode.d.ts +7 -0
  117. package/dist/composer/RealtimeVoiceMode.d.ts.map +1 -1
  118. package/dist/composer/RealtimeVoiceMode.js +9 -2
  119. package/dist/composer/RealtimeVoiceMode.js.map +1 -1
  120. package/dist/composer/TiptapComposer.d.ts +7 -0
  121. package/dist/composer/TiptapComposer.d.ts.map +1 -1
  122. package/dist/composer/TiptapComposer.js +12 -4
  123. package/dist/composer/TiptapComposer.js.map +1 -1
  124. package/dist/composer/VoiceButton.d.ts +2 -0
  125. package/dist/composer/VoiceButton.d.ts.map +1 -1
  126. package/dist/composer/VoiceButton.js +5 -4
  127. package/dist/composer/VoiceButton.js.map +1 -1
  128. package/dist/composer/index.d.ts +2 -2
  129. package/dist/composer/index.d.ts.map +1 -1
  130. package/dist/composer/index.js +1 -1
  131. package/dist/composer/index.js.map +1 -1
  132. package/dist/composer/prompt-attachments.d.ts +20 -0
  133. package/dist/composer/prompt-attachments.d.ts.map +1 -1
  134. package/dist/composer/prompt-attachments.js +188 -11
  135. package/dist/composer/prompt-attachments.js.map +1 -1
  136. package/dist/composer/realtime-voice-transcript.d.ts +27 -0
  137. package/dist/composer/realtime-voice-transcript.d.ts.map +1 -1
  138. package/dist/composer/realtime-voice-transcript.js +34 -1
  139. package/dist/composer/realtime-voice-transcript.js.map +1 -1
  140. package/dist/composer/realtime-voice-turn-metrics.d.ts +43 -0
  141. package/dist/composer/realtime-voice-turn-metrics.d.ts.map +1 -0
  142. package/dist/composer/realtime-voice-turn-metrics.js +132 -0
  143. package/dist/composer/realtime-voice-turn-metrics.js.map +1 -0
  144. package/dist/composer/runtime-adapters.d.ts +4 -1
  145. package/dist/composer/runtime-adapters.d.ts.map +1 -1
  146. package/dist/composer/runtime-adapters.js +2 -1
  147. package/dist/composer/runtime-adapters.js.map +1 -1
  148. package/dist/composer/useRealtimeVoiceMode.d.ts +61 -9
  149. package/dist/composer/useRealtimeVoiceMode.d.ts.map +1 -1
  150. package/dist/composer/useRealtimeVoiceMode.js +536 -99
  151. package/dist/composer/useRealtimeVoiceMode.js.map +1 -1
  152. package/dist/composer/voice-chat-icon.d.ts +7 -0
  153. package/dist/composer/voice-chat-icon.d.ts.map +1 -0
  154. package/dist/composer/voice-chat-icon.js +14 -0
  155. package/dist/composer/voice-chat-icon.js.map +1 -0
  156. package/dist/editor/DragHandle.d.ts +12 -1
  157. package/dist/editor/DragHandle.d.ts.map +1 -1
  158. package/dist/editor/DragHandle.js +165 -41
  159. package/dist/editor/DragHandle.js.map +1 -1
  160. package/dist/editor/RegistryBlockNode.d.ts +20 -0
  161. package/dist/editor/RegistryBlockNode.d.ts.map +1 -1
  162. package/dist/editor/RegistryBlockNode.js +58 -13
  163. package/dist/editor/RegistryBlockNode.js.map +1 -1
  164. package/dist/editor/index.d.ts +2 -2
  165. package/dist/editor/index.d.ts.map +1 -1
  166. package/dist/editor/index.js +1 -1
  167. package/dist/editor/index.js.map +1 -1
  168. package/dist/styles.css +2 -0
  169. package/dist/ui/dropdown-menu.d.ts.map +1 -1
  170. package/dist/ui/dropdown-menu.js +5 -1
  171. package/dist/ui/dropdown-menu.js.map +1 -1
  172. package/package.json +14 -4
  173. package/src/app/agentkit/react/components.regenerate-readiness.spec.tsx +3 -1
  174. package/src/app/agentkit/react/components.spec.tsx +24 -4
  175. package/src/app/agentkit/react/components.tsx +174 -44
  176. package/src/app/agentkit/react/composer-context.spec.tsx +3 -0
  177. package/src/app/agentkit/react/disclosures.spec.tsx +124 -0
  178. package/src/app/agentkit/react/lifecycle.spec.tsx +8 -2
  179. package/src/app/agentkit/react/message-actions.spec.tsx +161 -5
  180. package/src/app/agentkit/react/saved-reply-reload.spec.tsx +206 -0
  181. package/src/app/agentkit/react/styles.css +93 -65
  182. package/src/app/agentkit/react/voice-transcripts.spec.tsx +239 -4
  183. package/src/app/agentkit/react/voice-transcripts.ts +245 -8
  184. package/src/app/chat/AgentKitAssistantChat.spec.tsx +59 -11
  185. package/src/app/chat/AgentKitAssistantChat.tsx +74 -62
  186. package/src/app/chat/agentkit-chat/guided-answers-context.spec.ts +9 -0
  187. package/src/app/chat/agentkit-chat/guided-questions.tsx +17 -7
  188. package/src/app/chat/agentkit-chat/index.ts +1 -0
  189. package/src/app/chat/chat/run-recovery.spec.tsx +45 -0
  190. package/src/app/chat/chat/run-recovery.tsx +6 -1
  191. package/src/app/chat/composer/runtime-adapters.tsx +2 -0
  192. package/src/app/chat/reply-connection-suggestion.spec.ts +121 -0
  193. package/src/app/chat/reply-connection-suggestion.ts +76 -0
  194. package/src/app/i18n/catalogs/ar-SA.ts +10 -0
  195. package/src/app/i18n/catalogs/de-DE.ts +10 -0
  196. package/src/app/i18n/catalogs/en-US.ts +10 -0
  197. package/src/app/i18n/catalogs/es-ES.ts +10 -0
  198. package/src/app/i18n/catalogs/fr-FR.ts +10 -0
  199. package/src/app/i18n/catalogs/hi-IN.ts +10 -0
  200. package/src/app/i18n/catalogs/ja-JP.ts +10 -0
  201. package/src/app/i18n/catalogs/ko-KR.ts +10 -0
  202. package/src/app/i18n/catalogs/pt-BR.ts +10 -0
  203. package/src/app/i18n/catalogs/zh-CN.ts +10 -0
  204. package/src/app/i18n/catalogs/zh-TW.ts +10 -0
  205. package/src/app/mcp-approval/McpApprovalReview.spec.tsx +687 -0
  206. package/src/app/mcp-approval/McpApprovalReview.tsx +913 -0
  207. package/src/app/onboarding/FirstRunOnboarding.spec.tsx +736 -26
  208. package/src/app/onboarding/FirstRunOnboarding.tsx +473 -145
  209. package/src/app/onboarding/GettingStartedCard.tsx +1 -1
  210. package/src/app/onboarding/first-run-builder-credits-flag.spec.ts +13 -0
  211. package/src/app/onboarding/first-run-builder-credits-flag.ts +9 -0
  212. package/src/app/providers/AppProviders.spec.tsx +109 -0
  213. package/src/app/providers/AppProviders.tsx +53 -1
  214. package/src/app/resources/McpConnectionSuggestion.spec.ts +77 -12
  215. package/src/app/resources/McpConnectionSuggestion.tsx +69 -51
  216. package/src/app/settings/VoiceChatSettings.spec.tsx +6 -1
  217. package/src/app/settings/account/PreferencesSettings.spec.tsx +73 -0
  218. package/src/app/settings/account/PreferencesSettings.tsx +24 -7
  219. package/src/app/settings/account/ThemeFamilySettings.tsx +2 -2
  220. package/src/app/settings/account/search-entries.spec.ts +14 -0
  221. package/src/app/settings/account/search-entries.ts +9 -0
  222. package/src/app/settings/shell/SettingsShell.tsx +29 -2
  223. package/src/app/shared/AppShellSkeleton.spec.tsx +2 -2
  224. package/src/app/shared/AppShellSkeleton.tsx +3 -16
  225. package/src/app/shared/EnvironmentBadge.tsx +3 -4
  226. package/src/app/shared/is-builder-io-employee.ts +17 -0
  227. package/src/app/styles/agent-conversation.css +30 -17
  228. package/src/app/styles/theme-families.css +22 -5
  229. package/src/app/styles/theme-families.spec.ts +73 -0
  230. package/src/app/styles/tokens/agent-kit.css +3 -3
  231. package/src/composer/AgentSuggestionBar.overflow.spec.tsx +1 -1
  232. package/src/composer/AttachmentChip.spec.tsx +87 -0
  233. package/src/composer/PromptComposer.context.spec.tsx +8 -4
  234. package/src/composer/PromptComposer.setup-card.spec.tsx +170 -0
  235. package/src/composer/PromptComposer.tsx +125 -14
  236. package/src/composer/RealtimeVoiceMode.spec.tsx +48 -0
  237. package/src/composer/RealtimeVoiceMode.tsx +45 -2
  238. package/src/composer/TiptapComposer.tsx +25 -0
  239. package/src/composer/TiptapComposer.voice-toolbar.spec.tsx +4 -1
  240. package/src/composer/VoiceButton.tsx +8 -3
  241. package/src/composer/index.ts +4 -0
  242. package/src/composer/prompt-attachments.spec.ts +160 -8
  243. package/src/composer/prompt-attachments.ts +221 -12
  244. package/src/composer/realtime-voice-transcript.spec.ts +36 -0
  245. package/src/composer/realtime-voice-transcript.ts +56 -1
  246. package/src/composer/realtime-voice-turn-metrics.spec.ts +175 -0
  247. package/src/composer/realtime-voice-turn-metrics.ts +192 -0
  248. package/src/composer/runtime-adapters.tsx +5 -1
  249. package/src/composer/useRealtimeVoiceMode.session.spec.tsx +487 -2
  250. package/src/composer/useRealtimeVoiceMode.spec.ts +267 -65
  251. package/src/composer/useRealtimeVoiceMode.tsx +716 -139
  252. package/src/composer/voice-chat-icon.tsx +19 -0
  253. package/src/editor/DragHandle.spec.ts +217 -0
  254. package/src/editor/DragHandle.ts +214 -55
  255. package/src/editor/RegistryBlockNode.spec.ts +172 -2
  256. package/src/editor/RegistryBlockNode.tsx +91 -13
  257. package/src/editor/index.ts +4 -0
  258. package/src/styles.css +2 -0
  259. package/src/ui/dropdown-menu.tsx +4 -0
@@ -1,6 +1,10 @@
1
+ import { injectedAgentNativeConfig } from "@agent-native/core/client/app-config";
1
2
  import { useOptionalLocale, useT } from "@agent-native/core/client/i18n";
3
+ import { useSession } from "@agent-native/core/client/use-session";
4
+ import { useEffect, useState } from "react";
2
5
 
3
6
  import { LanguagePicker } from "../../shared/index.js";
7
+ import { canShowThemeFamilySwitcher } from "../../shared/is-builder-io-employee.js";
4
8
  import { SchedulingTimezoneField } from "../SchedulingTimezoneField.js";
5
9
  import { SettingsGroup, SettingsRow } from "../SettingsRow.js";
6
10
  import { VoiceChatSettings } from "../VoiceChatSettings.js";
@@ -16,7 +20,18 @@ const key = (name: string) => `agentChat.settingsShell.account.${name}`;
16
20
  export function PreferencesSettings() {
17
21
  const t = useT();
18
22
  const hasLocale = useOptionalLocale() !== null;
23
+ const { session, status } = useSession();
24
+ const [clientReady, setClientReady] = useState(false);
19
25
  const languageLabel = t("agentChat.settingsShell.interfaceLanguage");
26
+ const canSwitchTheme = canShowThemeFamilySwitcher({
27
+ clientReady,
28
+ authenticated: status === "authenticated",
29
+ email: session?.email,
30
+ familyCount: injectedAgentNativeConfig().themeFamily?.families.length ?? 1,
31
+ });
32
+
33
+ useEffect(() => setClientReady(true), []);
34
+
20
35
  return (
21
36
  <div className="flex flex-col gap-8">
22
37
  <SettingsGroup id="language-region" title={t(key("languageAndRegion"))}>
@@ -39,13 +54,15 @@ export function PreferencesSettings() {
39
54
  control={<SchedulingTimezoneField compact />}
40
55
  />
41
56
  </SettingsGroup>
42
- <SettingsGroup id="appearance" title={t(key("appearance"))}>
43
- <SettingsRow
44
- id="theme-family"
45
- label={t(key("themeFamily"))}
46
- control={<ThemeFamilySettings />}
47
- />
48
- </SettingsGroup>
57
+ {canSwitchTheme ? (
58
+ <SettingsGroup id="appearance" title={t(key("appearance"))}>
59
+ <SettingsRow
60
+ id="theme-family"
61
+ label={t(key("themeFamily"))}
62
+ control={<ThemeFamilySettings />}
63
+ />
64
+ </SettingsGroup>
65
+ ) : null}
49
66
  <SettingsGroup id="voice-input" title={t(key("voiceInput"))}>
50
67
  <VoiceTranscriptionSection compact />
51
68
  </SettingsGroup>
@@ -13,7 +13,7 @@ const key = (name: string) => `agentChat.settingsShell.account.${name}`;
13
13
 
14
14
  export function ThemeFamilySettings() {
15
15
  const t = useT();
16
- const { family, status, setFamily } = useThemeFamily();
16
+ const { family, status, isForcedByUrl, setFamily } = useThemeFamily();
17
17
  const [saving, setSaving] = useState(false);
18
18
  const [saveFailed, setSaveFailed] = useState(false);
19
19
 
@@ -37,7 +37,7 @@ export function ThemeFamilySettings() {
37
37
  <Select
38
38
  value={family}
39
39
  onValueChange={(value) => void changeFamily(value)}
40
- disabled={saving || status === "loading"}
40
+ disabled={saving || status === "loading" || isForcedByUrl}
41
41
  >
42
42
  <SelectTrigger aria-label={t(key("themeFamily"))}>
43
43
  <SelectValue />
@@ -7,6 +7,7 @@ import {
7
7
  PREFERENCES_SEARCH_ENTRIES,
8
8
  PROFILE_SEARCH_ENTRIES,
9
9
  SECURITY_SEARCH_ENTRIES,
10
+ visiblePreferenceSearchEntries,
10
11
  } from "./search-entries.js";
11
12
 
12
13
  const ALL = [
@@ -44,4 +45,17 @@ describe("account page search entries", () => {
44
45
  const sections = getCoreSettingsSearchEntries().get("preferences") ?? [];
45
46
  expect(sections.map((entry) => entry.id)).not.toContain("section:voice");
46
47
  });
48
+
49
+ it("does not index the theme-family row while the switch is hidden", () => {
50
+ expect(
51
+ visiblePreferenceSearchEntries(PREFERENCES_SEARCH_ENTRIES, false).map(
52
+ (entry) => entry.id,
53
+ ),
54
+ ).not.toContain("theme-family");
55
+ expect(
56
+ visiblePreferenceSearchEntries(PREFERENCES_SEARCH_ENTRIES, true).map(
57
+ (entry) => entry.id,
58
+ ),
59
+ ).toContain("theme-family");
60
+ });
47
61
  });
@@ -87,3 +87,12 @@ export const SECURITY_SEARCH_ENTRIES: readonly SettingsPageSearchEntry[] = [
87
87
  anchor: "data-deletion",
88
88
  },
89
89
  ];
90
+
91
+ export function visiblePreferenceSearchEntries(
92
+ entries: readonly SettingsPageSearchEntry[],
93
+ canShowThemeFamily: boolean,
94
+ ): readonly SettingsPageSearchEntry[] {
95
+ return canShowThemeFamily
96
+ ? entries
97
+ : entries.filter((entry) => entry.id !== "theme-family");
98
+ }
@@ -1,4 +1,5 @@
1
1
  import { appMountedPath } from "@agent-native/core/client/api-path";
2
+ import { injectedAgentNativeConfig } from "@agent-native/core/client/app-config";
2
3
  import {
3
4
  deleteClientAppState,
4
5
  writeClientAppState,
@@ -12,6 +13,7 @@ import { useFeatureFlags } from "@agent-native/core/client/feature-flags/use-fea
12
13
  import { useT } from "@agent-native/core/client/i18n";
13
14
  import { useLabStates } from "@agent-native/core/client/labs/use-lab";
14
15
  import { useOrg } from "@agent-native/core/client/org";
16
+ import { useSession } from "@agent-native/core/client/use-session";
15
17
  import { STANDARD_APP_ROUTES } from "@agent-native/core/navigation";
16
18
  import {
17
19
  SETTINGS_VIEW_STATE_KEY,
@@ -50,6 +52,8 @@ import {
50
52
  } from "react";
51
53
  import { useInRouterContext, useLocation, useNavigate } from "react-router";
52
54
 
55
+ import { canShowThemeFamilySwitcher } from "../../shared/is-builder-io-employee.js";
56
+ import { visiblePreferenceSearchEntries } from "../account/search-entries.js";
53
57
  import { getCoreSettingsSearchEntries } from "../agent-settings-search.js";
54
58
  import { SettingsSkeleton } from "../SettingsSkeleton.js";
55
59
  import {
@@ -395,6 +399,15 @@ function SettingsShellContent({
395
399
  ...bridgeInput
396
400
  }: ShellContentProps) {
397
401
  const t = useT();
402
+ const { session, status: sessionStatus } = useSession();
403
+ const [themeFamilyClientReady, setThemeFamilyClientReady] = useState(false);
404
+ useEffect(() => setThemeFamilyClientReady(true), []);
405
+ const canShowThemeFamily = canShowThemeFamilySwitcher({
406
+ clientReady: themeFamilyClientReady,
407
+ authenticated: sessionStatus === "authenticated",
408
+ email: session?.email,
409
+ familyCount: injectedAgentNativeConfig().themeFamily?.families.length ?? 1,
410
+ });
398
411
  const { location, go } = navigator;
399
412
 
400
413
  const { data: org } = useOrg();
@@ -785,14 +798,28 @@ function SettingsShellContent({
785
798
  label: pageLabel(page),
786
799
  groupLabel: groupLabel(page.group),
787
800
  entries: [
788
- ...(page.searchEntries ?? []),
801
+ ...(page.id === "preferences"
802
+ ? visiblePreferenceSearchEntries(
803
+ page.searchEntries ?? [],
804
+ canShowThemeFamily,
805
+ )
806
+ : (page.searchEntries ?? [])),
789
807
  ...(coreEntries.get(page.id) ?? []),
790
808
  ...(bridgedEntries.get(page.id) ?? []),
791
809
  ],
792
810
  })),
793
811
  t,
794
812
  );
795
- }, [bridge, groupLabel, pageIcon, pageLabel, pages, t, visiblePages]);
813
+ }, [
814
+ bridge,
815
+ canShowThemeFamily,
816
+ groupLabel,
817
+ pageIcon,
818
+ pageLabel,
819
+ pages,
820
+ t,
821
+ visiblePages,
822
+ ]);
796
823
 
797
824
  const shellContext = useMemo<SettingsShellContextValue>(
798
825
  () => ({ route: { page: routePage, sub: routeSub }, navigate, setHeader }),
@@ -29,10 +29,10 @@ describe("AppShellSkeleton home layout", () => {
29
29
  "[data-agent-native-app-skeleton-home-hero]",
30
30
  );
31
31
  expect(hero?.style.justifyContent).toBe("center");
32
- // Mark, title, two lead lines, composer and hint.
32
+ // Mark, title and composer.
33
33
  expect(
34
34
  hero?.querySelectorAll("[data-agent-native-skeleton-block]"),
35
- ).toHaveLength(6);
35
+ ).toHaveLength(3);
36
36
 
37
37
  const footer = shell.querySelector<HTMLElement>(
38
38
  "[data-agent-native-app-skeleton-home-footer]",
@@ -970,8 +970,8 @@ function LaunchpadLayout() {
970
970
  }
971
971
 
972
972
  /**
973
- * A starter home page: the centered hero (mark, title, lead, large composer,
974
- * hint) over a two-column resource footer, with no header row.
973
+ * A starter home page: the centered hero (mark, title, large composer) over a
974
+ * two-column resource footer, with no header row.
975
975
  */
976
976
  function HomeLayout() {
977
977
  return (
@@ -1000,19 +1000,7 @@ function HomeLayout() {
1000
1000
  }}
1001
1001
  >
1002
1002
  <Block style={{ width: 56, height: 32 }} />
1003
- <div
1004
- style={{
1005
- display: "flex",
1006
- width: "100%",
1007
- flexDirection: "column",
1008
- alignItems: "center",
1009
- gap: 12,
1010
- }}
1011
- >
1012
- <Block style={{ width: "min(100%, 280px)", height: 44 }} />
1013
- <Block style={{ width: "min(100%, 400px)", height: 16 }} />
1014
- <Block style={{ width: "min(100%, 320px)", height: 16 }} />
1015
- </div>
1003
+ <Block style={{ width: "min(100%, 280px)", height: 44 }} />
1016
1004
  <Block
1017
1005
  style={{
1018
1006
  width: "100%",
@@ -1022,7 +1010,6 @@ function HomeLayout() {
1022
1010
  borderRadius: 28,
1023
1011
  }}
1024
1012
  />
1025
- <Block style={{ width: "min(100%, 360px)", height: 14 }} />
1026
1013
  </section>
1027
1014
  <div
1028
1015
  data-agent-native-app-skeleton-home-footer="true"
@@ -35,6 +35,9 @@ import { cn } from "@agent-native/toolkit/utils";
35
35
  import { useEffect, useMemo, useRef, useState } from "react";
36
36
 
37
37
  import { FeedbackButton } from "../feedback/FeedbackButton.js";
38
+ import { isBuilderIoEmployee } from "./is-builder-io-employee.js";
39
+
40
+ export { isBuilderIoEmployee };
38
41
 
39
42
  export {
40
43
  BETA_FORCE_QUERY_PARAM,
@@ -51,10 +54,6 @@ export {
51
54
  type EnvironmentBadgeTargets,
52
55
  } from "@agent-native/core/shared/environment-lanes";
53
56
 
54
- export function isBuilderIoEmployee(email: string | null | undefined): boolean {
55
- return email?.trim().toLowerCase().endsWith("@builder.io") ?? false;
56
- }
57
-
58
57
  export function isAgentNativeDesktopUserAgent(
59
58
  userAgent: string | undefined,
60
59
  ): boolean {
@@ -0,0 +1,17 @@
1
+ export function isBuilderIoEmployee(email: string | null | undefined): boolean {
2
+ return email?.trim().toLowerCase().endsWith("@builder.io") ?? false;
3
+ }
4
+
5
+ export function canShowThemeFamilySwitcher(input: {
6
+ clientReady: boolean;
7
+ authenticated: boolean;
8
+ email: string | null | undefined;
9
+ familyCount: number;
10
+ }): boolean {
11
+ return (
12
+ input.clientReady &&
13
+ input.authenticated &&
14
+ input.familyCount > 1 &&
15
+ isBuilderIoEmployee(input.email)
16
+ );
17
+ }
@@ -539,22 +539,29 @@
539
539
  line-height: 1.5;
540
540
  }
541
541
 
542
+ /* Inside an AgentKit transcript, markdown follows its line height. The
543
+ default lives in this fallback, not a declaration on the chat root, so a
544
+ host can still set the variable on any ancestor. */
545
+ :is(.agentkit-chat, .agentkit-tokens) .agent-markdown {
546
+ line-height: var(--agentkit-transcript-message-line-height, 1.25rem);
547
+ }
548
+
542
549
  .agent-markdown > :last-child {
543
550
  margin-bottom: 0;
544
551
  }
545
552
 
546
553
  .agent-markdown p {
547
- margin: 0.4em 0;
554
+ margin: 0.25rem 0;
548
555
  }
549
556
 
550
557
  .agent-markdown ul,
551
558
  .agent-markdown ol {
552
- margin: 0.4em 0;
553
- padding-inline-start: 1.5em;
559
+ margin: 0.25rem 0;
560
+ padding-inline-start: 1.25rem;
554
561
  }
555
562
 
556
563
  .agent-markdown li {
557
- margin: 0.15em 0;
564
+ margin: 0.25rem 0;
558
565
  }
559
566
 
560
567
  .agent-markdown li > p {
@@ -564,19 +571,19 @@
564
571
  .agent-markdown h1 {
565
572
  font-size: 1.25em;
566
573
  font-weight: 600;
567
- margin: 0.75em 0 0.25em;
574
+ margin: 0.75rem 0 0.25rem;
568
575
  }
569
576
 
570
577
  .agent-markdown h2 {
571
578
  font-size: 1.125em;
572
579
  font-weight: 600;
573
- margin: 0.75em 0 0.25em;
580
+ margin: 0.75rem 0 0.25rem;
574
581
  }
575
582
 
576
583
  .agent-markdown h3 {
577
584
  font-size: 1em;
578
585
  font-weight: 600;
579
- margin: 0.75em 0 0.25em;
586
+ margin: 0.75rem 0 0.25rem;
580
587
  }
581
588
 
582
589
  .agent-markdown strong {
@@ -589,7 +596,7 @@
589
596
 
590
597
  .agent-markdown code {
591
598
  font-size: 0.875em;
592
- padding: 0.15em 0.35em;
599
+ padding: 0.125rem 0.25rem;
593
600
  border-radius: 0.25em;
594
601
  background: hsl(var(--muted, 0 0% 15%));
595
602
  color: hsl(var(--foreground, 0 0% 90%));
@@ -597,8 +604,8 @@
597
604
  }
598
605
 
599
606
  .agent-markdown pre {
600
- margin: 0.5em 0;
601
- padding: 0.75em 1em;
607
+ margin: 0.5rem 0;
608
+ padding: 0.75rem 1rem;
602
609
  border-radius: 0.375em;
603
610
  background: hsl(var(--muted, 0 0% 15%));
604
611
  color: hsl(var(--foreground, 0 0% 90%));
@@ -606,6 +613,12 @@
606
613
  border: 1px solid hsl(var(--border, 0 0% 80%));
607
614
  }
608
615
 
616
+ /* A code span's own line, on a different font's baseline, would stretch its
617
+ line past the transcript's line height. */
618
+ .agent-markdown :not(pre) > code {
619
+ line-height: 1;
620
+ }
621
+
609
622
  .agent-markdown pre code {
610
623
  padding: 0;
611
624
  background: transparent;
@@ -617,7 +630,7 @@
617
630
  .agent-markdown hr {
618
631
  border: none;
619
632
  border-top: 1px solid hsl(var(--border, 0 0% 20%));
620
- margin: 0.75em 0 1em;
633
+ margin: 0.75rem 0 1rem;
621
634
  }
622
635
 
623
636
  .agent-markdown a {
@@ -631,14 +644,14 @@
631
644
 
632
645
  .agent-markdown blockquote {
633
646
  border-inline-start: 2px solid hsl(var(--border, 0 0% 20%));
634
- padding-inline-start: 0.75em;
635
- margin: 0.5em 0;
647
+ padding-inline-start: 0.75rem;
648
+ margin: 0.5rem 0;
636
649
  opacity: 0.8;
637
650
  }
638
651
 
639
652
  .agent-markdown table {
640
653
  border-collapse: collapse;
641
- margin: 0.5em 0;
654
+ margin: 0.5rem 0;
642
655
  font-size: 0.875em;
643
656
  }
644
657
 
@@ -669,7 +682,7 @@
669
682
  .agent-markdown th,
670
683
  .agent-markdown td {
671
684
  border: 1px solid hsl(var(--border, 0 0% 20%));
672
- padding: 0.35em 0.65em;
685
+ padding: 0.25rem 0.5rem;
673
686
  text-align: start;
674
687
  }
675
688
 
@@ -680,7 +693,7 @@
680
693
  }
681
694
 
682
695
  .agent-markdown-shiki {
683
- margin: 0.5em 0;
696
+ margin: 0.25rem 0;
684
697
  border-radius: 0.375em;
685
698
  overflow: hidden;
686
699
  font-size: 0.8125em;
@@ -688,7 +701,7 @@
688
701
 
689
702
  .agent-markdown-shiki pre {
690
703
  margin: 0;
691
- padding: 0.75em 1em;
704
+ padding: 0.5rem 0.75rem;
692
705
  overflow-x: auto;
693
706
  background: var(--shiki-light-bg);
694
707
  color: var(--shiki-light);
@@ -1,7 +1,18 @@
1
- /*
2
- * The agent-native family uses the shared Tailwind/shadcn palette from the
3
- * Design template. App styles remain the original family by default.
4
- */
1
+ /* Family changes stay token-only so every app keeps the same markup. */
2
+ :root[data-theme-family="agent-native"],
3
+ :root[data-theme-family="agent-native"][data-appearance],
4
+ .dark[data-theme-family="agent-native"],
5
+ .dark[data-theme-family="agent-native"][data-appearance] {
6
+ --font-sans: "Inter Variable", "Inter", sans-serif;
7
+ --font-wordmark: "Geist Variable", "Geist", sans-serif;
8
+ --radius: 0.75rem;
9
+ --radius-xl: 0.75rem;
10
+ --agent-native-shadow-color: 0 0% 10%;
11
+ --shadow-composer: 0 8px 15px hsl(var(--agent-native-shadow-color) / 0.06);
12
+ --agent-kit-composer-radius: 0.75rem;
13
+ --agent-kit-composer-elevation: var(--shadow-composer);
14
+ }
15
+
5
16
  :root[data-theme-family="agent-native"],
6
17
  :root[data-theme-family="agent-native"][data-appearance] {
7
18
  --background: 0 0% 100%;
@@ -23,7 +34,7 @@
23
34
  --border: 0 0% 90%;
24
35
  --input: 0 0% 90%;
25
36
  --ring: 0 0% 40%;
26
- --radius: 0.5rem;
37
+ --radius: 0.75rem;
27
38
  --sidebar-background: 0 0% 97%;
28
39
  --sidebar-foreground: 0 0% 45%;
29
40
  --sidebar-primary: 0 0% 15%;
@@ -64,3 +75,9 @@
64
75
  --sidebar-border: 0 0% 20%;
65
76
  --sidebar-ring: 0 0% 60%;
66
77
  }
78
+
79
+ .dark[data-theme-family="agent-native"],
80
+ .dark[data-theme-family="agent-native"][data-appearance] {
81
+ --shadow-composer: 0 8px 30px hsl(var(--background) / 0.22);
82
+ --agent-kit-composer-elevation: var(--shadow-composer);
83
+ }
@@ -6,6 +6,10 @@ const css = readFileSync(
6
6
  new URL("./theme-families.css", import.meta.url),
7
7
  "utf8",
8
8
  );
9
+ const sharedCss = readFileSync(
10
+ new URL("./agent-native.css", import.meta.url),
11
+ "utf8",
12
+ );
9
13
 
10
14
  describe("theme families", () => {
11
15
  it("provides a shared palette for the resolved light and dark modes", () => {
@@ -16,6 +20,10 @@ describe("theme families", () => {
16
20
  expect(css).not.toContain("prefers-color-scheme");
17
21
  });
18
22
 
23
+ it("leaves Original apps without family-specific variable overrides", () => {
24
+ expect(css).not.toContain('data-theme-family="original"');
25
+ });
26
+
19
27
  it("keeps the selected family palette ahead of appearance presets", () => {
20
28
  expect(css).toContain(
21
29
  ':root[data-theme-family="agent-native"][data-appearance]',
@@ -26,4 +34,69 @@ describe("theme families", () => {
26
34
  expect(css).toContain("--background: 0 0% 100%");
27
35
  expect(css).toContain("--background: 0 0% 13%");
28
36
  });
37
+
38
+ it("loads the selected family font and shared radius and composer tokens", () => {
39
+ expect(css).toContain('--font-sans: "Inter Variable", "Inter", sans-serif');
40
+ expect(css).toContain(
41
+ '--font-wordmark: "Geist Variable", "Geist", sans-serif',
42
+ );
43
+ expect(css).toContain("--radius: 0.75rem");
44
+ expect(css).toContain("--radius-xl: 0.75rem");
45
+ expect(sharedCss).toContain("--radius-lg: var(--radius)");
46
+ expect(sharedCss).toContain("--radius-md: calc(var(--radius) - 2px)");
47
+ expect(sharedCss).toContain("--radius-sm: calc(var(--radius) - 4px)");
48
+ expect(css).toContain("--agent-kit-composer-radius: 0.75rem");
49
+ expect(css).toContain(
50
+ "--agent-kit-composer-elevation: var(--shadow-composer)",
51
+ );
52
+ expect(css).toContain("--agent-native-shadow-color: 0 0% 10%");
53
+ expect(css).toContain(
54
+ "0 8px 15px hsl(var(--agent-native-shadow-color) / 0.06)",
55
+ );
56
+ });
57
+
58
+ it("keeps the light family palette radius at twelve pixels", () => {
59
+ const blocks = [
60
+ ...css.matchAll(
61
+ /([^{}]*data-theme-family="agent-native"[^{}]*)\{([^{}]*)\}/g,
62
+ ),
63
+ ];
64
+ const lightPalette = blocks.find(
65
+ ([, selectors, declarations]) =>
66
+ selectors.includes(":root[data-theme-family=") &&
67
+ declarations.includes("--background:"),
68
+ );
69
+
70
+ expect(lightPalette?.[2]).toMatch(/--radius:\s*0\.75rem/);
71
+ });
72
+
73
+ it("uses the code dark-palette composer elevation in dark mode", () => {
74
+ expect(css).toContain(
75
+ '.dark[data-theme-family="agent-native"][data-appearance]',
76
+ );
77
+ expect(css).toContain(
78
+ "--shadow-composer: 0 8px 30px hsl(var(--background) / 0.22)",
79
+ );
80
+ });
81
+
82
+ it("limits each family block to custom properties", () => {
83
+ const blocks = [
84
+ ...css.matchAll(
85
+ /([^{}]*data-theme-family="agent-native"[^{}]*)\{([^{}]*)\}/g,
86
+ ),
87
+ ];
88
+
89
+ expect(blocks.length).toBeGreaterThan(0);
90
+ for (const [, selectors, declarations] of blocks) {
91
+ expect(selectors).toContain("data-theme-family=");
92
+ const entries = declarations
93
+ .split(";")
94
+ .map((entry) => entry.trim())
95
+ .filter(Boolean);
96
+ expect(entries.length).toBeGreaterThan(0);
97
+ for (const entry of entries) {
98
+ expect(entry).toMatch(/^--[\w-]+\s*:/);
99
+ }
100
+ }
101
+ });
29
102
  });
@@ -58,8 +58,8 @@
58
58
  hsl(var(--border))
59
59
  );
60
60
  --agent-kit-composer-editor-padding-inline: 1rem;
61
- --agent-kit-composer-editor-padding-block-start: 0.875rem;
62
- --agent-kit-composer-editor-padding-block-end: 0.125rem;
61
+ --agent-kit-composer-editor-padding-block-start: 0.75rem;
62
+ --agent-kit-composer-editor-padding-block-end: 0.25rem;
63
63
  --agent-kit-composer-editor-min-height: 1lh;
64
64
  --agent-kit-composer-editor-max-height: 12rem;
65
65
  --agent-kit-composer-font-size: 0.875rem;
@@ -71,7 +71,7 @@
71
71
  --agent-kit-composer-toolbar-padding-block-end: 0.5rem;
72
72
  --agent-kit-composer-toolbar-control-size: 1.5rem;
73
73
  --agent-kit-composer-toolbar-control-gap: 0.25rem;
74
- --agent-kit-composer-toolbar-control-padding-inline: 0.375rem;
74
+ --agent-kit-composer-toolbar-control-padding-inline: 0.5rem;
75
75
  --agent-kit-composer-toolbar-control-font-size: var(
76
76
  --agent-kit-supporting-font-size
77
77
  );
@@ -271,7 +271,7 @@ describe("AgentSuggestionBar overflow", () => {
271
271
  /\[data-agent-suggestion-scroller="true"\]\[data-overflow-end\] \{\n\s+--agent-suggestion-fade-end: 1\.5rem;/,
272
272
  );
273
273
  expect(styles).toMatch(
274
- /\.agentkit-suggestions \{\n\s+--agent-suggestion-gap: 0\.375rem;/,
274
+ /\.agentkit-suggestions \{\n\s+--agent-suggestion-gap: 0\.5rem;/,
275
275
  );
276
276
  });
277
277
  });
@@ -0,0 +1,87 @@
1
+ // @vitest-environment happy-dom
2
+
3
+ import type { Attachment } from "@assistant-ui/react";
4
+ import { act } from "react";
5
+ import { createRoot, type Root } from "react-dom/client";
6
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
7
+
8
+ import { AGENT_PROMPT_MAX_TEXT_FILE_BYTES } from "./prompt-attachments.js";
9
+ import { AttachmentChip } from "./PromptComposer.js";
10
+ import { ComposerRuntimeAdaptersProvider } from "./runtime-adapters.js";
11
+
12
+ describe("AttachmentChip", () => {
13
+ let container: HTMLDivElement;
14
+ let root: Root;
15
+
16
+ beforeEach(() => {
17
+ vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
18
+ container = document.createElement("div");
19
+ document.body.appendChild(container);
20
+ root = createRoot(container);
21
+ });
22
+
23
+ afterEach(() => {
24
+ act(() => root.unmount());
25
+ container.remove();
26
+ vi.unstubAllGlobals();
27
+ });
28
+
29
+ async function renderChip(file: File) {
30
+ const attachment = {
31
+ id: "file-1",
32
+ type: "file",
33
+ name: file.name,
34
+ file,
35
+ status: { type: "requires-action", reason: "composer-send" },
36
+ } as unknown as Attachment;
37
+ await act(async () => {
38
+ root.render(
39
+ <ComposerRuntimeAdaptersProvider
40
+ adapters={{
41
+ translate: (_key, options) => String(options?.defaultValue ?? ""),
42
+ }}
43
+ >
44
+ <AttachmentChip attachment={attachment} onRemove={() => {}} />
45
+ </ComposerRuntimeAdaptersProvider>,
46
+ );
47
+ });
48
+ }
49
+
50
+ it("shows a file the browser cannot read before it is sent", async () => {
51
+ const file = new File(["# Design"], "DESIGN.md", { type: "text/markdown" });
52
+ vi.spyOn(file, "arrayBuffer").mockRejectedValue(
53
+ new Error("NotReadableError"),
54
+ );
55
+
56
+ await renderChip(file);
57
+
58
+ await vi.waitFor(() => {
59
+ expect(container.querySelector('[role="status"]')?.textContent).toContain(
60
+ "Couldn't read this file",
61
+ );
62
+ });
63
+ });
64
+
65
+ it("shows a text file over the read limit", async () => {
66
+ const file = new File(["<svg/>"], "logo.svg", { type: "image/svg+xml" });
67
+ Object.defineProperty(file, "size", {
68
+ value: AGENT_PROMPT_MAX_TEXT_FILE_BYTES + 1,
69
+ });
70
+
71
+ await renderChip(file);
72
+
73
+ await vi.waitFor(() => {
74
+ expect(container.textContent).toContain("File is over 8 MB");
75
+ });
76
+ });
77
+
78
+ it("keeps the plain chip for a readable file", async () => {
79
+ await renderChip(
80
+ new File(["# Design"], "DESIGN.md", { type: "text/markdown" }),
81
+ );
82
+
83
+ await act(async () => {});
84
+ expect(container.textContent).toContain("DESIGN.md");
85
+ expect(container.querySelector('[role="status"]')).toBeNull();
86
+ });
87
+ });