@agent-native/core 0.149.6 → 0.151.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 (177) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  3. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +83 -45
  4. package/corpus/templates/analytics/changelog/2026-08-11-analytics-dashboards-keep-the-selected-tab-when-reopened.md +6 -0
  5. package/corpus/templates/assets/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  6. package/corpus/templates/brain/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  7. package/corpus/templates/calendar/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  8. package/corpus/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  9. package/corpus/templates/clips/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  10. package/corpus/templates/clips/changelog/2026-08-11-clips-recovers-from-transient-updates-and-avoids-macos-priva.md +6 -0
  11. package/corpus/templates/clips/desktop/src/app.tsx +32 -176
  12. package/corpus/templates/clips/desktop/src/lib/updater.ts +52 -37
  13. package/corpus/templates/clips/desktop/src/styles.css +1 -166
  14. package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +2 -0
  15. package/corpus/templates/clips/desktop/src-tauri/Info.plist +4 -0
  16. package/corpus/templates/clips/desktop/src-tauri/src/eventkit.rs +28 -1
  17. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -0
  18. package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +48 -1
  19. package/corpus/templates/clips/desktop/src-tauri/src/permission_status.rs +3 -0
  20. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +5 -0
  21. package/corpus/templates/clips/server/plugins/auth.ts +3 -0
  22. package/corpus/templates/content/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  23. package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +2 -1
  24. package/corpus/templates/design/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  25. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +5 -1
  26. package/corpus/templates/design/changelog/2026-08-11-design-agent-prompts-copy-successfully-in-the-desktop-app.md +6 -0
  27. package/corpus/templates/dispatch/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  28. package/corpus/templates/dispatch/app/global.css +2 -2
  29. package/corpus/templates/dispatch/changelog/2026-08-10-desktop-workspace-sign-in.md +6 -0
  30. package/corpus/templates/dispatch/changelog/2026-08-11-dispatch-no-longer-shows-the-generic-chat-starter-among-defa.md +6 -0
  31. package/corpus/templates/dispatch/changelog/2026-08-11-integrations-and-scheduled-work-open-as-first-class-electron-pages.md +6 -0
  32. package/corpus/templates/dispatch/changelog/2026-08-11-sidebar-text-is-slightly-easier-to-read-in-light-and-dark-mo.md +6 -0
  33. package/corpus/templates/dispatch/server/lib/identity-sso.ts +57 -31
  34. package/corpus/templates/dispatch/server/plugins/feature-flags.ts +5 -0
  35. package/corpus/templates/dispatch/server/plugins/identity-sso.ts +82 -33
  36. package/corpus/templates/dispatch/server/plugins/org-apps-directory.ts +7 -15
  37. package/corpus/templates/dispatch/server/plugins/setup-dispatch.ts +9 -1
  38. package/corpus/templates/dispatch/shared/feature-flags.ts +15 -0
  39. package/corpus/templates/factory/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  40. package/corpus/templates/forms/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  41. package/corpus/templates/forms/.agents/skills/form-responses/SKILL.md +8 -7
  42. package/corpus/templates/forms/app/hooks/use-forms.ts +8 -1
  43. package/corpus/templates/forms/changelog/2026-08-11-fixed-public-forms-so-conditional-questions-stay-hidden-unti.md +6 -0
  44. package/corpus/templates/forms/server/handlers/submissions.ts +2 -1
  45. package/corpus/templates/forms/server/lib/public-form-ssr.ts +37 -2
  46. package/corpus/templates/forms/shared/page-url.ts +54 -0
  47. package/corpus/templates/forms/shared/types.ts +4 -4
  48. package/corpus/templates/mail/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  49. package/corpus/templates/plan/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  50. package/corpus/templates/slides/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  51. package/corpus/templates/slides/actions/add-slide.ts +0 -27
  52. package/corpus/templates/slides/actions/import-file.ts +28 -9
  53. package/corpus/templates/slides/actions/view-screen.ts +4 -4
  54. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +8 -1
  55. package/corpus/templates/slides/app/components/editor/AiEditingMarker.tsx +25 -0
  56. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +43 -48
  57. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +9 -6
  58. package/corpus/templates/slides/app/components/editor/GeneratingSlidePreview.tsx +1 -9
  59. package/corpus/templates/slides/app/components/editor/ImageDropPromptPopover.tsx +2 -0
  60. package/corpus/templates/slides/app/components/editor/ImageOverlay.tsx +0 -26
  61. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +904 -217
  62. package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +1 -0
  63. package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +11 -0
  64. package/corpus/templates/slides/app/components/editor/inline-edit-session.ts +16 -0
  65. package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +22 -6
  66. package/corpus/templates/slides/app/components/editor/style-clipboard.ts +61 -0
  67. package/corpus/templates/slides/app/components/layout/Layout.tsx +26 -2
  68. package/corpus/templates/slides/app/components/ui/context-menu.tsx +1 -0
  69. package/corpus/templates/slides/app/context/DeckContext.tsx +75 -25
  70. package/corpus/templates/slides/app/global.css +1 -1
  71. package/corpus/templates/slides/app/i18n/en-US.ts +6 -1
  72. package/corpus/templates/slides/app/lib/create-deck-generation.ts +1 -1
  73. package/corpus/templates/slides/app/lib/image-drop-to-agent.ts +12 -12
  74. package/corpus/templates/slides/app/lib/slide-agent-context.ts +52 -0
  75. package/corpus/templates/slides/app/lib/slide-image-replacement.ts +61 -0
  76. package/corpus/templates/slides/app/pages/DeckEditor.tsx +55 -116
  77. package/corpus/templates/slides/app/pages/Index.tsx +28 -3
  78. package/corpus/templates/slides/changelog/2026-08-11-agent-chat-now-follows-the-current-slide-and-selection.md +6 -0
  79. package/corpus/templates/slides/changelog/2026-08-11-deck-titles-now-use-slide-content-instead-of-placeholder-filenames.md +6 -0
  80. package/corpus/templates/slides/changelog/2026-08-11-history-now-opens-from-the-deck-overflow-menu.md +6 -0
  81. package/corpus/templates/slides/changelog/2026-08-11-images-can-be-dropped-directly-onto-slides-and-resized-or-re.md +6 -0
  82. package/corpus/templates/slides/changelog/2026-08-11-new-decks-now-transition-directly-to-a-full-page-editor-load.md +6 -0
  83. package/corpus/templates/slides/changelog/2026-08-11-selected-slide-layers-can-be-nudged-precisely-with-arrow-key.md +6 -0
  84. package/corpus/templates/slides/changelog/2026-08-11-slides-can-copy-and-paste-element-styles-with-cmd-option-c-v.md +6 -0
  85. package/corpus/templates/slides/changelog/2026-08-11-slides-shows-one-compact-ai-marker-and-keeps-your-current-sl.md +6 -0
  86. package/corpus/templates/slides/changelog/2026-08-11-text-edits-preserve-slide-layout-when-no-changes-are-made.md +6 -0
  87. package/corpus/templates/slides/changelog/2026-08-11-the-style-toolbar-now-uses-the-full-available-width.md +6 -0
  88. package/corpus/templates/slides/changelog/2026-08-11-undo-and-redo-now-move-one-visible-slide-state-at-a-time.md +6 -0
  89. package/corpus/templates/slides/server/lib/chat-attachments.ts +6 -2
  90. package/corpus/templates/slides/shared/deck-title.ts +56 -0
  91. package/corpus/templates/tasks/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  92. package/dist/agent/run-store.js +6 -1
  93. package/dist/agent/thread-data-builder.js +19 -44
  94. package/dist/agent/types.d.ts +13 -0
  95. package/dist/catalog.json +1 -0
  96. package/dist/cli/create.js +1 -1
  97. package/dist/client/AssistantChat.js +58 -10
  98. package/dist/client/FileStorageSetupCard.d.ts +6 -0
  99. package/dist/client/FileStorageSetupCard.js +18 -0
  100. package/dist/client/NewWorkspaceAppFlow.js +10 -0
  101. package/dist/client/agent-chat-adapter.js +87 -11
  102. package/dist/client/agent-chat.d.ts +1 -1
  103. package/dist/client/agent-chat.js +8 -3
  104. package/dist/client/chat/attachment-adapters.js +10 -0
  105. package/dist/client/chat/message-components.d.ts +4 -1
  106. package/dist/client/chat/message-components.js +37 -13
  107. package/dist/client/chat/tool-call-display.js +14 -0
  108. package/dist/client/chat-first/apps-rail.d.ts +1 -1
  109. package/dist/client/chat-first/apps-rail.js +6 -6
  110. package/dist/client/chat-first/copy.js +1 -0
  111. package/dist/client/chat-first/types.d.ts +1 -0
  112. package/dist/client/extensions/EmbeddedExtension.js +1 -1
  113. package/dist/client/extensions/ExtensionViewer.js +1 -1
  114. package/dist/client/extensions/InlineExtensionFrame.js +1 -1
  115. package/dist/client/onboarding/FirstRunOnboarding.js +17 -2
  116. package/dist/client/settings/FileStorageSettingsForm.d.ts +2 -0
  117. package/dist/client/settings/FileStorageSettingsForm.js +113 -0
  118. package/dist/client/settings/SettingsPanel.js +2 -1
  119. package/dist/client/sse-event-processor.js +21 -0
  120. package/dist/collab/awareness.d.ts +2 -2
  121. package/dist/collab/struct-routes.d.ts +1 -1
  122. package/dist/extensions/actions.js +2 -2
  123. package/dist/extensions/html-shell.js +3 -1
  124. package/dist/file-upload/pre-upload-attachments.d.ts +15 -10
  125. package/dist/file-upload/pre-upload-attachments.js +68 -24
  126. package/dist/file-upload/registry.d.ts +4 -5
  127. package/dist/file-upload/registry.js +7 -14
  128. package/dist/file-upload/s3.d.ts +9 -0
  129. package/dist/file-upload/s3.js +168 -0
  130. package/dist/file-upload/types.d.ts +3 -3
  131. package/dist/file-upload/types.js +2 -2
  132. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  133. package/dist/notifications/routes.d.ts +6 -6
  134. package/dist/observability/routes.d.ts +3 -3
  135. package/dist/onboarding/app-profile.js +23 -1
  136. package/dist/onboarding/default-steps.js +69 -0
  137. package/dist/onboarding/types.d.ts +2 -0
  138. package/dist/progress/routes.d.ts +1 -1
  139. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  140. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  141. package/dist/secrets/routes.d.ts +3 -3
  142. package/dist/server/agent-chat/browser-team-tools.js +20 -0
  143. package/dist/server/agent-chat-plugin.js +12 -3
  144. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  145. package/dist/server/auth.js +45 -21
  146. package/dist/server/better-auth-instance.d.ts +2 -0
  147. package/dist/server/better-auth-instance.js +2 -2
  148. package/dist/server/core-routes-plugin.d.ts +1 -0
  149. package/dist/server/core-routes-plugin.js +26 -16
  150. package/dist/server/identity-sso-store.d.ts +3 -0
  151. package/dist/server/identity-sso-store.js +45 -0
  152. package/dist/server/identity-sso.d.ts +20 -10
  153. package/dist/server/identity-sso.js +79 -31
  154. package/dist/server/index.d.ts +1 -1
  155. package/dist/server/index.js +1 -1
  156. package/dist/server/realtime-token.d.ts +1 -1
  157. package/dist/server/transcribe-voice.d.ts +1 -1
  158. package/dist/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  159. package/dist/templates/default/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  160. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +24 -1
  161. package/dist/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  162. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -2
  163. package/dist/templates/workspace-core/.agents/skills/extensions/references/api.md +1 -1
  164. package/dist/templates/workspace-core/.agents/skills/generative-ui/SKILL.md +3 -1
  165. package/docs/content/authentication.mdx +27 -0
  166. package/docs/content/cross-app-sso.mdx +38 -8
  167. package/docs/content/extensions.mdx +15 -15
  168. package/docs/content/file-uploads.mdx +10 -12
  169. package/docs/content/generative-ui.mdx +6 -1
  170. package/package.json +2 -2
  171. package/src/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  172. package/src/templates/default/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  173. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +24 -1
  174. package/src/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  175. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -2
  176. package/src/templates/workspace-core/.agents/skills/extensions/references/api.md +1 -1
  177. package/src/templates/workspace-core/.agents/skills/generative-ui/SKILL.md +3 -1
@@ -41,16 +41,16 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
41
41
  thumbsUpRate: number;
42
42
  avgEvalScore: number;
43
43
  } | {
44
+ error?: undefined;
44
45
  summary: import("./types.js").TraceSummary;
45
46
  spans: import("./types.js").TraceSpan[];
46
47
  id?: undefined;
47
- error?: undefined;
48
48
  ok?: undefined;
49
49
  } | {
50
+ error?: undefined;
50
51
  summary?: undefined;
51
52
  spans?: undefined;
52
53
  id: string;
53
- error?: undefined;
54
54
  ok?: undefined;
55
55
  } | {
56
56
  summary?: undefined;
@@ -59,9 +59,9 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
59
59
  error: any;
60
60
  ok?: undefined;
61
61
  } | {
62
+ error?: undefined;
62
63
  summary?: undefined;
63
64
  spans?: undefined;
64
65
  id?: undefined;
65
- error?: undefined;
66
66
  ok: boolean;
67
67
  }>>;
@@ -14,6 +14,15 @@ const DESIGN_SYSTEM_INTELLIGENCE_CAPABILITY = {
14
14
  keySummary: "Builder Design System Intelligence",
15
15
  why: "Uses your brand and design-system guidance to keep generated work on brand.",
16
16
  };
17
+ const FILE_UPLOAD_STORAGE_CAPABILITY = {
18
+ id: "file-storage",
19
+ label: "File uploads and storage",
20
+ required: false,
21
+ suggested: true,
22
+ builderIncluded: true,
23
+ keySummary: "Builder file storage or an S3-compatible bucket, credentials, and public base URL",
24
+ why: "Uploaded images and files need durable object storage so the agent can reuse them throughout a thread.",
25
+ };
17
26
  const PROFILES = {
18
27
  analytics: {
19
28
  appId: "analytics",
@@ -381,8 +390,21 @@ export function resolveOnboardingAppId(explicit) {
381
390
  export function getOnboardingAppProfile(appId) {
382
391
  const resolvedId = resolveOnboardingAppId(appId);
383
392
  const profile = PROFILES[resolvedId] ?? FALLBACK_PROFILE;
393
+ const capabilities = profile.capabilities.some((capability) => capability.id === FILE_UPLOAD_STORAGE_CAPABILITY.id)
394
+ ? profile.capabilities.map((capability) => capability.id === FILE_UPLOAD_STORAGE_CAPABILITY.id
395
+ ? {
396
+ ...FILE_UPLOAD_STORAGE_CAPABILITY,
397
+ // Assets and other domain-specific profiles can still make
398
+ // storage required while sharing the framework-wide contract.
399
+ required: capability.required,
400
+ builderIncluded: capability.builderIncluded,
401
+ }
402
+ : { ...capability })
403
+ : profile.capabilities.flatMap((capability, index) => index === 0
404
+ ? [{ ...capability }, { ...FILE_UPLOAD_STORAGE_CAPABILITY }]
405
+ : [{ ...capability }]);
384
406
  return {
385
407
  ...profile,
386
- capabilities: profile.capabilities.map((capability) => ({ ...capability })),
408
+ capabilities,
387
409
  };
388
410
  }
@@ -7,6 +7,8 @@
7
7
  */
8
8
  import { PROVIDER_ENV_META, PROVIDER_ENV_VARS, } from "../agent/engine/provider-env-vars.js";
9
9
  import { detectEngineFromUserSecrets, isAgentEngineSettingConfigured, } from "../agent/engine/registry.js";
10
+ import { getActiveFileUploadProviderForRequest, registerFileUploadProvider, } from "../file-upload/registry.js";
11
+ import { s3FileUploadProvider } from "../file-upload/s3.js";
10
12
  import { canUseDeployCredentialFallbackForRequest, readDeployCredentialEnv, resolveSecret, } from "../server/credential-provider.js";
11
13
  import { getSetting } from "../settings/store.js";
12
14
  import { registerOnboardingStep } from "./registry.js";
@@ -374,13 +376,80 @@ const githubRepositoryStep = {
374
376
  readDeployCredentialEnv("GH_TOKEN"));
375
377
  },
376
378
  };
379
+ const fileStorageStep = {
380
+ id: "file-storage",
381
+ order: 15,
382
+ required: false,
383
+ title: "File uploads and storage",
384
+ description: "Keep uploaded images and files available throughout the thread with Builder or S3-compatible object storage.",
385
+ methods: [
386
+ {
387
+ id: "builder",
388
+ kind: "builder-cli-auth",
389
+ label: "Connect Builder",
390
+ description: "Builder includes managed file storage alongside its AI connection.",
391
+ primary: true,
392
+ badge: "free",
393
+ payload: { scope: "llm" },
394
+ },
395
+ {
396
+ id: "s3",
397
+ kind: "form",
398
+ label: "Use custom storage keys",
399
+ description: "Connect AWS S3, Cloudflare R2, MinIO, or another S3-compatible bucket with a stable public base URL.",
400
+ payload: {
401
+ writeScope: "workspace",
402
+ saveTo: "scoped-secrets",
403
+ secretDescription: "S3-compatible object storage for file uploads",
404
+ fields: [
405
+ {
406
+ key: "S3_ENDPOINT",
407
+ label: "Endpoint URL",
408
+ placeholder: "https://s3.us-east-1.amazonaws.com",
409
+ },
410
+ {
411
+ key: "S3_BUCKET",
412
+ label: "Bucket name",
413
+ placeholder: "my-uploads-bucket",
414
+ },
415
+ {
416
+ key: "S3_ACCESS_KEY_ID",
417
+ label: "Access key ID",
418
+ placeholder: "AKIA...",
419
+ },
420
+ {
421
+ key: "S3_SECRET_ACCESS_KEY",
422
+ label: "Secret access key",
423
+ secret: true,
424
+ },
425
+ {
426
+ key: "S3_REGION",
427
+ label: "Region",
428
+ placeholder: "auto",
429
+ },
430
+ {
431
+ key: "S3_PUBLIC_BASE_URL",
432
+ label: "Public base URL",
433
+ placeholder: "https://cdn.example.com",
434
+ },
435
+ ],
436
+ },
437
+ },
438
+ ],
439
+ isComplete: async () => (await getActiveFileUploadProviderForRequest()) !== null,
440
+ };
377
441
  let registered = false;
378
442
  /** Idempotent. Safe to call from every plugin-mount call. */
379
443
  export function registerDefaultOnboardingSteps() {
380
444
  if (registered)
381
445
  return;
382
446
  registered = true;
447
+ // The framework provides a generic S3/R2 implementation for the custom-key
448
+ // onboarding path. Templates may replace the same provider id with a
449
+ // domain-specific implementation after this default plugin mounts.
450
+ registerFileUploadProvider(s3FileUploadProvider);
383
451
  registerOnboardingStep(llmStep);
452
+ registerOnboardingStep(fileStorageStep);
384
453
  registerOnboardingStep(databaseStep);
385
454
  registerOnboardingStep(authStep);
386
455
  registerOnboardingStep(emailStep);
@@ -91,6 +91,8 @@ export interface OnboardingCapability {
91
91
  label: string;
92
92
  /** Whether this capability blocks the app's normal setup. */
93
93
  required: boolean;
94
+ /** Show this optional capability as a recommended BYOK setup. */
95
+ suggested?: boolean;
94
96
  /** Whether Builder's managed connection covers this capability. */
95
97
  builderIncluded: boolean;
96
98
  /** Compact description of the key or connection the BYOK path needs. */
@@ -15,6 +15,6 @@ export declare function createProgressHandler(): import("h3").EventHandlerWithFe
15
15
  error: string;
16
16
  ok?: undefined;
17
17
  } | {
18
- ok: boolean;
19
18
  error?: undefined;
19
+ ok: boolean;
20
20
  }>>;
@@ -77,7 +77,7 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
77
77
  }, z.core.$strip>>, {
78
78
  id?: undefined;
79
79
  deleted?: undefined;
80
- provider?: undefined;
80
+ message?: undefined;
81
81
  providers: {
82
82
  id: string;
83
83
  label: string;
@@ -88,45 +88,45 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
88
88
  updatedAt: number;
89
89
  }[];
90
90
  count: number;
91
+ provider?: undefined;
91
92
  found?: undefined;
92
93
  registered?: undefined;
93
94
  label?: undefined;
94
- message?: undefined;
95
95
  } | {
96
+ count?: undefined;
96
97
  id?: undefined;
97
98
  deleted?: undefined;
98
- count?: undefined;
99
+ message?: undefined;
99
100
  providers?: undefined;
100
101
  found: boolean;
101
102
  provider: import("../custom-registry.js").CustomProviderConfig;
102
103
  registered?: undefined;
103
104
  label?: undefined;
104
- message?: undefined;
105
105
  } | {
106
- deleted?: undefined;
107
106
  count?: undefined;
108
- provider?: undefined;
107
+ deleted?: undefined;
108
+ message?: undefined;
109
109
  providers?: undefined;
110
+ provider?: undefined;
110
111
  found: boolean;
111
112
  id: string;
112
113
  registered?: undefined;
113
114
  label?: undefined;
114
- message?: undefined;
115
115
  } | {
116
116
  count?: undefined;
117
- provider?: undefined;
117
+ message?: undefined;
118
118
  providers?: undefined;
119
+ provider?: undefined;
119
120
  found?: undefined;
120
121
  deleted: boolean;
121
122
  id: string;
122
123
  registered?: undefined;
123
124
  label?: undefined;
124
- message?: undefined;
125
125
  } | {
126
- deleted?: undefined;
127
126
  count?: undefined;
128
- provider?: undefined;
127
+ deleted?: undefined;
129
128
  providers?: undefined;
129
+ provider?: undefined;
130
130
  found?: undefined;
131
131
  registered: boolean;
132
132
  id: string;
@@ -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
- message?: undefined;
315
314
  id?: undefined;
315
+ provider?: undefined;
316
316
  deleted?: undefined;
317
317
  providers: {
318
318
  id: string;
@@ -324,12 +324,11 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
324
324
  updatedAt: number;
325
325
  }[];
326
326
  count: number;
327
- provider?: undefined;
328
327
  found?: undefined;
329
328
  registered?: undefined;
330
329
  label?: undefined;
331
- } | {
332
330
  message?: undefined;
331
+ } | {
333
332
  count?: undefined;
334
333
  id?: undefined;
335
334
  deleted?: undefined;
@@ -338,31 +337,32 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
338
337
  provider: import("../custom-registry.js").CustomProviderConfig;
339
338
  registered?: undefined;
340
339
  label?: undefined;
341
- } | {
342
340
  message?: undefined;
341
+ } | {
343
342
  count?: undefined;
343
+ provider?: undefined;
344
344
  deleted?: undefined;
345
345
  providers?: undefined;
346
- provider?: undefined;
347
346
  found: boolean;
348
347
  id: string;
349
348
  registered?: undefined;
350
349
  label?: undefined;
351
- } | {
352
350
  message?: undefined;
351
+ } | {
353
352
  count?: undefined;
354
- providers?: undefined;
355
353
  provider?: undefined;
354
+ providers?: undefined;
356
355
  found?: undefined;
357
356
  deleted: boolean;
358
357
  id: string;
359
358
  registered?: undefined;
360
359
  label?: undefined;
360
+ message?: undefined;
361
361
  } | {
362
362
  count?: undefined;
363
+ provider?: undefined;
363
364
  deleted?: undefined;
364
365
  providers?: undefined;
365
- provider?: undefined;
366
366
  found?: undefined;
367
367
  registered: boolean;
368
368
  id: string;
@@ -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;
@@ -1,4 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
+ import { getActiveFileUploadProviderForRequest } from "../../file-upload/registry.js";
2
3
  import { areBuiltinMcpCapabilitiesSupported, buildMergedConfig, setBuiltinMcpCapabilityEnabled, } from "../../mcp-client/index.js";
3
4
  import { getBuilderBrowserConnectUrlForOwner, resolveBuilderBranchProjectId, } from "../builder-browser.js";
4
5
  import { getRequestUserEmail } from "../request-context.js";
@@ -73,6 +74,25 @@ export function createBuilderBrowserTool(deps) {
73
74
  return { ok: true, enabledIds: enabledIds ?? [] };
74
75
  };
75
76
  const entries = {
77
+ "connect-file-storage": {
78
+ tool: {
79
+ description: "Render the inline file-storage setup card when an image or file attachment could not be durably uploaded. The card lets the user connect Builder for managed object storage or open the same custom-key setup used by onboarding. Call it immediately when the attachment context says storage is missing; do not ask the user to upload the file again.",
80
+ parameters: {
81
+ type: "object",
82
+ properties: {},
83
+ },
84
+ },
85
+ run: async () => {
86
+ const activeProvider = await getActiveFileUploadProviderForRequest();
87
+ const ownerEmail = deps.getOwner?.() ?? getRequestUserEmail();
88
+ return JSON.stringify({
89
+ kind: "connect-file-storage-card",
90
+ configured: !!activeProvider,
91
+ provider: activeProvider?.name ?? null,
92
+ connectUrl: getBuilderBrowserConnectUrlForOwner(deps.getOrigin(), ownerEmail),
93
+ });
94
+ },
95
+ },
76
96
  "connect-builder": {
77
97
  tool: {
78
98
  description: `Render a Builder.io card inline in the chat. Call this as the first step (no code exploration or planning needed) when the user asks to modify the APP'S OWN SOURCE CODE: add a feature, change the UI chrome, edit a React component, add a route, add an integration, fix a bug in the app itself, or anything else that requires source-file edits while in hosted/production mode. ${extensionRequestGuidance}Do NOT call this for content the app is meant to produce — creating a video, generating a design, drafting an email, building a slide deck, making a dashboard, etc. — those run through the app's own domain actions, not Builder. Do NOT mention 'click Send to Builder' in your response unless this card is already in the conversation. The tool result includes \`builderEnabled\`; treat \`true\` as "Builder Cloud Agents can take the code-change handoff" and \`false\` as "this still needs a code change, but no Builder Cloud Agent can run here." If Builder is connected and Builder Cloud Agents are available, the card shows a 'Send to Builder' button that hands the work off to Builder's cloud agent and returns a branch URL. If \`builderEnabled\` is false, the card still renders but shows the code-change fallback: "This requires a code change. Edit locally or use Builder.io to edit this code in the cloud and continue customizing the app any way you like." Never tell the user to enable Builder Cloud Agents in Builder org settings or beta settings, and do not claim the Builder card has everything, is pre-loaded for handoff, or can run the cloud agent when \`builderEnabled\` is false. When you call this for a code-change request, pass the user's request verbatim as the \`prompt\` arg so the card can forward it to Builder unchanged when cloud agents are available.`,
@@ -951,9 +951,18 @@ export function createAgentChatPlugin(options) {
951
951
  const corpusToolNames = loadCorpusToolsInitially
952
952
  ? corpusToolNamesTaughtByPrompt(corpusPromptRegistry)
953
953
  : [];
954
- const effectiveInitialToolNames = corpusToolNames.length > 0
955
- ? [...new Set([...templateInitialToolNames, ...corpusToolNames])]
956
- : templateInitialToolNames;
954
+ const effectiveInitialToolNames = [
955
+ ...new Set([
956
+ ...templateInitialToolNames,
957
+ ...corpusToolNames,
958
+ // Attachment setup is a recovery action, but it must be available on
959
+ // the first request so a missing provider renders the CTA immediately
960
+ // instead of spending another turn in tool-search.
961
+ ...(browserTools["connect-file-storage"]
962
+ ? ["connect-file-storage"]
963
+ : []),
964
+ ]),
965
+ ];
957
966
  const resolveExtraContext = async (event, owner) => {
958
967
  if (!options?.extraContext)
959
968
  return "";
@@ -27,10 +27,10 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
27
27
  export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
28
28
  error: any;
29
29
  } | {
30
+ error?: undefined;
30
31
  ok: boolean;
31
32
  key: string;
32
33
  baseUrlKey?: string;
33
34
  scope: AgentEngineApiKeyScope;
34
- error?: undefined;
35
35
  }>>;
36
36
  export {};
@@ -55,6 +55,7 @@ import { normalizeWorkspaceAppAudience, workspaceAppAudienceFromEnv, workspaceAp
55
55
  import { isValidWorkspaceAppIdFormat } from "../shared/workspace-app-id.js";
56
56
  import { injectAnalyticsIntoHtml } from "./analytics.js";
57
57
  import { getConfiguredAppBasePath } from "./app-base-path.js";
58
+ import { getAppProductionUrl } from "./app-url.js";
58
59
  import { readAnalyticsAnonymousId, signupAttributionFromCookieHeader, } from "./attribution.js";
59
60
  import { getAuthLoginMode } from "./auth-login-mode.js";
60
61
  import { createBetterAuthSessionForEmail, ensureGoogleAuthIdentity, getBetterAuth, getBetterAuthSync, isDeployPreview, } from "./better-auth-instance.js";
@@ -64,10 +65,7 @@ import { getAllowedCorsOrigin, readCorsAllowedOrigins, } from "./cors-origins.js
64
65
  import { readDesktopSso, writeDesktopSso, clearDesktopSso, } from "./desktop-sso.js";
65
66
  import { resolveGoogleSignInCredentials } from "./google-oauth-credentials.js";
66
67
  import { isElectron as isElectronRequest, getAppBasePath, getAppUrl, getOrigin, encodeOAuthState, decodeOAuthState, createOAuthSession, oauthCallbackResponse, oauthDesktopExchangePage, oauthErrorPage, resolveOAuthRedirectUri, isAllowedOAuthRedirectUri, } from "./google-oauth.js";
67
- // Pure env-read feature switch from a leaf module (no dependency back on
68
- // auth.ts), so the guard and the SSO route handler share one validator and
69
- // can never disagree about whether federated SSO is enabled.
70
- import { isIdentitySsoEnabled } from "./identity-sso-store.js";
68
+ import { isCanonicalAgentNativeAppRequest, isDesktopSsoCanaryUserAgent, isIdentitySsoEnabled, } from "./identity-sso-store.js";
71
69
  import { ensureCanonicalUserForLegacySession } from "./legacy-auth-migration.js";
72
70
  import { safeOAuthReturnUrl } from "./oauth-return-url.js";
73
71
  import { getOnboardingHtml, getResetPasswordHtml, } from "./onboarding-html.js";
@@ -312,6 +310,23 @@ export function isDevEnvironment() {
312
310
  export function safeReturnPath(raw) {
313
311
  return normalizeAppPath(raw) ?? "/";
314
312
  }
313
+ // Better Auth's relative callback validator is stricter than normalizeAppPath:
314
+ // query values such as UTM labels may contain characters that are safe here but
315
+ // invalid as a Better Auth relative callback. Promote those paths to the
316
+ // canonical app origin so the callback remains same-origin and valid there.
317
+ const BETTER_AUTH_RELATIVE_CALLBACK_PATH_RE = /^\/(?!\/|\\|%2f|%5c)[\w\-.\+/@]*(?:\?[\w\-.\+/=&%@]*)?$/i;
318
+ function betterAuthCallbackURL(raw, forceAbsolute = false, event) {
319
+ const safePath = safeReturnPath(raw);
320
+ if (!forceAbsolute && BETTER_AUTH_RELATIVE_CALLBACK_PATH_RE.test(safePath)) {
321
+ return safePath;
322
+ }
323
+ try {
324
+ return new URL(safePath, getAppProductionUrl(event)).toString();
325
+ }
326
+ catch {
327
+ return "/";
328
+ }
329
+ }
315
330
  /**
316
331
  * Return the configured login HTML for this request, or `null` when no auth
317
332
  * guard is installed. Used by the `/_agent-native/open` deep-link route to
@@ -1693,13 +1708,16 @@ function createAuthGuardFn() {
1693
1708
  // definition, NOT yet signed in to THIS app) must bypass the blanket
1694
1709
  // 401-for-/_agent-native/*: they resolve / mint the browser session
1695
1710
  // themselves and verify a signature-bound, single-use, CSRF-stated
1696
- // hub token — not a cookie. This bypass is GATED on the opt-in env var
1697
- // so an unset `AGENT_NATIVE_IDENTITY_HUB_URL` is a true no-op (the
1698
- // guard's behaviour is byte-for-byte unchanged when SSO is off). The
1699
- // handler itself 404s when disabled as defence in depth.
1700
- if (isIdentitySsoEnabled() &&
1701
- (p === "/_agent-native/identity/login" ||
1702
- p === "/_agent-native/identity/callback")) {
1711
+ // hub token — not a cookie. The handler fails closed with 404 unless
1712
+ // direct web SSO is configured or this is the packaged SSO Canary on a
1713
+ // canonical app origin. Keeping the bypass exact lets that request-scoped
1714
+ // decision happen without exposing any other identity subpath.
1715
+ const isIdentitySsoEntryPath = p === "/_agent-native/identity/login" ||
1716
+ p === "/_agent-native/identity/callback";
1717
+ const isDesktopCanaryIdentityRequest = isDesktopSsoCanaryUserAgent(getHeader(event, "user-agent")) &&
1718
+ isCanonicalAgentNativeAppRequest(getHeader(event, "host"), getHeader(event, "x-forwarded-proto"));
1719
+ if (isIdentitySsoEntryPath &&
1720
+ (isIdentitySsoEnabled() || isDesktopCanaryIdentityRequest)) {
1703
1721
  return;
1704
1722
  }
1705
1723
  // Internal processor endpoint for the A2A async-mode fanout. Mirrors the
@@ -2971,6 +2989,7 @@ async function mountBetterAuthRoutes(app, options) {
2971
2989
  // need for a separate "Connect Google" page.
2972
2990
  const betterAuthConfig = {
2973
2991
  ...(options.betterAuth ?? {}),
2992
+ ...(options.maxAge !== undefined ? { sessionMaxAge: options.maxAge } : {}),
2974
2993
  ...(options.googleScopes ? { googleScopes: options.googleScopes } : {}),
2975
2994
  };
2976
2995
  const auth = await getBetterAuth(betterAuthConfig);
@@ -3046,10 +3065,13 @@ async function mountBetterAuthRoutes(app, options) {
3046
3065
  }
3047
3066
  }
3048
3067
  // The signup wrapper sanitizes callbackURL before calling Better Auth,
3049
- // but the resend endpoint is exposed directly so users can request a
3050
- // fresh link while unauthenticated. Keep that path equally strict:
3051
- // only same-origin relative return paths survive into the email.
3052
- if (isSendVerificationEmail || isMagicLinkRequest) {
3068
+ // but the direct email and magic-link endpoints are also reachable from
3069
+ // the browser. Keep every callback path valid for Better Auth's own
3070
+ // stricter relative URL validator before it is embedded in an email.
3071
+ if (isSendVerificationEmail ||
3072
+ isMagicLinkRequest ||
3073
+ reqPath.includes("/sign-up/email") ||
3074
+ reqPath.includes("/sign-in/email")) {
3053
3075
  try {
3054
3076
  const body = (await authRequest
3055
3077
  .clone()
@@ -3064,7 +3086,7 @@ async function mountBetterAuthRoutes(app, options) {
3064
3086
  for (const key of callbackKeys) {
3065
3087
  if (typeof body[key] !== "string")
3066
3088
  continue;
3067
- const callbackURL = safeReturnPath(body[key]);
3089
+ const callbackURL = betterAuthCallbackURL(body[key], false, event);
3068
3090
  if (callbackURL !== body[key]) {
3069
3091
  sanitizedBody[key] = callbackURL;
3070
3092
  changed = true;
@@ -3273,7 +3295,7 @@ async function mountBetterAuthRoutes(app, options) {
3273
3295
  const body = await readBody(event);
3274
3296
  const rawEmail = typeof body?.email === "string" ? body.email : "";
3275
3297
  const email = normalizeAuthEmail(rawEmail);
3276
- let callbackURL = typeof body?.callbackURL === "string"
3298
+ let callbackPath = typeof body?.callbackURL === "string"
3277
3299
  ? safeReturnPath(body.callbackURL)
3278
3300
  : "/";
3279
3301
  let desktopFlow;
@@ -3286,15 +3308,17 @@ async function mountBetterAuthRoutes(app, options) {
3286
3308
  return { error: GOOGLE_AUTH_REQUIRED_MESSAGE };
3287
3309
  }
3288
3310
  try {
3289
- if (isDesktopMagicLinkCallbackPath(callbackURL)) {
3311
+ if (isDesktopMagicLinkCallbackPath(callbackPath)) {
3290
3312
  desktopFlow = await issueDesktopMagicLinkFlow();
3291
- callbackURL = withDesktopMagicLinkFlow(callbackURL, desktopFlow);
3313
+ callbackPath = withDesktopMagicLinkFlow(callbackPath, desktopFlow);
3292
3314
  }
3315
+ const callbackURL = betterAuthCallbackURL(callbackPath, false, event);
3316
+ const newUserCallbackPath = `${getAppBasePath()}/_agent-native/auth/magic-link/new-user?return=${encodeURIComponent(callbackPath)}`;
3293
3317
  await auth.api.signInMagicLink({
3294
3318
  body: {
3295
3319
  email,
3296
3320
  callbackURL,
3297
- newUserCallbackURL: `${getAppBasePath()}/_agent-native/auth/magic-link/new-user?return=${encodeURIComponent(callbackURL)}`,
3321
+ newUserCallbackURL: betterAuthCallbackURL(newUserCallbackPath, callbackURL !== callbackPath, event),
3298
3322
  },
3299
3323
  headers: event.headers,
3300
3324
  });
@@ -3323,7 +3347,7 @@ async function mountBetterAuthRoutes(app, options) {
3323
3347
  const email = normalizeAuthEmail(rawEmail);
3324
3348
  const password = body?.password;
3325
3349
  const callbackURL = typeof body?.callbackURL === "string"
3326
- ? safeReturnPath(body.callbackURL)
3350
+ ? betterAuthCallbackURL(body.callbackURL, false, event)
3327
3351
  : "/";
3328
3352
  if (!email) {
3329
3353
  setResponseStatus(event, 400);
@@ -118,6 +118,8 @@ export interface BetterAuthInstance {
118
118
  export interface BetterAuthConfig {
119
119
  /** Base path for Better Auth routes. Default: "/_agent-native/auth/ba" */
120
120
  basePath?: string;
121
+ /** Session max age in seconds. Defaults to the framework's 30-day lifetime. */
122
+ sessionMaxAge?: number;
121
123
  /** Additional social providers beyond what env vars auto-detect */
122
124
  socialProviders?: BetterAuthOptions["socialProviders"];
123
125
  /** Additional Better Auth plugins */
@@ -1048,8 +1048,8 @@ async function createBetterAuthInstance(config) {
1048
1048
  },
1049
1049
  },
1050
1050
  session: {
1051
- expiresIn: 60 * 60 * 24 * 30, // 30 days
1052
- updateAge: 60 * 60 * 24, // refresh daily
1051
+ expiresIn: config?.sessionMaxAge ?? 60 * 60 * 24 * 30,
1052
+ updateAge: Math.min(60 * 60 * 24, config?.sessionMaxAge ?? 60 * 60 * 24 * 30), // refresh daily, or sooner for short custom sessions
1053
1053
  cookieCache: {
1054
1054
  enabled: true,
1055
1055
  maxAge: 5 * 60, // 5 min cache
@@ -293,6 +293,7 @@ export declare function readLegacyCoreRouteInitSettings(readSetting?: CoreRouteS
293
293
  * their cold-start budget on legacy cleanup or best-effort table warmups.
294
294
  */
295
295
  export declare function shouldRunCoreRouteBootDatabaseWork(env?: NodeJS.ProcessEnv): boolean;
296
+ export declare function ensureS3FileUploadProvider(): void;
296
297
  export declare function createCoreRoutesPlugin(options?: CoreRoutesPluginOptions): NitroPluginDef;
297
298
  /**
298
299
  * Default core routes plugin — mount with no configuration needed.