@agent-native/core 0.12.25 → 0.12.27

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 (56) hide show
  1. package/dist/agent/production-agent.d.ts.map +1 -1
  2. package/dist/agent/production-agent.js +20 -2
  3. package/dist/agent/production-agent.js.map +1 -1
  4. package/dist/client/AgentTaskCard.d.ts.map +1 -1
  5. package/dist/client/AgentTaskCard.js +16 -3
  6. package/dist/client/AgentTaskCard.js.map +1 -1
  7. package/dist/client/AssistantChat.d.ts.map +1 -1
  8. package/dist/client/AssistantChat.js +22 -12
  9. package/dist/client/AssistantChat.js.map +1 -1
  10. package/dist/client/IframeEmbed.d.ts.map +1 -1
  11. package/dist/client/IframeEmbed.js +2 -2
  12. package/dist/client/IframeEmbed.js.map +1 -1
  13. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  14. package/dist/client/agent-chat-adapter.js +62 -9
  15. package/dist/client/agent-chat-adapter.js.map +1 -1
  16. package/dist/client/composer/ComposerPlusMenu.d.ts.map +1 -1
  17. package/dist/client/composer/ComposerPlusMenu.js +1 -1
  18. package/dist/client/composer/ComposerPlusMenu.js.map +1 -1
  19. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  20. package/dist/client/composer/PromptComposer.js +8 -7
  21. package/dist/client/composer/PromptComposer.js.map +1 -1
  22. package/dist/client/composer/attachment-accept.d.ts +7 -0
  23. package/dist/client/composer/attachment-accept.d.ts.map +1 -0
  24. package/dist/client/composer/attachment-accept.js +36 -0
  25. package/dist/client/composer/attachment-accept.js.map +1 -0
  26. package/dist/client/sse-event-processor.d.ts.map +1 -1
  27. package/dist/client/sse-event-processor.js +8 -0
  28. package/dist/client/sse-event-processor.js.map +1 -1
  29. package/dist/db/client.d.ts +3 -0
  30. package/dist/db/client.d.ts.map +1 -1
  31. package/dist/db/client.js +70 -34
  32. package/dist/db/client.js.map +1 -1
  33. package/dist/db/create-get-db.d.ts.map +1 -1
  34. package/dist/db/create-get-db.js +30 -7
  35. package/dist/db/create-get-db.js.map +1 -1
  36. package/dist/deploy/build.js +64 -0
  37. package/dist/deploy/build.js.map +1 -1
  38. package/dist/scripts/db/exec.d.ts.map +1 -1
  39. package/dist/scripts/db/exec.js +3 -6
  40. package/dist/scripts/db/exec.js.map +1 -1
  41. package/dist/scripts/db/patch.d.ts.map +1 -1
  42. package/dist/scripts/db/patch.js +3 -6
  43. package/dist/scripts/db/patch.js.map +1 -1
  44. package/dist/scripts/db/query.d.ts.map +1 -1
  45. package/dist/scripts/db/query.js +3 -6
  46. package/dist/scripts/db/query.js.map +1 -1
  47. package/dist/scripts/db/schema.d.ts.map +1 -1
  48. package/dist/scripts/db/schema.js +3 -6
  49. package/dist/scripts/db/schema.js.map +1 -1
  50. package/dist/scripts/db/sqlite-client.d.ts +15 -0
  51. package/dist/scripts/db/sqlite-client.d.ts.map +1 -0
  52. package/dist/scripts/db/sqlite-client.js +51 -0
  53. package/dist/scripts/db/sqlite-client.js.map +1 -0
  54. package/dist/server/better-auth-instance.js +4 -3
  55. package/dist/server/better-auth-instance.js.map +1 -1
  56. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"IframeEmbed.d.ts","sourceRoot":"","sources":["../../src/client/IframeEmbed.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA2BD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAmBtE;AAiBD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,gBAAgB,2CA2D3E"}
1
+ {"version":3,"file":"IframeEmbed.d.ts","sourceRoot":"","sources":["../../src/client/IframeEmbed.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA2BD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAmBtE;AAiBD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,gBAAgB,2CAqE3E"}
@@ -1,7 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useRef, useState } from "react";
3
3
  import { IconAlertTriangle } from "@tabler/icons-react";
4
- import { cn } from "./utils.js";
5
4
  import { AGENT_NAVIGATE_MESSAGE_TYPE } from "./embed.js";
6
5
  const ALLOWED_ASPECTS = new Set(["16/9", "4/3", "1/1", "21/9", "3/2", "2/1"]);
7
6
  function isSameOriginSrc(src) {
@@ -73,6 +72,7 @@ export function IframeEmbed({ src, aspect, title, height }) {
73
72
  const [loaded, setLoaded] = useState(false);
74
73
  const iframeRef = useRef(null);
75
74
  const resolvedAspect = aspect && ALLOWED_ASPECTS.has(aspect) ? aspect : "16/9";
75
+ const displayTitle = title?.trim() || "Embedded content";
76
76
  const paddingBottom = useMemo(() => aspectToPaddingBottom(resolvedAspect), [resolvedAspect]);
77
77
  useEffect(() => {
78
78
  function onMessage(e) {
@@ -103,6 +103,6 @@ export function IframeEmbed({ src, aspect, title, height }) {
103
103
  const style = height
104
104
  ? { height: `${height}px` }
105
105
  : { paddingBottom };
106
- return (_jsxs("div", { className: cn("my-2 rounded-lg border border-border overflow-hidden bg-muted/20 relative w-full"), style: style, children: [!loaded && (_jsx("div", { className: "absolute inset-0 animate-pulse bg-muted/40" })), _jsx("iframe", { ref: iframeRef, src: src, title: title || "Embedded content", sandbox: "allow-scripts allow-same-origin allow-forms allow-popups", referrerPolicy: "same-origin", loading: "lazy", onLoad: () => setLoaded(true), className: "absolute inset-0 w-full h-full border-0 bg-transparent" })] }));
106
+ return (_jsxs("div", { className: "my-2 w-full overflow-hidden rounded-lg border border-border bg-background/60", children: [_jsxs("div", { className: "flex min-h-8 items-center gap-2 border-b border-border bg-muted/30 px-3 py-1.5", children: [_jsx("span", { className: "shrink-0 text-[10px] font-medium uppercase text-muted-foreground", children: "Preview" }), _jsx("span", { "aria-hidden": "true", className: "h-3 w-px shrink-0 bg-border" }), _jsx("span", { className: "min-w-0 flex-1 truncate text-xs font-medium text-foreground", title: displayTitle, children: displayTitle })] }), _jsxs("div", { className: "relative w-full bg-muted/20", style: style, children: [!loaded && (_jsx("div", { className: "absolute inset-0 animate-pulse bg-muted/40" })), _jsx("iframe", { ref: iframeRef, src: src, title: displayTitle, sandbox: "allow-scripts allow-same-origin allow-forms allow-popups", referrerPolicy: "same-origin", loading: "lazy", onLoad: () => setLoaded(true), className: "absolute inset-0 h-full w-full border-0 bg-transparent" })] })] }));
107
107
  }
108
108
  //# sourceMappingURL=IframeEmbed.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"IframeEmbed.js","sourceRoot":"","sources":["../../src/client/IframeEmbed.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport { IconAlertTriangle } from \"@tabler/icons-react\";\nimport { cn } from \"./utils.js\";\nimport { AGENT_NAVIGATE_MESSAGE_TYPE } from \"./embed.js\";\n\nexport interface IframeEmbedProps {\n src?: string;\n aspect?: string;\n title?: string;\n height?: number;\n}\n\nconst ALLOWED_ASPECTS = new Set([\"16/9\", \"4/3\", \"1/1\", \"21/9\", \"3/2\", \"2/1\"]);\n\nfunction isSameOriginSrc(src: string): boolean {\n if (typeof window === \"undefined\") return false;\n const trimmed = src.trim();\n if (!trimmed) return false;\n if (trimmed.startsWith(\"javascript:\") || trimmed.startsWith(\"data:\")) {\n return false;\n }\n if (trimmed.startsWith(\"/\") && !trimmed.startsWith(\"//\")) return true;\n if (trimmed.startsWith(\"./\") || trimmed.startsWith(\"../\")) return true;\n try {\n const url = new URL(trimmed, window.location.origin);\n return url.origin === window.location.origin;\n } catch {\n return false;\n }\n}\n\nfunction aspectToPaddingBottom(aspect: string): string {\n const [w, h] = aspect.split(\"/\").map((n) => Number(n.trim()));\n if (!w || !h) return \"56.25%\";\n return `${(h / w) * 100}%`;\n}\n\n/**\n * Parses the body of a ```embed fenced block. Accepts simple `key: value`\n * lines, ignoring blanks and unknown keys. No YAML — keeps the surface small.\n */\nexport function parseEmbedBody(body: string): Partial<IframeEmbedProps> {\n const out: Partial<IframeEmbedProps> = {};\n for (const raw of body.split(/\\r?\\n/)) {\n const line = raw.trim();\n if (!line || line.startsWith(\"#\")) continue;\n const idx = line.indexOf(\":\");\n if (idx <= 0) continue;\n const key = line.slice(0, idx).trim().toLowerCase();\n const value = line.slice(idx + 1).trim();\n if (!value) continue;\n if (key === \"src\") out.src = value;\n else if (key === \"aspect\") out.aspect = value;\n else if (key === \"title\") out.title = value;\n else if (key === \"height\") {\n const n = Number(value);\n if (Number.isFinite(n) && n > 0) out.height = n;\n }\n }\n return out;\n}\n\nfunction BlockedEmbed({ reason, src }: { reason: string; src?: string }) {\n return (\n <div className=\"my-2 rounded-lg border border-border bg-muted/40 px-3 py-2 text-xs text-muted-foreground flex items-start gap-2\">\n <IconAlertTriangle className=\"h-3.5 w-3.5 shrink-0 mt-0.5\" />\n <div className=\"min-w-0\">\n <div className=\"font-medium text-foreground\">Embed blocked</div>\n <div className=\"mt-0.5\">{reason}</div>\n {src && (\n <div className=\"mt-1 font-mono text-[10px] truncate\">{src}</div>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Inline iframe embed for assistant chat. Rendered from a ```embed fenced\n * code block. Same-origin paths only; sandboxed.\n */\nexport function IframeEmbed({ src, aspect, title, height }: IframeEmbedProps) {\n const [loaded, setLoaded] = useState(false);\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const resolvedAspect =\n aspect && ALLOWED_ASPECTS.has(aspect) ? aspect : \"16/9\";\n const paddingBottom = useMemo(\n () => aspectToPaddingBottom(resolvedAspect),\n [resolvedAspect],\n );\n\n useEffect(() => {\n function onMessage(e: MessageEvent) {\n if (e.origin !== window.location.origin) return;\n const iframe = iframeRef.current;\n if (!iframe || e.source !== iframe.contentWindow) return;\n const data = e.data as { type?: unknown; path?: unknown } | null;\n if (!data || data.type !== AGENT_NAVIGATE_MESSAGE_TYPE) return;\n if (typeof data.path !== \"string\" || !data.path.startsWith(\"/\")) return;\n if (data.path.startsWith(\"//\")) return;\n window.history.pushState({}, \"\", data.path);\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n }\n window.addEventListener(\"message\", onMessage);\n return () => window.removeEventListener(\"message\", onMessage);\n }, []);\n\n if (!src) {\n return <BlockedEmbed reason=\"Missing src\" />;\n }\n if (!isSameOriginSrc(src)) {\n return <BlockedEmbed reason=\"Cross-origin URL not allowed\" src={src} />;\n }\n\n const style: React.CSSProperties = height\n ? { height: `${height}px` }\n : { paddingBottom };\n\n return (\n <div\n className={cn(\n \"my-2 rounded-lg border border-border overflow-hidden bg-muted/20 relative w-full\",\n )}\n style={style}\n >\n {!loaded && (\n <div className=\"absolute inset-0 animate-pulse bg-muted/40\" />\n )}\n <iframe\n ref={iframeRef}\n src={src}\n title={title || \"Embedded content\"}\n sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups\"\n referrerPolicy=\"same-origin\"\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n className=\"absolute inset-0 w-full h-full border-0 bg-transparent\"\n />\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"IframeEmbed.js","sourceRoot":"","sources":["../../src/client/IframeEmbed.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport { IconAlertTriangle } from \"@tabler/icons-react\";\nimport { cn } from \"./utils.js\";\nimport { AGENT_NAVIGATE_MESSAGE_TYPE } from \"./embed.js\";\n\nexport interface IframeEmbedProps {\n src?: string;\n aspect?: string;\n title?: string;\n height?: number;\n}\n\nconst ALLOWED_ASPECTS = new Set([\"16/9\", \"4/3\", \"1/1\", \"21/9\", \"3/2\", \"2/1\"]);\n\nfunction isSameOriginSrc(src: string): boolean {\n if (typeof window === \"undefined\") return false;\n const trimmed = src.trim();\n if (!trimmed) return false;\n if (trimmed.startsWith(\"javascript:\") || trimmed.startsWith(\"data:\")) {\n return false;\n }\n if (trimmed.startsWith(\"/\") && !trimmed.startsWith(\"//\")) return true;\n if (trimmed.startsWith(\"./\") || trimmed.startsWith(\"../\")) return true;\n try {\n const url = new URL(trimmed, window.location.origin);\n return url.origin === window.location.origin;\n } catch {\n return false;\n }\n}\n\nfunction aspectToPaddingBottom(aspect: string): string {\n const [w, h] = aspect.split(\"/\").map((n) => Number(n.trim()));\n if (!w || !h) return \"56.25%\";\n return `${(h / w) * 100}%`;\n}\n\n/**\n * Parses the body of a ```embed fenced block. Accepts simple `key: value`\n * lines, ignoring blanks and unknown keys. No YAML — keeps the surface small.\n */\nexport function parseEmbedBody(body: string): Partial<IframeEmbedProps> {\n const out: Partial<IframeEmbedProps> = {};\n for (const raw of body.split(/\\r?\\n/)) {\n const line = raw.trim();\n if (!line || line.startsWith(\"#\")) continue;\n const idx = line.indexOf(\":\");\n if (idx <= 0) continue;\n const key = line.slice(0, idx).trim().toLowerCase();\n const value = line.slice(idx + 1).trim();\n if (!value) continue;\n if (key === \"src\") out.src = value;\n else if (key === \"aspect\") out.aspect = value;\n else if (key === \"title\") out.title = value;\n else if (key === \"height\") {\n const n = Number(value);\n if (Number.isFinite(n) && n > 0) out.height = n;\n }\n }\n return out;\n}\n\nfunction BlockedEmbed({ reason, src }: { reason: string; src?: string }) {\n return (\n <div className=\"my-2 rounded-lg border border-border bg-muted/40 px-3 py-2 text-xs text-muted-foreground flex items-start gap-2\">\n <IconAlertTriangle className=\"h-3.5 w-3.5 shrink-0 mt-0.5\" />\n <div className=\"min-w-0\">\n <div className=\"font-medium text-foreground\">Embed blocked</div>\n <div className=\"mt-0.5\">{reason}</div>\n {src && (\n <div className=\"mt-1 font-mono text-[10px] truncate\">{src}</div>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Inline iframe embed for assistant chat. Rendered from a ```embed fenced\n * code block. Same-origin paths only; sandboxed.\n */\nexport function IframeEmbed({ src, aspect, title, height }: IframeEmbedProps) {\n const [loaded, setLoaded] = useState(false);\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const resolvedAspect =\n aspect && ALLOWED_ASPECTS.has(aspect) ? aspect : \"16/9\";\n const displayTitle = title?.trim() || \"Embedded content\";\n const paddingBottom = useMemo(\n () => aspectToPaddingBottom(resolvedAspect),\n [resolvedAspect],\n );\n\n useEffect(() => {\n function onMessage(e: MessageEvent) {\n if (e.origin !== window.location.origin) return;\n const iframe = iframeRef.current;\n if (!iframe || e.source !== iframe.contentWindow) return;\n const data = e.data as { type?: unknown; path?: unknown } | null;\n if (!data || data.type !== AGENT_NAVIGATE_MESSAGE_TYPE) return;\n if (typeof data.path !== \"string\" || !data.path.startsWith(\"/\")) return;\n if (data.path.startsWith(\"//\")) return;\n window.history.pushState({}, \"\", data.path);\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n }\n window.addEventListener(\"message\", onMessage);\n return () => window.removeEventListener(\"message\", onMessage);\n }, []);\n\n if (!src) {\n return <BlockedEmbed reason=\"Missing src\" />;\n }\n if (!isSameOriginSrc(src)) {\n return <BlockedEmbed reason=\"Cross-origin URL not allowed\" src={src} />;\n }\n\n const style: React.CSSProperties = height\n ? { height: `${height}px` }\n : { paddingBottom };\n\n return (\n <div className=\"my-2 w-full overflow-hidden rounded-lg border border-border bg-background/60\">\n <div className=\"flex min-h-8 items-center gap-2 border-b border-border bg-muted/30 px-3 py-1.5\">\n <span className=\"shrink-0 text-[10px] font-medium uppercase text-muted-foreground\">\n Preview\n </span>\n <span aria-hidden=\"true\" className=\"h-3 w-px shrink-0 bg-border\" />\n <span\n className=\"min-w-0 flex-1 truncate text-xs font-medium text-foreground\"\n title={displayTitle}\n >\n {displayTitle}\n </span>\n </div>\n <div className=\"relative w-full bg-muted/20\" style={style}>\n {!loaded && (\n <div className=\"absolute inset-0 animate-pulse bg-muted/40\" />\n )}\n <iframe\n ref={iframeRef}\n src={src}\n title={displayTitle}\n sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups\"\n referrerPolicy=\"same-origin\"\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n className=\"absolute inset-0 h-full w-full border-0 bg-transparent\"\n />\n </div>\n </div>\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;AAehF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAsgBrE;;;;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,CA80BnB"}
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;AA0jBrE;;;;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,CAk2BnB"}
@@ -1,7 +1,7 @@
1
1
  import { setActiveRun, updateActiveRunSeq, clearActiveRun, } from "./active-run-state.js";
2
2
  import { AgentAutoContinueSignal, readSSEStream, } from "./sse-event-processor.js";
3
3
  import { agentNativePath } from "./api-path.js";
4
- import { normalizeChatError } from "./error-format.js";
4
+ import { formatChatErrorText, normalizeChatError } from "./error-format.js";
5
5
  import { captureError } from "./analytics.js";
6
6
  import { unwrapAttachmentEnvelope } from "./composer/pasted-text.js";
7
7
  const TEXT_ATTACHMENT_CONTENT_TYPES = new Set([
@@ -389,6 +389,25 @@ function authErrorReasonFromMessage(message) {
389
389
  ? "session-expired"
390
390
  : "auth-required";
391
391
  }
392
+ function authErrorText(reason, message) {
393
+ const fallback = reason === "session-expired"
394
+ ? "Your chat session expired. Refresh chat and sign in again to continue."
395
+ : "Authentication required. Sign in again to use chat.";
396
+ if (!message)
397
+ return formatChatErrorText(fallback);
398
+ try {
399
+ const parsed = JSON.parse(message);
400
+ const raw = typeof parsed.error === "string"
401
+ ? parsed.error
402
+ : typeof parsed.message === "string"
403
+ ? parsed.message
404
+ : undefined;
405
+ return formatChatErrorText(raw || fallback);
406
+ }
407
+ catch {
408
+ return formatChatErrorText(message || fallback);
409
+ }
410
+ }
392
411
  function safeAgentNativePath(path) {
393
412
  try {
394
413
  return agentNativePath(path);
@@ -408,6 +427,20 @@ function isMissingCredentialMessage(message) {
408
427
  msg.includes("no llm provider") ||
409
428
  msg.includes("llm provider is connected"));
410
429
  }
430
+ function missingCredentialErrorText(message) {
431
+ try {
432
+ const parsed = JSON.parse(message);
433
+ const raw = typeof parsed.error === "string"
434
+ ? parsed.error
435
+ : typeof parsed.message === "string"
436
+ ? parsed.message
437
+ : message;
438
+ return formatChatErrorText(raw, typeof parsed.upgradeUrl === "string" ? parsed.upgradeUrl : undefined, typeof parsed.errorCode === "string" ? parsed.errorCode : undefined);
439
+ }
440
+ catch {
441
+ return formatChatErrorText(message);
442
+ }
443
+ }
411
444
  /**
412
445
  * The composer's exec mode is sent as explicit request metadata. The server
413
446
  * owns the plan-mode prompt and read-only tool filtering so the chat history
@@ -860,7 +893,10 @@ export function createAgentChatAdapter(options) {
860
893
  continue;
861
894
  }
862
895
  dispatchAuthError("auth-required");
863
- content.push({ type: "text", text: "" });
896
+ content.push({
897
+ type: "text",
898
+ text: authErrorText("auth-required"),
899
+ });
864
900
  yield {
865
901
  content: [...content],
866
902
  status: {
@@ -877,7 +913,10 @@ export function createAgentChatAdapter(options) {
877
913
  continue;
878
914
  }
879
915
  dispatchAuthError("session-expired");
880
- content.push({ type: "text", text: "" });
916
+ content.push({
917
+ type: "text",
918
+ text: authErrorText("session-expired"),
919
+ });
881
920
  yield {
882
921
  content: [...content],
883
922
  status: {
@@ -894,8 +933,12 @@ export function createAgentChatAdapter(options) {
894
933
  if (await tryRecoverAuthOnce()) {
895
934
  continue;
896
935
  }
897
- dispatchAuthError(authErrorReasonFromMessage(body));
898
- content.push({ type: "text", text: "" });
936
+ const reason = authErrorReasonFromMessage(body);
937
+ dispatchAuthError(reason);
938
+ content.push({
939
+ type: "text",
940
+ text: authErrorText(reason, body),
941
+ });
899
942
  yield {
900
943
  content: [...content],
901
944
  status: {
@@ -909,7 +952,10 @@ export function createAgentChatAdapter(options) {
909
952
  if (typeof window !== "undefined") {
910
953
  window.dispatchEvent(new Event("agent-chat:missing-api-key"));
911
954
  }
912
- content.push({ type: "text", text: "" });
955
+ content.push({
956
+ type: "text",
957
+ text: missingCredentialErrorText(body),
958
+ });
913
959
  yield {
914
960
  content: [...content],
915
961
  status: {
@@ -1022,8 +1068,12 @@ export function createAgentChatAdapter(options) {
1022
1068
  if (await tryRecoverAuthOnce()) {
1023
1069
  continue;
1024
1070
  }
1025
- dispatchAuthError(authErrorReasonFromMessage(errMsg));
1026
- content.push({ type: "text", text: "" });
1071
+ const reason = authErrorReasonFromMessage(errMsg);
1072
+ dispatchAuthError(reason);
1073
+ content.push({
1074
+ type: "text",
1075
+ text: authErrorText(reason, errMsg),
1076
+ });
1027
1077
  yield {
1028
1078
  content: [...content],
1029
1079
  status: {
@@ -1038,7 +1088,10 @@ export function createAgentChatAdapter(options) {
1038
1088
  if (typeof window !== "undefined") {
1039
1089
  window.dispatchEvent(new Event("agent-chat:missing-api-key"));
1040
1090
  }
1041
- content.push({ type: "text", text: "" });
1091
+ content.push({
1092
+ type: "text",
1093
+ text: missingCredentialErrorText(errMsg),
1094
+ });
1042
1095
  yield {
1043
1096
  content: [...content],
1044
1097
  status: {