@agent-native/core 0.22.9 → 0.22.11

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 (42) hide show
  1. package/dist/client/AgentPanel.d.ts.map +1 -1
  2. package/dist/client/AgentPanel.js +8 -12
  3. package/dist/client/AgentPanel.js.map +1 -1
  4. package/dist/client/AssistantChat.d.ts +7 -0
  5. package/dist/client/AssistantChat.d.ts.map +1 -1
  6. package/dist/client/AssistantChat.js +106 -23
  7. package/dist/client/AssistantChat.js.map +1 -1
  8. package/dist/client/FeedbackButton.d.ts +5 -1
  9. package/dist/client/FeedbackButton.d.ts.map +1 -1
  10. package/dist/client/FeedbackButton.js +20 -3
  11. package/dist/client/FeedbackButton.js.map +1 -1
  12. package/dist/client/agent-chat-adapter.d.ts +10 -0
  13. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  14. package/dist/client/agent-chat-adapter.js +6 -19
  15. package/dist/client/agent-chat-adapter.js.map +1 -1
  16. package/dist/client/analytics.d.ts +1 -1
  17. package/dist/client/analytics.d.ts.map +1 -1
  18. package/dist/client/analytics.js +2 -40
  19. package/dist/client/analytics.js.map +1 -1
  20. package/dist/client/clipboard.d.ts +2 -0
  21. package/dist/client/clipboard.d.ts.map +1 -0
  22. package/dist/client/clipboard.js +51 -0
  23. package/dist/client/clipboard.js.map +1 -0
  24. package/dist/client/feedback-context.d.ts +11 -0
  25. package/dist/client/feedback-context.d.ts.map +1 -0
  26. package/dist/client/feedback-context.js +73 -0
  27. package/dist/client/feedback-context.js.map +1 -0
  28. package/dist/client/url-scrub.d.ts +2 -0
  29. package/dist/client/url-scrub.d.ts.map +1 -0
  30. package/dist/client/url-scrub.js +41 -0
  31. package/dist/client/url-scrub.js.map +1 -0
  32. package/dist/mcp/build-server.d.ts.map +1 -1
  33. package/dist/mcp/build-server.js +161 -17
  34. package/dist/mcp/build-server.js.map +1 -1
  35. package/dist/server/agent-chat-plugin.d.ts +5 -0
  36. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  37. package/dist/server/agent-chat-plugin.js +74 -59
  38. package/dist/server/agent-chat-plugin.js.map +1 -1
  39. package/docs/content/actions.md +2 -2
  40. package/docs/content/external-agents.md +3 -1
  41. package/docs/content/mcp-protocol.md +5 -3
  42. package/package.json +1 -1
@@ -13,6 +13,10 @@ export interface FeedbackButtonProps {
13
13
  align?: "start" | "center" | "end";
14
14
  /** Placeholder text for the textarea. */
15
15
  placeholder?: string;
16
+ /** Current chat session/thread id, when the host already knows it. */
17
+ chatSessionId?: string | null;
18
+ /** Chat localStorage namespace, when the host uses per-app chat storage. */
19
+ chatStorageKey?: string | null;
16
20
  }
17
- export declare function FeedbackButton({ variant, label, url, className, side, align, placeholder, }: FeedbackButtonProps): import("react/jsx-runtime").JSX.Element;
21
+ export declare function FeedbackButton({ variant, label, url, className, side, align, placeholder, chatSessionId, chatStorageKey, }: FeedbackButtonProps): import("react/jsx-runtime").JSX.Element;
18
22
  //# sourceMappingURL=FeedbackButton.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FeedbackButton.d.ts","sourceRoot":"","sources":["../../src/client/FeedbackButton.tsx"],"names":[],"mappings":"AAyEA,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,2CA+NrB"}
1
+ {"version":3,"file":"FeedbackButton.d.ts","sourceRoot":"","sources":["../../src/client/FeedbackButton.tsx"],"names":[],"mappings":"AA0EA,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;IACrB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAeD,wBAAgB,cAAc,CAAC,EAC7B,OAAmB,EACnB,KAAkB,EAClB,GAA0B,EAC1B,SAAS,EACT,IAAI,EACJ,KAAa,EACb,WAAW,EACX,aAAa,EACb,cAAc,GACf,EAAE,mBAAmB,2CA+OrB"}
@@ -5,6 +5,7 @@ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
5
5
  import { IconMessage2, IconCheck } from "@tabler/icons-react";
6
6
  import { cn } from "./utils.js";
7
7
  import { useSession } from "./use-session.js";
8
+ import { getFeedbackClientContext } from "./feedback-context.js";
8
9
  const DEFAULT_FEEDBACK_URL = "https://forms.agent-native.com/f/agent-native-feedback/_16ewV";
9
10
  const DEFAULT_PLACEHOLDER = 'What\'s working, what\'s broken, or what would you change?\n\ne.g. "The Send button isn\'t obvious", "I wish I could change the theme", "Search is slow when…"';
10
11
  const DEFAULT_SUBMIT_TEXT = "Send feedback";
@@ -57,7 +58,7 @@ const honeypotStyle = {
57
58
  height: "1px",
58
59
  overflow: "hidden",
59
60
  };
60
- export function FeedbackButton({ variant = "sidebar", label = "Feedback", url = DEFAULT_FEEDBACK_URL, className, side, align = "end", placeholder, }) {
61
+ export function FeedbackButton({ variant = "sidebar", label = "Feedback", url = DEFAULT_FEEDBACK_URL, className, side, align = "end", placeholder, chatSessionId, chatStorageKey, }) {
61
62
  const target = parseTarget(url);
62
63
  const { session } = useSession();
63
64
  const [open, setOpen] = useState(false);
@@ -117,6 +118,10 @@ export function FeedbackButton({ variant = "sidebar", label = "Feedback", url =
117
118
  if (!schema)
118
119
  setSchema(resolvedSchema);
119
120
  const submitterEmail = session?.email;
121
+ const feedbackContext = getFeedbackClientContext({
122
+ chatSessionId,
123
+ storageKey: chatStorageKey,
124
+ });
120
125
  const res = await fetch(`${target.endpoint}/api/submit/${encodeURIComponent(resolvedSchema.formId)}`, {
121
126
  method: "POST",
122
127
  headers: { "Content-Type": "application/json" },
@@ -124,7 +129,10 @@ export function FeedbackButton({ variant = "sidebar", label = "Feedback", url =
124
129
  data: { [resolvedSchema.fieldId]: trimmed },
125
130
  _t: openedAtRef.current,
126
131
  _hp: honeypot,
127
- ...(submitterEmail ? { _meta: { submitterEmail } } : {}),
132
+ _meta: {
133
+ ...(submitterEmail ? { submitterEmail } : {}),
134
+ ...feedbackContext,
135
+ },
128
136
  }),
129
137
  });
130
138
  if (!res.ok) {
@@ -138,7 +146,16 @@ export function FeedbackButton({ variant = "sidebar", label = "Feedback", url =
138
146
  setSubmitting(false);
139
147
  setError(err instanceof Error ? err.message : "Couldn't send feedback");
140
148
  }
141
- }, [target, schema, value, honeypot, submitting, session?.email]);
149
+ }, [
150
+ target,
151
+ schema,
152
+ value,
153
+ honeypot,
154
+ submitting,
155
+ session?.email,
156
+ chatSessionId,
157
+ chatStorageKey,
158
+ ]);
142
159
  let trigger;
143
160
  if (variant === "icon") {
144
161
  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-[300] 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 }) })] }) }));
@@ -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}\n\nconst DEFAULT_PLACEHOLDER =\n 'What\\'s working, what\\'s broken, or what would you change?\\n\\ne.g. \"The Send button isn\\'t obvious\", \"I wish I could change the theme\", \"Search is slow when…\"';\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 setSchema(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 || 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 resolvedSchema = schema ?? (await loadSchema(target));\n if (!schema) setSchema(resolvedSchema);\n const submitterEmail = session?.email;\n const res = await fetch(\n `${target.endpoint}/api/submit/${encodeURIComponent(resolvedSchema.formId)}`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n data: { [resolvedSchema.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-[300] 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
+ {"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\";\nimport { getFeedbackClientContext } from \"./feedback-context.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 =\n 'What\\'s working, what\\'s broken, or what would you change?\\n\\ne.g. \"The Send button isn\\'t obvious\", \"I wish I could change the theme\", \"Search is slow when…\"';\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 /** Current chat session/thread id, when the host already knows it. */\n chatSessionId?: string | null;\n /** Chat localStorage namespace, when the host uses per-app chat storage. */\n chatStorageKey?: string | null;\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 chatSessionId,\n chatStorageKey,\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 setSchema(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 || 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 resolvedSchema = schema ?? (await loadSchema(target));\n if (!schema) setSchema(resolvedSchema);\n const submitterEmail = session?.email;\n const feedbackContext = getFeedbackClientContext({\n chatSessionId,\n storageKey: chatStorageKey,\n });\n const res = await fetch(\n `${target.endpoint}/api/submit/${encodeURIComponent(resolvedSchema.formId)}`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n data: { [resolvedSchema.fieldId]: trimmed },\n _t: openedAtRef.current,\n _hp: honeypot,\n _meta: {\n ...(submitterEmail ? { submitterEmail } : {}),\n ...feedbackContext,\n },\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 [\n target,\n schema,\n value,\n honeypot,\n submitting,\n session?.email,\n chatSessionId,\n chatStorageKey,\n ],\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-[300] 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,6 +1,15 @@
1
1
  import type { ChatModelAdapter } from "@assistant-ui/react";
2
2
  import type { ReasoningEffort } from "../shared/reasoning-effort.js";
3
3
  import type { ChatThreadScope } from "./use-chat-threads.js";
4
+ export type AgentChatSurfaceKind =
5
+ /**
6
+ * Chat rendered by the app itself, including the normal AgentSidebar. This
7
+ * surface must not receive code-editing dev tools because source edits can
8
+ * reload the same React tree that is hosting the chat.
9
+ */
10
+ "app"
11
+ /** Chat rendered by the outer local dev frame, outside the app iframe. */
12
+ | "dev-frame";
4
13
  /**
5
14
  * The composer's exec mode is sent as explicit request metadata. The server
6
15
  * owns the plan-mode prompt and read-only tool filtering so the chat history
@@ -30,5 +39,6 @@ export declare function createAgentChatAdapter(options?: {
30
39
  scopeRef?: {
31
40
  current: ChatThreadScope | null | undefined;
32
41
  };
42
+ surface?: AgentChatSurfaceKind;
33
43
  }): ChatModelAdapter;
34
44
  //# sourceMappingURL=agent-chat-adapter.d.ts.map
@@ -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;AAehF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAKrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAmuB7D;;;;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;IACxD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,CAAA;KAAE,CAAC;CAC5D,GAAG,gBAAgB,CAq+BnB"}
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;AAehF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAKrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,MAAM,MAAM,oBAAoB;AAC9B;;;;GAIG;AACD,KAAK;AACP,0EAA0E;GACxE,WAAW,CAAC;AAmuBhB;;;;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;IACxD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,CAAA;KAAE,CAAC;IAC3D,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAChC,GAAG,gBAAgB,CAu9BnB"}
@@ -584,6 +584,7 @@ export function createAgentChatAdapter(options) {
584
584
  const execModeRef = options?.execModeRef;
585
585
  const browserTabId = options?.browserTabId;
586
586
  const scopeRef = options?.scopeRef;
587
+ const surface = options?.surface ?? "app";
587
588
  return {
588
589
  async *run({ messages, abortSignal, runConfig }) {
589
590
  // Extract latest user message and build history from prior messages
@@ -783,25 +784,11 @@ export function createAgentChatAdapter(options) {
783
784
  catch {
784
785
  // Non-browser or Intl unavailable — tool calls will fall back to UTC.
785
786
  }
786
- // Surface hint — the server uses this to gate code-editing dev tools
787
- // when the chat is running in a plain browser tab on localhost. Editing
788
- // source files there would trigger HMR/page reloads and kill the chat
789
- // session, so the agent must redirect users to Desktop / Claude Code /
790
- // Codex / Builder.io instead of attempting code work.
791
- try {
792
- const ua = typeof navigator !== "undefined" ? navigator.userAgent || "" : "";
793
- const inIframe = typeof window !== "undefined" && window.parent !== window;
794
- const surface = /AgentNativeDesktop/i.test(ua)
795
- ? "desktop"
796
- : inIframe
797
- ? "frame"
798
- : "browser";
799
- headers["x-agent-native-surface"] = surface;
800
- }
801
- catch {
802
- // Non-browser environment — leave the header off and let the server
803
- // fall back to its own UA/host detection.
804
- }
787
+ // Surface hint — the server uses this to keep code-editing dev tools
788
+ // out of the app-rendered sidebar. The outer dev frame passes
789
+ // "dev-frame" explicitly; the reusable in-product chat defaults to
790
+ // "app" even when it is running in Desktop or inside a preview iframe.
791
+ headers["x-agent-native-surface"] = surface;
805
792
  const reconnectCurrentRun = async function* () {
806
793
  if (!runId)
807
794
  return false;