@agent-native/core 0.144.2 → 0.144.3
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.
- package/corpus/templates/analytics/app/pages/DataSources.tsx +28 -4
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +7 -3
- package/corpus/templates/analytics/server/plugins/dashboard-report-jobs.ts +13 -3
- package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +64 -23
- package/corpus/templates/calendar/app/hooks/use-google-auth.ts +69 -46
- package/corpus/templates/calendar/app/hooks/use-view-preferences.ts +35 -6
- package/corpus/templates/calendar/app/hooks/use-zoom-auth.ts +24 -3
- package/corpus/templates/clips/app/components/player/transcript-panel.tsx +45 -6
- package/corpus/templates/clips/app/components/recorder/storage-setup-card.tsx +38 -5
- package/corpus/templates/clips/desktop/src/app.tsx +146 -45
- package/corpus/templates/clips/server/jobs/brain-export.ts +13 -6
- package/corpus/templates/clips/server/jobs/builder-media-compression.ts +10 -3
- package/corpus/templates/clips/server/jobs/meeting-reminders.ts +10 -3
- package/corpus/templates/clips/server/jobs/poll-calendars.ts +23 -21
- package/corpus/templates/clips/server/jobs/stale-meeting-sweeper.ts +10 -3
- package/corpus/templates/clips/server/jobs/transactional-emails.ts +10 -3
- package/corpus/templates/content/app/components/sidebar/NotionButton.tsx +1 -0
- package/corpus/templates/design/app/components/design/FusionAppBanner.tsx +15 -2
- package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +82 -39
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +31 -9
- package/corpus/templates/mail/server/plugins/mail-jobs.ts +36 -17
- package/dist/client/AssistantChat.js +73 -43
- package/dist/client/MultiTabAssistantChat.d.ts +3 -1
- package/dist/client/MultiTabAssistantChat.js +79 -92
- package/dist/client/browser-session-bridge.js +97 -54
- package/dist/client/db-admin/useAgentSync.js +34 -43
- package/dist/client/dynamic-suggestions.d.ts +3 -0
- package/dist/client/dynamic-suggestions.js +54 -52
- package/dist/client/hooks/index.d.ts +1 -0
- package/dist/client/hooks/index.js +1 -0
- package/dist/client/i18n.d.ts +7 -0
- package/dist/client/i18n.js +12 -3
- package/dist/client/integrations/useIntegrationStatus.d.ts +1 -1
- package/dist/client/integrations/useIntegrationStatus.js +9 -22
- package/dist/client/notifications/NotificationsBell.js +14 -9
- package/dist/client/progress/RunsTray.js +6 -5
- package/dist/client/settings/useBuilderStatus.js +95 -73
- package/dist/client/transcription/BuilderTranscriptionCta.js +27 -31
- package/dist/client/use-agent-engine-configured.js +21 -3
- package/dist/client/use-pausing-interval.d.ts +6 -0
- package/dist/client/use-pausing-interval.js +6 -0
- package/dist/client/use-poll-loop.d.ts +39 -0
- package/dist/client/use-poll-loop.js +73 -0
- package/dist/client/use-run-stuck-detection.js +41 -13
- package/dist/collab/routes.d.ts +1 -1
- package/dist/integrations/google-docs-poller.js +26 -7
- package/dist/integrations/pending-tasks-retry-job.js +17 -23
- package/dist/integrations/plugin.js +16 -15
- package/dist/integrations/remote-push-delivery-job.js +16 -25
- package/dist/integrations/remote-retry-job.js +19 -23
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/oauth-tokens/google-refresh.js +12 -19
- package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/server/agent-chat-plugin.js +26 -29
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/interval-job.d.ts +25 -0
- package/dist/server/interval-job.js +19 -0
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +1 -0
- package/dist/shared/poll-engine.d.ts +49 -0
- package/dist/shared/poll-engine.js +148 -0
- package/dist/templates/default/.agents/skills/internationalization/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/internationalization/SKILL.md +5 -0
- package/dist/tracking/providers.js +10 -1
- package/package.json +4 -3
- package/src/templates/default/.agents/skills/internationalization/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/internationalization/SKILL.md +5 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createPollEngine } from "../shared/poll-engine.js";
|
|
2
|
+
/**
|
|
3
|
+
* Run a background job on a recurring interval without hand-rolling a
|
|
4
|
+
* `running` overlap guard or a request timeout — see `createPollEngine` for
|
|
5
|
+
* the underlying guarantees. `runOnce` keeps its normal exported signature
|
|
6
|
+
* (serverless schedulers can still call it directly, bypassing the loop);
|
|
7
|
+
* this only replaces the `setInterval` + module-level flag wiring around it.
|
|
8
|
+
* The internal timer is `.unref()`'d so it never keeps the process alive on
|
|
9
|
+
* its own.
|
|
10
|
+
*/
|
|
11
|
+
export function startIntervalJob(runOnce, options) {
|
|
12
|
+
const engine = createPollEngine(runOnce, options);
|
|
13
|
+
engine.start();
|
|
14
|
+
return {
|
|
15
|
+
stop() {
|
|
16
|
+
engine.stop();
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -26,8 +26,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
|
|
|
26
26
|
expiresAt?: undefined;
|
|
27
27
|
ttlSeconds?: undefined;
|
|
28
28
|
} | {
|
|
29
|
+
error?: undefined;
|
|
29
30
|
token: string;
|
|
30
31
|
expiresAt: string;
|
|
31
32
|
ttlSeconds: number;
|
|
32
|
-
error?: undefined;
|
|
33
33
|
}>>;
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export { llmConnectionTrackingProperties, normalizeLlmConnection, type LlmConnec
|
|
|
9
9
|
export { DISPATCH_WORKSPACE_ROOT_REDIRECTS, RESERVED_WORKSPACE_APP_IDS, assertValidWorkspaceAppId, getWorkspaceAppIdValidationError, isValidWorkspaceAppIdFormat, } from "./workspace-app-id.js";
|
|
10
10
|
export { DEFAULT_WORKSPACE_APP_AUDIENCE, WORKSPACE_APP_AUDIENCES, normalizeWorkspaceAppAudience, normalizeWorkspaceAppPathList, workspaceAppAudienceFromEnv, workspaceAppAudienceFromPackageJson, workspaceAppRouteAccessFromEnv, workspaceAppRouteAccessFromPackageJson, type WorkspaceAppRouteAccess, type WorkspaceAppRouteAccessFromConfig, type WorkspaceAppAudience, } from "./workspace-app-audience.js";
|
|
11
11
|
export { AGENT_NATIVE_OPEN_PATH, AGENT_SIDEBAR_QUERY_PARAM, AGENT_SIDEBAR_QUERY_VALUE_CLOSED, isAgentNativeOpenDeepLink, withCollapsedAgentSidebarParam, } from "./agent-sidebar-url.js";
|
|
12
|
+
export { createPollEngine, type PollEngineOptions, type PollEngineHandle, } from "./poll-engine.js";
|
|
12
13
|
export { AGENT_NATIVE_DEFAULT_SOCIAL_IMAGE, AGENT_NATIVE_SOCIAL_IMAGE_CACHE_BUSTER, AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, defaultSocialImageMeta, withAgentNativeSocialImageCacheBuster, withDefaultSocialImage, type SocialMetaDescriptor, } from "./social-meta.js";
|
|
13
14
|
export { EMBED_MODE_QUERY_PARAM, EMBED_SESSION_COOKIE, EMBED_START_PATH, EMBED_TOKEN_QUERY_PARAM, } from "./embed-auth.js";
|
|
14
15
|
export { AGENT_ACCESS_PARAM, DEFAULT_AGENT_ACCESS_TTL_SECONDS, appendAgentAccessParam, buildAgentAccessApiUrl, buildAgentAccessUrl, normalizeAgentAccessBasePath, normalizeAgentAccessOrigin, scopedAgentAccessResourceId, toAgentAccessUrl, type AgentAccessApiUrlOptions, type AgentAccessResourceScope, type AgentAccessUrlOptions, } from "./agent-access.js";
|
package/dist/shared/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export { llmConnectionTrackingProperties, normalizeLlmConnection, } from "./llm-
|
|
|
9
9
|
export { DISPATCH_WORKSPACE_ROOT_REDIRECTS, RESERVED_WORKSPACE_APP_IDS, assertValidWorkspaceAppId, getWorkspaceAppIdValidationError, isValidWorkspaceAppIdFormat, } from "./workspace-app-id.js";
|
|
10
10
|
export { DEFAULT_WORKSPACE_APP_AUDIENCE, WORKSPACE_APP_AUDIENCES, normalizeWorkspaceAppAudience, normalizeWorkspaceAppPathList, workspaceAppAudienceFromEnv, workspaceAppAudienceFromPackageJson, workspaceAppRouteAccessFromEnv, workspaceAppRouteAccessFromPackageJson, } from "./workspace-app-audience.js";
|
|
11
11
|
export { AGENT_NATIVE_OPEN_PATH, AGENT_SIDEBAR_QUERY_PARAM, AGENT_SIDEBAR_QUERY_VALUE_CLOSED, isAgentNativeOpenDeepLink, withCollapsedAgentSidebarParam, } from "./agent-sidebar-url.js";
|
|
12
|
+
export { createPollEngine, } from "./poll-engine.js";
|
|
12
13
|
export { AGENT_NATIVE_DEFAULT_SOCIAL_IMAGE, AGENT_NATIVE_SOCIAL_IMAGE_CACHE_BUSTER, AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, defaultSocialImageMeta, withAgentNativeSocialImageCacheBuster, withDefaultSocialImage, } from "./social-meta.js";
|
|
13
14
|
export { EMBED_MODE_QUERY_PARAM, EMBED_SESSION_COOKIE, EMBED_START_PATH, EMBED_TOKEN_QUERY_PARAM, } from "./embed-auth.js";
|
|
14
15
|
export { AGENT_ACCESS_PARAM, DEFAULT_AGENT_ACCESS_TTL_SECONDS, appendAgentAccessParam, buildAgentAccessApiUrl, buildAgentAccessUrl, normalizeAgentAccessBasePath, normalizeAgentAccessOrigin, scopedAgentAccessResourceId, toAgentAccessUrl, } from "./agent-access.js";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared recurring-poll engine used by both `usePollLoop` (client) and
|
|
3
|
+
* `startIntervalJob` (server) so every polling loop in the codebase gets the
|
|
4
|
+
* same three properties for free instead of hand-rolling them per call site:
|
|
5
|
+
*
|
|
6
|
+
* 1. Never overlaps: the next attempt is scheduled via `setTimeout` only
|
|
7
|
+
* after the current one settles, not on a fixed `setInterval` cadence.
|
|
8
|
+
* This also avoids the latency `setInterval` + skip-if-busy introduces —
|
|
9
|
+
* a skipped tick there means waiting a full extra cadence before the next
|
|
10
|
+
* retry; here the gap after completion is always exactly `intervalMs`.
|
|
11
|
+
* 2. Never stalls silently: every attempt is bounded by a timeout (paired
|
|
12
|
+
* with an `AbortController` so a `fetch` can actually cancel, not just be
|
|
13
|
+
* abandoned), and that timeout reports through `onError` the moment it
|
|
14
|
+
* fires. An attempt that ignores its `signal` keeps holding the loop —
|
|
15
|
+
* reported, not hidden — because releasing the slot to the next attempt
|
|
16
|
+
* would trade a visible stall for a silent overlap.
|
|
17
|
+
* 3. Never double-fires: a single internal in-flight flag, owned by this
|
|
18
|
+
* engine rather than duplicated in every caller.
|
|
19
|
+
*/
|
|
20
|
+
export interface PollEngineOptions {
|
|
21
|
+
/** Delay in ms before the next attempt. Evaluated fresh before each schedule. */
|
|
22
|
+
intervalMs: number | (() => number);
|
|
23
|
+
/** Per-attempt timeout. Default: `Math.max(timeoutFloorMs, intervalMs * 4)`. */
|
|
24
|
+
timeoutMs?: number | (() => number);
|
|
25
|
+
/** Floor used by the default `timeoutMs`. Default: 10_000. */
|
|
26
|
+
timeoutFloorMs?: number;
|
|
27
|
+
/** Called when an attempt throws or times out. Default: swallow. */
|
|
28
|
+
onError?: (err: unknown) => void;
|
|
29
|
+
/** Run the first attempt immediately on `start()`. Default: true. */
|
|
30
|
+
leading?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface PollEngineHandle {
|
|
33
|
+
/** Arm the loop. No-op if already running. */
|
|
34
|
+
start(): void;
|
|
35
|
+
/** Halt the loop and abort any in-flight attempt; its eventual settlement is a no-op. */
|
|
36
|
+
stop(): void;
|
|
37
|
+
/** Cancel the pending wait and run now. No-op if not running or an attempt is already in flight. */
|
|
38
|
+
pollNow(): void;
|
|
39
|
+
/**
|
|
40
|
+
* Re-arm the pending wait using a freshly resolved `intervalMs`, without
|
|
41
|
+
* running an attempt. Use this when `intervalMs` is a function whose
|
|
42
|
+
* result can change externally (e.g. tab visibility) — otherwise a
|
|
43
|
+
* change only takes effect the next time an attempt completes. No-op if
|
|
44
|
+
* there's no pending wait (not running, or an attempt is in flight).
|
|
45
|
+
*/
|
|
46
|
+
reschedule(): void;
|
|
47
|
+
readonly isRunning: boolean;
|
|
48
|
+
}
|
|
49
|
+
export declare function createPollEngine(attempt: (signal: AbortSignal) => Promise<void>, options: PollEngineOptions): PollEngineHandle;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared recurring-poll engine used by both `usePollLoop` (client) and
|
|
3
|
+
* `startIntervalJob` (server) so every polling loop in the codebase gets the
|
|
4
|
+
* same three properties for free instead of hand-rolling them per call site:
|
|
5
|
+
*
|
|
6
|
+
* 1. Never overlaps: the next attempt is scheduled via `setTimeout` only
|
|
7
|
+
* after the current one settles, not on a fixed `setInterval` cadence.
|
|
8
|
+
* This also avoids the latency `setInterval` + skip-if-busy introduces —
|
|
9
|
+
* a skipped tick there means waiting a full extra cadence before the next
|
|
10
|
+
* retry; here the gap after completion is always exactly `intervalMs`.
|
|
11
|
+
* 2. Never stalls silently: every attempt is bounded by a timeout (paired
|
|
12
|
+
* with an `AbortController` so a `fetch` can actually cancel, not just be
|
|
13
|
+
* abandoned), and that timeout reports through `onError` the moment it
|
|
14
|
+
* fires. An attempt that ignores its `signal` keeps holding the loop —
|
|
15
|
+
* reported, not hidden — because releasing the slot to the next attempt
|
|
16
|
+
* would trade a visible stall for a silent overlap.
|
|
17
|
+
* 3. Never double-fires: a single internal in-flight flag, owned by this
|
|
18
|
+
* engine rather than duplicated in every caller.
|
|
19
|
+
*/
|
|
20
|
+
const DEFAULT_TIMEOUT_FLOOR_MS = 10_000;
|
|
21
|
+
function resolve(value) {
|
|
22
|
+
return typeof value === "function" ? value() : value;
|
|
23
|
+
}
|
|
24
|
+
function maybeUnref(timer) {
|
|
25
|
+
if (timer &&
|
|
26
|
+
typeof timer === "object" &&
|
|
27
|
+
"unref" in timer &&
|
|
28
|
+
typeof timer.unref === "function") {
|
|
29
|
+
timer.unref();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function createPollEngine(attempt, options) {
|
|
33
|
+
const timeoutFloorMs = options.timeoutFloorMs ?? DEFAULT_TIMEOUT_FLOOR_MS;
|
|
34
|
+
const getTimeoutMs = () => options.timeoutMs != null
|
|
35
|
+
? resolve(options.timeoutMs)
|
|
36
|
+
: Math.max(timeoutFloorMs, resolve(options.intervalMs) * 4);
|
|
37
|
+
const onError = options.onError ?? (() => { });
|
|
38
|
+
const leading = options.leading ?? true;
|
|
39
|
+
let generation = 0;
|
|
40
|
+
let running = false;
|
|
41
|
+
let inFlight = false;
|
|
42
|
+
let timer = null;
|
|
43
|
+
let activeController = null;
|
|
44
|
+
function clearTimer() {
|
|
45
|
+
if (timer != null) {
|
|
46
|
+
clearTimeout(timer);
|
|
47
|
+
timer = null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function schedule(gen) {
|
|
51
|
+
clearTimer();
|
|
52
|
+
timer = setTimeout(() => {
|
|
53
|
+
timer = null;
|
|
54
|
+
void tick(gen);
|
|
55
|
+
}, resolve(options.intervalMs));
|
|
56
|
+
maybeUnref(timer);
|
|
57
|
+
}
|
|
58
|
+
async function tick(gen) {
|
|
59
|
+
if (gen !== generation || !running)
|
|
60
|
+
return;
|
|
61
|
+
if (inFlight) {
|
|
62
|
+
// An attempt from a superseded generation is still settling — stop()
|
|
63
|
+
// aborted it but the caller has not returned yet. Its own `finally`
|
|
64
|
+
// sees a stale generation and will not reschedule, so re-arming here
|
|
65
|
+
// is what keeps a stop()/start() cycle (tab hidden then visible) from
|
|
66
|
+
// leaving the engine alive-but-timerless, i.e. permanently dead.
|
|
67
|
+
schedule(gen);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
inFlight = true;
|
|
71
|
+
const controller = new AbortController();
|
|
72
|
+
activeController = controller;
|
|
73
|
+
const timeoutMs = getTimeoutMs();
|
|
74
|
+
const abortTimer = setTimeout(() => controller.abort(), timeoutMs);
|
|
75
|
+
maybeUnref(abortTimer);
|
|
76
|
+
let reported = false;
|
|
77
|
+
const report = (err) => {
|
|
78
|
+
if (reported)
|
|
79
|
+
return;
|
|
80
|
+
reported = true;
|
|
81
|
+
onError(err);
|
|
82
|
+
};
|
|
83
|
+
// The attempt is retained separately from the timeout race below. The
|
|
84
|
+
// timeout reports a slow attempt immediately, but the in-flight slot is
|
|
85
|
+
// only released once the attempt itself settles: releasing on the
|
|
86
|
+
// timeout would let the next tick start while an attempt that ignores
|
|
87
|
+
// `signal` is still doing work, which is the overlap (duplicate external
|
|
88
|
+
// requests, racing writes) this engine exists to prevent. An attempt that
|
|
89
|
+
// never settles blocks further attempts by design — `onError` has already
|
|
90
|
+
// fired, so it is loud rather than silent.
|
|
91
|
+
const settled = Promise.resolve()
|
|
92
|
+
.then(() => attempt(controller.signal))
|
|
93
|
+
.then(() => { }, (err) => report(err));
|
|
94
|
+
try {
|
|
95
|
+
await Promise.race([
|
|
96
|
+
settled,
|
|
97
|
+
new Promise((_, reject) => {
|
|
98
|
+
controller.signal.addEventListener("abort", () => reject(new Error(`poll attempt timed out after ${timeoutMs}ms`)), { once: true });
|
|
99
|
+
}),
|
|
100
|
+
]);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
report(err);
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
await settled;
|
|
107
|
+
clearTimeout(abortTimer);
|
|
108
|
+
if (activeController === controller)
|
|
109
|
+
activeController = null;
|
|
110
|
+
inFlight = false;
|
|
111
|
+
if (gen === generation && running)
|
|
112
|
+
schedule(gen);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
start() {
|
|
117
|
+
if (running)
|
|
118
|
+
return;
|
|
119
|
+
running = true;
|
|
120
|
+
generation++;
|
|
121
|
+
const gen = generation;
|
|
122
|
+
if (leading)
|
|
123
|
+
void tick(gen);
|
|
124
|
+
else
|
|
125
|
+
schedule(gen);
|
|
126
|
+
},
|
|
127
|
+
stop() {
|
|
128
|
+
running = false;
|
|
129
|
+
generation++;
|
|
130
|
+
clearTimer();
|
|
131
|
+
activeController?.abort();
|
|
132
|
+
},
|
|
133
|
+
pollNow() {
|
|
134
|
+
if (!running || inFlight)
|
|
135
|
+
return;
|
|
136
|
+
clearTimer();
|
|
137
|
+
void tick(generation);
|
|
138
|
+
},
|
|
139
|
+
reschedule() {
|
|
140
|
+
if (!running || inFlight || timer == null)
|
|
141
|
+
return;
|
|
142
|
+
schedule(generation);
|
|
143
|
+
},
|
|
144
|
+
get isRunning() {
|
|
145
|
+
return running;
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
@@ -29,6 +29,11 @@ Templates use `app/i18n/`:
|
|
|
29
29
|
Use BCP-47 filenames from the supported set: `en-US`, `zh-CN`, `es-ES`,
|
|
30
30
|
`fr-FR`, `de-DE`, `ja-JP`, `ko-KR`, `pt-BR`, `hi-IN`, `ar-SA`.
|
|
31
31
|
|
|
32
|
+
If an app only ships translations for a subset of that set, set
|
|
33
|
+
`supportedLocales` on the `AgentNativeI18nCatalog` to that subset. Without it,
|
|
34
|
+
`<LanguagePicker />` lists every framework-supported locale regardless of
|
|
35
|
+
whether `loadMessages` can actually resolve it.
|
|
36
|
+
|
|
32
37
|
## UI Pattern
|
|
33
38
|
|
|
34
39
|
- Wrap apps with `AppProviders i18n={{ catalog: i18nCatalog }}`.
|
|
@@ -29,6 +29,11 @@ Templates use `app/i18n/`:
|
|
|
29
29
|
Use BCP-47 filenames from the supported set: `en-US`, `zh-CN`, `es-ES`,
|
|
30
30
|
`fr-FR`, `de-DE`, `ja-JP`, `ko-KR`, `pt-BR`, `hi-IN`, `ar-SA`.
|
|
31
31
|
|
|
32
|
+
If an app only ships translations for a subset of that set, set
|
|
33
|
+
`supportedLocales` on the `AgentNativeI18nCatalog` to that subset. Without it,
|
|
34
|
+
`<LanguagePicker />` lists every framework-supported locale regardless of
|
|
35
|
+
whether `loadMessages` can actually resolve it.
|
|
36
|
+
|
|
32
37
|
## UI Pattern
|
|
33
38
|
|
|
34
39
|
- Wrap apps with `AppProviders i18n={{ catalog: i18nCatalog }}`.
|
|
@@ -38,7 +38,16 @@ function setTimer(t) {
|
|
|
38
38
|
function enqueue(url, body, headers, options) {
|
|
39
39
|
const queue = getQueue();
|
|
40
40
|
queue.push({ url, body, headers });
|
|
41
|
-
|
|
41
|
+
// The batch timer is unref'd so it never keeps a long-lived server alive —
|
|
42
|
+
// but on Netlify/Vercel/Lambda the execution environment can freeze the
|
|
43
|
+
// moment the event loop looks empty, which is exactly when an unref'd timer
|
|
44
|
+
// doesn't count. Without a signal, a warm container freezing between
|
|
45
|
+
// invocations never fires that timer, silently dropping every provider's
|
|
46
|
+
// queued events for a request that ends in a crash. Default to flushing
|
|
47
|
+
// synchronously with the response in that environment; a caller (e.g.
|
|
48
|
+
// Agent Native Analytics' flush-mode override) can still force either way.
|
|
49
|
+
const flushImmediately = options?.flushImmediately ?? isServerlessRuntime();
|
|
50
|
+
if (flushImmediately || queue.length >= MAX_BATCH_SIZE) {
|
|
42
51
|
void drainQueue();
|
|
43
52
|
}
|
|
44
53
|
else if (!getTimer()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.144.
|
|
3
|
+
"version": "0.144.3",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
"./server/request-context": "./dist/server/request-context.js",
|
|
73
73
|
"./server/design-token-utils": "./dist/server/design-token-utils.js",
|
|
74
74
|
"./server/poll": "./dist/server/poll.js",
|
|
75
|
+
"./server/interval-job": "./dist/server/interval-job.js",
|
|
75
76
|
"./server/sse": "./dist/server/sse.js",
|
|
76
77
|
"./server/short-lived-token": "./dist/server/short-lived-token.js",
|
|
77
78
|
"./integrations": "./dist/integrations/index.js",
|
|
@@ -411,8 +412,8 @@
|
|
|
411
412
|
"y-protocols": "^1.0.7",
|
|
412
413
|
"yjs": "^13.6.31",
|
|
413
414
|
"zod": "^4.3.6",
|
|
414
|
-
"@agent-native/
|
|
415
|
-
"@agent-native/
|
|
415
|
+
"@agent-native/toolkit": "^0.13.3",
|
|
416
|
+
"@agent-native/recap-cli": "0.5.3"
|
|
416
417
|
},
|
|
417
418
|
"devDependencies": {
|
|
418
419
|
"@ai-sdk/anthropic": "^3.0.71",
|
|
@@ -29,6 +29,11 @@ Templates use `app/i18n/`:
|
|
|
29
29
|
Use BCP-47 filenames from the supported set: `en-US`, `zh-CN`, `es-ES`,
|
|
30
30
|
`fr-FR`, `de-DE`, `ja-JP`, `ko-KR`, `pt-BR`, `hi-IN`, `ar-SA`.
|
|
31
31
|
|
|
32
|
+
If an app only ships translations for a subset of that set, set
|
|
33
|
+
`supportedLocales` on the `AgentNativeI18nCatalog` to that subset. Without it,
|
|
34
|
+
`<LanguagePicker />` lists every framework-supported locale regardless of
|
|
35
|
+
whether `loadMessages` can actually resolve it.
|
|
36
|
+
|
|
32
37
|
## UI Pattern
|
|
33
38
|
|
|
34
39
|
- Wrap apps with `AppProviders i18n={{ catalog: i18nCatalog }}`.
|
|
@@ -29,6 +29,11 @@ Templates use `app/i18n/`:
|
|
|
29
29
|
Use BCP-47 filenames from the supported set: `en-US`, `zh-CN`, `es-ES`,
|
|
30
30
|
`fr-FR`, `de-DE`, `ja-JP`, `ko-KR`, `pt-BR`, `hi-IN`, `ar-SA`.
|
|
31
31
|
|
|
32
|
+
If an app only ships translations for a subset of that set, set
|
|
33
|
+
`supportedLocales` on the `AgentNativeI18nCatalog` to that subset. Without it,
|
|
34
|
+
`<LanguagePicker />` lists every framework-supported locale regardless of
|
|
35
|
+
whether `loadMessages` can actually resolve it.
|
|
36
|
+
|
|
32
37
|
## UI Pattern
|
|
33
38
|
|
|
34
39
|
- Wrap apps with `AppProviders i18n={{ catalog: i18nCatalog }}`.
|