@agent-native/core 0.7.82 → 0.8.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 (265) hide show
  1. package/dist/action.js +1 -1
  2. package/dist/action.js.map +1 -1
  3. package/dist/agent/production-agent.d.ts.map +1 -1
  4. package/dist/agent/production-agent.js +8 -8
  5. package/dist/agent/production-agent.js.map +1 -1
  6. package/dist/agent/run-manager.d.ts +2 -0
  7. package/dist/agent/run-manager.d.ts.map +1 -1
  8. package/dist/agent/run-manager.js +44 -18
  9. package/dist/agent/run-manager.js.map +1 -1
  10. package/dist/agent/types.d.ts +1 -1
  11. package/dist/agent/types.d.ts.map +1 -1
  12. package/dist/agent/types.js.map +1 -1
  13. package/dist/cli/create.d.ts +1 -1
  14. package/dist/cli/create.d.ts.map +1 -1
  15. package/dist/cli/create.js +87 -19
  16. package/dist/cli/create.js.map +1 -1
  17. package/dist/cli/workspacify.d.ts.map +1 -1
  18. package/dist/cli/workspacify.js +12 -9
  19. package/dist/cli/workspacify.js.map +1 -1
  20. package/dist/client/AgentPanel.d.ts +1 -1
  21. package/dist/client/AgentPanel.d.ts.map +1 -1
  22. package/dist/client/AgentPanel.js +22 -1
  23. package/dist/client/AgentPanel.js.map +1 -1
  24. package/dist/client/FeedbackButton.d.ts +3 -2
  25. package/dist/client/FeedbackButton.d.ts.map +1 -1
  26. package/dist/client/FeedbackButton.js +18 -14
  27. package/dist/client/FeedbackButton.js.map +1 -1
  28. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  29. package/dist/client/agent-chat-adapter.js +254 -29
  30. package/dist/client/agent-chat-adapter.js.map +1 -1
  31. package/dist/client/agent-chat.d.ts +2 -0
  32. package/dist/client/agent-chat.d.ts.map +1 -1
  33. package/dist/client/agent-chat.js +11 -2
  34. package/dist/client/agent-chat.js.map +1 -1
  35. package/dist/client/builder-frame.d.ts +11 -0
  36. package/dist/client/builder-frame.d.ts.map +1 -1
  37. package/dist/client/builder-frame.js +40 -9
  38. package/dist/client/builder-frame.js.map +1 -1
  39. package/dist/client/composer/ComposerPlusMenu.js +1 -1
  40. package/dist/client/composer/ComposerPlusMenu.js.map +1 -1
  41. package/dist/client/composer/PromptComposer.d.ts +2 -0
  42. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  43. package/dist/client/composer/PromptComposer.js +3 -3
  44. package/dist/client/composer/PromptComposer.js.map +1 -1
  45. package/dist/client/composer/TiptapComposer.d.ts +3 -1
  46. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  47. package/dist/client/composer/TiptapComposer.js +25 -13
  48. package/dist/client/composer/TiptapComposer.js.map +1 -1
  49. package/dist/client/composer/types.d.ts +1 -1
  50. package/dist/client/composer/types.d.ts.map +1 -1
  51. package/dist/client/composer/types.js.map +1 -1
  52. package/dist/client/extensions/EmbeddedExtension.d.ts +20 -0
  53. package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -0
  54. package/dist/client/{tools/EmbeddedTool.js → extensions/EmbeddedExtension.js} +41 -41
  55. package/dist/client/extensions/EmbeddedExtension.js.map +1 -0
  56. package/dist/client/extensions/ExtensionEditor.d.ts +5 -0
  57. package/dist/client/extensions/ExtensionEditor.d.ts.map +1 -0
  58. package/dist/client/extensions/ExtensionEditor.js +129 -0
  59. package/dist/client/extensions/ExtensionEditor.js.map +1 -0
  60. package/dist/client/{tools → extensions}/ExtensionSlot.d.ts +3 -3
  61. package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -0
  62. package/dist/client/{tools → extensions}/ExtensionSlot.js +14 -14
  63. package/dist/client/extensions/ExtensionSlot.js.map +1 -0
  64. package/dist/client/extensions/ExtensionViewer.d.ts +5 -0
  65. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -0
  66. package/dist/client/{tools/ToolViewer.js → extensions/ExtensionViewer.js} +67 -65
  67. package/dist/client/extensions/ExtensionViewer.js.map +1 -0
  68. package/dist/client/extensions/ExtensionViewerPage.d.ts +2 -0
  69. package/dist/client/extensions/ExtensionViewerPage.d.ts.map +1 -0
  70. package/dist/client/{tools/ToolViewerPage.js → extensions/ExtensionViewerPage.js} +8 -8
  71. package/dist/client/extensions/ExtensionViewerPage.js.map +1 -0
  72. package/dist/client/extensions/ExtensionsListPage.d.ts +2 -0
  73. package/dist/client/extensions/ExtensionsListPage.d.ts.map +1 -0
  74. package/dist/client/extensions/ExtensionsListPage.js +67 -0
  75. package/dist/client/extensions/ExtensionsListPage.js.map +1 -0
  76. package/dist/client/extensions/ExtensionsSidebarSection.d.ts +2 -0
  77. package/dist/client/extensions/ExtensionsSidebarSection.d.ts.map +1 -0
  78. package/dist/client/{tools/ToolsSidebarSection.js → extensions/ExtensionsSidebarSection.js} +58 -58
  79. package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -0
  80. package/dist/client/{tools/tool-order.d.ts → extensions/extension-order.d.ts} +2 -2
  81. package/dist/client/extensions/extension-order.d.ts.map +1 -0
  82. package/dist/client/{tools/tool-order.js → extensions/extension-order.js} +3 -3
  83. package/dist/client/extensions/extension-order.js.map +1 -0
  84. package/dist/client/{tools → extensions}/iframe-bridge.d.ts +11 -11
  85. package/dist/client/extensions/iframe-bridge.d.ts.map +1 -0
  86. package/dist/client/{tools → extensions}/iframe-bridge.js +24 -24
  87. package/dist/client/extensions/iframe-bridge.js.map +1 -0
  88. package/dist/client/extensions/index.d.ts +14 -0
  89. package/dist/client/extensions/index.d.ts.map +1 -0
  90. package/dist/client/extensions/index.js +19 -0
  91. package/dist/client/extensions/index.js.map +1 -0
  92. package/dist/client/integrations/IntegrationsPanel.d.ts.map +1 -1
  93. package/dist/client/integrations/IntegrationsPanel.js +4 -1
  94. package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
  95. package/dist/client/sse-event-processor.d.ts +2 -1
  96. package/dist/client/sse-event-processor.d.ts.map +1 -1
  97. package/dist/client/sse-event-processor.js +87 -6
  98. package/dist/client/sse-event-processor.js.map +1 -1
  99. package/dist/extensions/actions.d.ts +3 -0
  100. package/dist/extensions/actions.d.ts.map +1 -0
  101. package/dist/{tools → extensions}/actions.js +54 -51
  102. package/dist/extensions/actions.js.map +1 -0
  103. package/dist/{tools → extensions}/fetch-tool.d.ts +4 -0
  104. package/dist/extensions/fetch-tool.d.ts.map +1 -0
  105. package/dist/{tools → extensions}/fetch-tool.js +12 -7
  106. package/dist/extensions/fetch-tool.js.map +1 -0
  107. package/dist/extensions/html-shell.d.ts +56 -0
  108. package/dist/extensions/html-shell.d.ts.map +1 -0
  109. package/dist/{tools → extensions}/html-shell.js +101 -83
  110. package/dist/extensions/html-shell.js.map +1 -0
  111. package/dist/{tools → extensions}/proxy-security.d.ts +2 -2
  112. package/dist/extensions/proxy-security.d.ts.map +1 -0
  113. package/dist/{tools → extensions}/proxy-security.js +3 -3
  114. package/dist/extensions/proxy-security.js.map +1 -0
  115. package/dist/extensions/routes.d.ts +2 -0
  116. package/dist/extensions/routes.d.ts.map +1 -0
  117. package/dist/{tools → extensions}/routes.js +73 -69
  118. package/dist/extensions/routes.js.map +1 -0
  119. package/dist/{tools → extensions}/schema.d.ts +44 -38
  120. package/dist/extensions/schema.d.ts.map +1 -0
  121. package/dist/{tools → extensions}/schema.js +41 -34
  122. package/dist/extensions/schema.js.map +1 -0
  123. package/dist/extensions/slots/routes.d.ts +15 -0
  124. package/dist/extensions/slots/routes.d.ts.map +1 -0
  125. package/dist/{tools → extensions}/slots/routes.js +26 -26
  126. package/dist/extensions/slots/routes.js.map +1 -0
  127. package/dist/{tools → extensions}/slots/schema.d.ts +24 -21
  128. package/dist/extensions/slots/schema.d.ts.map +1 -0
  129. package/dist/extensions/slots/schema.js +79 -0
  130. package/dist/extensions/slots/schema.js.map +1 -0
  131. package/dist/extensions/slots/store.d.ts +66 -0
  132. package/dist/extensions/slots/store.d.ts.map +1 -0
  133. package/dist/extensions/slots/store.js +238 -0
  134. package/dist/extensions/slots/store.js.map +1 -0
  135. package/dist/extensions/store.d.ts +40 -0
  136. package/dist/extensions/store.d.ts.map +1 -0
  137. package/dist/{tools → extensions}/store.js +59 -54
  138. package/dist/extensions/store.js.map +1 -0
  139. package/dist/extensions/theme.d.ts.map +1 -0
  140. package/dist/extensions/theme.js.map +1 -0
  141. package/dist/{tools → extensions}/url-safety.d.ts +5 -3
  142. package/dist/extensions/url-safety.d.ts.map +1 -0
  143. package/dist/{tools → extensions}/url-safety.js +11 -4
  144. package/dist/extensions/url-safety.js.map +1 -0
  145. package/dist/server/action-discovery.d.ts +15 -0
  146. package/dist/server/action-discovery.d.ts.map +1 -1
  147. package/dist/server/action-discovery.js +45 -0
  148. package/dist/server/action-discovery.js.map +1 -1
  149. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  150. package/dist/server/agent-chat-plugin.js +12 -10
  151. package/dist/server/agent-chat-plugin.js.map +1 -1
  152. package/dist/server/auth.d.ts +5 -4
  153. package/dist/server/auth.d.ts.map +1 -1
  154. package/dist/server/auth.js +80 -28
  155. package/dist/server/auth.js.map +1 -1
  156. package/dist/server/core-routes-plugin.d.ts +15 -0
  157. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  158. package/dist/server/core-routes-plugin.js +65 -13
  159. package/dist/server/core-routes-plugin.js.map +1 -1
  160. package/dist/server/csrf.d.ts +3 -2
  161. package/dist/server/csrf.d.ts.map +1 -1
  162. package/dist/server/csrf.js +3 -2
  163. package/dist/server/csrf.js.map +1 -1
  164. package/dist/server/google-oauth.d.ts.map +1 -1
  165. package/dist/server/google-oauth.js +15 -3
  166. package/dist/server/google-oauth.js.map +1 -1
  167. package/dist/server/index.d.ts +2 -2
  168. package/dist/server/index.d.ts.map +1 -1
  169. package/dist/server/index.js +1 -1
  170. package/dist/server/index.js.map +1 -1
  171. package/dist/shared/workspace-app-id.d.ts +1 -1
  172. package/dist/shared/workspace-app-id.d.ts.map +1 -1
  173. package/dist/shared/workspace-app-id.js +5 -1
  174. package/dist/shared/workspace-app-id.js.map +1 -1
  175. package/dist/templates/workspace-root/README.md +5 -4
  176. package/dist/usage/store.d.ts +1 -1
  177. package/dist/usage/store.d.ts.map +1 -1
  178. package/dist/usage/store.js +1 -1
  179. package/dist/usage/store.js.map +1 -1
  180. package/dist/vite/client.d.ts.map +1 -1
  181. package/dist/vite/client.js +17 -1
  182. package/dist/vite/client.js.map +1 -1
  183. package/docs/content/actions.md +10 -10
  184. package/docs/content/extensions.md +230 -0
  185. package/docs/content/key-concepts.md +2 -2
  186. package/docs/content/server.md +13 -13
  187. package/docs/content/sharing.md +2 -2
  188. package/docs/content/template-analytics.md +10 -0
  189. package/docs/content/template-calendar.md +10 -0
  190. package/docs/content/template-clips.md +10 -0
  191. package/docs/content/template-content.md +10 -0
  192. package/docs/content/template-dispatch.md +15 -0
  193. package/docs/content/template-forms.md +10 -0
  194. package/docs/content/template-mail.md +10 -0
  195. package/docs/content/template-slides.md +11 -1
  196. package/docs/content/template-starter.md +10 -0
  197. package/docs/content/template-video.md +10 -0
  198. package/docs/content/what-is-agent-native.md +1 -1
  199. package/package.json +22 -17
  200. package/src/templates/workspace-root/README.md +5 -4
  201. package/dist/client/tools/EmbeddedTool.d.ts +0 -20
  202. package/dist/client/tools/EmbeddedTool.d.ts.map +0 -1
  203. package/dist/client/tools/EmbeddedTool.js.map +0 -1
  204. package/dist/client/tools/ExtensionSlot.d.ts.map +0 -1
  205. package/dist/client/tools/ExtensionSlot.js.map +0 -1
  206. package/dist/client/tools/ToolEditor.d.ts +0 -5
  207. package/dist/client/tools/ToolEditor.d.ts.map +0 -1
  208. package/dist/client/tools/ToolEditor.js +0 -129
  209. package/dist/client/tools/ToolEditor.js.map +0 -1
  210. package/dist/client/tools/ToolViewer.d.ts +0 -5
  211. package/dist/client/tools/ToolViewer.d.ts.map +0 -1
  212. package/dist/client/tools/ToolViewer.js.map +0 -1
  213. package/dist/client/tools/ToolViewerPage.d.ts +0 -2
  214. package/dist/client/tools/ToolViewerPage.d.ts.map +0 -1
  215. package/dist/client/tools/ToolViewerPage.js.map +0 -1
  216. package/dist/client/tools/ToolsListPage.d.ts +0 -2
  217. package/dist/client/tools/ToolsListPage.d.ts.map +0 -1
  218. package/dist/client/tools/ToolsListPage.js +0 -67
  219. package/dist/client/tools/ToolsListPage.js.map +0 -1
  220. package/dist/client/tools/ToolsSidebarSection.d.ts +0 -2
  221. package/dist/client/tools/ToolsSidebarSection.d.ts.map +0 -1
  222. package/dist/client/tools/ToolsSidebarSection.js.map +0 -1
  223. package/dist/client/tools/iframe-bridge.d.ts.map +0 -1
  224. package/dist/client/tools/iframe-bridge.js.map +0 -1
  225. package/dist/client/tools/index.d.ts +0 -8
  226. package/dist/client/tools/index.d.ts.map +0 -1
  227. package/dist/client/tools/index.js +0 -8
  228. package/dist/client/tools/index.js.map +0 -1
  229. package/dist/client/tools/tool-order.d.ts.map +0 -1
  230. package/dist/client/tools/tool-order.js.map +0 -1
  231. package/dist/tools/actions.d.ts +0 -3
  232. package/dist/tools/actions.d.ts.map +0 -1
  233. package/dist/tools/actions.js.map +0 -1
  234. package/dist/tools/fetch-tool.d.ts.map +0 -1
  235. package/dist/tools/fetch-tool.js.map +0 -1
  236. package/dist/tools/html-shell.d.ts +0 -45
  237. package/dist/tools/html-shell.d.ts.map +0 -1
  238. package/dist/tools/html-shell.js.map +0 -1
  239. package/dist/tools/proxy-security.d.ts.map +0 -1
  240. package/dist/tools/proxy-security.js.map +0 -1
  241. package/dist/tools/routes.d.ts +0 -2
  242. package/dist/tools/routes.d.ts.map +0 -1
  243. package/dist/tools/routes.js.map +0 -1
  244. package/dist/tools/schema.d.ts.map +0 -1
  245. package/dist/tools/schema.js.map +0 -1
  246. package/dist/tools/slots/routes.d.ts +0 -15
  247. package/dist/tools/slots/routes.d.ts.map +0 -1
  248. package/dist/tools/slots/routes.js.map +0 -1
  249. package/dist/tools/slots/schema.d.ts.map +0 -1
  250. package/dist/tools/slots/schema.js +0 -76
  251. package/dist/tools/slots/schema.js.map +0 -1
  252. package/dist/tools/slots/store.d.ts +0 -66
  253. package/dist/tools/slots/store.d.ts.map +0 -1
  254. package/dist/tools/slots/store.js +0 -227
  255. package/dist/tools/slots/store.js.map +0 -1
  256. package/dist/tools/store.d.ts +0 -40
  257. package/dist/tools/store.d.ts.map +0 -1
  258. package/dist/tools/store.js.map +0 -1
  259. package/dist/tools/theme.d.ts.map +0 -1
  260. package/dist/tools/theme.js.map +0 -1
  261. package/dist/tools/url-safety.d.ts.map +0 -1
  262. package/dist/tools/url-safety.js.map +0 -1
  263. package/docs/content/tools.md +0 -205
  264. /package/dist/{tools → extensions}/theme.d.ts +0 -0
  265. /package/dist/{tools → extensions}/theme.js +0 -0
@@ -2,15 +2,16 @@ export interface FeedbackButtonProps {
2
2
  /**
3
3
  * "sidebar" renders a full-width row with icon + label (for app left sidebars).
4
4
  * "icon" renders a small icon-only button (for dense toolbars, e.g. the agent panel header).
5
+ * "outlined" renders an outlined pill button with icon + label (for top-nav bars, e.g. docs).
5
6
  */
6
- variant?: "sidebar" | "icon";
7
+ variant?: "sidebar" | "icon" | "outlined";
7
8
  label?: string;
8
9
  url?: string;
9
10
  className?: string;
10
11
  /** Which side the popover opens on. Defaults match the variant. */
11
12
  side?: "top" | "bottom" | "left" | "right";
12
13
  align?: "start" | "center" | "end";
13
- /** Placeholder text for the textarea. Falls back to the form's placeholder. */
14
+ /** Placeholder text for the textarea. */
14
15
  placeholder?: string;
15
16
  }
16
17
  export declare function FeedbackButton({ variant, label, url, className, side, align, placeholder, }: FeedbackButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"FeedbackButton.d.ts","sourceRoot":"","sources":["../../src/client/FeedbackButton.tsx"],"names":[],"mappings":"AA+EA,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,IAAI,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;IAC3C,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAeD,wBAAgB,cAAc,CAAC,EAC7B,OAAmB,EACnB,KAAkB,EAClB,GAA0B,EAC1B,SAAS,EACT,IAAI,EACJ,KAAa,EACb,WAAW,GACZ,EAAE,mBAAmB,2CA2MrB"}
1
+ {"version":3,"file":"FeedbackButton.d.ts","sourceRoot":"","sources":["../../src/client/FeedbackButton.tsx"],"names":[],"mappings":"AAwEA,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,IAAI,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;IAC3C,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAeD,wBAAgB,cAAc,CAAC,EAC7B,OAAmB,EACnB,KAAkB,EAClB,GAA0B,EAC1B,SAAS,EACT,IAAI,EACJ,KAAa,EACb,WAAW,GACZ,EAAE,mBAAmB,2CA4NrB"}
@@ -6,6 +6,9 @@ import { IconMessage2, IconCheck } from "@tabler/icons-react";
6
6
  import { cn } from "./utils.js";
7
7
  import { useSession } from "./use-session.js";
8
8
  const DEFAULT_FEEDBACK_URL = "https://forms.agent-native.com/f/agent-native-feedback/_16ewV";
9
+ const DEFAULT_PLACEHOLDER = "Tell us what's on your mind…";
10
+ const DEFAULT_SUBMIT_TEXT = "Send feedback";
11
+ const DEFAULT_SUCCESS_MESSAGE = "Thanks for the feedback!";
9
12
  function parseTarget(url) {
10
13
  try {
11
14
  const u = new URL(url);
@@ -37,13 +40,7 @@ async function loadSchema(target) {
37
40
  body.fields[0];
38
41
  if (!field)
39
42
  throw new Error("form has no fields");
40
- return {
41
- formId: body.id,
42
- fieldId: field.id,
43
- placeholder: field.placeholder,
44
- submitText: body.settings?.submitText ?? "Send feedback",
45
- successMessage: body.settings?.successMessage ?? "Thanks for the feedback!",
46
- };
43
+ return { formId: body.id, fieldId: field.id };
47
44
  })();
48
45
  pending.catch(() => schemaCache.delete(key));
49
46
  schemaCache.set(key, pending);
@@ -138,15 +135,22 @@ export function FeedbackButton({ variant = "sidebar", label = "Feedback", url =
138
135
  setError(err instanceof Error ? err.message : "Couldn't send feedback");
139
136
  }
140
137
  }, [target, schema, value, honeypot, submitting, session?.email]);
141
- const trigger = variant === "icon" ? (_jsx(TooltipPrimitive.Provider, { delayDuration: 200, children: _jsxs(TooltipPrimitive.Root, { children: [_jsx(TooltipPrimitive.Trigger, { asChild: true, children: _jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": label, className: cn("flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", className), children: _jsx(IconMessage2, { size: 14 }) }) }) }), _jsx(TooltipPrimitive.Portal, { children: _jsx(TooltipPrimitive.Content, { sideOffset: 6, className: "z-[230] overflow-hidden rounded-md border border-border bg-popover px-2 py-1 text-[11px] text-foreground shadow-md animate-in fade-in-0 zoom-in-95", children: label }) })] }) })) : (_jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsxs("button", { type: "button", className: cn("flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground", className), children: [_jsx(IconMessage2, { className: "h-4 w-4" }), _jsx("span", { children: label })] }) }));
142
- const resolvedSide = side ?? (variant === "icon" ? "bottom" : "top");
143
- const resolvedPlaceholder = placeholder ?? schema?.placeholder ?? "Tell us what's on your mind…";
144
- return (_jsxs(PopoverPrimitive.Root, { open: open, onOpenChange: setOpen, children: [trigger, _jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { side: resolvedSide, align: align, sideOffset: 8, collisionPadding: 16, className: "z-[300] overflow-hidden rounded-lg border border-border bg-popover shadow-xl outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", style: surfaceStyle, children: submitted ? (_jsxs("div", { className: "flex flex-col items-center justify-center gap-3 px-6 py-10 text-center", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-emerald-500/10 text-emerald-500", children: _jsx(IconCheck, { size: 20, stroke: 2.5 }) }), _jsx("div", { className: "text-sm font-medium text-foreground", children: schema?.successMessage ?? "Thanks for the feedback!" })] })) : (_jsxs("form", { onSubmit: submit, className: "flex flex-col gap-3 p-3", children: [_jsx("textarea", { ref: textareaRef, value: value, onChange: (e) => setValue(e.target.value), onKeyDown: (e) => {
138
+ let trigger;
139
+ if (variant === "icon") {
140
+ trigger = (_jsx(TooltipPrimitive.Provider, { delayDuration: 200, children: _jsxs(TooltipPrimitive.Root, { children: [_jsx(TooltipPrimitive.Trigger, { asChild: true, children: _jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": label, className: cn("flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", className), children: _jsx(IconMessage2, { size: 14 }) }) }) }), _jsx(TooltipPrimitive.Portal, { children: _jsx(TooltipPrimitive.Content, { sideOffset: 6, className: "z-[230] overflow-hidden rounded-md border border-border bg-popover px-2 py-1 text-[11px] text-foreground shadow-md animate-in fade-in-0 zoom-in-95", children: label }) })] }) }));
141
+ }
142
+ else if (variant === "outlined") {
143
+ trigger = (_jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsxs("button", { type: "button", "aria-label": label, className: cn("flex h-8 items-center gap-2 rounded-md border border-border bg-transparent px-3 text-sm text-muted-foreground transition hover:border-foreground/40 hover:text-foreground", className), children: [_jsx(IconMessage2, { size: 14, stroke: 1.5 }), _jsx("span", { children: label })] }) }));
144
+ }
145
+ else {
146
+ trigger = (_jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsxs("button", { type: "button", className: cn("flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground", className), children: [_jsx(IconMessage2, { className: "h-4 w-4" }), _jsx("span", { children: label })] }) }));
147
+ }
148
+ const resolvedSide = side ?? (variant === "sidebar" ? "top" : "bottom");
149
+ const resolvedPlaceholder = placeholder ?? DEFAULT_PLACEHOLDER;
150
+ return (_jsxs(PopoverPrimitive.Root, { open: open, onOpenChange: setOpen, children: [trigger, _jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { side: resolvedSide, align: align, sideOffset: 8, collisionPadding: 16, className: "z-[300] overflow-hidden rounded-lg border border-border bg-popover shadow-xl outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", style: surfaceStyle, children: submitted ? (_jsxs("div", { className: "flex flex-col items-center justify-center gap-3 px-6 py-10 text-center", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-emerald-500/10 text-emerald-500", children: _jsx(IconCheck, { size: 20, stroke: 2.5 }) }), _jsx("div", { className: "text-sm font-medium text-foreground", children: DEFAULT_SUCCESS_MESSAGE })] })) : (_jsxs("form", { onSubmit: submit, className: "flex flex-col gap-3 p-3", children: [_jsx("textarea", { ref: textareaRef, value: value, onChange: (e) => setValue(e.target.value), onKeyDown: (e) => {
145
151
  if ((e.metaKey || e.ctrlKey) && e.key === "Enter")
146
152
  submit();
147
153
  }, placeholder: resolvedPlaceholder, rows: 5, maxLength: 10000, className: "w-full resize-none rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring" }), _jsx("input", { type: "text", tabIndex: -1, autoComplete: "off", "aria-hidden": "true", value: honeypot, onChange: (e) => setHoneypot(e.target.value), style: honeypotStyle }), _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("div", { className: cn("text-[11px]", error ? "text-destructive" : "text-muted-foreground/75"), children: error ??
148
- `${/Mac|iPhone|iPad/.test(navigator.userAgent) ? "⌘" : "Ctrl"}+Enter to send` }), _jsx("button", { type: "submit", disabled: submitting || !value.trim(), className: "inline-flex h-8 items-center justify-center rounded-md bg-primary px-3 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50", children: submitting
149
- ? "Sending…"
150
- : (schema?.submitText ?? "Send feedback") })] })] })) }) })] }));
154
+ `${/Mac|iPhone|iPad/.test(navigator.userAgent) ? "⌘" : "Ctrl"}+Enter to send` }), _jsx("button", { type: "submit", disabled: submitting || !value.trim(), className: "inline-flex h-8 items-center justify-center rounded-md bg-primary px-3 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50", children: submitting ? "Sending…" : DEFAULT_SUBMIT_TEXT })] })] })) }) })] }));
151
155
  }
152
156
  //# sourceMappingURL=FeedbackButton.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FeedbackButton.js","sourceRoot":"","sources":["../../src/client/FeedbackButton.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useState,\n useEffect,\n useRef,\n useCallback,\n type CSSProperties,\n type FormEvent,\n} from \"react\";\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport { IconMessage2, IconCheck } from \"@tabler/icons-react\";\nimport { cn } from \"./utils.js\";\nimport { useSession } from \"./use-session.js\";\n\nconst DEFAULT_FEEDBACK_URL =\n \"https://forms.agent-native.com/f/agent-native-feedback/_16ewV\";\n\ninterface ParsedTarget {\n endpoint: string;\n slug: string;\n}\n\ninterface FormSchema {\n formId: string;\n fieldId: string;\n placeholder?: string;\n submitText: string;\n successMessage: string;\n}\n\nfunction parseTarget(url: string): ParsedTarget | null {\n try {\n const u = new URL(url);\n const idx = u.pathname.indexOf(\"/f/\");\n if (idx === -1) return null;\n const slug = u.pathname.slice(idx + 3).replace(/\\/$/, \"\");\n if (!slug) return null;\n return { endpoint: u.origin, slug };\n } catch {\n return null;\n }\n}\n\nconst schemaCache = new Map<string, Promise<FormSchema>>();\n\nasync function loadSchema(target: ParsedTarget): Promise<FormSchema> {\n const key = `${target.endpoint}|${target.slug}`;\n let pending = schemaCache.get(key);\n if (pending) return pending;\n pending = (async () => {\n const res = await fetch(\n `${target.endpoint}/api/forms/public/${encodeURIComponent(target.slug)}`,\n { headers: { Accept: \"application/json\" } },\n );\n if (!res.ok) throw new Error(`form fetch ${res.status}`);\n const body = (await res.json()) as {\n id: string;\n fields: Array<{ id: string; type: string; placeholder?: string }>;\n settings?: { submitText?: string; successMessage?: string };\n };\n const field =\n body.fields.find((f) => f.type === \"textarea\") ??\n body.fields.find((f) => f.type === \"text\") ??\n body.fields[0];\n if (!field) throw new Error(\"form has no fields\");\n return {\n formId: body.id,\n fieldId: field.id,\n placeholder: field.placeholder,\n submitText: body.settings?.submitText ?? \"Send feedback\",\n successMessage:\n body.settings?.successMessage ?? \"Thanks for the feedback!\",\n };\n })();\n pending.catch(() => schemaCache.delete(key));\n schemaCache.set(key, pending);\n return pending;\n}\n\nexport interface FeedbackButtonProps {\n /**\n * \"sidebar\" renders a full-width row with icon + label (for app left sidebars).\n * \"icon\" renders a small icon-only button (for dense toolbars, e.g. the agent panel header).\n */\n variant?: \"sidebar\" | \"icon\";\n label?: string;\n url?: string;\n className?: string;\n /** Which side the popover opens on. Defaults match the variant. */\n side?: \"top\" | \"bottom\" | \"left\" | \"right\";\n align?: \"start\" | \"center\" | \"end\";\n /** Placeholder text for the textarea. Falls back to the form's placeholder. */\n placeholder?: string;\n}\n\nconst surfaceStyle: CSSProperties = {\n width: \"min(380px, calc(100vw - 32px))\",\n};\n\nconst honeypotStyle: CSSProperties = {\n position: \"absolute\",\n left: \"-10000px\",\n top: \"auto\",\n width: \"1px\",\n height: \"1px\",\n overflow: \"hidden\",\n};\n\nexport function FeedbackButton({\n variant = \"sidebar\",\n label = \"Feedback\",\n url = DEFAULT_FEEDBACK_URL,\n className,\n side,\n align = \"end\",\n placeholder,\n}: FeedbackButtonProps) {\n const target = parseTarget(url);\n const { session } = useSession();\n\n const [open, setOpen] = useState(false);\n const [value, setValue] = useState(\"\");\n const [honeypot, setHoneypot] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [submitted, setSubmitted] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [schema, setSchema] = useState<FormSchema | null>(null);\n const openedAtRef = useRef<number>(0);\n const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const textareaRef = useRef<HTMLTextAreaElement | null>(null);\n\n // Reset transient state and kick off schema load on each open.\n useEffect(() => {\n if (!open) return;\n openedAtRef.current = Date.now();\n setValue(\"\");\n setHoneypot(\"\");\n setSubmitting(false);\n setSubmitted(false);\n setError(null);\n if (target) {\n loadSchema(target)\n .then((s) => setSchema(s))\n .catch((err) => {\n console.error(\"[FeedbackButton] schema load failed\", err);\n setError(\"Couldn't load feedback form\");\n });\n } else {\n setError(\"Invalid feedback URL\");\n }\n const t = setTimeout(() => textareaRef.current?.focus(), 30);\n return () => {\n clearTimeout(t);\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n };\n }, [open, url]);\n\n const submit = useCallback(\n async (e?: FormEvent) => {\n e?.preventDefault();\n if (!target || !schema || submitting) return;\n const trimmed = value.trim();\n if (!trimmed) {\n setError(\"Please write something first\");\n return;\n }\n setSubmitting(true);\n setError(null);\n try {\n const submitterEmail = session?.email;\n const res = await fetch(\n `${target.endpoint}/api/submit/${encodeURIComponent(schema.formId)}`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n data: { [schema.fieldId]: trimmed },\n _t: openedAtRef.current,\n _hp: honeypot,\n ...(submitterEmail ? { _meta: { submitterEmail } } : {}),\n }),\n },\n );\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(body.error || `submit failed (${res.status})`);\n }\n setSubmitted(true);\n closeTimerRef.current = setTimeout(() => setOpen(false), 1400);\n } catch (err) {\n setSubmitting(false);\n setError(err instanceof Error ? err.message : \"Couldn't send feedback\");\n }\n },\n [target, schema, value, honeypot, submitting, session?.email],\n );\n\n const trigger =\n variant === \"icon\" ? (\n <TooltipPrimitive.Provider delayDuration={200}>\n <TooltipPrimitive.Root>\n <TooltipPrimitive.Trigger asChild>\n <PopoverPrimitive.Trigger asChild>\n <button\n type=\"button\"\n aria-label={label}\n className={cn(\n \"flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50\",\n className,\n )}\n >\n <IconMessage2 size={14} />\n </button>\n </PopoverPrimitive.Trigger>\n </TooltipPrimitive.Trigger>\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n sideOffset={6}\n className=\"z-[230] overflow-hidden rounded-md border border-border bg-popover px-2 py-1 text-[11px] text-foreground shadow-md animate-in fade-in-0 zoom-in-95\"\n >\n {label}\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n </TooltipPrimitive.Root>\n </TooltipPrimitive.Provider>\n ) : (\n <PopoverPrimitive.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n \"flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground\",\n className,\n )}\n >\n <IconMessage2 className=\"h-4 w-4\" />\n <span>{label}</span>\n </button>\n </PopoverPrimitive.Trigger>\n );\n\n const resolvedSide = side ?? (variant === \"icon\" ? \"bottom\" : \"top\");\n const resolvedPlaceholder =\n placeholder ?? schema?.placeholder ?? \"Tell us what's on your mind…\";\n\n return (\n <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>\n {trigger}\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n side={resolvedSide}\n align={align}\n sideOffset={8}\n collisionPadding={16}\n className=\"z-[300] overflow-hidden rounded-lg border border-border bg-popover shadow-xl outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\"\n style={surfaceStyle}\n >\n {submitted ? (\n <div className=\"flex flex-col items-center justify-center gap-3 px-6 py-10 text-center\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-emerald-500/10 text-emerald-500\">\n <IconCheck size={20} stroke={2.5} />\n </div>\n <div className=\"text-sm font-medium text-foreground\">\n {schema?.successMessage ?? \"Thanks for the feedback!\"}\n </div>\n </div>\n ) : (\n <form onSubmit={submit} className=\"flex flex-col gap-3 p-3\">\n <textarea\n ref={textareaRef}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={(e) => {\n if ((e.metaKey || e.ctrlKey) && e.key === \"Enter\") submit();\n }}\n placeholder={resolvedPlaceholder}\n rows={5}\n maxLength={10000}\n className=\"w-full resize-none rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n <input\n type=\"text\"\n tabIndex={-1}\n autoComplete=\"off\"\n aria-hidden=\"true\"\n value={honeypot}\n onChange={(e) => setHoneypot(e.target.value)}\n style={honeypotStyle}\n />\n <div className=\"flex items-center justify-between gap-3\">\n <div\n className={cn(\n \"text-[11px]\",\n error ? \"text-destructive\" : \"text-muted-foreground/75\",\n )}\n >\n {error ??\n `${/Mac|iPhone|iPad/.test(navigator.userAgent) ? \"⌘\" : \"Ctrl\"}+Enter to send`}\n </div>\n <button\n type=\"submit\"\n disabled={submitting || !value.trim()}\n className=\"inline-flex h-8 items-center justify-center rounded-md bg-primary px-3 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n {submitting\n ? \"Sending…\"\n : (schema?.submitText ?? \"Send feedback\")}\n </button>\n </div>\n </form>\n )}\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </PopoverPrimitive.Root>\n );\n}\n"]}
1
+ {"version":3,"file":"FeedbackButton.js","sourceRoot":"","sources":["../../src/client/FeedbackButton.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useState,\n useEffect,\n useRef,\n useCallback,\n type CSSProperties,\n type FormEvent,\n} from \"react\";\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport { IconMessage2, IconCheck } from \"@tabler/icons-react\";\nimport { cn } from \"./utils.js\";\nimport { useSession } from \"./use-session.js\";\n\nconst DEFAULT_FEEDBACK_URL =\n \"https://forms.agent-native.com/f/agent-native-feedback/_16ewV\";\n\ninterface ParsedTarget {\n endpoint: string;\n slug: string;\n}\n\ninterface FormSchema {\n formId: string;\n fieldId: string;\n}\n\nconst DEFAULT_PLACEHOLDER = \"Tell us what's on your mind…\";\nconst DEFAULT_SUBMIT_TEXT = \"Send feedback\";\nconst DEFAULT_SUCCESS_MESSAGE = \"Thanks for the feedback!\";\n\nfunction parseTarget(url: string): ParsedTarget | null {\n try {\n const u = new URL(url);\n const idx = u.pathname.indexOf(\"/f/\");\n if (idx === -1) return null;\n const slug = u.pathname.slice(idx + 3).replace(/\\/$/, \"\");\n if (!slug) return null;\n return { endpoint: u.origin, slug };\n } catch {\n return null;\n }\n}\n\nconst schemaCache = new Map<string, Promise<FormSchema>>();\n\nasync function loadSchema(target: ParsedTarget): Promise<FormSchema> {\n const key = `${target.endpoint}|${target.slug}`;\n let pending = schemaCache.get(key);\n if (pending) return pending;\n pending = (async () => {\n const res = await fetch(\n `${target.endpoint}/api/forms/public/${encodeURIComponent(target.slug)}`,\n { headers: { Accept: \"application/json\" } },\n );\n if (!res.ok) throw new Error(`form fetch ${res.status}`);\n const body = (await res.json()) as {\n id: string;\n fields: Array<{ id: string; type: string }>;\n };\n const field =\n body.fields.find((f) => f.type === \"textarea\") ??\n body.fields.find((f) => f.type === \"text\") ??\n body.fields[0];\n if (!field) throw new Error(\"form has no fields\");\n return { formId: body.id, fieldId: field.id };\n })();\n pending.catch(() => schemaCache.delete(key));\n schemaCache.set(key, pending);\n return pending;\n}\n\nexport interface FeedbackButtonProps {\n /**\n * \"sidebar\" renders a full-width row with icon + label (for app left sidebars).\n * \"icon\" renders a small icon-only button (for dense toolbars, e.g. the agent panel header).\n * \"outlined\" renders an outlined pill button with icon + label (for top-nav bars, e.g. docs).\n */\n variant?: \"sidebar\" | \"icon\" | \"outlined\";\n label?: string;\n url?: string;\n className?: string;\n /** Which side the popover opens on. Defaults match the variant. */\n side?: \"top\" | \"bottom\" | \"left\" | \"right\";\n align?: \"start\" | \"center\" | \"end\";\n /** Placeholder text for the textarea. */\n placeholder?: string;\n}\n\nconst surfaceStyle: CSSProperties = {\n width: \"min(380px, calc(100vw - 32px))\",\n};\n\nconst honeypotStyle: CSSProperties = {\n position: \"absolute\",\n left: \"-10000px\",\n top: \"auto\",\n width: \"1px\",\n height: \"1px\",\n overflow: \"hidden\",\n};\n\nexport function FeedbackButton({\n variant = \"sidebar\",\n label = \"Feedback\",\n url = DEFAULT_FEEDBACK_URL,\n className,\n side,\n align = \"end\",\n placeholder,\n}: FeedbackButtonProps) {\n const target = parseTarget(url);\n const { session } = useSession();\n\n const [open, setOpen] = useState(false);\n const [value, setValue] = useState(\"\");\n const [honeypot, setHoneypot] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [submitted, setSubmitted] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [schema, setSchema] = useState<FormSchema | null>(null);\n const openedAtRef = useRef<number>(0);\n const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const textareaRef = useRef<HTMLTextAreaElement | null>(null);\n\n // Reset transient state and kick off schema load on each open.\n useEffect(() => {\n if (!open) return;\n openedAtRef.current = Date.now();\n setValue(\"\");\n setHoneypot(\"\");\n setSubmitting(false);\n setSubmitted(false);\n setError(null);\n if (target) {\n loadSchema(target)\n .then((s) => setSchema(s))\n .catch((err) => {\n console.error(\"[FeedbackButton] schema load failed\", err);\n setError(\"Couldn't load feedback form\");\n });\n } else {\n setError(\"Invalid feedback URL\");\n }\n const t = setTimeout(() => textareaRef.current?.focus(), 30);\n return () => {\n clearTimeout(t);\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n };\n }, [open, url]);\n\n const submit = useCallback(\n async (e?: FormEvent) => {\n e?.preventDefault();\n if (!target || !schema || submitting) return;\n const trimmed = value.trim();\n if (!trimmed) {\n setError(\"Please write something first\");\n return;\n }\n setSubmitting(true);\n setError(null);\n try {\n const submitterEmail = session?.email;\n const res = await fetch(\n `${target.endpoint}/api/submit/${encodeURIComponent(schema.formId)}`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n data: { [schema.fieldId]: trimmed },\n _t: openedAtRef.current,\n _hp: honeypot,\n ...(submitterEmail ? { _meta: { submitterEmail } } : {}),\n }),\n },\n );\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(body.error || `submit failed (${res.status})`);\n }\n setSubmitted(true);\n closeTimerRef.current = setTimeout(() => setOpen(false), 1400);\n } catch (err) {\n setSubmitting(false);\n setError(err instanceof Error ? err.message : \"Couldn't send feedback\");\n }\n },\n [target, schema, value, honeypot, submitting, session?.email],\n );\n\n let trigger;\n if (variant === \"icon\") {\n trigger = (\n <TooltipPrimitive.Provider delayDuration={200}>\n <TooltipPrimitive.Root>\n <TooltipPrimitive.Trigger asChild>\n <PopoverPrimitive.Trigger asChild>\n <button\n type=\"button\"\n aria-label={label}\n className={cn(\n \"flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50\",\n className,\n )}\n >\n <IconMessage2 size={14} />\n </button>\n </PopoverPrimitive.Trigger>\n </TooltipPrimitive.Trigger>\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n sideOffset={6}\n className=\"z-[230] overflow-hidden rounded-md border border-border bg-popover px-2 py-1 text-[11px] text-foreground shadow-md animate-in fade-in-0 zoom-in-95\"\n >\n {label}\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n </TooltipPrimitive.Root>\n </TooltipPrimitive.Provider>\n );\n } else if (variant === \"outlined\") {\n trigger = (\n <PopoverPrimitive.Trigger asChild>\n <button\n type=\"button\"\n aria-label={label}\n className={cn(\n \"flex h-8 items-center gap-2 rounded-md border border-border bg-transparent px-3 text-sm text-muted-foreground transition hover:border-foreground/40 hover:text-foreground\",\n className,\n )}\n >\n <IconMessage2 size={14} stroke={1.5} />\n <span>{label}</span>\n </button>\n </PopoverPrimitive.Trigger>\n );\n } else {\n trigger = (\n <PopoverPrimitive.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n \"flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground\",\n className,\n )}\n >\n <IconMessage2 className=\"h-4 w-4\" />\n <span>{label}</span>\n </button>\n </PopoverPrimitive.Trigger>\n );\n }\n\n const resolvedSide = side ?? (variant === \"sidebar\" ? \"top\" : \"bottom\");\n const resolvedPlaceholder = placeholder ?? DEFAULT_PLACEHOLDER;\n\n return (\n <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>\n {trigger}\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n side={resolvedSide}\n align={align}\n sideOffset={8}\n collisionPadding={16}\n className=\"z-[300] overflow-hidden rounded-lg border border-border bg-popover shadow-xl outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\"\n style={surfaceStyle}\n >\n {submitted ? (\n <div className=\"flex flex-col items-center justify-center gap-3 px-6 py-10 text-center\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-emerald-500/10 text-emerald-500\">\n <IconCheck size={20} stroke={2.5} />\n </div>\n <div className=\"text-sm font-medium text-foreground\">\n {DEFAULT_SUCCESS_MESSAGE}\n </div>\n </div>\n ) : (\n <form onSubmit={submit} className=\"flex flex-col gap-3 p-3\">\n <textarea\n ref={textareaRef}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={(e) => {\n if ((e.metaKey || e.ctrlKey) && e.key === \"Enter\") submit();\n }}\n placeholder={resolvedPlaceholder}\n rows={5}\n maxLength={10000}\n className=\"w-full resize-none rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n <input\n type=\"text\"\n tabIndex={-1}\n autoComplete=\"off\"\n aria-hidden=\"true\"\n value={honeypot}\n onChange={(e) => setHoneypot(e.target.value)}\n style={honeypotStyle}\n />\n <div className=\"flex items-center justify-between gap-3\">\n <div\n className={cn(\n \"text-[11px]\",\n error ? \"text-destructive\" : \"text-muted-foreground/75\",\n )}\n >\n {error ??\n `${/Mac|iPhone|iPad/.test(navigator.userAgent) ? \"⌘\" : \"Ctrl\"}+Enter to send`}\n </div>\n <button\n type=\"submit\"\n disabled={submitting || !value.trim()}\n className=\"inline-flex h-8 items-center justify-center rounded-md bg-primary px-3 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n {submitting ? \"Sending…\" : DEFAULT_SUBMIT_TEXT}\n </button>\n </div>\n </form>\n )}\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </PopoverPrimitive.Root>\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"agent-chat-adapter.d.ts","sourceRoot":"","sources":["../../src/client/agent-chat-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAsB,MAAM,qBAAqB,CAAC;AAahF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAiErE;;;;GAIG;AACH;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAC3C,SAAS,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAC5C,SAAS,CAAC,EAAE;QAAE,OAAO,EAAE,eAAe,GAAG,SAAS,CAAA;KAAE,CAAC;IACrD,WAAW,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;CACzD,GAAG,gBAAgB,CAkcnB"}
1
+ {"version":3,"file":"agent-chat-adapter.d.ts","sourceRoot":"","sources":["../../src/client/agent-chat-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAsB,MAAM,qBAAqB,CAAC;AAahF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAsJrE;;;;GAIG;AACH;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAC3C,SAAS,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAC5C,SAAS,CAAC,EAAE;QAAE,OAAO,EAAE,eAAe,GAAG,SAAS,CAAA;KAAE,CAAC;IACrD,WAAW,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;CACzD,GAAG,gBAAgB,CA2nBnB"}
@@ -3,6 +3,11 @@ import { AgentAutoContinueSignal, readSSEStream, } from "./sse-event-processor.j
3
3
  import { agentNativePath } from "./api-path.js";
4
4
  import { normalizeChatError } from "./error-format.js";
5
5
  const AUTO_CONTINUE_PROMPT = "Continue from where you left off and finish the user's original request. Do not repeat completed work, do not mention internal reconnects, time limits, or step limits, and continue as if this is the same uninterrupted run.";
6
+ const MAX_RECONNECT_ATTEMPTS = 5;
7
+ const MAX_STARTUP_RECOVERY_ATTEMPTS = 8;
8
+ const MAX_TRANSIENT_CONTINUATIONS = 8;
9
+ const RETRY_BASE_DELAY_MS = 500;
10
+ const RETRY_MAX_DELAY_MS = 8_000;
6
11
  function normalizeMentions(text) {
7
12
  return text.replace(/@\[([^\]|]+)\|[^\]]+\]/g, "@$1");
8
13
  }
@@ -32,12 +37,23 @@ function contentToContinuationHistory(content) {
32
37
  }
33
38
  return truncateForContinuation(chunks.join("\n\n"), 40_000).trim();
34
39
  }
40
+ function combineContinuationHistory(fragments) {
41
+ return truncateForContinuation(fragments.filter(Boolean).join("\n\n"), 40_000).trim();
42
+ }
43
+ function visibleTransientContinuationContent(content) {
44
+ return content.filter((part) => part.type === "tool-call" && part.result !== undefined);
45
+ }
46
+ function snapshotContent(content) {
47
+ return content.map((part) => part.type === "text" ? { ...part } : { ...part, args: { ...part.args } });
48
+ }
35
49
  function autoContinueMessage(signal) {
36
50
  const reason = signal.reason === "loop_limit"
37
51
  ? "The previous run reached an internal step budget."
38
- : signal.reason === "stream_ended"
39
- ? "The previous stream ended before the agent sent a final completion signal."
40
- : "The previous run reached an internal execution budget.";
52
+ : signal.reason === "no_progress"
53
+ ? "The previous run stopped producing progress events while the connection stayed open."
54
+ : signal.reason === "stream_ended"
55
+ ? "The previous stream ended before the agent sent a final completion signal."
56
+ : "The previous run reached an internal execution budget.";
41
57
  return `${AUTO_CONTINUE_PROMPT}\n\nInternal note: ${reason}`;
42
58
  }
43
59
  function delay(ms, abortSignal) {
@@ -51,6 +67,54 @@ function delay(ms, abortSignal) {
51
67
  }, { once: true });
52
68
  });
53
69
  }
70
+ function retryDelay(attempt, abortSignal) {
71
+ const base = Math.min(RETRY_MAX_DELAY_MS, RETRY_BASE_DELAY_MS * Math.pow(2, attempt));
72
+ const jitter = base * 0.2;
73
+ const ms = Math.max(0, base + (Math.random() * 2 - 1) * jitter);
74
+ return delay(ms, abortSignal);
75
+ }
76
+ function isRetryableStartupError(message) {
77
+ const msg = message.toLowerCase();
78
+ if (msg.includes("unauthorized") ||
79
+ msg.includes("not authenticated") ||
80
+ msg.includes("401") ||
81
+ msg.includes("403") ||
82
+ msg.includes("404") ||
83
+ msg.includes("405") ||
84
+ msg.includes("missing api key") ||
85
+ msg.includes("api key") ||
86
+ msg.includes("context_length") ||
87
+ msg.includes("input_too_long") ||
88
+ msg.includes("too many tokens") ||
89
+ msg.includes("prompt is too long") ||
90
+ msg.includes("credits-limit") ||
91
+ msg.includes("billing") ||
92
+ msg.includes("permission")) {
93
+ return false;
94
+ }
95
+ return (msg.includes("failed to fetch") ||
96
+ msg.includes("network") ||
97
+ msg.includes("connection") ||
98
+ msg.includes("reset") ||
99
+ msg.includes("econnreset") ||
100
+ msg.includes("socket") ||
101
+ msg.includes("timeout") ||
102
+ msg.includes("gateway timeout") ||
103
+ msg.includes("inactivity timeout") ||
104
+ msg.includes("temporarily unavailable") ||
105
+ msg.includes("server error: 408") ||
106
+ msg.includes("server error: 429") ||
107
+ msg.includes("server error: 500") ||
108
+ msg.includes("server error: 502") ||
109
+ msg.includes("server error: 503") ||
110
+ msg.includes("server error: 504") ||
111
+ msg.includes("429") ||
112
+ msg.includes("500") ||
113
+ msg.includes("502") ||
114
+ msg.includes("503") ||
115
+ msg.includes("504") ||
116
+ msg.includes("529"));
117
+ }
54
118
  /**
55
119
  * The composer's exec mode is sent as explicit request metadata. The server
56
120
  * owns the plan-mode prompt and read-only tool filtering so the chat history
@@ -152,6 +216,10 @@ export function createAgentChatAdapter(options) {
152
216
  let currentHistory = history;
153
217
  let includeAttachments = attachments.length > 0;
154
218
  let includeReferences = Boolean(runConfig?.custom?.references);
219
+ let startupRecoveryAttempts = 0;
220
+ let transientContinuationAttempts = 0;
221
+ const continuationHistoryFragments = [];
222
+ let visibleContinuationPrefix = [];
155
223
  try {
156
224
  const headers = {
157
225
  "Content-Type": "application/json",
@@ -167,7 +235,7 @@ export function createAgentChatAdapter(options) {
167
235
  const reconnectCurrentRun = async function* () {
168
236
  if (!runId)
169
237
  return false;
170
- for (let attempt = 0; attempt < 3; attempt++) {
238
+ for (let attempt = 0; attempt < MAX_RECONNECT_ATTEMPTS; attempt++) {
171
239
  try {
172
240
  const reconnectRes = await fetch(`${apiUrl}/runs/${encodeURIComponent(runId)}/events?after=${lastSeq + 1}`, { signal: abortSignal });
173
241
  if (!reconnectRes.ok || !reconnectRes.body)
@@ -187,13 +255,106 @@ export function createAgentChatAdapter(options) {
187
255
  return true;
188
256
  }
189
257
  if (reconnectErr instanceof AgentAutoContinueSignal) {
258
+ if (reconnectErr.reason === "no_progress") {
259
+ throw reconnectErr;
260
+ }
261
+ return false;
262
+ }
263
+ await retryDelay(attempt, abortSignal);
264
+ }
265
+ }
266
+ return false;
267
+ };
268
+ const abortCurrentRun = async () => {
269
+ if (!runId)
270
+ return;
271
+ try {
272
+ await fetch(`${apiUrl}/runs/${encodeURIComponent(runId)}/abort`, {
273
+ method: "POST",
274
+ signal: abortSignal,
275
+ });
276
+ }
277
+ catch {
278
+ // Best effort. The follow-up POST will still reconnect or 409 if
279
+ // the producer is alive and cannot be aborted cross-isolate.
280
+ }
281
+ finally {
282
+ clearActiveRun();
283
+ }
284
+ };
285
+ const reconnectActiveRunForThread = async function* () {
286
+ if (!threadId)
287
+ return false;
288
+ for (let attempt = 0; attempt < MAX_RECONNECT_ATTEMPTS; attempt++) {
289
+ try {
290
+ const activeRes = await fetch(`${apiUrl}/runs/active?threadId=${encodeURIComponent(threadId)}`, { signal: abortSignal });
291
+ if (!activeRes.ok)
190
292
  return false;
293
+ const active = await activeRes.json();
294
+ if (active?.active && active.runId) {
295
+ const activeRunId = String(active.runId);
296
+ runId = activeRunId;
297
+ lastSeq = -1;
298
+ setActiveRun({ threadId, runId: activeRunId, lastSeq: -1 });
299
+ const reconnected = yield* reconnectCurrentRun();
300
+ if (reconnected)
301
+ return true;
302
+ }
303
+ return false;
304
+ }
305
+ catch (activeErr) {
306
+ if (activeErr instanceof Error &&
307
+ activeErr.name === "AbortError") {
308
+ clearActiveRun();
309
+ return true;
191
310
  }
192
- await delay(1000, abortSignal);
311
+ await retryDelay(attempt, abortSignal);
193
312
  }
194
313
  }
195
314
  return false;
196
315
  };
316
+ const visibleContentForContinuation = () => {
317
+ if (visibleContinuationPrefix.length > 0 &&
318
+ visibleContinuationPrefix.every((part, index) => content[index] === part)) {
319
+ return content.slice(visibleContinuationPrefix.length);
320
+ }
321
+ return content;
322
+ };
323
+ const prepareAutoContinuation = (signal) => {
324
+ const isTransient = signal.reason !== "loop_limit";
325
+ if (signal.reason === "loop_limit") {
326
+ transientContinuationAttempts = 0;
327
+ }
328
+ else if (++transientContinuationAttempts > MAX_TRANSIENT_CONTINUATIONS) {
329
+ return { ok: false, resetVisibleContent: false };
330
+ }
331
+ const currentPartialHistory = contentToContinuationHistory(visibleContentForContinuation());
332
+ if (isTransient && currentPartialHistory) {
333
+ continuationHistoryFragments.push(currentPartialHistory);
334
+ }
335
+ const partialHistory = combineContinuationHistory(isTransient
336
+ ? continuationHistoryFragments
337
+ : [...continuationHistoryFragments, currentPartialHistory]);
338
+ currentHistory = [
339
+ ...history,
340
+ { role: "user", content: normalizeMentions(rawMessageText) },
341
+ ...(partialHistory
342
+ ? [{ role: "assistant", content: partialHistory }]
343
+ : []),
344
+ ];
345
+ currentMessageText = autoContinueMessage(signal);
346
+ includeAttachments = false;
347
+ includeReferences = false;
348
+ startupRecoveryAttempts = 0;
349
+ clearActiveRun();
350
+ if (!isTransient) {
351
+ return { ok: true, resetVisibleContent: false };
352
+ }
353
+ const preservedContent = visibleTransientContinuationContent(content);
354
+ content.splice(0, content.length, ...preservedContent);
355
+ visibleContinuationPrefix = preservedContent;
356
+ return { ok: true, resetVisibleContent: true };
357
+ };
197
358
  while (true) {
198
359
  try {
199
360
  runId = null;
@@ -337,23 +498,53 @@ export function createAgentChatAdapter(options) {
337
498
  return;
338
499
  }
339
500
  if (err instanceof AgentAutoContinueSignal) {
501
+ if (err.reason === "no_progress") {
502
+ await abortCurrentRun();
503
+ }
340
504
  if (err.reason === "stream_ended") {
341
505
  const reconnected = yield* reconnectCurrentRun();
342
506
  if (reconnected)
343
507
  return;
508
+ const activeReconnected = yield* reconnectActiveRunForThread();
509
+ if (activeReconnected)
510
+ return;
511
+ }
512
+ const continuation = prepareAutoContinuation(err);
513
+ if (!continuation.ok) {
514
+ const message = "The agent connection kept failing after several automatic recovery attempts.";
515
+ const runError = {
516
+ message,
517
+ errorCode: "connection_error",
518
+ recoverable: true,
519
+ ...(runId ? { runId } : {}),
520
+ };
521
+ if (typeof window !== "undefined") {
522
+ window.dispatchEvent(new CustomEvent("agent-chat:run-error", {
523
+ detail: { ...runError, tabId },
524
+ }));
525
+ }
526
+ content.push({
527
+ type: "text",
528
+ text: `Something went wrong: ${message}`,
529
+ });
530
+ yield {
531
+ content: [...content],
532
+ status: {
533
+ type: "incomplete",
534
+ reason: "error",
535
+ },
536
+ metadata: {
537
+ custom: { ...(runId ? { runId } : {}), runError },
538
+ },
539
+ };
540
+ clearActiveRun();
541
+ return;
542
+ }
543
+ if (continuation.resetVisibleContent) {
544
+ yield {
545
+ content: snapshotContent(content),
546
+ };
344
547
  }
345
- const partialHistory = contentToContinuationHistory(content);
346
- currentHistory = [
347
- ...history,
348
- { role: "user", content: normalizeMentions(rawMessageText) },
349
- ...(partialHistory
350
- ? [{ role: "assistant", content: partialHistory }]
351
- : []),
352
- ];
353
- currentMessageText = autoContinueMessage(err);
354
- includeAttachments = false;
355
- includeReferences = false;
356
- clearActiveRun();
357
548
  await delay(250, abortSignal);
358
549
  if (abortSignal.aborted)
359
550
  return;
@@ -385,26 +576,60 @@ export function createAgentChatAdapter(options) {
385
576
  const reconnected = yield* reconnectCurrentRun();
386
577
  if (reconnected)
387
578
  return;
579
+ const activeReconnected = yield* reconnectActiveRunForThread();
580
+ if (activeReconnected)
581
+ return;
388
582
  // Reconnect failed or not possible — keep going from the partial
389
583
  // streamed content instead of surfacing a transient transport error.
390
584
  if (content.length > 0) {
391
- const partialHistory = contentToContinuationHistory(content);
392
- currentHistory = [
393
- ...history,
394
- { role: "user", content: normalizeMentions(rawMessageText) },
395
- ...(partialHistory
396
- ? [{ role: "assistant", content: partialHistory }]
397
- : []),
398
- ];
399
- currentMessageText = autoContinueMessage(new AgentAutoContinueSignal({ reason: "stream_ended" }));
400
- includeAttachments = false;
401
- includeReferences = false;
402
- clearActiveRun();
585
+ const continuation = prepareAutoContinuation(new AgentAutoContinueSignal({ reason: "stream_ended" }));
586
+ if (!continuation.ok) {
587
+ const message = "The agent connection kept failing after several automatic recovery attempts.";
588
+ const runError = {
589
+ message,
590
+ errorCode: "connection_error",
591
+ recoverable: true,
592
+ ...(runId ? { runId } : {}),
593
+ };
594
+ if (typeof window !== "undefined") {
595
+ window.dispatchEvent(new CustomEvent("agent-chat:run-error", {
596
+ detail: { ...runError, tabId },
597
+ }));
598
+ }
599
+ content.push({
600
+ type: "text",
601
+ text: `Something went wrong: ${message}`,
602
+ });
603
+ yield {
604
+ content: [...content],
605
+ status: {
606
+ type: "incomplete",
607
+ reason: "error",
608
+ },
609
+ metadata: {
610
+ custom: { ...(runId ? { runId } : {}), runError },
611
+ },
612
+ };
613
+ clearActiveRun();
614
+ return;
615
+ }
616
+ if (continuation.resetVisibleContent) {
617
+ yield {
618
+ content: snapshotContent(content),
619
+ };
620
+ }
403
621
  await delay(250, abortSignal);
404
622
  if (abortSignal.aborted)
405
623
  return;
406
624
  continue;
407
625
  }
626
+ if (isRetryableStartupError(errMsg) &&
627
+ startupRecoveryAttempts < MAX_STARTUP_RECOVERY_ATTEMPTS) {
628
+ await retryDelay(startupRecoveryAttempts++, abortSignal);
629
+ if (abortSignal.aborted)
630
+ return;
631
+ continue;
632
+ }
408
633
  // No partial work exists, so this is still a real startup failure.
409
634
  const normalized = normalizeChatError(errMsg);
410
635
  const runError = {