@agent-native/core 0.148.1 → 0.149.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 (145) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/changelog/2026-08-10-wide-tables-in-analytics-chat-now-scroll-horizontally-within.md +6 -0
  3. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +13 -53
  4. package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -70
  5. package/corpus/templates/calendar/app/lib/event-layout.ts +122 -0
  6. package/corpus/templates/calendar/app/routes/_app.availability.tsx +1 -1
  7. package/corpus/templates/calendar/changelog/2026-08-10-opening-availability-settings-from-the-agent-lands-on-the-av.md +6 -0
  8. package/corpus/templates/calendar/vitest.config.ts +6 -1
  9. package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +3 -1
  10. package/corpus/templates/clips/app/components/player/video-player.tsx +44 -4
  11. package/corpus/templates/clips/changelog/2026-08-10-fixed-transcription-failures-for-recordings-without-captured.md +6 -0
  12. package/corpus/templates/clips/changelog/2026-08-10-mobile-clips-can-now-enter-fullscreen-on-iphone-safari.md +6 -0
  13. package/corpus/templates/content/actions/_property-utils.ts +11 -1
  14. package/corpus/templates/content/actions/view-screen.ts +62 -12
  15. package/corpus/templates/content/server/plugins/agent-chat.ts +2 -0
  16. package/corpus/templates/design/.agents/skills/design-templates/SKILL.md +22 -0
  17. package/corpus/templates/design/AGENTS.md +3 -0
  18. package/corpus/templates/design/actions/create-design-from-template.ts +19 -0
  19. package/corpus/templates/design/actions/get-design-snapshot.ts +18 -0
  20. package/corpus/templates/design/actions/get-design-template.ts +178 -0
  21. package/corpus/templates/design/actions/list-designs.ts +3 -1
  22. package/corpus/templates/design/actions/view-screen.ts +31 -0
  23. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +225 -214
  24. package/corpus/templates/design/app/components/design/multi-screen/types.ts +3 -0
  25. package/corpus/templates/design/app/i18n-data.ts +78 -0
  26. package/corpus/templates/design/app/lib/design-authors.ts +64 -0
  27. package/corpus/templates/design/app/pages/Index.tsx +114 -4
  28. package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +1 -0
  29. package/corpus/templates/design/changelog/2026-08-07-alt-dragging-an-element-to-copy-it-now-keeps-the-copy-visibl.md +6 -0
  30. package/corpus/templates/design/changelog/2026-08-07-design-cards-now-show-who-created-each-design-with-a-filter-.md +6 -0
  31. package/corpus/templates/design/changelog/2026-08-07-drawing-a-shape-on-the-overview-canvas-now-keeps-the-shape-s.md +6 -0
  32. package/corpus/templates/design/changelog/2026-08-07-hold-option-alt-while-dragging-a-frame-on-the-overview-canva.md +6 -0
  33. package/corpus/templates/design/server/lib/design-template-data.ts +143 -0
  34. package/corpus/templates/design/server/plugins/agent-chat.ts +1 -0
  35. package/corpus/templates/forms/AGENTS.md +2 -2
  36. package/corpus/templates/forms/actions/create-form.ts +1 -1
  37. package/corpus/templates/forms/actions/update-form.ts +5 -5
  38. package/corpus/templates/forms/changelog/2026-08-10-forms-now-keep-agent-applied-field-changes-visible-after-an-.md +6 -0
  39. package/corpus/templates/forms/changelog/2026-08-10-published-form-links-always-use-the-working-public-form-url.md +6 -0
  40. package/corpus/templates/forms/server/plugins/agent-chat.ts +2 -2
  41. package/corpus/templates/slides/AGENTS.md +4 -3
  42. package/corpus/templates/slides/actions/import-google-slides-reference.ts +56 -10
  43. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +12 -74
  44. package/corpus/templates/slides/app/components/editor/GeneratingSlidePreview.tsx +5 -1
  45. package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +15 -4
  46. package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +116 -55
  47. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1 -0
  48. package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +143 -18
  49. package/corpus/templates/slides/app/i18n/en-US.ts +6 -0
  50. package/corpus/templates/slides/app/lib/generation-state.ts +7 -1
  51. package/corpus/templates/slides/app/pages/DeckEditor.tsx +32 -14
  52. package/corpus/templates/slides/app/pages/Index.tsx +110 -128
  53. package/corpus/templates/slides/changelog/2026-08-10-imported-reference-decks-now-show-clear-success-and-stay-sel.md +6 -0
  54. package/corpus/templates/slides/changelog/2026-08-10-pasted-google-slides-links-import-after-reconnecting-google-.md +6 -0
  55. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +4 -0
  56. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +13 -0
  57. package/corpus/templates/slides/server/plugins/agent-chat.ts +1 -1
  58. package/dist/agent/engine/registry.d.ts +8 -2
  59. package/dist/agent/engine/registry.js +63 -29
  60. package/dist/agent/production-agent.js +7 -0
  61. package/dist/agent/run-manager.d.ts +5 -4
  62. package/dist/agent/run-manager.js +6 -5
  63. package/dist/cli/claude-code-participant.d.ts +2 -1
  64. package/dist/cli/claude-code-participant.js +19 -0
  65. package/dist/cli/code-agent-executor.js +223 -0
  66. package/dist/cli/create-workspace.js +3 -3
  67. package/dist/cli/create.d.ts +3 -2
  68. package/dist/cli/create.js +20 -24
  69. package/dist/client/AgentPanel.js +8 -4
  70. package/dist/client/AssistantChat.js +34 -1
  71. package/dist/client/agent-chat-adapter.d.ts +1 -0
  72. package/dist/client/agent-chat-adapter.js +10 -2
  73. package/dist/client/chat/markdown-renderer.d.ts +1 -0
  74. package/dist/client/chat/markdown-renderer.js +4 -0
  75. package/dist/client/chat/message-components.d.ts +1 -0
  76. package/dist/client/chat/message-components.js +9 -1
  77. package/dist/client/chat/tool-call-display.d.ts +8 -0
  78. package/dist/client/chat/tool-call-display.js +30 -21
  79. package/dist/client/chat-first/app-pane.js +1 -1
  80. package/dist/client/chat-first/apps-rail.d.ts +1 -1
  81. package/dist/client/chat-first/apps-rail.js +11 -11
  82. package/dist/client/chat-first/chat-history.d.ts +1 -1
  83. package/dist/client/chat-first/chat-history.js +2 -0
  84. package/dist/client/chat-first/primary-nav.js +1 -1
  85. package/dist/client/resources/McpConnectionSuggestion.js +2 -2
  86. package/dist/client/settings/SettingsTabsPage.d.ts +3 -1
  87. package/dist/client/settings/SettingsTabsPage.js +2 -2
  88. package/dist/client/sse-event-processor.d.ts +8 -0
  89. package/dist/client/sse-event-processor.js +13 -6
  90. package/dist/collab/awareness.d.ts +2 -2
  91. package/dist/collab/routes.d.ts +1 -1
  92. package/dist/collab/struct-routes.d.ts +1 -1
  93. package/dist/deploy/build.d.ts +5 -7
  94. package/dist/deploy/build.js +19 -12
  95. package/dist/localization/default-messages.js +1 -1
  96. package/dist/notifications/routes.d.ts +3 -3
  97. package/dist/observability/routes.d.ts +6 -6
  98. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  99. package/dist/resources/handlers.d.ts +1 -1
  100. package/dist/scripts/call-agent.js +3 -3
  101. package/dist/scripts/describe-workspace-apps.js +1 -1
  102. package/dist/secrets/routes.d.ts +3 -3
  103. package/dist/server/agent-capabilities.js +0 -0
  104. package/dist/server/agent-chat/context-tools.js +1 -1
  105. package/dist/server/agent-chat/prompt-resources.js +1 -1
  106. package/dist/server/agent-chat-plugin.js +1 -1
  107. package/dist/server/auth.js +190 -42
  108. package/dist/server/better-auth-migrations.js +53 -0
  109. package/dist/server/http-response-telemetry.js +7 -1
  110. package/dist/server/onboarding-html.js +119 -33
  111. package/dist/server/transcribe-voice.d.ts +1 -1
  112. package/dist/shared/password-policy.d.ts +2 -1
  113. package/dist/shared/password-policy.js +2 -1
  114. package/dist/styles/agent-conversation.css +20 -3
  115. package/dist/styles/agent-native.css +14 -2
  116. package/dist/templates/default/app/i18n/ar-SA.ts +1 -1
  117. package/dist/templates/default/app/i18n/de-DE.ts +1 -1
  118. package/dist/templates/default/app/i18n/en-US.ts +1 -1
  119. package/dist/templates/default/app/i18n/es-ES.ts +1 -1
  120. package/dist/templates/default/app/i18n/fr-FR.ts +1 -1
  121. package/dist/templates/default/app/i18n/hi-IN.ts +1 -1
  122. package/dist/templates/default/app/i18n/ja-JP.ts +1 -1
  123. package/dist/templates/default/app/i18n/ko-KR.ts +1 -1
  124. package/dist/templates/default/app/i18n/pt-BR.ts +1 -1
  125. package/dist/templates/default/app/i18n/zh-CN.ts +1 -1
  126. package/dist/templates/default/app/i18n/zh-TW.ts +1 -1
  127. package/dist/templates/default/pnpm-workspace.yaml +1 -0
  128. package/dist/templates/workspace-root/pnpm-workspace.yaml +2 -0
  129. package/docs/content/cloneable-saas.mdx +6 -6
  130. package/docs/content/deployment.mdx +10 -8
  131. package/docs/content/environment-variables.mdx +4 -3
  132. package/package.json +2 -2
  133. package/src/templates/default/app/i18n/ar-SA.ts +1 -1
  134. package/src/templates/default/app/i18n/de-DE.ts +1 -1
  135. package/src/templates/default/app/i18n/en-US.ts +1 -1
  136. package/src/templates/default/app/i18n/es-ES.ts +1 -1
  137. package/src/templates/default/app/i18n/fr-FR.ts +1 -1
  138. package/src/templates/default/app/i18n/hi-IN.ts +1 -1
  139. package/src/templates/default/app/i18n/ja-JP.ts +1 -1
  140. package/src/templates/default/app/i18n/ko-KR.ts +1 -1
  141. package/src/templates/default/app/i18n/pt-BR.ts +1 -1
  142. package/src/templates/default/app/i18n/zh-CN.ts +1 -1
  143. package/src/templates/default/app/i18n/zh-TW.ts +1 -1
  144. package/src/templates/default/pnpm-workspace.yaml +1 -0
  145. package/src/templates/workspace-root/pnpm-workspace.yaml +2 -0
@@ -2,5 +2,5 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
2
2
  import { IconClock, IconPlus, IconPlugConnected, IconSearch, } from "@tabler/icons-react";
3
3
  import { defaultChatFirstCopy } from "./copy.js";
4
4
  export function ChatFirstPrimaryNavigation({ onNewChat, onOpenIntegrations, onOpenScheduled, onSearch, copy = defaultChatFirstCopy, }) {
5
- return (_jsxs(_Fragment, { children: [onNewChat ? (_jsxs("button", { type: "button", className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-[13px] font-medium text-sidebar-foreground/80 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: onNewChat, children: [_jsx(IconPlus, { size: 15, className: "shrink-0", "aria-hidden": "true" }), _jsx("span", { children: copy("newChat") })] })) : null, _jsxs("button", { type: "button", className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-[13px] font-medium text-sidebar-foreground/80 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: onOpenIntegrations, children: [_jsx(IconPlugConnected, { size: 15, className: "shrink-0", "aria-hidden": "true" }), _jsx("span", { children: copy("integrations") })] }), _jsxs("button", { type: "button", className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-[13px] font-medium text-sidebar-foreground/80 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: onOpenScheduled, children: [_jsx(IconClock, { size: 15, className: "shrink-0", "aria-hidden": "true" }), _jsx("span", { children: copy("scheduled") })] }), onSearch ? (_jsxs("button", { type: "button", className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-[13px] font-medium text-sidebar-foreground/80 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: onSearch, children: [_jsx(IconSearch, { size: 15, className: "shrink-0", "aria-hidden": "true" }), _jsx("span", { children: copy("search") })] })) : null] }));
5
+ return (_jsxs(_Fragment, { children: [onNewChat ? (_jsxs("button", { type: "button", className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-[13px] font-medium text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: onNewChat, children: [_jsx(IconPlus, { size: 15, className: "shrink-0", "aria-hidden": "true" }), _jsx("span", { children: copy("newChat") })] })) : null, _jsxs("button", { type: "button", className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-[13px] font-medium text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: onOpenIntegrations, children: [_jsx(IconPlugConnected, { size: 15, className: "shrink-0", "aria-hidden": "true" }), _jsx("span", { children: copy("integrations") })] }), _jsxs("button", { type: "button", className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-[13px] font-medium text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: onOpenScheduled, children: [_jsx(IconClock, { size: 15, className: "shrink-0", "aria-hidden": "true" }), _jsx("span", { children: copy("scheduled") })] }), onSearch ? (_jsxs("button", { type: "button", className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-[13px] font-medium text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: onSearch, children: [_jsx(IconSearch, { size: 15, className: "shrink-0", "aria-hidden": "true" }), _jsx("span", { children: copy("search") })] })) : null] }));
6
6
  }
@@ -145,7 +145,7 @@ export function McpConnectionSuggestion({ text, contextText = "", variant = "com
145
145
  : t("mcpIntegrations.connect");
146
146
  return (_jsxs(_Fragment, { children: [_jsxs("div", { className: variant === "response"
147
147
  ? "agent-mcp-connection-suggestion agent-mcp-connection-suggestion--response mt-3 flex max-w-[520px] items-center gap-2 rounded-lg border border-primary/20 bg-primary/5 px-3 py-2 text-[12px]"
148
- : "agent-mcp-connection-suggestion agent-mcp-connection-suggestion--composer mx-auto mb-2 flex w-[min(calc(100%_-_1.5rem),684px)] items-center gap-2 rounded-lg border border-primary/20 bg-primary/5 px-3 py-2 text-[12px]", "data-mcp-connection-suggestion": integration.id, "data-mcp-connection-suggestion-variant": variant, children: [_jsx(McpIntegrationLogo, { name: integration.name, logoUrl: integration.logoUrl, integrationId: integration.id, className: "size-6 rounded-md text-[10px]", imageClassName: "size-5" }), _jsx("span", { className: "min-w-0 flex-1 leading-snug text-foreground", children: t(hasApiFallback(apiFallback)
148
+ : "agent-mcp-connection-suggestion agent-mcp-connection-suggestion--composer mx-auto mb-2 flex w-[min(calc(100%_-_1.5rem),750px)] items-center gap-2 rounded-lg border border-primary/20 bg-primary/5 px-3 py-2 text-[12px]", "data-mcp-connection-suggestion": integration.id, "data-mcp-connection-suggestion-variant": variant, children: [_jsx(McpIntegrationLogo, { name: integration.name, logoUrl: integration.logoUrl, integrationId: integration.id, className: "size-6 rounded-md text-[10px]", imageClassName: "size-5" }), _jsx("span", { className: "min-w-0 flex-1 leading-snug text-foreground", children: t(hasApiFallback(apiFallback)
149
149
  ? "mcpIntegrations.connectSuggestionWithApiToken"
150
150
  : "mcpIntegrations.connectSuggestion", { name: integration.name }) }), _jsxs("button", { type: "button", onClick: () => void connect(), disabled: connecting, "aria-busy": connecting, className: "inline-flex shrink-0 items-center gap-1 rounded-md bg-primary px-2.5 py-1.5 text-[11px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-60", children: [connecting && _jsx(IconLoader2, { className: "h-3 w-3 animate-spin" }), !connecting &&
151
151
  canStartOAuth(integration) &&
@@ -153,7 +153,7 @@ export function McpConnectionSuggestion({ text, contextText = "", variant = "com
153
153
  !canStartOAuth(integration) &&
154
154
  !hasApiFallback(apiFallback) && (_jsx(IconArrowUpRight, { className: "h-3 w-3" }))] }), _jsx("button", { type: "button", onClick: () => setDismissedId(integration.id), className: "inline-flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-background hover:text-foreground", "aria-label": t("mcpIntegrations.dismissSuggestion"), children: _jsx(IconX, { className: "h-3.5 w-3.5" }) })] }), error && (_jsx("div", { className: variant === "response"
155
155
  ? "agent-mcp-connection-suggestion-error agent-mcp-connection-suggestion-error--response mt-1 max-w-[520px] text-[11px] text-destructive"
156
- : "agent-mcp-connection-suggestion-error agent-mcp-connection-suggestion-error--composer mx-auto mb-2 w-[min(calc(100%_-_1.5rem),684px)] text-[11px] text-destructive", children: error })), _jsx(McpIntegrationDialog, { open: dialogOpen, onOpenChange: (open) => {
156
+ : "agent-mcp-connection-suggestion-error agent-mcp-connection-suggestion-error--composer mx-auto mb-2 w-[min(calc(100%_-_1.5rem),750px)] text-[11px] text-destructive", children: error })), _jsx(McpIntegrationDialog, { open: dialogOpen, onOpenChange: (open) => {
157
157
  setDialogOpen(open);
158
158
  if (!open)
159
159
  clearMcpConnectionResume();
@@ -60,6 +60,8 @@ export interface SettingsTabsPageProps {
60
60
  defaultTab?: string;
61
61
  className?: string;
62
62
  navClassName?: string;
63
+ /** Optional content rendered at the top of the settings navigation rail. */
64
+ navHeader?: ReactNode;
63
65
  contentClassName?: string;
64
66
  /** Whether to render the settings search box. Defaults to true. */
65
67
  enableSearch?: boolean;
@@ -83,5 +85,5 @@ export interface SettingsTabsPageProps {
83
85
  */
84
86
  onValueChange?: (tabId: string) => void;
85
87
  }
86
- export declare function SettingsTabsPage({ general, account, team, whatsNew, extraTabs, generalLabel, accountLabel, teamLabel, whatsNewLabel, ariaLabel, defaultTab, className, navClassName, contentClassName, enableSearch, searchPlaceholder, searchEntries, generalSearchEntries, value, onValueChange, }: SettingsTabsPageProps): import("react").JSX.Element;
88
+ export declare function SettingsTabsPage({ general, account, team, whatsNew, extraTabs, generalLabel, accountLabel, teamLabel, whatsNewLabel, ariaLabel, defaultTab, className, navClassName, navHeader, contentClassName, enableSearch, searchPlaceholder, searchEntries, generalSearchEntries, value, onValueChange, }: SettingsTabsPageProps): import("react").JSX.Element;
87
89
  export {};
@@ -118,7 +118,7 @@ function isEditableElement(element) {
118
118
  tagName === "select" ||
119
119
  element.isContentEditable);
120
120
  }
121
- export function SettingsTabsPage({ general, account, team, whatsNew, extraTabs = [], generalLabel = "General", accountLabel = "Account", teamLabel = "Team", whatsNewLabel = "What's new", ariaLabel = "Settings sections", defaultTab = "general", className, navClassName, contentClassName, enableSearch = true, searchPlaceholder = "Search settings", searchEntries, generalSearchEntries, value, onValueChange, }) {
121
+ export function SettingsTabsPage({ general, account, team, whatsNew, extraTabs = [], generalLabel = "General", accountLabel = "Account", teamLabel = "Team", whatsNewLabel = "What's new", ariaLabel = "Settings sections", defaultTab = "general", className, navClassName, navHeader, contentClassName, enableSearch = true, searchPlaceholder = "Search settings", searchEntries, generalSearchEntries, value, onValueChange, }) {
122
122
  const rootRef = useRef(null);
123
123
  const searchInputRef = useRef(null);
124
124
  const autoFocusedSearchRef = useRef(false);
@@ -375,7 +375,7 @@ export function SettingsTabsPage({ general, account, team, whatsNew, extraTabs =
375
375
  }
376
376
  };
377
377
  const searching = enableSearch && trimmedQuery.length > 0;
378
- return (_jsxs("div", { ref: rootRef, className: cn("flex h-full min-h-0 w-full flex-col overflow-hidden bg-background sm:flex-row", className), children: [_jsxs("div", { className: cn("flex shrink-0 flex-col gap-2 bg-background p-2 sm:min-h-0 sm:w-60 sm:overflow-y-auto sm:p-4", navClassName), children: [enableSearch ? (_jsxs("div", { className: "relative sm:mb-2", children: [_jsx(IconSearch, { className: "pointer-events-none absolute start-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground" }), _jsx("input", { ref: searchInputRef, type: "search", value: query, onChange: (event) => setQuery(event.target.value), onKeyDown: (event) => {
378
+ return (_jsxs("div", { ref: rootRef, className: cn("flex h-full min-h-0 w-full flex-col overflow-hidden bg-background sm:flex-row", className), children: [_jsxs("div", { className: cn("flex shrink-0 flex-col gap-2 bg-background p-2 sm:min-h-0 sm:w-60 sm:overflow-y-auto sm:p-4", navClassName), children: [navHeader, enableSearch ? (_jsxs("div", { className: "relative sm:mb-2", children: [_jsx(IconSearch, { className: "pointer-events-none absolute start-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground" }), _jsx("input", { ref: searchInputRef, type: "search", value: query, onChange: (event) => setQuery(event.target.value), onKeyDown: (event) => {
379
379
  if (event.key === "Escape")
380
380
  setQuery("");
381
381
  if (event.key === "Enter" && results[0]) {
@@ -188,6 +188,14 @@ export interface SSEStreamOptions {
188
188
  * the tight foreground 75s/90s windows.
189
189
  */
190
190
  durableBackgroundRun?: boolean;
191
+ /**
192
+ * Optional reader-local watchdog override. A background follow reader can
193
+ * use a shorter value because a timeout only detaches that read; the follow
194
+ * loop immediately re-checks the server-owned run state.
195
+ */
196
+ noProgressTimeoutMs?: number;
197
+ /** Reader-local counterpart to `noProgressTimeoutMs` for action preparation. */
198
+ actionPreparationStallTimeoutMs?: number;
191
199
  /**
192
200
  * Optional caller-owned preparation watchdog state. Passing the same object
193
201
  * across reconnect reads keeps a stuck action preparation from getting a
@@ -113,15 +113,22 @@ export function sseInFlightWorkDelta(ev) {
113
113
  */
114
114
  export const SSE_DURABLE_NO_PROGRESS_TIMEOUT_MS = 13 * 60_000;
115
115
  export const SSE_DURABLE_ACTION_PREPARATION_STALL_TIMEOUT_MS = 13 * 60_000;
116
+ function sseTimeoutOverrideMs(value) {
117
+ return typeof value === "number" && Number.isFinite(value) && value >= 0
118
+ ? value
119
+ : undefined;
120
+ }
116
121
  export function sseNoProgressTimeoutMs(options) {
117
- return options?.durableBackgroundRun === true
118
- ? SSE_DURABLE_NO_PROGRESS_TIMEOUT_MS
119
- : SSE_NO_PROGRESS_TIMEOUT_MS;
122
+ return (sseTimeoutOverrideMs(options?.noProgressTimeoutMs) ??
123
+ (options?.durableBackgroundRun === true
124
+ ? SSE_DURABLE_NO_PROGRESS_TIMEOUT_MS
125
+ : SSE_NO_PROGRESS_TIMEOUT_MS));
120
126
  }
121
127
  function sseActionPreparationStallTimeoutMs(options) {
122
- return options?.durableBackgroundRun === true
123
- ? SSE_DURABLE_ACTION_PREPARATION_STALL_TIMEOUT_MS
124
- : SSE_ACTION_PREPARATION_STALL_TIMEOUT_MS;
128
+ return (sseTimeoutOverrideMs(options?.actionPreparationStallTimeoutMs) ??
129
+ (options?.durableBackgroundRun === true
130
+ ? SSE_DURABLE_ACTION_PREPARATION_STALL_TIMEOUT_MS
131
+ : SSE_ACTION_PREPARATION_STALL_TIMEOUT_MS));
125
132
  }
126
133
  function activityProgressBytes(ev) {
127
134
  return typeof ev.progressBytes === "number" &&
@@ -62,11 +62,11 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
62
62
  error: string;
63
63
  states?: undefined;
64
64
  } | {
65
- error?: undefined;
66
65
  states: {
67
66
  clientId: number;
68
67
  state: string;
69
68
  }[];
69
+ error?: undefined;
70
70
  }>>;
71
71
  /**
72
72
  * GET /_agent-native/collab/:docId/users
@@ -77,9 +77,9 @@ export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("
77
77
  error: string;
78
78
  users?: undefined;
79
79
  } | {
80
- error?: undefined;
81
80
  users: {
82
81
  clientId: number;
83
82
  lastSeen: number;
84
83
  }[];
84
+ error?: undefined;
85
85
  }>>;
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
26
26
  * Body: { update: string (base64), requestSource?: string }
27
27
  */
28
28
  export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
29
- error: string;
30
29
  ok?: undefined;
30
+ error: string;
31
31
  } | {
32
32
  error?: undefined;
33
33
  ok: boolean;
@@ -13,8 +13,8 @@
13
13
  * Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
14
14
  */
15
15
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
16
- ok?: undefined;
17
16
  error: string;
17
+ ok?: undefined;
18
18
  } | {
19
19
  error?: undefined;
20
20
  ok: boolean;
@@ -103,12 +103,9 @@ export declare function isIntegrationDurableDispatchDeployEnabled(): boolean;
103
103
  export declare const NETLIFY_RECURRING_JOBS_FUNCTION_NAME = "agent-native-recurring-jobs";
104
104
  export declare function isRecurringJobsDeployEnabled(): boolean;
105
105
  /**
106
- * Keep-warm is ON by default, and on a provisioned database that is the right
107
- * default. It is the wrong default on a metered scale-to-zero tier: a
108
- * once-a-minute wake means autosuspend NEVER fires, so the endpoint bills (and
109
- * quota-limits) as if it were awake 100% of the time with zero users online. On
110
- * a free-tier Neon that exhausts the compute quota and the database then
111
- * hard-blocks every read mid-session — the symptom is a dead app, not a slow one.
106
+ * Keep-warm is opt-in because a once-a-minute wake prevents autosuspend on
107
+ * metered scale-to-zero databases. `AGENT_NATIVE_DISABLE_KEEP_WARM` remains a
108
+ * compatibility kill switch and wins when both flags are set.
112
109
  */
113
110
  export declare function isKeepWarmDeployEnabled(): boolean;
114
111
  /**
@@ -138,7 +135,8 @@ export declare function resolveKeepWarmSchedule(): string;
138
135
  * delayed by tens of minutes, which is longer than a scale-to-zero database's
139
136
  * autosuspend window and leaves the next visitor to pay the cold-start cost.
140
137
  *
141
- * Both halves are opt-out and the cadence is configurable — see
138
+ * The feature is opt-in, the background half has its own kill switch, and the
139
+ * cadence is configurable — see
142
140
  * `isKeepWarmDeployEnabled`, `isKeepWarmBackgroundDeployEnabled`, and
143
141
  * `resolveKeepWarmSchedule`. The tradeoff this function encodes is next-visitor
144
142
  * latency against database awake-time, and only the deployment knows which of
@@ -2256,24 +2256,26 @@ export function isIntegrationDurableDispatchDeployEnabled() {
2256
2256
  }
2257
2257
  const NETLIFY_KEEP_WARM_FUNCTION_NAME = "agent-native-keep-warm";
2258
2258
  export const NETLIFY_RECURRING_JOBS_FUNCTION_NAME = "agent-native-recurring-jobs";
2259
- /** Shared shape for the `AGENT_NATIVE_DISABLE_*` build kill switches. */
2260
- function isDisabledByEnv(name) {
2259
+ /** Shared parser for truthy build environment flags. */
2260
+ function isTruthyEnv(name) {
2261
2261
  const value = process.env[name]?.trim();
2262
2262
  return !!value && ["1", "true", "yes", "on"].includes(value.toLowerCase());
2263
2263
  }
2264
+ /** Shared shape for the `AGENT_NATIVE_DISABLE_*` build kill switches. */
2265
+ function isDisabledByEnv(name) {
2266
+ return isTruthyEnv(name);
2267
+ }
2264
2268
  export function isRecurringJobsDeployEnabled() {
2265
2269
  return !isDisabledByEnv("AGENT_NATIVE_DISABLE_RECURRING_JOBS");
2266
2270
  }
2267
2271
  /**
2268
- * Keep-warm is ON by default, and on a provisioned database that is the right
2269
- * default. It is the wrong default on a metered scale-to-zero tier: a
2270
- * once-a-minute wake means autosuspend NEVER fires, so the endpoint bills (and
2271
- * quota-limits) as if it were awake 100% of the time with zero users online. On
2272
- * a free-tier Neon that exhausts the compute quota and the database then
2273
- * hard-blocks every read mid-session — the symptom is a dead app, not a slow one.
2272
+ * Keep-warm is opt-in because a once-a-minute wake prevents autosuspend on
2273
+ * metered scale-to-zero databases. `AGENT_NATIVE_DISABLE_KEEP_WARM` remains a
2274
+ * compatibility kill switch and wins when both flags are set.
2274
2275
  */
2275
2276
  export function isKeepWarmDeployEnabled() {
2276
- return !isDisabledByEnv("AGENT_NATIVE_DISABLE_KEEP_WARM");
2277
+ return (isTruthyEnv("AGENT_NATIVE_ENABLE_KEEP_WARM") &&
2278
+ !isDisabledByEnv("AGENT_NATIVE_DISABLE_KEEP_WARM"));
2277
2279
  }
2278
2280
  /**
2279
2281
  * The background warm is a separate, much more expensive knob than the server
@@ -2286,7 +2288,8 @@ export function isKeepWarmDeployEnabled() {
2286
2288
  * while dropping the probe storm.
2287
2289
  */
2288
2290
  export function isKeepWarmBackgroundDeployEnabled() {
2289
- return !isDisabledByEnv("AGENT_NATIVE_DISABLE_KEEP_WARM_BACKGROUND");
2291
+ return (isKeepWarmDeployEnabled() &&
2292
+ !isDisabledByEnv("AGENT_NATIVE_DISABLE_KEEP_WARM_BACKGROUND"));
2290
2293
  }
2291
2294
  const DEFAULT_KEEP_WARM_SCHEDULE = "* * * * *";
2292
2295
  /**
@@ -2319,7 +2322,8 @@ export function resolveKeepWarmSchedule() {
2319
2322
  * delayed by tens of minutes, which is longer than a scale-to-zero database's
2320
2323
  * autosuspend window and leaves the next visitor to pay the cold-start cost.
2321
2324
  *
2322
- * Both halves are opt-out and the cadence is configurable — see
2325
+ * The feature is opt-in, the background half has its own kill switch, and the
2326
+ * cadence is configurable — see
2323
2327
  * `isKeepWarmDeployEnabled`, `isKeepWarmBackgroundDeployEnabled`, and
2324
2328
  * `resolveKeepWarmSchedule`. The tradeoff this function encodes is next-visitor
2325
2329
  * latency against database awake-time, and only the deployment knows which of
@@ -2327,7 +2331,10 @@ export function resolveKeepWarmSchedule() {
2327
2331
  */
2328
2332
  export function emitSingleTemplateNetlifyKeepWarmFunction(projectCwd) {
2329
2333
  if (!isKeepWarmDeployEnabled()) {
2330
- console.log("[build] Keep-warm emit skipped: AGENT_NATIVE_DISABLE_KEEP_WARM is set. " +
2334
+ const reason = isDisabledByEnv("AGENT_NATIVE_DISABLE_KEEP_WARM")
2335
+ ? "AGENT_NATIVE_DISABLE_KEEP_WARM is set."
2336
+ : "AGENT_NATIVE_ENABLE_KEEP_WARM is not enabled.";
2337
+ console.log(`[build] Keep-warm emit skipped: ${reason} ` +
2331
2338
  "The database is free to autosuspend; the next visitor after an idle " +
2332
2339
  "period pays its cold start.");
2333
2340
  return;
@@ -434,7 +434,7 @@ const messages = {
434
434
  newTerminal: "New terminal",
435
435
  panelOptions: "Agent panel options",
436
436
  collapseSidebar: "Collapse sidebar",
437
- widenChat: "Widen chat to 75%",
437
+ widenChat: "Widen chat",
438
438
  returnChatToLayout: "Return chat to layout",
439
439
  expandSidebar: "Expand sidebar",
440
440
  hideChats: "Hide chats",
@@ -11,14 +11,14 @@
11
11
  * DELETE /_agent-native/notifications/:id — delete
12
12
  */
13
13
  export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
14
- error?: undefined;
15
14
  count: number;
16
15
  updated?: undefined;
16
+ error?: undefined;
17
17
  ok?: undefined;
18
18
  } | {
19
- error?: undefined;
20
19
  count?: undefined;
21
20
  updated: number;
21
+ error?: undefined;
22
22
  ok?: undefined;
23
23
  } | {
24
24
  count?: undefined;
@@ -26,8 +26,8 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
26
26
  error: string;
27
27
  ok?: undefined;
28
28
  } | {
29
- error?: undefined;
30
29
  count?: undefined;
31
30
  updated?: undefined;
31
+ error?: undefined;
32
32
  ok: boolean;
33
33
  }>>;
@@ -41,27 +41,27 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
41
41
  thumbsUpRate: number;
42
42
  avgEvalScore: number;
43
43
  } | {
44
- ok?: undefined;
45
- error?: undefined;
46
44
  summary: import("./types.js").TraceSummary;
47
45
  spans: import("./types.js").TraceSpan[];
48
46
  id?: undefined;
49
- } | {
50
- ok?: undefined;
51
47
  error?: undefined;
48
+ ok?: undefined;
49
+ } | {
52
50
  summary?: undefined;
53
51
  spans?: undefined;
54
52
  id: string;
55
- } | {
53
+ error?: undefined;
56
54
  ok?: undefined;
55
+ } | {
57
56
  summary?: undefined;
58
57
  spans?: undefined;
59
58
  id?: undefined;
60
59
  error: any;
60
+ ok?: undefined;
61
61
  } | {
62
- error?: undefined;
63
62
  summary?: undefined;
64
63
  spans?: undefined;
65
64
  id?: undefined;
66
65
  ok: boolean;
66
+ error?: undefined;
67
67
  }>>;
@@ -311,8 +311,8 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
311
311
  notes?: string | undefined;
312
312
  scope?: "org" | "user" | undefined;
313
313
  }, {
314
- id?: undefined;
315
314
  deleted?: undefined;
315
+ id?: undefined;
316
316
  providers: {
317
317
  id: string;
318
318
  label: string;
@@ -329,9 +329,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
329
329
  label?: undefined;
330
330
  message?: undefined;
331
331
  } | {
332
- id?: undefined;
333
332
  deleted?: undefined;
334
333
  count?: undefined;
334
+ id?: undefined;
335
335
  providers?: undefined;
336
336
  found: boolean;
337
337
  provider: import("../custom-registry.js").CustomProviderConfig;
@@ -48,8 +48,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
48
48
  }>;
49
49
  /** DELETE /_agent-native/resources/:id — delete a resource */
50
50
  export declare function handleDeleteResource(event: any): Promise<{
51
- error: string;
52
51
  ok?: undefined;
52
+ error: string;
53
53
  } | {
54
54
  error?: undefined;
55
55
  ok: boolean;
@@ -219,7 +219,7 @@ function formatDownstreamLlmCredentialFailure(agentName, value) {
219
219
  : null;
220
220
  }
221
221
  export const tool = {
222
- description: "Ask a DIFFERENT, separately-deployed app's agent over A2A. Use message by default so the receiving specialist interprets the objective with its own instructions, skills, connected sources, data dictionary, and tools. The receiver owns provider, schema, query, join, and SQL decisions. Use action + input only for an exact, explicitly known, bounded read whose complete input schema is already known; never expose or call a direct action to work around slow or unreliable delegation, and never guess receiver-owned query logic. NEVER use this to call your own app or perform actions you can do with your own tools. Using call-agent on yourself will fail and waste time. " +
222
+ description: "Ask a DIFFERENT, separately-deployed app's agent over A2A. Use message by default so the receiving specialist interprets the objective with its own instructions, skills, connected sources, data dictionary, and tools. The receiver owns provider, schema, query, join, and SQL decisions. Use action + input only for an exact, explicitly known, bounded read whose complete input schema is already known. Never put a create, update, delete, send, save, publish, or any other side effect in action; omit action and send the objective as message instead; never expose or call a direct action to work around slow or unreliable delegation, and never guess receiver-owned query logic. NEVER use this to call your own app or perform actions you can do with your own tools. Using call-agent on yourself will fail and waste time. " +
223
223
  'For brand-consistent generated media, the first-party Assets agent is available as agent="assets"; use it when another app needs generated heroes, diagrams, product shots, thumbnails, videos, or design imagery, unless the current app has its own generation action that already delegates there. ' +
224
224
  "IMPORTANT — handling the response: " +
225
225
  "(a) If it contains a URL or ID, copy it VERBATIM into your reply. Do not 'correct' or pluralize the path (e.g. /deck/ → /decks/), normalize casing, or change the slug — any edit breaks the link. " +
@@ -243,11 +243,11 @@ export const tool = {
243
243
  },
244
244
  action: {
245
245
  type: "string",
246
- description: "Optional exact read-only action for an explicitly known bounded operation. Prefer message when the target agent must interpret data, choose sources or tools, synthesize, mutate, or do multi-step work. Never guess the action schema or send receiver-owned SQL.",
246
+ description: "Optional exact read-only action for an explicitly known bounded operation. This field is never for creates, updates, deletes, sends, saves, publishes, or any other side effect. Prefer message when the target agent must interpret data, choose sources or tools, synthesize, mutate, or do multi-step work. Never guess the action schema or send receiver-owned SQL.",
247
247
  },
248
248
  input: {
249
249
  type: "object",
250
- description: "Complete input object for action. The target app validates it and refuses actions that are not explicitly exposed read-only operations.",
250
+ description: "Complete input object for action. The target app validates it and refuses actions that are not explicitly exposed read-only operations. For a mutating request, omit action and use message.",
251
251
  additionalProperties: true,
252
252
  },
253
253
  approvedActions: {
@@ -22,7 +22,7 @@ export async function run(args, _context, selfAppId) {
22
22
  .join(", ");
23
23
  return `Error: no workspace app "${requested}". Available: ${available || "(none)"}`;
24
24
  }
25
- return formatCapabilityDetail(await loadCapabilities(agent), (appId) => `Ask this specialist with call-agent: agent="${appId}", message="<objective>". Use action + input only for an exact bounded read with a fully known schema.`);
25
+ return formatCapabilityDetail(await loadCapabilities(agent), (appId) => `Ask this specialist with call-agent: agent="${appId}", message="<objective>". Use action + input only for an exact bounded read with a fully known schema; use message for creates, updates, deletes, sends, saves, publishes, or any other side effect.`);
26
26
  }
27
27
  const agents = await discoverAgents(selfAppId);
28
28
  if (agents.length === 0) {
@@ -34,16 +34,16 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
34
34
  /** POST /_agent-native/secrets/:key — write a secret. */
35
35
  export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
36
36
  error: string;
37
- status?: undefined;
38
37
  ok?: undefined;
38
+ status?: undefined;
39
39
  } | {
40
40
  ok: boolean;
41
41
  status: string;
42
42
  error?: undefined;
43
43
  } | {
44
+ ok?: undefined;
44
45
  error: string;
45
46
  removed?: undefined;
46
- ok?: undefined;
47
47
  } | {
48
48
  ok: boolean;
49
49
  removed: boolean;
@@ -54,9 +54,9 @@ export declare function createWriteSecretHandler(): import("h3").EventHandlerWit
54
54
  * or the current stored value without changing anything.
55
55
  */
56
56
  export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
57
+ ok?: undefined;
57
58
  error: string;
58
59
  note?: undefined;
59
- ok?: undefined;
60
60
  } | {
61
61
  ok: boolean;
62
62
  note?: undefined;
Binary file
@@ -138,7 +138,7 @@ Prefer \`web-request\` for simple API calls and static pages. Use browser automa
138
138
 
139
139
  The \`call-agent\` tool sends a message to a DIFFERENT, separately-deployed app's agent (A2A protocol). It is **not** for calling actions within the current app.
140
140
 
141
- Use a natural-language \`message\` by default. The receiving app owns interpretation and runs with its own instructions, skills, connected sources, data dictionary, and tools. Do not choose its provider, schema, query, joins, or SQL for it. A direct \`action\` + \`input\` call is only for an exact bounded read whose complete contract is already known; it is never a workaround for unreliable delegation.
141
+ Use a natural-language \`message\` by default. The receiving app owns interpretation and runs with its own instructions, skills, connected sources, data dictionary, and tools. Do not choose its provider, schema, query, joins, or SQL for it. A direct \`action\` + \`input\` call is only for an exact bounded read whose complete contract is already known; it is never for a create, update, delete, send, save, publish, or other side effect, and it is never a workaround for unreliable delegation.
142
142
 
143
143
  **NEVER use \`call-agent\` to:**
144
144
  - Call your own app by name
@@ -787,7 +787,7 @@ export async function loadResourcesForPrompt(owner, compact = false, selfAppId,
787
787
  // Nothing else in the prompt or the initial tool surface tells the agent
788
788
  // which peer apps exist, so this block is not droppable: without it the
789
789
  // agent reports cross-app work as impossible instead of delegating.
790
- addSection(`<available-apps>\nWorkspace apps available over A2A/call-agent:\n${lines.join("\n")}\n\nWhen another app owns the work or data, use \`call-agent\` with the app id and a natural-language message. The receiving specialist owns source selection, schema interpretation, queries, joins, and use of its local tools. Direct action invocation is optional for an exact bounded read with a fully known schema; never use it to compensate for unreliable delegation.\n\nThese one-liners are the only cross-app detail in this prompt. Before building a capability another app may already own, before telling the user what is or is not possible across apps, and whenever the user asks which app to use, call \`describe-workspace-apps\` - it reads each peer's live agent card for current purpose and optional capability details. Never hand-maintain a list of workspace apps in code or docs; it goes stale silently.\n</available-apps>`, "required");
790
+ addSection(`<available-apps>\nWorkspace apps available over A2A/call-agent:\n${lines.join("\n")}\n\nWhen another app owns the work or data, use \`call-agent\` with the app id and a natural-language message. The receiving specialist owns source selection, schema interpretation, queries, joins, and use of its local tools. Direct action invocation is only for an explicitly read-only bounded action with a fully known schema. Never put creates, updates, deletes, sends, saves, publishes, or other side effects in direct action mode; put those objectives in the natural-language message.\n\nThese one-liners are the only cross-app detail in this prompt. Before building a capability another app may already own, before telling the user what is or is not possible across apps, and whenever the user asks which app to use, call \`describe-workspace-apps\` - it reads each peer's live agent card for current purpose and optional capability details. Never hand-maintain a list of workspace apps in code or docs; it goes stale silently.\n</available-apps>`, "required");
791
791
  }
792
792
  }
793
793
  catch {
@@ -1081,7 +1081,7 @@ export function createAgentChatPlugin(options) {
1081
1081
  if (!entry) {
1082
1082
  return {
1083
1083
  status: "failed",
1084
- output: "Unknown or unavailable read-only action",
1084
+ output: "Unknown or unavailable read-only action. Direct cross-app action mode only accepts explicitly exposed read-only operations; retry creates, updates, deletes, sends, saves, publishes, and other side effects with a natural-language message.",
1085
1085
  };
1086
1086
  }
1087
1087
  const result = await executeAgentToolCall({