@agent-native/core 0.196.0-nightly-20260928172902 → 0.196.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 (86) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/CHANGELOG.md +17 -0
  3. package/corpus/templates/assets/CHANGELOG.md +18 -0
  4. package/corpus/templates/brain/CHANGELOG.md +6 -0
  5. package/corpus/templates/calendar/CHANGELOG.md +4 -0
  6. package/corpus/templates/clips/CHANGELOG.md +19 -0
  7. package/corpus/templates/clips/actions/create-recording-agent-link.ts +8 -2
  8. package/corpus/templates/clips/actions/update-recording.ts +5 -1
  9. package/corpus/templates/clips/app/routes/share.$shareId.tsx +10 -3
  10. package/corpus/templates/clips/changelog/2026-09-28-agent-links-stay-valid-when-clip-details-change.md +6 -0
  11. package/corpus/templates/clips/changelog/2026-09-28-password-changes-immediately-invalidate-old-recording-links.md +6 -0
  12. package/corpus/templates/clips/changelog/2026-09-28-password-protected-recording-links-stop-working-when-the-pas.md +6 -0
  13. package/corpus/templates/clips/server/db/schema.ts +3 -0
  14. package/corpus/templates/clips/server/lib/player-video-url.ts +9 -1
  15. package/corpus/templates/clips/server/lib/public-agent-context.ts +12 -4
  16. package/corpus/templates/clips/server/lib/share-password.ts +25 -0
  17. package/corpus/templates/clips/server/plugins/db.ts +36 -0
  18. package/corpus/templates/clips/server/routes/[...page].get.ts +8 -1
  19. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +33 -6
  20. package/corpus/templates/clips/server/routes/api/thumbnail/[recordingId].get.ts +34 -6
  21. package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +26 -5
  22. package/corpus/templates/content/CHANGELOG.md +1 -0
  23. package/corpus/templates/crm/CHANGELOG.md +12 -0
  24. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +265 -3
  25. package/corpus/templates/design/CHANGELOG.md +21 -0
  26. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +463 -6
  27. package/corpus/templates/design/app/pages/Index.tsx +1 -1
  28. package/corpus/templates/design/changelog/2026-09-27-auto-focused-app-fields-no-longer-interrupt-canvas-shortcuts.md +6 -0
  29. package/corpus/templates/design/changelog/2026-09-28-model-picker-loads-available-models.md +6 -0
  30. package/corpus/templates/design/changelog/2026-09-28-template-menus-stay-available-on-hover.md +6 -0
  31. package/corpus/templates/dispatch/CHANGELOG.md +18 -0
  32. package/corpus/templates/forms/CHANGELOG.md +6 -0
  33. package/corpus/templates/mail/.env.example +1 -1
  34. package/corpus/templates/mail/CHANGELOG.md +33 -0
  35. package/corpus/templates/mail/changelog/2026-09-28-fixed-inbox-loading-stalls-and-showed-progress-during-google-2.md +6 -0
  36. package/corpus/templates/mail/changelog/2026-09-28-fixed-inbox-loading-stalls-and-showed-progress-during-google.md +6 -0
  37. package/corpus/templates/mail/server/db/schema.ts +7 -0
  38. package/corpus/templates/mail/server/lib/ai-filter-backfill.ts +4 -0
  39. package/corpus/templates/mail/server/lib/jobs.ts +5 -2
  40. package/corpus/templates/mail/server/plugins/db.ts +16 -0
  41. package/corpus/templates/mail/server/plugins/mail-jobs.ts +355 -44
  42. package/corpus/templates/slides/CHANGELOG.md +28 -0
  43. package/corpus/templates/slides/app/pages/Index.tsx +1 -1
  44. package/corpus/templates/slides/changelog/2026-09-28-model-picker-loads-available-models.md +6 -0
  45. package/corpus/templates/slides/changelog/2026-09-28-template-menus-stay-available-on-hover.md +6 -0
  46. package/dist/automation/index.d.ts +1 -1
  47. package/dist/client/auth/AuthPage.js +3 -2
  48. package/dist/client/org/OrgSwitcher.js +31 -19
  49. package/dist/client/settings/UsageSection.js +3 -3
  50. package/dist/client/use-action.js +1 -1
  51. package/dist/collab/awareness.d.ts +2 -2
  52. package/dist/collab/routes.d.ts +1 -1
  53. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  54. package/dist/jobs/background-automation-runner.d.ts +2 -0
  55. package/dist/jobs/background-automation-runner.js +20 -1
  56. package/dist/jobs/sweep-hooks.d.ts +6 -2
  57. package/dist/jobs/sweep-hooks.js +17 -9
  58. package/dist/localization/core-messages/ar-SA.js +2 -2
  59. package/dist/localization/core-messages/de-DE.js +2 -2
  60. package/dist/localization/core-messages/en-US.d.ts +2 -2
  61. package/dist/localization/core-messages/en-US.js +2 -2
  62. package/dist/localization/core-messages/es-ES.js +2 -2
  63. package/dist/localization/core-messages/fr-FR.js +2 -2
  64. package/dist/localization/core-messages/hi-IN.js +2 -2
  65. package/dist/localization/core-messages/ja-JP.js +2 -2
  66. package/dist/localization/core-messages/ko-KR.js +2 -2
  67. package/dist/localization/core-messages/pt-BR.js +2 -2
  68. package/dist/localization/core-messages/zh-CN.js +2 -2
  69. package/dist/localization/core-messages/zh-TW.js +2 -2
  70. package/dist/localization/core-messages.d.ts +2 -2
  71. package/dist/notifications/routes.d.ts +5 -5
  72. package/dist/observability/routes.d.ts +6 -6
  73. package/dist/progress/routes.d.ts +1 -1
  74. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  75. package/dist/provider-api/actions/provider-api.d.ts +7 -7
  76. package/dist/resources/handlers.d.ts +1 -1
  77. package/dist/secrets/routes.d.ts +4 -4
  78. package/dist/server/agent-chat-plugin.js +6 -2
  79. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  80. package/dist/server/agent-engine-default-model-route.d.ts +1 -1
  81. package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
  82. package/dist/server/index.d.ts +1 -1
  83. package/dist/triggers/dispatcher.js +167 -36
  84. package/dist/triggers/event-queue.d.ts +18 -1
  85. package/dist/triggers/event-queue.js +143 -10
  86. package/package.json +4 -4
@@ -1,7 +1,7 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { ActionButton, Avatar, TextField, } from "@agent-native/toolkit/design-system";
3
3
  import { ResourceIcon } from "@agent-native/toolkit/icons";
4
- import { IconArrowUpRight, IconBriefcase, IconChartBar, IconCheck, IconChevronLeft, IconChevronRight, IconDownload, IconExternalLink, IconAlertCircle, IconKey, IconLoader2, IconLogout, IconPlus, IconPresentation, IconSelector, IconSettings, IconUser, IconUsersGroup, } from "@tabler/icons-react";
4
+ import { IconArrowUpRight, IconBriefcase, IconChartBar, IconCheck, IconChevronLeft, IconChevronRight, IconDownload, IconExternalLink, IconAlertCircle, IconKey, IconLoader2, IconLogout, IconPlus, IconPresentation, IconSelector, IconSettings, IconUsersGroup, } from "@tabler/icons-react";
5
5
  import { useEffect, useMemo, useRef, useState, } from "react";
6
6
  import { Link, useNavigate } from "react-router";
7
7
  import { setBrowserDemoModeEnabled } from "../../demo/browser-state.js";
@@ -32,9 +32,9 @@ export function BuilderCreditNotice({ compact = false, className, }) {
32
32
  return null;
33
33
  }
34
34
  const quotaLabel = builderCreditStatus.data.period === "daily"
35
- ? t("agentChat.usage.dailyFreeLimit")
35
+ ? t("agentChat.usage.dailyDefaultLimit")
36
36
  : builderCreditStatus.data.period === "monthly"
37
- ? t("agentChat.usage.monthlyPlan")
37
+ ? t("agentChat.usage.monthlyLimit")
38
38
  : null;
39
39
  const title = [t("agentChat.billing.builderCreditLimitTitle"), quotaLabel]
40
40
  .filter((label) => label !== null)
@@ -84,7 +84,7 @@ function OrgSwitcherLoadingPlaceholder({ className, compact, label, }) {
84
84
  * downloads, and Log out. Renders nothing in dev / no-auth mode.
85
85
  */
86
86
  export function OrgSwitcher({ className, hideWhenSingle, reserveSpace, compact, hideBuilderCreditNotice, utilityLinks, }) {
87
- const { data: org, isLoading } = useOrg();
87
+ const { data: org, isLoading, dataUpdatedAt } = useOrg();
88
88
  const { session } = useSession();
89
89
  const { enabled: demoModeEnabled } = useDemoModeStatus();
90
90
  const t = useT();
@@ -115,6 +115,25 @@ export function OrgSwitcher({ className, hideWhenSingle, reserveSpace, compact,
115
115
  ?.querySelector('[role="menuitem"]:not([data-disabled])')
116
116
  ?.focus();
117
117
  }, [view]);
118
+ // Accounts that picked the retired "Personal" choice have `orgId: null`
119
+ // stored while still holding memberships, which strands them outside the
120
+ // org-scoped Builder.io connection and vault credentials. Move them back.
121
+ // A failed switch retries on the next org fetch, not on the next render:
122
+ // the mutation's state changes would otherwise re-run this in a tight loop.
123
+ const personalRecoveryRef = useRef(false);
124
+ const firstMembershipId = org?.orgs?.[0]?.orgId ?? null;
125
+ const switchOrgMutate = switchOrg.mutate;
126
+ useEffect(() => {
127
+ if (org?.orgId || !firstMembershipId || personalRecoveryRef.current) {
128
+ return;
129
+ }
130
+ personalRecoveryRef.current = true;
131
+ switchOrgMutate(firstMembershipId, {
132
+ onError: () => {
133
+ personalRecoveryRef.current = false;
134
+ },
135
+ });
136
+ }, [org?.orgId, firstMembershipId, switchOrgMutate, dataUpdatedAt]);
118
137
  const showView = (next) => {
119
138
  viewChangedRef.current = true;
120
139
  setView(next);
@@ -187,29 +206,22 @@ export function OrgSwitcher({ className, hideWhenSingle, reserveSpace, compact,
187
206
  const avatar = (_jsx(Avatar, { name: displayName, src: avatarUrl, fallback: initials(displayName), className: cn(AVATAR_CLASS, compact ? "size-6" : "size-7") }));
188
207
  const trigger = compact ? (_jsx("button", { type: "button", "aria-label": triggerLabel, className: cn(COMPACT_TRIGGER_CLASS, className), children: avatar })) : (_jsxs("button", { type: "button", "aria-label": triggerLabel, className: cn(TRIGGER_CLASS, className), children: [avatar, _jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("span", { className: "truncate text-[13px] font-medium leading-tight", children: displayName }), _jsxs("span", { className: "flex min-w-0 items-center gap-1 text-xs leading-tight text-muted-foreground", children: [inOrg && org.icon ? (_jsx(ResourceIcon, { value: org.icon, size: 12, resolveImageUrl: (image) => image.authority === "url" ? image.assetId : undefined, fallback: _jsx(IconBriefcase, { className: "size-3 shrink-0" }) })) : null, _jsx("span", { className: "truncate", children: organizationLabel }), demoModeEnabled && (_jsxs("span", { className: "inline-flex shrink-0 items-center gap-0.5 rounded-full bg-primary/10 px-1.5 text-[10px] font-medium text-primary", children: [_jsx(IconPresentation, { className: "size-3", "aria-hidden": "true" }), t("agentChat.accountMenu.demoMode")] }))] })] }), _jsx(IconSelector, { className: "size-3.5 shrink-0 text-muted-foreground" })] }));
189
208
  const selectOrg = (orgId) => {
190
- if (orgId === (org.orgId ?? null)) {
209
+ if (orgId === org.orgId) {
191
210
  setOpen(false);
192
211
  return;
193
212
  }
194
- // `null` switches to Personal, which the server stores as an explicit
195
- // choice rather than falling back to the first membership.
196
213
  switchOrg.mutate(orgId, { onSuccess: () => setOpen(false) });
197
214
  };
198
215
  const isSwitchingTo = (orgId) => switchOrg.isPending && switchOrg.variables === orgId;
199
- const mainItems = (_jsxs(_Fragment, { children: [!demoModeEnabled && org.email ? (_jsx(DropdownMenuLabel, { className: "truncate text-xs font-normal text-muted-foreground", children: org.email })) : null, demoModeEnabled && (_jsxs(_Fragment, { children: [_jsxs("div", { role: "status", className: "mx-1 mb-1 rounded-md border border-primary/20 bg-primary/5 px-2 py-1.5 text-[11px]", children: [_jsxs("div", { className: "flex items-center gap-1.5 font-medium text-primary", children: [_jsx(IconPresentation, { className: "size-3.5 shrink-0", "aria-hidden": "true" }), t("agentChat.accountMenu.demoModeOn")] }), _jsx("p", { className: "mt-0.5 leading-snug text-muted-foreground", children: t("agentChat.accountMenu.demoModeDescription") })] }), _jsxs(DropdownMenuItem, { className: ITEM_CLASS, onSelect: () => setBrowserDemoModeEnabled(false), children: [_jsx(IconPresentation, { className: ITEM_ICON_CLASS }), _jsx("span", { className: "flex-1", children: t("agentChat.accountMenu.turnOffDemoMode") })] }), _jsx(DropdownMenuSeparator, {})] })), _jsxs(DropdownMenuGroup, { children: [orgs.map((o) => {
200
- const current = o.orgId === org.orgId;
201
- return (_jsxs(DropdownMenuItem, { className: ITEM_CLASS, disabled: switchOrg.isPending && !current, onSelect: (event) => {
202
- if (current)
203
- return;
204
- event.preventDefault();
205
- selectOrg(o.orgId);
206
- }, children: [_jsx(ResourceIcon, { value: o.icon, size: 14, resolveImageUrl: (image) => image.authority === "url" ? image.assetId : undefined, fallback: _jsx(IconBriefcase, { className: ITEM_ICON_CLASS }) }), _jsx("span", { className: "min-w-0 flex-1 truncate", children: o.orgName }), isSwitchingTo(o.orgId) ? (_jsx(IconLoader2, { className: cn(ITEM_ICON_CLASS, "animate-spin") })) : current ? (_jsx(IconCheck, { className: ITEM_ICON_CLASS })) : null] }, o.orgId));
207
- }), _jsxs(DropdownMenuItem, { className: ITEM_CLASS, disabled: switchOrg.isPending && inOrg, onSelect: (event) => {
208
- if (!inOrg)
216
+ const mainItems = (_jsxs(_Fragment, { children: [!demoModeEnabled && org.email ? (_jsx(DropdownMenuLabel, { className: "truncate text-xs font-normal text-muted-foreground", children: org.email })) : null, demoModeEnabled && (_jsxs(_Fragment, { children: [_jsxs("div", { role: "status", className: "mx-1 mb-1 rounded-md border border-primary/20 bg-primary/5 px-2 py-1.5 text-[11px]", children: [_jsxs("div", { className: "flex items-center gap-1.5 font-medium text-primary", children: [_jsx(IconPresentation, { className: "size-3.5 shrink-0", "aria-hidden": "true" }), t("agentChat.accountMenu.demoModeOn")] }), _jsx("p", { className: "mt-0.5 leading-snug text-muted-foreground", children: t("agentChat.accountMenu.demoModeDescription") })] }), _jsxs(DropdownMenuItem, { className: ITEM_CLASS, onSelect: () => setBrowserDemoModeEnabled(false), children: [_jsx(IconPresentation, { className: ITEM_ICON_CLASS }), _jsx("span", { className: "flex-1", children: t("agentChat.accountMenu.turnOffDemoMode") })] }), _jsx(DropdownMenuSeparator, {})] })), _jsx(DropdownMenuGroup, { children: orgs.map((o) => {
217
+ const current = o.orgId === org.orgId;
218
+ return (_jsxs(DropdownMenuItem, { className: ITEM_CLASS, disabled: switchOrg.isPending && !current, onSelect: (event) => {
219
+ if (current)
209
220
  return;
210
221
  event.preventDefault();
211
- selectOrg(null);
212
- }, children: [_jsx(IconUser, { className: ITEM_ICON_CLASS }), _jsx("span", { className: "min-w-0 flex-1 truncate", children: t("agentChat.accountMenu.personal") }), isSwitchingTo(null) ? (_jsx(IconLoader2, { className: cn(ITEM_ICON_CLASS, "animate-spin") })) : !inOrg ? (_jsx(IconCheck, { className: ITEM_ICON_CLASS })) : null] })] }), pendingInvitations.length > 0 && (_jsxs(DropdownMenuGroup, { children: [_jsx(DropdownMenuLabel, { className: "pb-0.5 text-[11px] font-normal text-muted-foreground", children: t("agentChat.accountMenu.invitations") }), pendingInvitations.map((inv) => (_jsxs(DropdownMenuItem, { className: cn(ITEM_CLASS, "flex-col items-stretch gap-1"), disabled: acceptInvitation.isPending, onSelect: (event) => {
222
+ selectOrg(o.orgId);
223
+ }, children: [_jsx(ResourceIcon, { value: o.icon, size: 14, resolveImageUrl: (image) => image.authority === "url" ? image.assetId : undefined, fallback: _jsx(IconBriefcase, { className: ITEM_ICON_CLASS }) }), _jsx("span", { className: "min-w-0 flex-1 truncate", children: o.orgName }), isSwitchingTo(o.orgId) ? (_jsx(IconLoader2, { className: cn(ITEM_ICON_CLASS, "animate-spin") })) : current ? (_jsx(IconCheck, { className: ITEM_ICON_CLASS })) : null] }, o.orgId));
224
+ }) }), pendingInvitations.length > 0 && (_jsxs(DropdownMenuGroup, { children: [_jsx(DropdownMenuLabel, { className: "pb-0.5 text-[11px] font-normal text-muted-foreground", children: t("agentChat.accountMenu.invitations") }), pendingInvitations.map((inv) => (_jsxs(DropdownMenuItem, { className: cn(ITEM_CLASS, "flex-col items-stretch gap-1"), disabled: acceptInvitation.isPending, onSelect: (event) => {
213
225
  event.preventDefault();
214
226
  acceptInvitation.mutate(inv.id, {
215
227
  onSuccess: () => setOpen(false),
@@ -175,10 +175,10 @@ export function BuilderCreditUsageSkeleton() {
175
175
  export function BuilderCreditUsagePanel({ usage, }) {
176
176
  const t = useT();
177
177
  const quotaLabel = usage.quota.period === "daily"
178
- ? t("agentChat.usage.dailyFreeLimit", {
179
- defaultValue: "Free daily limit",
178
+ ? t("agentChat.usage.dailyDefaultLimit", {
179
+ defaultValue: "Default daily limit",
180
180
  })
181
- : t("agentChat.usage.monthlyPlan", { defaultValue: "Monthly plan" });
181
+ : t("agentChat.usage.monthlyLimit", { defaultValue: "Monthly limit" });
182
182
  const canAddCredits = usage.quota.remaining === 0;
183
183
  const used = usage.quota.used.toLocaleString(undefined, {
184
184
  maximumFractionDigits: 2,
@@ -20,7 +20,7 @@ function isActionTimeout(error) {
20
20
  error.timedOut === true);
21
21
  }
22
22
  function isRetryableActionStatus(status) {
23
- return status === 429 || status === 502 || status === 503 || status === 504;
23
+ return status === 429 || status === 502 || status === 503;
24
24
  }
25
25
  function actionErrorStatus(error) {
26
26
  const status = error?.status;
@@ -38,19 +38,19 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
38
38
  error: string;
39
39
  states?: undefined;
40
40
  } | {
41
+ error?: undefined;
41
42
  states: {
42
43
  clientId: number;
43
44
  state: string;
44
45
  }[];
45
- error?: undefined;
46
46
  }>>;
47
47
  export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
48
48
  error: string;
49
49
  users?: undefined;
50
50
  } | {
51
+ error?: undefined;
51
52
  users: {
52
53
  clientId: number;
53
54
  lastSeen: number;
54
55
  }[];
55
- error?: undefined;
56
56
  }>>;
@@ -8,8 +8,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
8
8
  state: string;
9
9
  }>>;
10
10
  export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
11
- error: string;
12
11
  ok?: undefined;
12
+ error: string;
13
13
  } | {
14
14
  error?: undefined;
15
15
  ok: boolean;
@@ -33,9 +33,9 @@ declare const _default: import("../../action.js").ActionDefinition<{
33
33
  idempotencyKey: string;
34
34
  deleted: boolean;
35
35
  } | {
36
- id?: undefined;
37
36
  error: string;
38
37
  url?: undefined;
38
+ id?: undefined;
39
39
  provider?: undefined;
40
40
  configured?: undefined;
41
41
  } | {
@@ -45,8 +45,8 @@ declare const _default: import("../../action.js").ActionDefinition<{
45
45
  configured?: undefined;
46
46
  error?: undefined;
47
47
  } | {
48
- id?: undefined;
49
48
  url?: undefined;
49
+ id?: undefined;
50
50
  provider?: undefined;
51
51
  error: string;
52
52
  configured: boolean;
@@ -38,6 +38,8 @@ export interface BackgroundAutomationRunOptions {
38
38
  actionCaller?: ActionCaller;
39
39
  actionAutomation?: ActionAutomationContext;
40
40
  historyId?: string;
41
+ hardTimeoutMs?: number;
42
+ hardDeadlineAt?: number;
41
43
  noProgressTimeoutMs?: number;
42
44
  backgroundNoProgressTimeoutMs?: number;
43
45
  }
@@ -140,6 +140,11 @@ export function backgroundRunCutOffReason(run) {
140
140
  function uniqueToolNames(names) {
141
141
  return [...new Set(names)];
142
142
  }
143
+ function assertHardDeadline(deadlineAt) {
144
+ if (deadlineAt !== undefined && Date.now() >= deadlineAt) {
145
+ throw new BackgroundAutomationRunError("Background automation time budget expired during setup.", "background_automation_hard_timeout");
146
+ }
147
+ }
143
148
  function assertRequestedMcpToolsAvailable(automation, actions) {
144
149
  const requested = automation.meta.mcpTools ?? [];
145
150
  const missing = requested.filter((toolName) => !actions[toolName]);
@@ -153,6 +158,7 @@ function createRunId(prefix) {
153
158
  }
154
159
  export async function runBackgroundAutomation(options, deps) {
155
160
  const { automation } = options;
161
+ assertHardDeadline(options.hardDeadlineAt);
156
162
  let historyId = null;
157
163
  if (options.historyId) {
158
164
  historyId = options.historyId;
@@ -297,7 +303,9 @@ async function executeBackgroundAutomation(options, deps, historyId, runIdRef) {
297
303
  userEmail: ownerEmail,
298
304
  orgId,
299
305
  }, async () => {
306
+ assertHardDeadline(options.hardDeadlineAt);
300
307
  const baseActions = await deps.getActions(automation);
308
+ assertHardDeadline(options.hardDeadlineAt);
301
309
  assertRequestedMcpToolsAvailable(automation, baseActions);
302
310
  const configuredInitialTools = deps.getInitialToolNames?.(automation);
303
311
  const initialToolNames = configuredInitialTools
@@ -311,7 +319,9 @@ async function executeBackgroundAutomation(options, deps, historyId, runIdRef) {
311
319
  : baseActions;
312
320
  const availableTools = actionsToEngineTools(actions);
313
321
  const tools = filterInitialEngineTools(availableTools, initialToolNames);
322
+ assertHardDeadline(options.hardDeadlineAt);
314
323
  const ownerApiKey = await resolveOwnerEngineApiKey({ ownerEmail });
324
+ assertHardDeadline(options.hardDeadlineAt);
315
325
  const apiKey = ownerApiKey.apiKey ?? deps.apiKey;
316
326
  const apiKeyProvenance = ownerApiKey.apiKey
317
327
  ? ownerApiKey.credentialProvenance
@@ -328,26 +338,32 @@ async function executeBackgroundAutomation(options, deps, historyId, runIdRef) {
328
338
  appId: deps.appId,
329
339
  credentialIdentity: { userEmail: ownerEmail, orgId },
330
340
  }));
341
+ assertHardDeadline(options.hardDeadlineAt);
331
342
  const modelCandidate = automation.meta.model ??
332
343
  deps.model ??
333
344
  (await getStoredModelForEngine(engine, { appId: deps.appId })) ??
334
345
  engine.defaultModel;
335
346
  const model = normalizeModelForEngine(engine, modelCandidate);
347
+ assertHardDeadline(options.hardDeadlineAt);
336
348
  const systemPrompt = await deps.getSystemPrompt(ownerEmail);
349
+ assertHardDeadline(options.hardDeadlineAt);
337
350
  const thread = await createThread(ownerEmail, {
338
351
  title: threadTitle,
339
352
  orgId: orgId ?? null,
340
353
  });
354
+ assertHardDeadline(options.hardDeadlineAt);
341
355
  const runId = createRunId(options.runIdPrefix);
342
356
  if (runIdRef)
343
357
  runIdRef.current = runId;
344
358
  await recordRunThread(historyId, thread.id, runId);
345
- const hardTimeoutMs = resolveBackgroundRunHardTimeoutMs();
359
+ assertHardDeadline(options.hardDeadlineAt);
360
+ const maxHardTimeoutMs = Math.min(options.hardTimeoutMs ?? Number.POSITIVE_INFINITY, resolveBackgroundRunHardTimeoutMs());
346
361
  const softTimeoutMs = resolveBackgroundAutomationSoftTimeoutMs();
347
362
  const usageRef = { current: null };
348
363
  let responseText = "";
349
364
  let hardAbortTimer = null;
350
365
  let hardTimedOut = false;
366
+ assertHardDeadline(options.hardDeadlineAt);
351
367
  await insertRun(runId, thread.id, undefined, {
352
368
  dispatchMode: "background",
353
369
  });
@@ -355,6 +371,9 @@ async function executeBackgroundAutomation(options, deps, historyId, runIdRef) {
355
371
  if (!claimedOwnRun) {
356
372
  throw new Error(`Background automation "${automation.name}" (run "${runId}") could not claim its own freshly-inserted run row`);
357
373
  }
374
+ const hardTimeoutMs = Math.min(maxHardTimeoutMs, options.hardDeadlineAt === undefined
375
+ ? Number.POSITIVE_INFINITY
376
+ : Math.max(1, options.hardDeadlineAt - Date.now()));
358
377
  await new Promise((resolve, reject) => {
359
378
  const activeRun = startRun(runId, thread.id, async (send, signal, control) => {
360
379
  const loopOpts = {
@@ -1,7 +1,11 @@
1
- export type RecurringSweepHandler = () => Promise<void>;
1
+ export declare const RECURRING_SWEEP_BUDGET_MS = 90000;
2
+ export interface RecurringSweepContext {
3
+ deadlineAt: number;
4
+ }
5
+ export type RecurringSweepHandler = (context: RecurringSweepContext) => Promise<void>;
2
6
  export declare function registerRecurringSweepHandler(id: string, handler: RecurringSweepHandler): () => void;
3
7
  export declare function hasRecurringSweepHandler(id: string): boolean;
4
- export declare function runRecurringSweepHandlers(): Promise<{
8
+ export declare function runRecurringSweepHandlers(context: RecurringSweepContext): Promise<{
5
9
  registered: number;
6
10
  failed: string[];
7
11
  }>;
@@ -1,3 +1,4 @@
1
+ export const RECURRING_SWEEP_BUDGET_MS = 90_000;
1
2
  const handlers = new Map();
2
3
  export function registerRecurringSweepHandler(id, handler) {
3
4
  const key = id.trim();
@@ -12,17 +13,24 @@ export function registerRecurringSweepHandler(id, handler) {
12
13
  export function hasRecurringSweepHandler(id) {
13
14
  return handlers.has(id);
14
15
  }
15
- export async function runRecurringSweepHandlers() {
16
- const failed = [];
16
+ export async function runRecurringSweepHandlers(context) {
17
17
  const snapshot = [...handlers.entries()];
18
- for (const [id, handler] of snapshot) {
19
- try {
20
- await handler();
18
+ const outcomes = await Promise.allSettled(snapshot.map(async ([id, handler]) => {
19
+ if (Date.now() >= context.deadlineAt) {
20
+ throw new Error("Recurring sweep deadline elapsed before handler start.");
21
21
  }
22
- catch (error) {
23
- console.error(`[recurring-sweep] handler ${id} failed:`, error);
24
- failed.push(id);
22
+ await handler(context);
23
+ if (Date.now() > context.deadlineAt) {
24
+ throw new Error("Recurring sweep handler exceeded its deadline.");
25
25
  }
26
- }
26
+ return id;
27
+ }));
28
+ const failed = outcomes.flatMap((outcome, index) => {
29
+ if (outcome.status === "fulfilled")
30
+ return [];
31
+ const id = snapshot[index][0];
32
+ console.error(`[recurring-sweep] handler ${id} failed:`, outcome.reason);
33
+ return [id];
34
+ });
27
35
  return { registered: snapshot.length, failed };
28
36
  }
@@ -1112,8 +1112,8 @@ const messages = {
1112
1112
  "usage.copyInviteLink": "نسخ رابط الدعوة",
1113
1113
  "usage.inviteLinkCopied": "تم نسخ رابط الدعوة",
1114
1114
  "usage.creditBalance": "رصيد مساحة العمل",
1115
- "usage.monthlyPlan": "الخطة الشهرية",
1116
- "usage.dailyFreeLimit": "الحد اليومي المجاني",
1115
+ "usage.monthlyLimit": "الحد الشهري",
1116
+ "usage.dailyDefaultLimit": "الحد اليومي الافتراضي",
1117
1117
  "usage.creditUsedOfLimit": "استخدام {{used}} من {{limit}}",
1118
1118
  "usage.creditRemaining": "المتبقي {{amount}}",
1119
1119
  "usage.creditUsageUnavailable": "تعذّر تحميل استخدام أرصدة Builder.",
@@ -1076,8 +1076,8 @@ const messages = {
1076
1076
  "usage.copyInviteLink": "Einladungslink kopieren",
1077
1077
  "usage.inviteLinkCopied": "Einladungslink kopiert",
1078
1078
  "usage.creditBalance": "Workspace-Guthaben",
1079
- "usage.monthlyPlan": "Monatsplan",
1080
- "usage.dailyFreeLimit": "Tägliches Gratislimit",
1079
+ "usage.monthlyLimit": "Monatliches Limit",
1080
+ "usage.dailyDefaultLimit": "Tägliches Standardlimit",
1081
1081
  "usage.creditUsedOfLimit": "{{used}} von {{limit}} verbraucht",
1082
1082
  "usage.creditRemaining": "{{amount}} verbleibend",
1083
1083
  "usage.creditUsageUnavailable": "Der Builder-Credit-Verbrauch konnte nicht geladen werden.",
@@ -1076,8 +1076,8 @@ declare const messages: {
1076
1076
  readonly "usage.copyInviteLink": "Copy invite link";
1077
1077
  readonly "usage.inviteLinkCopied": "Invite link copied";
1078
1078
  readonly "usage.creditBalance": "Workspace balance";
1079
- readonly "usage.monthlyPlan": "Monthly plan";
1080
- readonly "usage.dailyFreeLimit": "Free daily limit";
1079
+ readonly "usage.monthlyLimit": "Monthly limit";
1080
+ readonly "usage.dailyDefaultLimit": "Default daily limit";
1081
1081
  readonly "usage.creditUsedOfLimit": "{{used}} of {{limit}} used";
1082
1082
  readonly "usage.creditRemaining": "{{amount}} remaining";
1083
1083
  readonly "usage.creditUsageUnavailable": "Builder credit usage couldn’t be loaded.";
@@ -1076,8 +1076,8 @@ const messages = {
1076
1076
  "usage.copyInviteLink": "Copy invite link",
1077
1077
  "usage.inviteLinkCopied": "Invite link copied",
1078
1078
  "usage.creditBalance": "Workspace balance",
1079
- "usage.monthlyPlan": "Monthly plan",
1080
- "usage.dailyFreeLimit": "Free daily limit",
1079
+ "usage.monthlyLimit": "Monthly limit",
1080
+ "usage.dailyDefaultLimit": "Default daily limit",
1081
1081
  "usage.creditUsedOfLimit": "{{used}} of {{limit}} used",
1082
1082
  "usage.creditRemaining": "{{amount}} remaining",
1083
1083
  "usage.creditUsageUnavailable": "Builder credit usage couldn’t be loaded.",
@@ -1085,8 +1085,8 @@ const messages = {
1085
1085
  "usage.copyInviteLink": "Copiar enlace de invitación",
1086
1086
  "usage.inviteLinkCopied": "Enlace de invitación copiado",
1087
1087
  "usage.creditBalance": "Saldo del espacio de trabajo",
1088
- "usage.monthlyPlan": "Plan mensual",
1089
- "usage.dailyFreeLimit": "Límite diario gratuito",
1088
+ "usage.monthlyLimit": "Límite mensual",
1089
+ "usage.dailyDefaultLimit": "Límite diario predeterminado",
1090
1090
  "usage.creditUsedOfLimit": "{{used}} de {{limit}} usados",
1091
1091
  "usage.creditRemaining": "Quedan {{amount}}",
1092
1092
  "usage.creditUsageUnavailable": "No se pudo cargar el uso de créditos de Builder.",
@@ -1085,8 +1085,8 @@ const messages = {
1085
1085
  "usage.copyInviteLink": "Copier le lien d’invitation",
1086
1086
  "usage.inviteLinkCopied": "Lien d’invitation copié",
1087
1087
  "usage.creditBalance": "Solde de l’espace de travail",
1088
- "usage.monthlyPlan": "Forfait mensuel",
1089
- "usage.dailyFreeLimit": "Limite quotidienne gratuite",
1088
+ "usage.monthlyLimit": "Limite mensuelle",
1089
+ "usage.dailyDefaultLimit": "Limite quotidien par défaut",
1090
1090
  "usage.creditUsedOfLimit": "{{used}} sur {{limit}} utilisés",
1091
1091
  "usage.creditRemaining": "{{amount}} restants",
1092
1092
  "usage.creditUsageUnavailable": "Impossible de charger l’utilisation des crédits Builder.",
@@ -1076,8 +1076,8 @@ const messages = {
1076
1076
  "usage.copyInviteLink": "आमंत्रण लिंक कॉपी करें",
1077
1077
  "usage.inviteLinkCopied": "आमंत्रण लिंक कॉपी हो गया",
1078
1078
  "usage.creditBalance": "वर्कस्पेस बैलेंस",
1079
- "usage.monthlyPlan": "मासिक प्लान",
1080
- "usage.dailyFreeLimit": "मुफ़्त दैनिक सीमा",
1079
+ "usage.monthlyLimit": "मासिक सीमा",
1080
+ "usage.dailyDefaultLimit": "डिफ़ॉल्ट दैनिक सीमा",
1081
1081
  "usage.creditUsedOfLimit": "{{limit}} में से {{used}} उपयोग किए",
1082
1082
  "usage.creditRemaining": "{{amount}} शेष",
1083
1083
  "usage.creditUsageUnavailable": "Builder क्रेडिट उपयोग लोड नहीं हो सका।",
@@ -1068,8 +1068,8 @@ const messages = {
1068
1068
  "usage.copyInviteLink": "招待リンクをコピー",
1069
1069
  "usage.inviteLinkCopied": "招待リンクをコピーしました",
1070
1070
  "usage.creditBalance": "ワークスペース残高",
1071
- "usage.monthlyPlan": "月間プラン",
1072
- "usage.dailyFreeLimit": "無料の日次上限",
1071
+ "usage.monthlyLimit": "月間上限",
1072
+ "usage.dailyDefaultLimit": "デフォルトの日次上限",
1073
1073
  "usage.creditUsedOfLimit": "{{limit}} 中 {{used}} を使用",
1074
1074
  "usage.creditRemaining": "残り {{amount}}",
1075
1075
  "usage.creditUsageUnavailable": "Builder クレジットの使用状況を読み込めませんでした。",
@@ -1068,8 +1068,8 @@ const messages = {
1068
1068
  "usage.copyInviteLink": "초대 링크 복사",
1069
1069
  "usage.inviteLinkCopied": "초대 링크를 복사했습니다",
1070
1070
  "usage.creditBalance": "워크스페이스 잔액",
1071
- "usage.monthlyPlan": "월간 플랜",
1072
- "usage.dailyFreeLimit": "무료 일일 한도",
1071
+ "usage.monthlyLimit": "월간 한도",
1072
+ "usage.dailyDefaultLimit": "기본 일일 한도",
1073
1073
  "usage.creditUsedOfLimit": "{{limit}} 중 {{used}} 사용",
1074
1074
  "usage.creditRemaining": "{{amount}} 남음",
1075
1075
  "usage.creditUsageUnavailable": "Builder 크레딧 사용량을 불러오지 못했습니다.",
@@ -1085,8 +1085,8 @@ const messages = {
1085
1085
  "usage.copyInviteLink": "Copiar link de convite",
1086
1086
  "usage.inviteLinkCopied": "Link de convite copiado",
1087
1087
  "usage.creditBalance": "Saldo do workspace",
1088
- "usage.monthlyPlan": "Plano mensal",
1089
- "usage.dailyFreeLimit": "Limite diário gratuito",
1088
+ "usage.monthlyLimit": "Limite mensal",
1089
+ "usage.dailyDefaultLimit": "Limite diário padrão",
1090
1090
  "usage.creditUsedOfLimit": "{{used}} de {{limit}} usados",
1091
1091
  "usage.creditRemaining": "{{amount}} restantes",
1092
1092
  "usage.creditUsageUnavailable": "Não foi possível carregar o uso de créditos do Builder.",
@@ -1068,8 +1068,8 @@ const messages = {
1068
1068
  "usage.copyInviteLink": "复制邀请链接",
1069
1069
  "usage.inviteLinkCopied": "邀请链接已复制",
1070
1070
  "usage.creditBalance": "工作区余额",
1071
- "usage.monthlyPlan": "月度套餐",
1072
- "usage.dailyFreeLimit": "免费每日上限",
1071
+ "usage.monthlyLimit": "月度限额",
1072
+ "usage.dailyDefaultLimit": "默认每日限额",
1073
1073
  "usage.creditUsedOfLimit": "已使用 {{used}} / {{limit}}",
1074
1074
  "usage.creditRemaining": "剩余 {{amount}}",
1075
1075
  "usage.creditUsageUnavailable": "无法加载 Builder 积分使用情况。",
@@ -1068,8 +1068,8 @@ const messages = {
1068
1068
  "usage.copyInviteLink": "複製邀請連結",
1069
1069
  "usage.inviteLinkCopied": "邀請連結已複製",
1070
1070
  "usage.creditBalance": "工作區餘額",
1071
- "usage.monthlyPlan": "月度方案",
1072
- "usage.dailyFreeLimit": "免費每日上限",
1071
+ "usage.monthlyLimit": "每月上限",
1072
+ "usage.dailyDefaultLimit": "預設每日上限",
1073
1073
  "usage.creditUsedOfLimit": "已使用 {{used}} / {{limit}}",
1074
1074
  "usage.creditRemaining": "剩餘 {{amount}}",
1075
1075
  "usage.creditUsageUnavailable": "無法載入 Builder 點數使用情況。",
@@ -1078,8 +1078,8 @@ export declare const englishAgentChatMessages: {
1078
1078
  readonly "usage.copyInviteLink": "Copy invite link";
1079
1079
  readonly "usage.inviteLinkCopied": "Invite link copied";
1080
1080
  readonly "usage.creditBalance": "Workspace balance";
1081
- readonly "usage.monthlyPlan": "Monthly plan";
1082
- readonly "usage.dailyFreeLimit": "Free daily limit";
1081
+ readonly "usage.monthlyLimit": "Monthly limit";
1082
+ readonly "usage.dailyDefaultLimit": "Default daily limit";
1083
1083
  readonly "usage.creditUsedOfLimit": "{{used}} of {{limit}} used";
1084
1084
  readonly "usage.creditRemaining": "{{amount}} remaining";
1085
1085
  readonly "usage.creditUsageUnavailable": "Builder credit usage couldn’t be loaded.";
@@ -1,21 +1,21 @@
1
1
  export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
2
2
  count: number;
3
3
  updated?: undefined;
4
- ok?: undefined;
5
4
  error?: undefined;
5
+ ok?: undefined;
6
6
  } | {
7
+ count?: undefined;
7
8
  updated: number;
8
- ok?: undefined;
9
9
  error?: undefined;
10
- count?: undefined;
10
+ ok?: undefined;
11
11
  } | {
12
+ count?: undefined;
12
13
  updated?: undefined;
13
14
  error: string;
14
15
  ok?: undefined;
15
- count?: undefined;
16
16
  } | {
17
+ count?: undefined;
17
18
  updated?: undefined;
18
19
  ok: boolean;
19
20
  error?: undefined;
20
- count?: undefined;
21
21
  }>>;
@@ -20,27 +20,27 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
20
20
  thumbsUpRate: number;
21
21
  avgEvalScore: number;
22
22
  } | {
23
+ error?: undefined;
24
+ id?: undefined;
23
25
  summary: import("./types.js").TraceSummary;
24
26
  spans: import("./types.js").TraceSpan[];
25
- id?: undefined;
26
- error?: undefined;
27
27
  ok?: undefined;
28
28
  } | {
29
+ error?: undefined;
29
30
  summary?: undefined;
30
31
  spans?: undefined;
31
32
  id: string;
32
- error?: undefined;
33
33
  ok?: undefined;
34
34
  } | {
35
+ id?: undefined;
35
36
  summary?: undefined;
36
37
  spans?: undefined;
37
- id?: undefined;
38
38
  error: any;
39
39
  ok?: undefined;
40
40
  } | {
41
+ error?: undefined;
42
+ id?: undefined;
41
43
  summary?: undefined;
42
44
  spans?: undefined;
43
- id?: undefined;
44
- error?: undefined;
45
45
  ok: boolean;
46
46
  }>>;
@@ -2,6 +2,6 @@ export declare function createProgressHandler(): import("h3").EventHandlerWithFe
2
2
  error: string;
3
3
  ok?: undefined;
4
4
  } | {
5
- ok: boolean;
6
5
  error?: undefined;
6
+ ok: boolean;
7
7
  }>>;
@@ -77,6 +77,9 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
77
77
  }, z.core.$strip>>, {
78
78
  deleted?: undefined;
79
79
  id?: undefined;
80
+ provider?: undefined;
81
+ message?: undefined;
82
+ found?: undefined;
80
83
  providers: {
81
84
  id: string;
82
85
  label: string;
@@ -87,47 +90,44 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
87
90
  updatedAt: number;
88
91
  }[];
89
92
  count: number;
90
- provider?: undefined;
91
- found?: undefined;
92
93
  registered?: undefined;
93
94
  label?: undefined;
94
- message?: undefined;
95
95
  } | {
96
96
  deleted?: undefined;
97
97
  id?: undefined;
98
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
106
  deleted?: undefined;
107
+ provider?: undefined;
107
108
  count?: undefined;
109
+ message?: undefined;
108
110
  providers?: undefined;
109
- provider?: undefined;
110
111
  found: boolean;
111
112
  id: string;
112
113
  registered?: undefined;
113
114
  label?: undefined;
114
- message?: undefined;
115
115
  } | {
116
- count?: undefined;
117
- providers?: undefined;
118
116
  provider?: undefined;
117
+ count?: undefined;
118
+ message?: undefined;
119
119
  found?: undefined;
120
+ providers?: undefined;
120
121
  deleted: boolean;
121
122
  id: string;
122
123
  registered?: undefined;
123
124
  label?: undefined;
124
- message?: undefined;
125
125
  } | {
126
126
  deleted?: undefined;
127
- count?: undefined;
128
- providers?: undefined;
129
127
  provider?: undefined;
128
+ count?: undefined;
130
129
  found?: undefined;
130
+ providers?: undefined;
131
131
  registered: boolean;
132
132
  id: string;
133
133
  label: string;