@agent-native/toolkit 0.213.1 → 0.216.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 (222) hide show
  1. package/agent-native.eject.json +9 -0
  2. package/dist/app/agentkit/react/chat.d.ts.map +1 -1
  3. package/dist/app/agentkit/react/chat.js +2 -2
  4. package/dist/app/agentkit/react/chat.js.map +1 -1
  5. package/dist/app/agentkit/react/components.d.ts +4 -1
  6. package/dist/app/agentkit/react/components.d.ts.map +1 -1
  7. package/dist/app/agentkit/react/components.js +73 -13
  8. package/dist/app/agentkit/react/components.js.map +1 -1
  9. package/dist/app/agentkit/react/context.d.ts +19 -1
  10. package/dist/app/agentkit/react/context.d.ts.map +1 -1
  11. package/dist/app/agentkit/react/context.js +7 -1
  12. package/dist/app/agentkit/react/context.js.map +1 -1
  13. package/dist/app/agentkit/react/index.d.ts +2 -0
  14. package/dist/app/agentkit/react/index.d.ts.map +1 -1
  15. package/dist/app/agentkit/react/index.js +2 -0
  16. package/dist/app/agentkit/react/index.js.map +1 -1
  17. package/dist/app/agentkit/react/message-content-order.d.ts +21 -0
  18. package/dist/app/agentkit/react/message-content-order.d.ts.map +1 -0
  19. package/dist/app/agentkit/react/message-content-order.js +173 -0
  20. package/dist/app/agentkit/react/message-content-order.js.map +1 -0
  21. package/dist/app/agentkit/react/root.d.ts +6 -1
  22. package/dist/app/agentkit/react/root.d.ts.map +1 -1
  23. package/dist/app/agentkit/react/root.js +2 -2
  24. package/dist/app/agentkit/react/root.js.map +1 -1
  25. package/dist/app/agentkit/react/styles.css +45 -8
  26. package/dist/app/agentkit/react/transcript-layout.d.ts +51 -0
  27. package/dist/app/agentkit/react/transcript-layout.d.ts.map +1 -0
  28. package/dist/app/agentkit/react/transcript-layout.js +34 -0
  29. package/dist/app/agentkit/react/transcript-layout.js.map +1 -0
  30. package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
  31. package/dist/app/chat/AgentKitAssistantChat.js +9 -4
  32. package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
  33. package/dist/app/chat/AgentPanel.d.ts +16 -2
  34. package/dist/app/chat/AgentPanel.d.ts.map +1 -1
  35. package/dist/app/chat/AgentPanel.js +26 -5
  36. package/dist/app/chat/AgentPanel.js.map +1 -1
  37. package/dist/app/chat/chat/index.d.ts +2 -0
  38. package/dist/app/chat/chat/index.d.ts.map +1 -1
  39. package/dist/app/chat/chat/index.js.map +1 -1
  40. package/dist/app/chat/chat/surface-types.d.ts +15 -0
  41. package/dist/app/chat/chat/surface-types.d.ts.map +1 -1
  42. package/dist/app/chat/chat/surface-types.js.map +1 -1
  43. package/dist/app/chat/chat/tool-call-display.d.ts +7 -2
  44. package/dist/app/chat/chat/tool-call-display.d.ts.map +1 -1
  45. package/dist/app/chat/chat/tool-call-display.js +10 -9
  46. package/dist/app/chat/chat/tool-call-display.js.map +1 -1
  47. package/dist/app/chat/chat/widgets/DataChartRenderer.d.ts.map +1 -1
  48. package/dist/app/chat/chat/widgets/DataChartRenderer.js +300 -33
  49. package/dist/app/chat/chat/widgets/DataChartRenderer.js.map +1 -1
  50. package/dist/app/chat/chat/widgets/DataChartWidget.d.ts +3 -2
  51. package/dist/app/chat/chat/widgets/DataChartWidget.d.ts.map +1 -1
  52. package/dist/app/chat/chat/widgets/DataChartWidget.js +18 -9
  53. package/dist/app/chat/chat/widgets/DataChartWidget.js.map +1 -1
  54. package/dist/app/chat/chat/widgets/DataInsightsWidget.js +1 -1
  55. package/dist/app/chat/chat/widgets/DataInsightsWidget.js.map +1 -1
  56. package/dist/app/chat/chat/widgets/DataTableWidget.d.ts +3 -2
  57. package/dist/app/chat/chat/widgets/DataTableWidget.d.ts.map +1 -1
  58. package/dist/app/chat/chat/widgets/DataTableWidget.js +10 -66
  59. package/dist/app/chat/chat/widgets/DataTableWidget.js.map +1 -1
  60. package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.d.ts +11 -0
  61. package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.d.ts.map +1 -0
  62. package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.js +133 -0
  63. package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.js.map +1 -0
  64. package/dist/app/chat/chat/widgets/builtin-tool-renderers.js +2 -2
  65. package/dist/app/chat/chat/widgets/builtin-tool-renderers.js.map +1 -1
  66. package/dist/app/chat/mcp-apps/McpAppRenderer.d.ts.map +1 -1
  67. package/dist/app/chat/mcp-apps/McpAppRenderer.js +6 -5
  68. package/dist/app/chat/mcp-apps/McpAppRenderer.js.map +1 -1
  69. package/dist/app/chat/mcp-apps/mcp-app-theme.d.ts +2 -0
  70. package/dist/app/chat/mcp-apps/mcp-app-theme.d.ts.map +1 -0
  71. package/dist/app/chat/mcp-apps/mcp-app-theme.js +11 -0
  72. package/dist/app/chat/mcp-apps/mcp-app-theme.js.map +1 -0
  73. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  74. package/dist/app/i18n/catalogs/ar-SA.js +9 -0
  75. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  76. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  77. package/dist/app/i18n/catalogs/de-DE.js +9 -0
  78. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  79. package/dist/app/i18n/catalogs/en-US.d.ts +9 -0
  80. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  81. package/dist/app/i18n/catalogs/en-US.js +9 -0
  82. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  83. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  84. package/dist/app/i18n/catalogs/es-ES.js +9 -0
  85. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  86. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  87. package/dist/app/i18n/catalogs/fr-FR.js +9 -0
  88. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  89. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  90. package/dist/app/i18n/catalogs/hi-IN.js +9 -0
  91. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  92. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  93. package/dist/app/i18n/catalogs/ja-JP.js +9 -0
  94. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  95. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  96. package/dist/app/i18n/catalogs/ko-KR.js +9 -0
  97. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  98. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  99. package/dist/app/i18n/catalogs/pt-BR.js +9 -0
  100. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  101. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  102. package/dist/app/i18n/catalogs/zh-CN.js +9 -0
  103. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  104. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  105. package/dist/app/i18n/catalogs/zh-TW.js +9 -0
  106. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  107. package/dist/app/providers/AppProviders.d.ts +2 -1
  108. package/dist/app/providers/AppProviders.d.ts.map +1 -1
  109. package/dist/app/providers/AppProviders.js +4 -3
  110. package/dist/app/providers/AppProviders.js.map +1 -1
  111. package/dist/app/providers/ThemeFamilySync.d.ts +2 -0
  112. package/dist/app/providers/ThemeFamilySync.d.ts.map +1 -0
  113. package/dist/app/providers/ThemeFamilySync.js +6 -0
  114. package/dist/app/providers/ThemeFamilySync.js.map +1 -0
  115. package/dist/app/settings/account/PreferencesSettings.d.ts.map +1 -1
  116. package/dist/app/settings/account/PreferencesSettings.js +2 -1
  117. package/dist/app/settings/account/PreferencesSettings.js.map +1 -1
  118. package/dist/app/settings/account/ThemeFamilySettings.d.ts +2 -0
  119. package/dist/app/settings/account/ThemeFamilySettings.d.ts.map +1 -0
  120. package/dist/app/settings/account/ThemeFamilySettings.js +31 -0
  121. package/dist/app/settings/account/ThemeFamilySettings.js.map +1 -0
  122. package/dist/app/settings/account/search-entries.d.ts.map +1 -1
  123. package/dist/app/settings/account/search-entries.js +6 -0
  124. package/dist/app/settings/account/search-entries.js.map +1 -1
  125. package/dist/app/shared/DefaultSpinner.d.ts.map +1 -1
  126. package/dist/app/shared/DefaultSpinner.js +4 -5
  127. package/dist/app/shared/DefaultSpinner.js.map +1 -1
  128. package/dist/app/shared/ErrorBoundary.d.ts +1 -0
  129. package/dist/app/shared/ErrorBoundary.d.ts.map +1 -1
  130. package/dist/app/shared/ErrorBoundary.js +27 -12
  131. package/dist/app/shared/ErrorBoundary.js.map +1 -1
  132. package/dist/app/shared/PoweredByBadge.d.ts.map +1 -1
  133. package/dist/app/shared/PoweredByBadge.js +8 -49
  134. package/dist/app/shared/PoweredByBadge.js.map +1 -1
  135. package/dist/app/styles/agent-conversation.css +0 -23
  136. package/dist/app/styles/agent-native.css +1 -1
  137. package/dist/app/styles/theme-families.css +66 -0
  138. package/dist/composer/ComposerContextBanner.d.ts +24 -0
  139. package/dist/composer/ComposerContextBanner.d.ts.map +1 -0
  140. package/dist/composer/ComposerContextBanner.js +9 -0
  141. package/dist/composer/ComposerContextBanner.js.map +1 -0
  142. package/dist/composer/ComposerModePicker.d.ts +26 -0
  143. package/dist/composer/ComposerModePicker.d.ts.map +1 -0
  144. package/dist/composer/ComposerModePicker.js +14 -0
  145. package/dist/composer/ComposerModePicker.js.map +1 -0
  146. package/dist/composer/index.d.ts +2 -0
  147. package/dist/composer/index.d.ts.map +1 -1
  148. package/dist/composer/index.js +2 -0
  149. package/dist/composer/index.js.map +1 -1
  150. package/dist/styles.css +1 -0
  151. package/package.json +3 -3
  152. package/src/app/agentkit/react/chat.tsx +2 -0
  153. package/src/app/agentkit/react/components.interaction.spec.tsx +107 -0
  154. package/src/app/agentkit/react/components.spec.tsx +40 -1
  155. package/src/app/agentkit/react/components.tsx +186 -31
  156. package/src/app/agentkit/react/context.tsx +29 -0
  157. package/src/app/agentkit/react/index.ts +2 -0
  158. package/src/app/agentkit/react/lifecycle.spec.tsx +289 -4
  159. package/src/app/agentkit/react/message-content-order.spec.ts +190 -0
  160. package/src/app/agentkit/react/message-content-order.ts +246 -0
  161. package/src/app/agentkit/react/root.tsx +11 -0
  162. package/src/app/agentkit/react/styles.css +45 -8
  163. package/src/app/agentkit/react/transcript-layout.spec.ts +72 -0
  164. package/src/app/agentkit/react/transcript-layout.ts +97 -0
  165. package/src/app/auth/AuthPage.attribution.spec.tsx +6 -0
  166. package/src/app/chat/AgentKitAssistantChat.spec.tsx +58 -0
  167. package/src/app/chat/AgentKitAssistantChat.tsx +15 -1
  168. package/src/app/chat/AgentPanel.header.spec.ts +72 -14
  169. package/src/app/chat/AgentPanel.page-header-share.spec.tsx +101 -0
  170. package/src/app/chat/AgentPanel.tsx +111 -55
  171. package/src/app/chat/chat/index.ts +2 -0
  172. package/src/app/chat/chat/surface-types.ts +18 -0
  173. package/src/app/chat/chat/tool-call-display.spec.tsx +83 -0
  174. package/src/app/chat/chat/tool-call-display.tsx +40 -8
  175. package/src/app/chat/chat/widgets/DataChartRenderer.spec.tsx +849 -0
  176. package/src/app/chat/chat/widgets/DataChartRenderer.tsx +567 -72
  177. package/src/app/chat/chat/widgets/DataChartWidget.spec.tsx +432 -0
  178. package/src/app/chat/chat/widgets/DataChartWidget.ssr.spec.tsx +25 -0
  179. package/src/app/chat/chat/widgets/DataChartWidget.tsx +58 -33
  180. package/src/app/chat/chat/widgets/DataInsightsWidget.tsx +2 -2
  181. package/src/app/chat/chat/widgets/DataTableWidget.spec.tsx +37 -3
  182. package/src/app/chat/chat/widgets/DataTableWidget.tsx +22 -86
  183. package/src/app/chat/chat/widgets/DataWidgetDisplayControls.tsx +321 -0
  184. package/src/app/chat/chat/widgets/builtin-tool-renderers.tsx +5 -5
  185. package/src/app/chat/mcp-apps/McpAppRenderer.tsx +10 -5
  186. package/src/app/chat/mcp-apps/mcp-app-theme.spec.ts +30 -0
  187. package/src/app/chat/mcp-apps/mcp-app-theme.ts +11 -0
  188. package/src/app/i18n/catalogs/ar-SA.ts +10 -0
  189. package/src/app/i18n/catalogs/de-DE.ts +11 -0
  190. package/src/app/i18n/catalogs/en-US.ts +11 -0
  191. package/src/app/i18n/catalogs/es-ES.ts +12 -0
  192. package/src/app/i18n/catalogs/fr-FR.ts +12 -0
  193. package/src/app/i18n/catalogs/hi-IN.ts +10 -0
  194. package/src/app/i18n/catalogs/ja-JP.ts +11 -0
  195. package/src/app/i18n/catalogs/ko-KR.ts +10 -0
  196. package/src/app/i18n/catalogs/pt-BR.ts +11 -0
  197. package/src/app/i18n/catalogs/zh-CN.ts +9 -0
  198. package/src/app/i18n/catalogs/zh-TW.ts +10 -0
  199. package/src/app/providers/AppProviders.spec.tsx +71 -0
  200. package/src/app/providers/AppProviders.tsx +10 -0
  201. package/src/app/providers/ThemeFamilySync.tsx +6 -0
  202. package/src/app/settings/account/PreferencesSettings.spec.tsx +13 -2
  203. package/src/app/settings/account/PreferencesSettings.tsx +8 -0
  204. package/src/app/settings/account/ThemeFamilySettings.tsx +61 -0
  205. package/src/app/settings/account/search-entries.ts +6 -0
  206. package/src/app/shared/DefaultSpinner.spec.tsx +14 -0
  207. package/src/app/shared/DefaultSpinner.tsx +4 -5
  208. package/src/app/shared/ErrorBoundary.spec.tsx +45 -2
  209. package/src/app/shared/ErrorBoundary.tsx +37 -12
  210. package/src/app/shared/PoweredByBadge.spec.tsx +16 -0
  211. package/src/app/shared/PoweredByBadge.tsx +8 -50
  212. package/src/app/styles/agent-conversation.css +0 -23
  213. package/src/app/styles/agent-native.css +1 -1
  214. package/src/app/styles/agent-native.spec.ts +18 -0
  215. package/src/app/styles/theme-families.css +66 -0
  216. package/src/app/styles/theme-families.spec.ts +29 -0
  217. package/src/composer/ComposerContextBanner.spec.tsx +100 -0
  218. package/src/composer/ComposerContextBanner.tsx +77 -0
  219. package/src/composer/ComposerModePicker.spec.tsx +101 -0
  220. package/src/composer/ComposerModePicker.tsx +98 -0
  221. package/src/composer/index.ts +9 -0
  222. package/src/styles.css +1 -0
@@ -1068,6 +1068,11 @@ const messages: ToolkitAgentChatTranslation = {
1068
1068
  "tool.worked": "A travaillé",
1069
1069
  "tool.workedFor": "A travaillé pendant {{duration}}",
1070
1070
  "widget.chart": "Graphique",
1071
+ "widget.chartActions": "Actions du graphique",
1072
+ "widget.chartRowsOmitted":
1073
+ "Ce graphique n’affiche qu’une partie des lignes disponibles.",
1074
+ "widget.dataSources": "Sources de données",
1075
+ "widget.tableActions": "Actions du tableau",
1071
1076
  "widget.dataChart": "Graphique de données",
1072
1077
  "widget.dataInsights": "Informations sur les données",
1073
1078
  "widget.dataTable": "Tableau de données",
@@ -2245,6 +2250,13 @@ const messages: ToolkitAgentChatTranslation = {
2245
2250
  "settingsShell.account.languageAndRegion": "Langue et région",
2246
2251
  "settingsShell.account.languageDescription":
2247
2252
  "S’applique sur tous vos appareils.",
2253
+ "settingsShell.account.appearance": "Apparence",
2254
+ "settingsShell.account.themeFamily": "Famille de thème",
2255
+ "settingsShell.account.themeFamilyAgentNative": "Agent-Native",
2256
+ "settingsShell.account.themeFamilyOriginal":
2257
+ "Couleurs d’origine de l’application",
2258
+ "settingsShell.account.themeFamilySaveError":
2259
+ "Impossible de mettre à jour le thème. Réessayez.",
2248
2260
  "settingsShell.account.manage": "Gérer",
2249
2261
  "settingsShell.account.name": "Nom",
2250
2262
  "settingsShell.account.nameDescription":
@@ -1491,6 +1491,10 @@ const messages: ToolkitAgentChatTranslation = {
1491
1491
  "tool.worked": "काम किया",
1492
1492
  "tool.workedFor": "{{duration}} तक काम किया",
1493
1493
  "widget.chart": "चार्ट",
1494
+ "widget.chartActions": "चार्ट कार्रवाइयाँ",
1495
+ "widget.chartRowsOmitted": "यह चार्ट उपलब्ध पंक्तियों में से केवल कुछ दिखाता है।",
1496
+ "widget.dataSources": "डेटा स्रोत",
1497
+ "widget.tableActions": "टेबल कार्रवाइयाँ",
1494
1498
  "widget.dataChart": "डेटा चार्ट",
1495
1499
  "widget.dataInsights": "डेटा इनसाइट्स",
1496
1500
  "widget.dataTable": "डेटा तालिका",
@@ -2063,6 +2067,12 @@ const messages: ToolkitAgentChatTranslation = {
2063
2067
  "इस बदलाव की पुष्टि करने के निर्देशों के लिए अपना ईमेल देखें।",
2064
2068
  "settingsShell.account.languageAndRegion": "भाषा और क्षेत्र",
2065
2069
  "settingsShell.account.languageDescription": "आपके सभी डिवाइस पर लागू होता है।",
2070
+ "settingsShell.account.appearance": "रूप-रंग",
2071
+ "settingsShell.account.themeFamily": "थीम शैली",
2072
+ "settingsShell.account.themeFamilyAgentNative": "Agent-Native",
2073
+ "settingsShell.account.themeFamilyOriginal": "ऐप के मूल रंग",
2074
+ "settingsShell.account.themeFamilySaveError":
2075
+ "थीम शैली अपडेट नहीं की जा सकी। फिर कोशिश करें।",
2066
2076
  "settingsShell.account.manage": "प्रबंधित करें",
2067
2077
  "settingsShell.account.name": "नाम",
2068
2078
  "settingsShell.account.nameDescription":
@@ -1536,6 +1536,11 @@ const messages: ToolkitAgentChatTranslation = {
1536
1536
  "tool.worked": "作業しました",
1537
1537
  "tool.workedFor": "{{duration}} 作業しました",
1538
1538
  "widget.chart": "チャート",
1539
+ "widget.chartActions": "チャート操作",
1540
+ "widget.chartRowsOmitted":
1541
+ "このグラフには、利用可能な行の一部のみが表示されます。",
1542
+ "widget.dataSources": "データソース",
1543
+ "widget.tableActions": "テーブル操作",
1539
1544
  "widget.dataChart": "データチャート",
1540
1545
  "widget.dataInsights": "データインサイト",
1541
1546
  "widget.dataTable": "データテーブル",
@@ -2093,6 +2098,12 @@ const messages: ToolkitAgentChatTranslation = {
2093
2098
  "settingsShell.account.languageAndRegion": "言語と地域",
2094
2099
  "settingsShell.account.languageDescription":
2095
2100
  "すべてのデバイスに適用されます。",
2101
+ "settingsShell.account.appearance": "外観",
2102
+ "settingsShell.account.themeFamily": "テーマ",
2103
+ "settingsShell.account.themeFamilyAgentNative": "Agent-Native",
2104
+ "settingsShell.account.themeFamilyOriginal": "アプリのオリジナルカラー",
2105
+ "settingsShell.account.themeFamilySaveError":
2106
+ "テーマを更新できませんでした。もう一度お試しください。",
2096
2107
  "settingsShell.account.manage": "管理",
2097
2108
  "settingsShell.account.name": "名前",
2098
2109
  "settingsShell.account.nameDescription":
@@ -1510,6 +1510,10 @@ const messages: ToolkitAgentChatTranslation = {
1510
1510
  "tool.worked": "작업함",
1511
1511
  "tool.workedFor": "{{duration}} 동안 작업함",
1512
1512
  "widget.chart": "차트",
1513
+ "widget.chartActions": "차트 작업",
1514
+ "widget.chartRowsOmitted": "이 차트에는 사용 가능한 행 중 일부만 표시됩니다.",
1515
+ "widget.dataSources": "데이터 소스",
1516
+ "widget.tableActions": "표 작업",
1513
1517
  "widget.dataChart": "데이터 차트",
1514
1518
  "widget.dataInsights": "데이터 인사이트",
1515
1519
  "widget.dataTable": "데이터 테이블",
@@ -2057,6 +2061,12 @@ const messages: ToolkitAgentChatTranslation = {
2057
2061
  "이메일을 확인하고 안내에 따라 이 변경을 확정하세요.",
2058
2062
  "settingsShell.account.languageAndRegion": "언어 및 지역",
2059
2063
  "settingsShell.account.languageDescription": "모든 기기에 적용됩니다.",
2064
+ "settingsShell.account.appearance": "모양",
2065
+ "settingsShell.account.themeFamily": "테마 스타일",
2066
+ "settingsShell.account.themeFamilyAgentNative": "Agent-Native",
2067
+ "settingsShell.account.themeFamilyOriginal": "앱의 원래 색상",
2068
+ "settingsShell.account.themeFamilySaveError":
2069
+ "테마 스타일을 업데이트하지 못했습니다. 다시 시도하세요.",
2060
2070
  "settingsShell.account.manage": "관리",
2061
2071
  "settingsShell.account.name": "이름",
2062
2072
  "settingsShell.account.nameDescription":
@@ -1055,6 +1055,11 @@ const messages: ToolkitAgentChatTranslation = {
1055
1055
  "tool.worked": "Trabalhou",
1056
1056
  "tool.workedFor": "Trabalhou por {{duration}}",
1057
1057
  "widget.chart": "Gráfico",
1058
+ "widget.chartActions": "Ações do gráfico",
1059
+ "widget.chartRowsOmitted":
1060
+ "Este gráfico mostra apenas algumas das linhas disponíveis.",
1061
+ "widget.dataSources": "Fontes de dados",
1062
+ "widget.tableActions": "Ações da tabela",
1058
1063
  "widget.dataChart": "Gráfico de dados",
1059
1064
  "widget.dataInsights": "Insights de dados",
1060
1065
  "widget.dataTable": "Tabela de dados",
@@ -2220,6 +2225,12 @@ const messages: ToolkitAgentChatTranslation = {
2220
2225
  "settingsShell.account.languageAndRegion": "Idioma e região",
2221
2226
  "settingsShell.account.languageDescription":
2222
2227
  "Vale para todos os seus dispositivos.",
2228
+ "settingsShell.account.appearance": "Aparência",
2229
+ "settingsShell.account.themeFamily": "Família do tema",
2230
+ "settingsShell.account.themeFamilyAgentNative": "Agent-Native",
2231
+ "settingsShell.account.themeFamilyOriginal": "Cores originais do app",
2232
+ "settingsShell.account.themeFamilySaveError":
2233
+ "Não foi possível atualizar o tema. Tente novamente.",
2223
2234
  "settingsShell.account.manage": "Gerenciar",
2224
2235
  "settingsShell.account.name": "Nome",
2225
2236
  "settingsShell.account.nameDescription":
@@ -1419,6 +1419,10 @@ const messages: ToolkitAgentChatTranslation = {
1419
1419
  "tool.worked": "已处理",
1420
1420
  "tool.workedFor": "处理了 {{duration}}",
1421
1421
  "widget.chart": "图表",
1422
+ "widget.chartActions": "图表操作",
1423
+ "widget.chartRowsOmitted": "此图表仅显示部分可用行。",
1424
+ "widget.dataSources": "数据来源",
1425
+ "widget.tableActions": "表格操作",
1422
1426
  "widget.dataChart": "数据图表",
1423
1427
  "widget.dataInsights": "数据洞察",
1424
1428
  "widget.dataTable": "数据表",
@@ -1940,6 +1944,11 @@ const messages: ToolkitAgentChatTranslation = {
1940
1944
  "settingsShell.account.emailChangeSent": "请查看您的邮箱,按说明确认此更改。",
1941
1945
  "settingsShell.account.languageAndRegion": "语言和地区",
1942
1946
  "settingsShell.account.languageDescription": "适用于您的所有设备。",
1947
+ "settingsShell.account.appearance": "外观",
1948
+ "settingsShell.account.themeFamily": "主题样式",
1949
+ "settingsShell.account.themeFamilyAgentNative": "Agent-Native",
1950
+ "settingsShell.account.themeFamilyOriginal": "原应用配色",
1951
+ "settingsShell.account.themeFamilySaveError": "无法更新主题样式。请重试。",
1943
1952
  "settingsShell.account.manage": "管理",
1944
1953
  "settingsShell.account.name": "姓名",
1945
1954
  "settingsShell.account.nameDescription":
@@ -1424,6 +1424,10 @@ const messages: ToolkitAgentChatTranslation = {
1424
1424
  "tool.worked": "已處理",
1425
1425
  "tool.workedFor": "處理了 {{duration}}",
1426
1426
  "widget.chart": "圖表",
1427
+ "widget.chartActions": "圖表操作",
1428
+ "widget.chartRowsOmitted": "此圖表僅顯示部分可用資料列。",
1429
+ "widget.dataSources": "資料來源",
1430
+ "widget.tableActions": "表格操作",
1427
1431
  "widget.dataChart": "資料圖表",
1428
1432
  "widget.dataInsights": "資料洞察",
1429
1433
  "widget.dataTable": "資料表",
@@ -1950,6 +1954,12 @@ const messages: ToolkitAgentChatTranslation = {
1950
1954
  "請查看您的電子郵件,依照說明確認此變更。",
1951
1955
  "settingsShell.account.languageAndRegion": "語言和地區",
1952
1956
  "settingsShell.account.languageDescription": "套用至您的所有裝置。",
1957
+ "settingsShell.account.appearance": "外觀",
1958
+ "settingsShell.account.themeFamily": "主題樣式",
1959
+ "settingsShell.account.themeFamilyAgentNative": "Agent-Native",
1960
+ "settingsShell.account.themeFamilyOriginal": "原始應用程式配色",
1961
+ "settingsShell.account.themeFamilySaveError":
1962
+ "無法更新主題樣式,請再試一次。",
1953
1963
  "settingsShell.account.manage": "管理",
1954
1964
  "settingsShell.account.name": "姓名",
1955
1965
  "settingsShell.account.nameDescription":
@@ -9,12 +9,17 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
9
9
  import { resetAgentEngineReadinessForTests } from "../../../../core/src/client/agent-engine-readiness.js";
10
10
 
11
11
  const useSessionMock = vi.fn();
12
+ const useThemeFamilyMock = vi.fn();
12
13
  vi.mock("@agent-native/core/client/use-session", async (importOriginal) => ({
13
14
  ...(await importOriginal<
14
15
  typeof import("@agent-native/core/client/use-session")
15
16
  >()),
16
17
  useSession: () => useSessionMock(),
17
18
  }));
19
+ vi.mock("@agent-native/core/client/ui", async (importOriginal) => ({
20
+ ...(await importOriginal<typeof import("@agent-native/core/client/ui")>()),
21
+ useThemeFamily: () => useThemeFamilyMock(),
22
+ }));
18
23
  vi.mock("@agent-native/core/client/action-query-cache", () => ({
19
24
  ActionQueryCacheGate: ({ children }: { children: React.ReactNode }) => (
20
25
  <div data-testid="action-query-cache-gate">{children}</div>
@@ -48,9 +53,34 @@ let originalLocation: Location;
48
53
  let originalParent: Window;
49
54
  let originalFetch: typeof window.fetch;
50
55
  let originalModelContext: PropertyDescriptor | undefined;
56
+ let originalLocalStorage: PropertyDescriptor | undefined;
51
57
  let originalDocumentTitle: string;
52
58
  let replaceMock: ReturnType<typeof vi.fn>;
53
59
 
60
+ function createTestLocalStorage(): Storage {
61
+ const values = new Map<string, string>();
62
+ return {
63
+ get length() {
64
+ return values.size;
65
+ },
66
+ clear() {
67
+ values.clear();
68
+ },
69
+ getItem(key) {
70
+ return values.get(String(key)) ?? null;
71
+ },
72
+ key(index) {
73
+ return [...values.keys()][index] ?? null;
74
+ },
75
+ removeItem(key) {
76
+ values.delete(String(key));
77
+ },
78
+ setItem(key, value) {
79
+ values.set(String(key), String(value));
80
+ },
81
+ };
82
+ }
83
+
54
84
  beforeEach(() => {
55
85
  resetAgentEngineReadinessForTests();
56
86
  container = document.createElement("div");
@@ -64,6 +94,14 @@ beforeEach(() => {
64
94
  document,
65
95
  "modelContext",
66
96
  );
97
+ originalLocalStorage = Object.getOwnPropertyDescriptor(
98
+ window,
99
+ "localStorage",
100
+ );
101
+ Object.defineProperty(window, "localStorage", {
102
+ configurable: true,
103
+ value: createTestLocalStorage(),
104
+ });
67
105
  Object.defineProperty(window, "fetch", {
68
106
  configurable: true,
69
107
  value: vi
@@ -102,6 +140,11 @@ afterEach(() => {
102
140
  configurable: true,
103
141
  value: originalFetch,
104
142
  });
143
+ if (originalLocalStorage) {
144
+ Object.defineProperty(window, "localStorage", originalLocalStorage);
145
+ } else {
146
+ delete (window as Window & { localStorage?: Storage }).localStorage;
147
+ }
105
148
  if (originalModelContext) {
106
149
  Object.defineProperty(document, "modelContext", originalModelContext);
107
150
  } else {
@@ -115,6 +158,7 @@ function renderProviders(props: {
115
158
  isPublicPath?: boolean;
116
159
  sessionBypass?: boolean;
117
160
  skipFirstRunOnboarding?: boolean;
161
+ enableThemeFamily?: boolean;
118
162
  disableWebMcp?: boolean;
119
163
  children?: React.ReactNode;
120
164
  }) {
@@ -183,6 +227,33 @@ const SIGNED_IN_SESSION = {
183
227
  };
184
228
 
185
229
  describe("AppProviders session gate", () => {
230
+ it("mounts theme-family sync by default in an authenticated app shell", async () => {
231
+ useSessionMock.mockReturnValue(SIGNED_IN_SESSION);
232
+
233
+ renderProviders({ skipFirstRunOnboarding: true });
234
+ await act(async () => {
235
+ await import("./ThemeFamilySync.js");
236
+ });
237
+
238
+ expect(useThemeFamilyMock).toHaveBeenCalledOnce();
239
+ });
240
+
241
+ it("allows an authenticated app shell to disable theme-family sync", () => {
242
+ useSessionMock.mockReturnValue(SIGNED_IN_SESSION);
243
+
244
+ renderProviders({ skipFirstRunOnboarding: true, enableThemeFamily: false });
245
+
246
+ expect(useThemeFamilyMock).not.toHaveBeenCalled();
247
+ });
248
+
249
+ it("does not load theme-family settings on public routes", () => {
250
+ useSessionMock.mockReturnValue(SIGNED_OUT_SESSION);
251
+
252
+ renderProviders({ isPublicPath: true });
253
+
254
+ expect(useThemeFamilyMock).not.toHaveBeenCalled();
255
+ });
256
+
186
257
  it("uses Toolkit's theme-aware toaster by default", () => {
187
258
  useSessionMock.mockReturnValue(SIGNED_OUT_SESSION);
188
259
 
@@ -95,6 +95,8 @@ export interface AppProvidersProps {
95
95
  */
96
96
  ownsDocument?: boolean;
97
97
 
98
+ enableThemeFamily?: boolean;
99
+
98
100
  documentTitleFallback?: string;
99
101
 
100
102
  children: React.ReactNode;
@@ -397,6 +399,8 @@ function AgentEngineReadinessBootstrap() {
397
399
  return null;
398
400
  }
399
401
 
402
+ const ThemeFamilySync = React.lazy(() => import("./ThemeFamilySync.js"));
403
+
400
404
  function ProvidersInner({
401
405
  queryClient,
402
406
  defaultTheme = "system",
@@ -507,6 +511,7 @@ export function AppProviders({
507
511
  i18n,
508
512
  documentTitleFallback,
509
513
  ownsDocument = true,
514
+ enableThemeFamily = true,
510
515
  children,
511
516
  }: AppProvidersProps) {
512
517
  const fallback = clientOnlyFallback ?? (
@@ -543,6 +548,11 @@ export function AppProviders({
543
548
  children
544
549
  ) : (
545
550
  <>
551
+ {ownsDocument && enableThemeFamily ? (
552
+ <React.Suspense fallback={null}>
553
+ <ThemeFamilySync />
554
+ </React.Suspense>
555
+ ) : null}
546
556
  <AgentEngineReadinessBootstrap />
547
557
  <FirstRunOnboardingStartupGate
548
558
  suppressSurface={skipFirstRunOnboarding}
@@ -0,0 +1,6 @@
1
+ import { useThemeFamily } from "@agent-native/core/client/ui";
2
+
3
+ export default function ThemeFamilySync() {
4
+ useThemeFamily();
5
+ return null;
6
+ }
@@ -25,6 +25,9 @@ vi.mock("../VoiceTranscriptionSection.js", () => ({
25
25
  <div data-testid="voice" data-compact={String(!!compact)} />
26
26
  ),
27
27
  }));
28
+ vi.mock("./ThemeFamilySettings.js", () => ({
29
+ ThemeFamilySettings: () => <div data-testid="theme-family-settings" />,
30
+ }));
28
31
 
29
32
  import { AgentNativeI18nProvider } from "@agent-native/core/client/i18n";
30
33
 
@@ -70,12 +73,14 @@ describe("PreferencesSettings", () => {
70
73
  const groups = [...container.querySelectorAll("section")];
71
74
  expect(groups.map((group) => group.id)).toEqual([
72
75
  "language-region",
76
+ "appearance",
73
77
  "voice-input",
74
78
  ]);
75
79
  expect(groups[0]!.querySelector("h2")?.textContent).toBe(
76
80
  "Language and region",
77
81
  );
78
- expect(groups[1]!.querySelector("h2")?.textContent).toBe("Voice input");
82
+ expect(groups[1]!.querySelector("h2")?.textContent).toBe("Appearance");
83
+ expect(groups[2]!.querySelector("h2")?.textContent).toBe("Voice input");
79
84
 
80
85
  const language = container.querySelector("#interface-language");
81
86
  expect(language?.textContent).toContain("Interface language");
@@ -90,8 +95,14 @@ describe("PreferencesSettings", () => {
90
95
  "Used for timestamps and scheduled automations.",
91
96
  );
92
97
 
98
+ const themeFamily = container.querySelector("#theme-family");
99
+ expect(themeFamily?.textContent).toContain("Theme family");
100
+ expect(
101
+ themeFamily?.querySelector('[data-testid="theme-family-settings"]'),
102
+ ).not.toBeNull();
103
+
93
104
  expect(
94
- groups[1]!
105
+ groups[2]!
95
106
  .querySelector('[data-testid="voice"]')
96
107
  ?.getAttribute("data-compact"),
97
108
  ).toBe("true");
@@ -4,6 +4,7 @@ import { LanguagePicker } from "../../shared/index.js";
4
4
  import { SchedulingTimezoneField } from "../SchedulingTimezoneField.js";
5
5
  import { SettingsGroup, SettingsRow } from "../SettingsRow.js";
6
6
  import { VoiceTranscriptionSection } from "../VoiceTranscriptionSection.js";
7
+ import { ThemeFamilySettings } from "./ThemeFamilySettings.js";
7
8
 
8
9
  const key = (name: string) => `agentChat.settingsShell.account.${name}`;
9
10
 
@@ -37,6 +38,13 @@ export function PreferencesSettings() {
37
38
  control={<SchedulingTimezoneField compact />}
38
39
  />
39
40
  </SettingsGroup>
41
+ <SettingsGroup id="appearance" title={t(key("appearance"))}>
42
+ <SettingsRow
43
+ id="theme-family"
44
+ label={t(key("themeFamily"))}
45
+ control={<ThemeFamilySettings />}
46
+ />
47
+ </SettingsGroup>
40
48
  <SettingsGroup id="voice-input" title={t(key("voiceInput"))}>
41
49
  <VoiceTranscriptionSection compact />
42
50
  </SettingsGroup>
@@ -0,0 +1,61 @@
1
+ import { useT } from "@agent-native/core/client/i18n";
2
+ import { useThemeFamily, type ThemeFamily } from "@agent-native/core/client/ui";
3
+ import {
4
+ Select,
5
+ SelectContent,
6
+ SelectItem,
7
+ SelectTrigger,
8
+ SelectValue,
9
+ } from "@agent-native/toolkit/ui/select";
10
+ import { useState } from "react";
11
+
12
+ const key = (name: string) => `agentChat.settingsShell.account.${name}`;
13
+
14
+ export function ThemeFamilySettings() {
15
+ const t = useT();
16
+ const { family, status, setFamily } = useThemeFamily();
17
+ const [saving, setSaving] = useState(false);
18
+ const [saveFailed, setSaveFailed] = useState(false);
19
+
20
+ async function changeFamily(value: string) {
21
+ if (value !== "agent-native" && value !== "original") return;
22
+ if (value === family) return;
23
+
24
+ setSaving(true);
25
+ setSaveFailed(false);
26
+ try {
27
+ await setFamily(value as ThemeFamily);
28
+ } catch {
29
+ setSaveFailed(true);
30
+ } finally {
31
+ setSaving(false);
32
+ }
33
+ }
34
+
35
+ return (
36
+ <div className="w-full sm:w-56">
37
+ <Select
38
+ value={family}
39
+ onValueChange={(value) => void changeFamily(value)}
40
+ disabled={saving || status === "loading"}
41
+ >
42
+ <SelectTrigger aria-label={t(key("themeFamily"))}>
43
+ <SelectValue />
44
+ </SelectTrigger>
45
+ <SelectContent>
46
+ <SelectItem value="agent-native">
47
+ {t(key("themeFamilyAgentNative"))}
48
+ </SelectItem>
49
+ <SelectItem value="original">
50
+ {t(key("themeFamilyOriginal"))}
51
+ </SelectItem>
52
+ </SelectContent>
53
+ </Select>
54
+ {saveFailed || status === "error" ? (
55
+ <p className="mt-2 text-xs text-destructive" role="alert">
56
+ {t(key("themeFamilySaveError"))}
57
+ </p>
58
+ ) : null}
59
+ </div>
60
+ );
61
+ }
@@ -33,6 +33,12 @@ export const PREFERENCES_SEARCH_ENTRIES: readonly SettingsPageSearchEntry[] = [
33
33
  keywords: "language locale translation",
34
34
  anchor: "interface-language",
35
35
  },
36
+ {
37
+ id: "theme-family",
38
+ labelKey: key("themeFamily"),
39
+ keywords: "theme appearance style colors",
40
+ anchor: "theme-family",
41
+ },
36
42
  {
37
43
  id: "timezone",
38
44
  labelKey: key("timezone"),
@@ -0,0 +1,14 @@
1
+ import { renderToStaticMarkup } from "react-dom/server";
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ import { DefaultSpinner } from "./DefaultSpinner.js";
5
+
6
+ describe("DefaultSpinner theme styles", () => {
7
+ it("uses the selected dark theme instead of the operating system preference", () => {
8
+ const html = renderToStaticMarkup(<DefaultSpinner />);
9
+
10
+ expect(html).toContain("html.dark");
11
+ expect(html).toContain('html[data-theme="dark"]');
12
+ expect(html).not.toContain("prefers-color-scheme");
13
+ });
14
+ });
@@ -117,11 +117,10 @@ export function DefaultSpinner({
117
117
  background: hsl(var(--background, 0 0% 100%));
118
118
  color: hsl(var(--foreground, 240 10% 3.9%));
119
119
  }
120
- @media (prefers-color-scheme: dark) {
121
- html {
122
- background: hsl(var(--background, 240 10% 3.9%));
123
- color: hsl(var(--foreground, 0 0% 98%));
124
- }
120
+ html.dark,
121
+ html[data-theme="dark"]:not(.light) {
122
+ background: hsl(var(--background, 240 10% 3.9%));
123
+ color: hsl(var(--foreground, 0 0% 98%));
125
124
  }
126
125
  `}</style>
127
126
  </div>
@@ -1,6 +1,18 @@
1
- import { describe, expect, it } from "vitest";
1
+ import { describe, expect, it, vi } from "vitest";
2
2
 
3
- import { isExpectedRouteNotFound } from "./ErrorBoundary.js";
3
+ import {
4
+ isExpectedRouteNotFound,
5
+ resolveErrorBoundaryThemeClass,
6
+ } from "./ErrorBoundary.js";
7
+
8
+ function themeRoot(className: string, dataTheme: string | null) {
9
+ return {
10
+ classList: {
11
+ contains: (name: string) => className.split(" ").includes(name),
12
+ },
13
+ getAttribute: () => dataTheme,
14
+ } as unknown as Pick<HTMLElement, "classList" | "getAttribute">;
15
+ }
4
16
 
5
17
  describe("isExpectedRouteNotFound", () => {
6
18
  it("recognizes React Router 404 responses", () => {
@@ -26,3 +38,34 @@ describe("isExpectedRouteNotFound", () => {
26
38
  ).toBe(false);
27
39
  });
28
40
  });
41
+
42
+ describe("resolveErrorBoundaryThemeClass", () => {
43
+ it("honors an explicit data theme before storage or the system preference", () => {
44
+ const readStoredTheme = vi.fn(() => "dark");
45
+ const readSystemTheme = vi.fn(() => true);
46
+
47
+ expect(
48
+ resolveErrorBoundaryThemeClass(
49
+ themeRoot("", "light"),
50
+ readStoredTheme,
51
+ readSystemTheme,
52
+ ),
53
+ ).toBe("light");
54
+ expect(readStoredTheme).not.toHaveBeenCalled();
55
+ expect(readSystemTheme).not.toHaveBeenCalled();
56
+ });
57
+
58
+ it("uses the system theme only when no explicit theme is selected", () => {
59
+ const readStoredTheme = vi.fn(() => null);
60
+ const readSystemTheme = vi.fn(() => true);
61
+
62
+ expect(
63
+ resolveErrorBoundaryThemeClass(
64
+ themeRoot("", null),
65
+ readStoredTheme,
66
+ readSystemTheme,
67
+ ),
68
+ ).toBe("dark");
69
+ expect(readSystemTheme).toHaveBeenCalledOnce();
70
+ });
71
+ });
@@ -196,21 +196,46 @@ function useErrorCopy() {
196
196
  function useApplyThemeClass() {
197
197
  useEffect(() => {
198
198
  const root = document.documentElement;
199
- if (root.classList.contains("dark") || root.classList.contains("light"))
200
- return;
201
- try {
202
- const stored = localStorage.getItem("theme");
203
- if (stored === "dark") {
204
- root.classList.add("dark");
205
- } else if (stored === "light") {
206
- root.classList.add("light");
207
- } else if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
208
- root.classList.add("dark");
209
- }
210
- } catch {}
199
+ let storageUnreadable = false;
200
+ const theme = resolveErrorBoundaryThemeClass(
201
+ root,
202
+ () => {
203
+ try {
204
+ return localStorage.getItem("theme");
205
+ } catch {
206
+ storageUnreadable = true;
207
+ return null;
208
+ }
209
+ },
210
+ () =>
211
+ window.matchMedia?.("(prefers-color-scheme: dark)").matches ?? false,
212
+ );
213
+ if (storageUnreadable) {
214
+ root.setAttribute("data-theme-status", "unreadable");
215
+ } else {
216
+ root.removeAttribute("data-theme-status");
217
+ }
218
+ if (theme) root.classList.add(theme);
211
219
  }, []);
212
220
  }
213
221
 
222
+ export function resolveErrorBoundaryThemeClass(
223
+ root: Pick<HTMLElement, "classList" | "getAttribute">,
224
+ readStoredTheme: () => string | null,
225
+ readSystemTheme: () => boolean,
226
+ ): "dark" | "light" | undefined {
227
+ if (root.classList.contains("dark") || root.classList.contains("light")) {
228
+ return undefined;
229
+ }
230
+
231
+ const dataTheme = root.getAttribute("data-theme");
232
+ if (dataTheme === "dark" || dataTheme === "light") return dataTheme;
233
+
234
+ const storedTheme = readStoredTheme();
235
+ if (storedTheme === "dark" || storedTheme === "light") return storedTheme;
236
+ return readSystemTheme() ? "dark" : undefined;
237
+ }
238
+
214
239
  function errorMessageOf(error: unknown): string {
215
240
  if (error instanceof Error) return error.message;
216
241
  return typeof error === "string" ? error : "";
@@ -0,0 +1,16 @@
1
+ import { renderToStaticMarkup } from "react-dom/server";
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ import { PoweredByBadge } from "./PoweredByBadge.js";
5
+
6
+ describe("PoweredByBadge theme styles", () => {
7
+ it("follows the selected theme classes and data attribute", () => {
8
+ const html = renderToStaticMarkup(<PoweredByBadge />);
9
+
10
+ expect(html).toContain("html.dark");
11
+ expect(html).toContain('html[data-theme="dark"]');
12
+ expect(html).toContain("html.light");
13
+ expect(html).toContain('html[data-theme="light"]');
14
+ expect(html).not.toContain("prefers-color-scheme");
15
+ });
16
+ });