@agent-native/core 0.222.2-nightly-20261029152548 → 0.222.2
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/dist/client/agent-run-status.d.ts +2 -0
- package/dist/client/agent-run-status.js +3 -0
- package/dist/client/chat/agentkit-agent-native.js +1 -0
- package/dist/client/use-agent-chat-running-threads.d.ts +4 -0
- package/dist/deploy/build.js +43 -3
- package/dist/localization/default-messages.d.ts +5 -0
- package/dist/localization/default-messages.js +5 -0
- package/dist/server/ssr-handler.js +13 -3
- package/dist/shared/cache-control.d.ts +47 -0
- package/dist/shared/cache-control.js +90 -0
- package/dist/shared/index.d.ts +1 -1
- package/dist/shared/index.js +1 -1
- package/dist/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +37 -8
- package/package.json +4 -4
- package/src/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +37 -8
|
@@ -38,6 +38,9 @@ export async function readAgentRunStatus(input) {
|
|
|
38
38
|
...(typeof state.terminalReason === "string" && state.terminalReason
|
|
39
39
|
? { terminalReason: state.terminalReason }
|
|
40
40
|
: {}),
|
|
41
|
+
...(state.awaitingRedispatch === true
|
|
42
|
+
? { awaitingRedispatch: true }
|
|
43
|
+
: {}),
|
|
41
44
|
};
|
|
42
45
|
}
|
|
43
46
|
catch {
|
|
@@ -7,6 +7,10 @@ export interface AgentChatRunningEventDetail {
|
|
|
7
7
|
tabId?: string;
|
|
8
8
|
turnId?: string;
|
|
9
9
|
runId?: string;
|
|
10
|
+
/**
|
|
11
|
+
* `"run.submitted"` marks the run this client just started for a submitted
|
|
12
|
+
* message, which carries no successor link to any earlier run.
|
|
13
|
+
*/
|
|
10
14
|
reason?: string;
|
|
11
15
|
}
|
|
12
16
|
export interface UseAgentChatRunningThreadsOptions {
|
package/dist/deploy/build.js
CHANGED
|
@@ -17,7 +17,7 @@ import { RECURRING_JOBS_BUILD_MARKER_ENV_VAR, resolveRecurringJobsBuildMarker, }
|
|
|
17
17
|
import { normalizeAppBasePath } from "../server/app-base-path.js";
|
|
18
18
|
import { frameworkSessionHintCookieName, resolveAuthCookieNamespace, } from "../server/cookie-namespace.js";
|
|
19
19
|
import { resolveAgentNativeBuildId } from "../shared/build-id.js";
|
|
20
|
-
import { DEFAULT_SPECULATION_RULES_PATH, resolveChunkRecoveryCacheHeaders, resolveSsrCacheHeaders, resolveSsrCacheKeyHeaders, SSR_QUERY_CACHE_KEY_HEADER, } from "../shared/cache-control.js";
|
|
20
|
+
import { CHUNK_RECOVERY_BROWSER_CACHE_CONTROL, DEFAULT_SPECULATION_RULES_PATH, DISABLED_SSR_CACHE_HEADERS, resolveChunkRecoveryCacheHeaders, resolveSsrCacheHeaders, resolveSsrCacheKeyHeaders, resolveSsrCachePolicy, SSR_CACHEABLE_ERROR_STATUSES, SSR_MAX_AGE_HEADER, SSR_QUERY_CACHE_KEY_HEADER, ssrRouteCacheLimits, } from "../shared/cache-control.js";
|
|
21
21
|
import { EMBED_TARGET_QUERY_PARAM, EMBED_TOKEN_QUERY_PARAM, } from "../shared/embed-auth.js";
|
|
22
22
|
import { FRAMEWORK_INTERNAL_ROUTE_PREFIX, normalizeFrameworkRoutePrefix, toPublicFrameworkPath, } from "../shared/framework-route-prefix.js";
|
|
23
23
|
import { mcpEmbedStaticAssetRouteRules } from "../shared/mcp-embed-headers.js";
|
|
@@ -1090,6 +1090,7 @@ export function generateWorkerEntry(routes, pluginPaths, defaultPluginStems = []
|
|
|
1090
1090
|
const ssrCacheHeaders = resolveSsrCacheHeaders();
|
|
1091
1091
|
const chunkRecoveryCacheHeaders = resolveChunkRecoveryCacheHeaders(ssrCacheHeaders);
|
|
1092
1092
|
const ssrCacheKeyHeaders = resolveSsrCacheKeyHeaders();
|
|
1093
|
+
const ssrRouteLimits = ssrRouteCacheLimits(resolveSsrCachePolicy());
|
|
1093
1094
|
const ssrAuthRedirectCookieName = frameworkSessionHintCookieName(resolveAuthCookieNamespace().frameworkCookieName);
|
|
1094
1095
|
const hasActions = actions.length > 0;
|
|
1095
1096
|
const routeImports = [];
|
|
@@ -1806,6 +1807,13 @@ const SSR_CACHE_HEADERS = ${JSON.stringify(ssrCacheHeaders)};
|
|
|
1806
1807
|
const CHUNK_RECOVERY_ALIAS_CACHE_HEADERS = ${JSON.stringify(chunkRecoveryCacheHeaders)};
|
|
1807
1808
|
const SSR_CACHE_KEY_HEADERS = ${JSON.stringify(ssrCacheKeyHeaders)};
|
|
1808
1809
|
const SSR_QUERY_CACHE_KEY_HEADER = ${JSON.stringify(SSR_QUERY_CACHE_KEY_HEADER)};
|
|
1810
|
+
const SSR_MAX_AGE_HEADER = ${JSON.stringify(SSR_MAX_AGE_HEADER)};
|
|
1811
|
+
// The longest windows a route's SSR_MAX_AGE_HEADER can ask for; null when the
|
|
1812
|
+
// deployment stores nothing.
|
|
1813
|
+
const SSR_ROUTE_CACHE_LIMITS = ${JSON.stringify(ssrRouteLimits)};
|
|
1814
|
+
const SSR_UNSTORED_CACHE_HEADERS = ${JSON.stringify(DISABLED_SSR_CACHE_HEADERS)};
|
|
1815
|
+
const SSR_ROUTE_BROWSER_CACHE_CONTROL = ${JSON.stringify(CHUNK_RECOVERY_BROWSER_CACHE_CONTROL)};
|
|
1816
|
+
const SSR_CACHEABLE_ERROR_STATUSES = new Set(${JSON.stringify(SSR_CACHEABLE_ERROR_STATUSES)});
|
|
1809
1817
|
const CHUNK_RECOVERY_PATH_SUFFIX = ${JSON.stringify(CHUNK_RECOVERY_PATH_SUFFIX)};
|
|
1810
1818
|
const CHUNK_RECOVERY_QUERY_PARAM = ${JSON.stringify(CHUNK_RECOVERY_QUERY_PARAM)};
|
|
1811
1819
|
const CHUNK_RECOVERY_QUERY_VALUE = ${JSON.stringify(CHUNK_RECOVERY_QUERY_VALUE)};
|
|
@@ -1874,12 +1882,40 @@ function injectDefaultSocialImageMeta(html, imageUrl) {
|
|
|
1874
1882
|
}
|
|
1875
1883
|
|
|
1876
1884
|
function isSsrHtmlOrDataResponse(headers, status, pathname) {
|
|
1877
|
-
if (status < 200
|
|
1885
|
+
if (status < 200) return false;
|
|
1886
|
+
if (status >= 400 && !SSR_CACHEABLE_ERROR_STATUSES.has(status)) return false;
|
|
1878
1887
|
const contentType = (headers.get("content-type") || "").toLowerCase();
|
|
1879
1888
|
if (contentType.includes("text/html")) return true;
|
|
1880
1889
|
return pathname.endsWith(".data") && contentType.includes("text/x-script");
|
|
1881
1890
|
}
|
|
1882
1891
|
|
|
1892
|
+
// Mirror parseSsrMaxAge and ssrCacheHeadersWithin in shared/cache-control.ts;
|
|
1893
|
+
// build.spec.ts checks this worker against them.
|
|
1894
|
+
function parseSsrMaxAge(raw) {
|
|
1895
|
+
if (raw == null) return null;
|
|
1896
|
+
const value = raw.trim();
|
|
1897
|
+
return /^\\d+$/.test(value) ? Number(value) : 0;
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
function sharedWithin(window, seconds) {
|
|
1901
|
+
return (
|
|
1902
|
+
"s-maxage=" +
|
|
1903
|
+
Math.min(seconds, window.maxAge) +
|
|
1904
|
+
", stale-while-revalidate=" +
|
|
1905
|
+
Math.min(seconds, window.stale)
|
|
1906
|
+
);
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
function ssrCacheHeadersWithin(seconds) {
|
|
1910
|
+
if (!SSR_ROUTE_CACHE_LIMITS || seconds <= 0) return SSR_UNSTORED_CACHE_HEADERS;
|
|
1911
|
+
return {
|
|
1912
|
+
"cache-control": SSR_ROUTE_BROWSER_CACHE_CONTROL,
|
|
1913
|
+
"cdn-cache-control": "public, " + sharedWithin(SSR_ROUTE_CACHE_LIMITS.cdn, seconds),
|
|
1914
|
+
"netlify-cdn-cache-control":
|
|
1915
|
+
"public, durable, " + sharedWithin(SSR_ROUTE_CACHE_LIMITS.netlify, seconds),
|
|
1916
|
+
};
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1883
1919
|
/**
|
|
1884
1920
|
* Apply the SSR cache policy to the response headers.
|
|
1885
1921
|
*
|
|
@@ -1891,6 +1927,8 @@ function applyDefaultSsrCacheHeader(headers, status, pathname, isRecoveryAlias =
|
|
|
1891
1927
|
const varyByQuery =
|
|
1892
1928
|
(headers.get(SSR_QUERY_CACHE_KEY_HEADER) || "").trim().toLowerCase() === "query";
|
|
1893
1929
|
headers.delete(SSR_QUERY_CACHE_KEY_HEADER);
|
|
1930
|
+
const routeMaxAge = parseSsrMaxAge(headers.get(SSR_MAX_AGE_HEADER));
|
|
1931
|
+
headers.delete(SSR_MAX_AGE_HEADER);
|
|
1894
1932
|
if (!isSsrHtmlOrDataResponse(headers, status, pathname)) return;
|
|
1895
1933
|
|
|
1896
1934
|
headers.delete("set-cookie");
|
|
@@ -1907,7 +1945,9 @@ function applyDefaultSsrCacheHeader(headers, status, pathname, isRecoveryAlias =
|
|
|
1907
1945
|
else headers.delete("vary");
|
|
1908
1946
|
}
|
|
1909
1947
|
|
|
1910
|
-
|
|
1948
|
+
const cacheHeaders =
|
|
1949
|
+
routeMaxAge === null ? SSR_CACHE_HEADERS : ssrCacheHeadersWithin(routeMaxAge);
|
|
1950
|
+
for (const [name, value] of Object.entries(cacheHeaders)) {
|
|
1911
1951
|
headers.set(name, value);
|
|
1912
1952
|
}
|
|
1913
1953
|
const netlifyVary = varyByQuery
|
|
@@ -104,6 +104,11 @@ declare const messages: {
|
|
|
104
104
|
composer: {
|
|
105
105
|
chatgptManageUsage: string;
|
|
106
106
|
chatgptPlanUsing: string;
|
|
107
|
+
newChatPlaceholder: string;
|
|
108
|
+
};
|
|
109
|
+
setup: {
|
|
110
|
+
connectBuilder: string;
|
|
111
|
+
connectPlaceholder: string;
|
|
107
112
|
};
|
|
108
113
|
error: {
|
|
109
114
|
chatgptPlanUsageLimit: string;
|
|
@@ -28,6 +28,11 @@ const messages = {
|
|
|
28
28
|
composer: {
|
|
29
29
|
chatgptManageUsage: "Manage usage",
|
|
30
30
|
chatgptPlanUsing: "Using ChatGPT plan",
|
|
31
|
+
newChatPlaceholder: "Ask anything",
|
|
32
|
+
},
|
|
33
|
+
setup: {
|
|
34
|
+
connectBuilder: "Connect Builder.io",
|
|
35
|
+
connectPlaceholder: "Connect AI to start chatting...",
|
|
31
36
|
},
|
|
32
37
|
error: {
|
|
33
38
|
chatgptPlanUsageLimit: "Your ChatGPT plan usage limit has been reached.",
|
|
@@ -2,7 +2,7 @@ import { defineEventHandler } from "h3";
|
|
|
2
2
|
import { createRequestHandler } from "react-router";
|
|
3
3
|
import { getAppConfig, resolveAppHomePath } from "../app-config/index.js";
|
|
4
4
|
import { isMcpPublicPath } from "../mcp/route-paths.js";
|
|
5
|
-
import { DEFAULT_SPECULATION_RULES_PATH, resolveChunkRecoveryCacheHeaders, resolveSsrCacheHeaders, resolveSsrCacheKeyHeaders, SSR_QUERY_CACHE_KEY_HEADER, } from "../shared/cache-control.js";
|
|
5
|
+
import { DEFAULT_SPECULATION_RULES_PATH, parseSsrMaxAge, resolveChunkRecoveryCacheHeaders, resolveSsrCacheHeaders, resolveSsrCacheKeyHeaders, resolveSsrCachePolicy, SSR_CACHEABLE_ERROR_STATUSES, SSR_MAX_AGE_HEADER, SSR_QUERY_CACHE_KEY_HEADER, ssrCacheHeadersWithin, } from "../shared/cache-control.js";
|
|
6
6
|
import { CHUNK_RECOVERY_PATH_SUFFIX, isLegacyChunkRecoveryRequest, } from "../shared/route-chunk-recovery-bootstrap.js";
|
|
7
7
|
import { 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, withAgentNativeSocialImageCacheBuster, } from "../shared/social-meta.js";
|
|
8
8
|
import { getSsrAuthRedirectScript } from "../shared/ssr-auth-redirect.js";
|
|
@@ -186,7 +186,7 @@ function injectDefaultSocialImageMeta(html, imageUrl) {
|
|
|
186
186
|
return html;
|
|
187
187
|
return html.slice(0, headCloseIdx) + tags.join("") + html.slice(headCloseIdx);
|
|
188
188
|
}
|
|
189
|
-
const CACHEABLE_ERROR_STATUSES = new Set(
|
|
189
|
+
const CACHEABLE_ERROR_STATUSES = new Set(SSR_CACHEABLE_ERROR_STATUSES);
|
|
190
190
|
function isSsrHtmlOrDataResponse(headers, status, pathname) {
|
|
191
191
|
if (status < 200)
|
|
192
192
|
return false;
|
|
@@ -227,6 +227,11 @@ function isSsrHtmlOrDataResponse(headers, status, pathname) {
|
|
|
227
227
|
* │ PER-USER response variation — no `private`, no `Vary: Cookie`, and no │
|
|
228
228
|
* │ request-specific content. Recovery keeps a bounded alias and never adds │
|
|
229
229
|
* │ arbitrary query-key variation to the normally cached shell. │
|
|
230
|
+
* │ │
|
|
231
|
+
* │ A route whose content can change or be taken down may SHORTEN its own │
|
|
232
|
+
* │ window with `SSR_MAX_AGE_HEADER`: one duration for every visitor of that │
|
|
233
|
+
* │ route, never longer than the deployment's, so it can't personalize the │
|
|
234
|
+
* │ shell or poison a shared key. │
|
|
230
235
|
* └──────────────────────────────────────────────────────────────────────────┘
|
|
231
236
|
*
|
|
232
237
|
* The same sharing rule governs any DIAGNOSTIC header on this response. A
|
|
@@ -240,6 +245,8 @@ function isSsrHtmlOrDataResponse(headers, status, pathname) {
|
|
|
240
245
|
function applyDefaultSsrCacheHeader(headers, status, pathname, isRecoveryAlias = false, isLegacyRecovery = false) {
|
|
241
246
|
const responseRequestsQueryVary = headers.get(SSR_QUERY_CACHE_KEY_HEADER)?.trim().toLowerCase() === "query";
|
|
242
247
|
headers.delete(SSR_QUERY_CACHE_KEY_HEADER);
|
|
248
|
+
const routeMaxAge = parseSsrMaxAge(headers.get(SSR_MAX_AGE_HEADER));
|
|
249
|
+
headers.delete(SSR_MAX_AGE_HEADER);
|
|
243
250
|
if (!isSsrHtmlOrDataResponse(headers, status, pathname))
|
|
244
251
|
return;
|
|
245
252
|
// Current recovery uses one fixed path alias. Still-deployed clients use the
|
|
@@ -267,7 +274,10 @@ function applyDefaultSsrCacheHeader(headers, status, pathname, isRecoveryAlias =
|
|
|
267
274
|
else
|
|
268
275
|
headers.delete("vary");
|
|
269
276
|
}
|
|
270
|
-
|
|
277
|
+
const cacheHeaders = routeMaxAge === null
|
|
278
|
+
? resolveSsrCacheHeaders()
|
|
279
|
+
: ssrCacheHeadersWithin(resolveSsrCachePolicy(), routeMaxAge);
|
|
280
|
+
for (const [name, value] of Object.entries(cacheHeaders)) {
|
|
271
281
|
headers.set(name, value);
|
|
272
282
|
}
|
|
273
283
|
const cacheKeyHeaders = resolveSsrCacheKeyHeaders(undefined, {
|
|
@@ -10,6 +10,20 @@ export declare const DEFAULT_SSR_CACHE_HEADERS: {
|
|
|
10
10
|
};
|
|
11
11
|
export declare const SSR_HTML_CONTENT_TYPE = "text/html; charset=utf-8";
|
|
12
12
|
export declare const SSR_QUERY_CACHE_KEY_HEADER = "x-agent-native-ssr-key";
|
|
13
|
+
/**
|
|
14
|
+
* Response header a route sets to the most seconds its SSR response may be
|
|
15
|
+
* kept anywhere, for a page whose content can change or be taken down (a
|
|
16
|
+
* public share page, say). The SSR handler reads and removes it. It only ever
|
|
17
|
+
* shortens the deployment's policy, and it names one duration for every
|
|
18
|
+
* visitor of the route, so it can't vary the shell per request or per user.
|
|
19
|
+
* `0` means don't store it at all.
|
|
20
|
+
*/
|
|
21
|
+
export declare const SSR_MAX_AGE_HEADER = "x-agent-native-ssr-max-age";
|
|
22
|
+
/**
|
|
23
|
+
* Error statuses whose SSR HTML/`.data` answer still gets the shared cache
|
|
24
|
+
* policy: a missing or removed page is the same for every visitor.
|
|
25
|
+
*/
|
|
26
|
+
export declare const SSR_CACHEABLE_ERROR_STATUSES: readonly number[];
|
|
13
27
|
export type SsrHtmlContentTypeOptions = {
|
|
14
28
|
varyByQuery?: boolean;
|
|
15
29
|
};
|
|
@@ -32,6 +46,39 @@ export type SsrCachePolicy = {
|
|
|
32
46
|
export type SsrCacheHeaders = Record<"cache-control" | "cdn-cache-control" | "netlify-cdn-cache-control", string>;
|
|
33
47
|
export declare function parseSsrCacheSetting(raw: string | undefined | null): SsrCachePolicy;
|
|
34
48
|
export declare function ssrCacheHeadersForPolicy(policy: SsrCachePolicy): SsrCacheHeaders;
|
|
49
|
+
/**
|
|
50
|
+
* The route's `SSR_MAX_AGE_HEADER` value in seconds, or null when unset. A
|
|
51
|
+
* value that isn't whole seconds reads as 0: the route asked for a shorter
|
|
52
|
+
* window, and falling back to the deployment's would keep a page it takes
|
|
53
|
+
* down for as long as that window.
|
|
54
|
+
*/
|
|
55
|
+
export declare function parseSsrMaxAge(raw: string | null | undefined): number | null;
|
|
56
|
+
export type SsrSharedWindow = {
|
|
57
|
+
maxAge: number;
|
|
58
|
+
stale: number;
|
|
59
|
+
};
|
|
60
|
+
export type SsrRouteCacheLimits = {
|
|
61
|
+
cdn: SsrSharedWindow;
|
|
62
|
+
netlify: SsrSharedWindow;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* The longest shared-cache windows a route's `SSR_MAX_AGE_HEADER` can ask for
|
|
66
|
+
* under `policy`, read from the headers the deployment would send, one per CDN
|
|
67
|
+
* header since they differ. Null when the deployment stores nothing. The
|
|
68
|
+
* generated edge worker inlines these at build time.
|
|
69
|
+
*/
|
|
70
|
+
export declare function ssrRouteCacheLimits(policy: SsrCachePolicy): SsrRouteCacheLimits | null;
|
|
71
|
+
/**
|
|
72
|
+
* The deployment's policy with every window cut to at most `seconds`, for a
|
|
73
|
+
* route that set `SSR_MAX_AGE_HEADER`. Browsers revalidate on each visit, so
|
|
74
|
+
* shared caches alone bound how old a copy gets: fresh for `seconds`, then
|
|
75
|
+
* served once more while it refreshes, so never more than twice `seconds`
|
|
76
|
+
* after the render. Nothing is served stale on origin errors either, since a
|
|
77
|
+
* page taken down must not come back while origin is failing.
|
|
78
|
+
*/
|
|
79
|
+
export declare function ssrCacheHeadersWithin(policy: SsrCachePolicy, seconds: number): SsrCacheHeaders;
|
|
80
|
+
/** The deployment-wide policy from `AGENT_NATIVE_SSR_CACHE`. */
|
|
81
|
+
export declare function resolveSsrCachePolicy(env?: Record<string, string | undefined>): SsrCachePolicy;
|
|
35
82
|
export declare function resolveSsrCacheHeaders(env?: Record<string, string | undefined>): Readonly<SsrCacheHeaders>;
|
|
36
83
|
export declare function resolveChunkRecoveryCacheHeaders(cacheHeaders?: Pick<SsrCacheHeaders, "cache-control">): Readonly<SsrCacheHeaders>;
|
|
37
84
|
export declare function resolveSsrNetlifyQueryVary(varyByQuery?: boolean, varyByLegacyRecovery?: boolean): string;
|
|
@@ -11,6 +11,20 @@ export const DEFAULT_SSR_CACHE_HEADERS = {
|
|
|
11
11
|
};
|
|
12
12
|
export const SSR_HTML_CONTENT_TYPE = "text/html; charset=utf-8";
|
|
13
13
|
export const SSR_QUERY_CACHE_KEY_HEADER = "x-agent-native-ssr-key";
|
|
14
|
+
/**
|
|
15
|
+
* Response header a route sets to the most seconds its SSR response may be
|
|
16
|
+
* kept anywhere, for a page whose content can change or be taken down (a
|
|
17
|
+
* public share page, say). The SSR handler reads and removes it. It only ever
|
|
18
|
+
* shortens the deployment's policy, and it names one duration for every
|
|
19
|
+
* visitor of the route, so it can't vary the shell per request or per user.
|
|
20
|
+
* `0` means don't store it at all.
|
|
21
|
+
*/
|
|
22
|
+
export const SSR_MAX_AGE_HEADER = "x-agent-native-ssr-max-age";
|
|
23
|
+
/**
|
|
24
|
+
* Error statuses whose SSR HTML/`.data` answer still gets the shared cache
|
|
25
|
+
* policy: a missing or removed page is the same for every visitor.
|
|
26
|
+
*/
|
|
27
|
+
export const SSR_CACHEABLE_ERROR_STATUSES = [404, 410];
|
|
14
28
|
export function withSsrHtmlContentType(response, options = {}) {
|
|
15
29
|
response.headers.set("content-type", SSR_HTML_CONTENT_TYPE);
|
|
16
30
|
if (options.varyByQuery) {
|
|
@@ -73,8 +87,84 @@ export function ssrCacheHeadersForPolicy(policy) {
|
|
|
73
87
|
"netlify-cdn-cache-control": netlifyControl,
|
|
74
88
|
};
|
|
75
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* The route's `SSR_MAX_AGE_HEADER` value in seconds, or null when unset. A
|
|
92
|
+
* value that isn't whole seconds reads as 0: the route asked for a shorter
|
|
93
|
+
* window, and falling back to the deployment's would keep a page it takes
|
|
94
|
+
* down for as long as that window.
|
|
95
|
+
*/
|
|
96
|
+
export function parseSsrMaxAge(raw) {
|
|
97
|
+
if (raw == null)
|
|
98
|
+
return null;
|
|
99
|
+
const value = raw.trim();
|
|
100
|
+
if (!/^\d+$/.test(value))
|
|
101
|
+
return 0;
|
|
102
|
+
return Math.min(Number(value), MAX_SSR_CACHE_SECONDS);
|
|
103
|
+
}
|
|
104
|
+
function directiveSeconds(control, name) {
|
|
105
|
+
const match = new RegExp(`(?:^|,)\\s*${name}=(\\d+)\\s*(?:,|$)`, "i").exec(control);
|
|
106
|
+
return match ? Number(match[1]) : null;
|
|
107
|
+
}
|
|
108
|
+
function sharedWindow(control) {
|
|
109
|
+
return {
|
|
110
|
+
maxAge: directiveSeconds(control, "s-maxage") ??
|
|
111
|
+
directiveSeconds(control, "max-age") ??
|
|
112
|
+
0,
|
|
113
|
+
stale: directiveSeconds(control, "stale-while-revalidate") ?? 0,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The longest shared-cache windows a route's `SSR_MAX_AGE_HEADER` can ask for
|
|
118
|
+
* under `policy`, read from the headers the deployment would send, one per CDN
|
|
119
|
+
* header since they differ. Null when the deployment stores nothing. The
|
|
120
|
+
* generated edge worker inlines these at build time.
|
|
121
|
+
*/
|
|
122
|
+
export function ssrRouteCacheLimits(policy) {
|
|
123
|
+
if (policy.kind === "disabled")
|
|
124
|
+
return null;
|
|
125
|
+
const headers = ssrCacheHeadersForPolicy(policy);
|
|
126
|
+
return {
|
|
127
|
+
cdn: sharedWindow(headers["cdn-cache-control"]),
|
|
128
|
+
netlify: sharedWindow(headers["netlify-cdn-cache-control"]),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function sharedWithin(window, seconds) {
|
|
132
|
+
return (`s-maxage=${Math.min(seconds, window.maxAge)}, ` +
|
|
133
|
+
`stale-while-revalidate=${Math.min(seconds, window.stale)}`);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The deployment's policy with every window cut to at most `seconds`, for a
|
|
137
|
+
* route that set `SSR_MAX_AGE_HEADER`. Browsers revalidate on each visit, so
|
|
138
|
+
* shared caches alone bound how old a copy gets: fresh for `seconds`, then
|
|
139
|
+
* served once more while it refreshes, so never more than twice `seconds`
|
|
140
|
+
* after the render. Nothing is served stale on origin errors either, since a
|
|
141
|
+
* page taken down must not come back while origin is failing.
|
|
142
|
+
*/
|
|
143
|
+
export function ssrCacheHeadersWithin(policy, seconds) {
|
|
144
|
+
const limits = ssrRouteCacheLimits(policy);
|
|
145
|
+
if (!limits || seconds <= 0)
|
|
146
|
+
return { ...DISABLED_SSR_CACHE_HEADERS };
|
|
147
|
+
return {
|
|
148
|
+
"cache-control": CHUNK_RECOVERY_BROWSER_CACHE_CONTROL,
|
|
149
|
+
"cdn-cache-control": `public, ${sharedWithin(limits.cdn, seconds)}`,
|
|
150
|
+
"netlify-cdn-cache-control": `public, durable, ${sharedWithin(limits.netlify, seconds)}`,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
76
153
|
let memoizedRaw;
|
|
77
154
|
let memoizedHeaders;
|
|
155
|
+
let memoizedPolicyRaw;
|
|
156
|
+
let memoizedPolicy;
|
|
157
|
+
/** The deployment-wide policy from `AGENT_NATIVE_SSR_CACHE`. */
|
|
158
|
+
export function resolveSsrCachePolicy(env = typeof process === "undefined"
|
|
159
|
+
? {}
|
|
160
|
+
: process.env) {
|
|
161
|
+
const raw = env[SSR_CACHE_ENV_VAR];
|
|
162
|
+
if (memoizedPolicy && raw === memoizedPolicyRaw)
|
|
163
|
+
return memoizedPolicy;
|
|
164
|
+
memoizedPolicyRaw = raw;
|
|
165
|
+
memoizedPolicy = parseSsrCacheSetting(raw);
|
|
166
|
+
return memoizedPolicy;
|
|
167
|
+
}
|
|
78
168
|
export function resolveSsrCacheHeaders(env = typeof process === "undefined"
|
|
79
169
|
? {}
|
|
80
170
|
: process.env) {
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export { formatAgentDesignSystemContext, loadAgentDesignSystemContext, type Agen
|
|
|
22
22
|
export { formatHtmlStyleSummary, summarizeHtmlStyles, type HtmlStyleFragment, type HtmlStyleSummary, type HtmlStyleValue, } from "./html-style-summary.js";
|
|
23
23
|
export { withBuilderUtmTrackingParams } from "./builder-link-tracking.js";
|
|
24
24
|
export { BETA_FORCE_QUERY_PARAM, BETA_FORCE_SESSION_STORAGE_KEY, BETA_LANE_REDIRECT_QUERY_PARAM, BETA_LANE_RETURN_STORAGE_KEY, BETA_LANE_RETURNED_STORAGE_KEY, BETA_REDIRECT_DURATION_MS, BETA_REDIRECT_STORAGE_KEY, BETA_REDIRECT_SIGN_OUT_STORAGE_KEY, BETA_OPT_OUT_DURATION_MS, BETA_OPT_OUT_QUERY_PARAM, BETA_OPT_OUT_STORAGE_KEY, buildAutomaticBetaRedirectUrl, ENVIRONMENT_BETA_HOSTS, resolveEnvironmentTargets, type EnvironmentBadgeTargets, } from "./environment-lanes.js";
|
|
25
|
-
export { SSR_HTML_CONTENT_TYPE, SSR_QUERY_CACHE_KEY_HEADER, type SsrHtmlContentTypeOptions, withSsrHtmlContentType, } from "./cache-control.js";
|
|
25
|
+
export { SSR_HTML_CONTENT_TYPE, SSR_MAX_AGE_HEADER, SSR_QUERY_CACHE_KEY_HEADER, type SsrHtmlContentTypeOptions, withSsrHtmlContentType, } from "./cache-control.js";
|
|
26
26
|
export { SURFACE_HIDDEN_FLAG, SURFACE_VISIBILITY_EVENT, addSurfaceVisibilityListener, buildSurfaceVisibilityScript, isHostSurfaceHidden, isSurfaceHidden, } from "./surface-visibility.js";
|
|
27
27
|
export { AGENT_NATIVE_DOCS_ORIGIN, docsUrl, type DocsUrlOptions, } from "./docs-url.js";
|
|
28
28
|
export { buildRuntimeConfigPrompt, formatRuntimeConfigReport, getRuntimeConfigReport, parseRuntimeConfigReport, runtimeConfigRequirementsFromSearchParams, type RuntimeConfigEnvironment, type RuntimeConfigIssue, type RuntimeConfigIssueCode, type RuntimeConfigIssueSeverity, type RuntimeConfigPhase, type RuntimeConfigReport, type RuntimeConfigRequirements, } from "./runtime-config.js";
|
package/dist/shared/index.js
CHANGED
|
@@ -22,7 +22,7 @@ export { formatAgentDesignSystemContext, loadAgentDesignSystemContext, } from ".
|
|
|
22
22
|
export { formatHtmlStyleSummary, summarizeHtmlStyles, } from "./html-style-summary.js";
|
|
23
23
|
export { withBuilderUtmTrackingParams } from "./builder-link-tracking.js";
|
|
24
24
|
export { BETA_FORCE_QUERY_PARAM, BETA_FORCE_SESSION_STORAGE_KEY, BETA_LANE_REDIRECT_QUERY_PARAM, BETA_LANE_RETURN_STORAGE_KEY, BETA_LANE_RETURNED_STORAGE_KEY, BETA_REDIRECT_DURATION_MS, BETA_REDIRECT_STORAGE_KEY, BETA_REDIRECT_SIGN_OUT_STORAGE_KEY, BETA_OPT_OUT_DURATION_MS, BETA_OPT_OUT_QUERY_PARAM, BETA_OPT_OUT_STORAGE_KEY, buildAutomaticBetaRedirectUrl, ENVIRONMENT_BETA_HOSTS, resolveEnvironmentTargets, } from "./environment-lanes.js";
|
|
25
|
-
export { SSR_HTML_CONTENT_TYPE, SSR_QUERY_CACHE_KEY_HEADER, withSsrHtmlContentType, } from "./cache-control.js";
|
|
25
|
+
export { SSR_HTML_CONTENT_TYPE, SSR_MAX_AGE_HEADER, SSR_QUERY_CACHE_KEY_HEADER, withSsrHtmlContentType, } from "./cache-control.js";
|
|
26
26
|
export { SURFACE_HIDDEN_FLAG, SURFACE_VISIBILITY_EVENT, addSurfaceVisibilityListener, buildSurfaceVisibilityScript, isHostSurfaceHidden, isSurfaceHidden, } from "./surface-visibility.js";
|
|
27
27
|
export { AGENT_NATIVE_DOCS_ORIGIN, docsUrl, } from "./docs-url.js";
|
|
28
28
|
export { buildRuntimeConfigPrompt, formatRuntimeConfigReport, getRuntimeConfigReport, parseRuntimeConfigReport, runtimeConfigRequirementsFromSearchParams, } from "./runtime-config.js";
|
|
@@ -163,9 +163,21 @@ checkout, or the expected worktree is missing, create one
|
|
|
163
163
|
to stop.
|
|
164
164
|
|
|
165
165
|
Window: roots posted in the last 5 days (or since the timestamp or permalink
|
|
166
|
-
the invocation gives), for new reports and open items alike.
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
the invocation gives), for new reports and open items alike. An older thread
|
|
167
|
+
is in the window too when we have already replied in it and a person has
|
|
168
|
+
replied since the window began: a channel read only shows roots, so search for
|
|
169
|
+
recent thread replies (`in:<#channel> is:thread after:<date>`) to find them.
|
|
170
|
+
On 10/29 a teammate's vote and question sat unanswered under a 3-week-old
|
|
171
|
+
root. Other older threads are left as they are, except reports listed under
|
|
172
|
+
`Reports` in a sweep PR opened or merged in that window: those always get
|
|
173
|
+
their close-out.
|
|
174
|
+
|
|
175
|
+
Reading a source is a good job for a helper: give each source below its own
|
|
176
|
+
helper on the cheapest model (Luna in Codex, Haiku in Claude Code), ask for a
|
|
177
|
+
short list of candidates with links, and close it as soon as it reports. On
|
|
178
|
+
10/29 the three source reads cost $0.44 together; reusing those same helpers
|
|
179
|
+
for fixes afterwards cost $6.36, because each new job paid for its whole
|
|
180
|
+
growing history.
|
|
169
181
|
|
|
170
182
|
- **Read the channels.** Use `slack_read_channel` with
|
|
171
183
|
`response_format: detailed` (paginate) back 5 days. Its output shows
|
|
@@ -250,8 +262,9 @@ apart from Steve's own 👀.
|
|
|
250
262
|
## 3. Fix as many as you can
|
|
251
263
|
|
|
252
264
|
- Group related reports so one cause gets one fix. Give each independent
|
|
253
|
-
group a subagent on
|
|
254
|
-
|
|
265
|
+
group a fresh subagent on your own model and effort, with disjoint files,
|
|
266
|
+
or fix it in the main thread. Never hand a finished helper a new job; start
|
|
267
|
+
a fresh one. The main thread plans, reviews diffs, and integrates.
|
|
255
268
|
- **Reproduce before you edit.** Get the failure on screen first: a test
|
|
256
269
|
that fails, the action returning the wrong thing, a stack trace, or the
|
|
257
270
|
flow broken in a signed-in local app. Reading code is not an attempt:
|
|
@@ -274,9 +287,12 @@ apart from Steve's own 👀.
|
|
|
274
287
|
green, stop editing and capture the real failure first (stack, logs, the
|
|
275
288
|
reporter's actual data). If that doesn't settle it within about 30
|
|
276
289
|
minutes, it becomes 🎫 with one line on what you learned.
|
|
277
|
-
- **Second opinion before the PR.** Give a fresh subagent
|
|
278
|
-
text, the diff, and the proof, and ask: does
|
|
279
|
-
reporter saw,
|
|
290
|
+
- **Second opinion before the PR, every time.** Give a fresh subagent on
|
|
291
|
+
your own model only the report text, the diff, and the proof, and ask: does
|
|
292
|
+
the check exercise what the reporter saw, is this the cause or a symptom,
|
|
293
|
+
and what edge case breaks it? Fix what it finds before you open the PR. The
|
|
294
|
+
10/29 run skipped this, and PR review found the edge cases one round at a
|
|
295
|
+
time instead.
|
|
280
296
|
- **Keep fixes small.** Each report's fix goes in its own commit so a bad
|
|
281
297
|
one can be reverted alone. A fix that grows past about 300 lines, or into
|
|
282
298
|
a new subsystem (timeouts, cancellation, retries) the reporter didn't ask
|
|
@@ -293,6 +309,19 @@ PR per item. End the PR body with a
|
|
|
293
309
|
Slack thread, or the Sentry, Analytics, or GitHub issue. That list is the
|
|
294
310
|
only set of threads a later `/ship` may close out as fixed.
|
|
295
311
|
|
|
312
|
+
Wait for CI with one blocking command, such as
|
|
313
|
+
`gh pr checks <number> --watch --required --interval 60`, and don't post a
|
|
314
|
+
status line while it runs: every turn re-sends your whole context, and on
|
|
315
|
+
10/28 polling CI was half the main thread's cost.
|
|
316
|
+
|
|
317
|
+
Fix each review round's findings in one batch. If a second round still finds
|
|
318
|
+
a problem in the same fix, take that fix out of the PR, remove its whole entry
|
|
319
|
+
from the PR's `Reports` section: the link and its `fix-proof:` and `visual:`
|
|
320
|
+
lines (close-out marks every listed report fixed, and a stray evidence line
|
|
321
|
+
counts toward the report above it). Then 🎫 its
|
|
322
|
+
report with what review found, and merge the rest. Close the PR only when nothing verified
|
|
323
|
+
is left in it.
|
|
324
|
+
|
|
296
325
|
Merge it the way this repo merges PRs. In a Factory workspace, that means
|
|
297
326
|
the workflow's merge step after its merge gate, never a direct merge.
|
|
298
327
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.222.2
|
|
3
|
+
"version": "0.222.2",
|
|
4
4
|
"description": "The agentic application framework for building autonomous agents with intuitive UIs",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -742,8 +742,8 @@
|
|
|
742
742
|
"yaml": "^2.9.0",
|
|
743
743
|
"yjs": "^13.6.33",
|
|
744
744
|
"zod": "^4.3.6",
|
|
745
|
-
"@agent-native/agentkit": "^0.222.2
|
|
746
|
-
"@agent-native/recap-cli": "^0.5.
|
|
745
|
+
"@agent-native/agentkit": "^0.222.2",
|
|
746
|
+
"@agent-native/recap-cli": "^0.5.93"
|
|
747
747
|
},
|
|
748
748
|
"devDependencies": {
|
|
749
749
|
"@ai-sdk/anthropic": "^3.0.71",
|
|
@@ -814,7 +814,7 @@
|
|
|
814
814
|
"xlsx": "^0.18.5"
|
|
815
815
|
},
|
|
816
816
|
"peerDependencies": {
|
|
817
|
-
"@agent-native/core-corpus": "0.
|
|
817
|
+
"@agent-native/core-corpus": ">=0.196.0",
|
|
818
818
|
"@ai-sdk/anthropic": ">=3",
|
|
819
819
|
"@ai-sdk/cohere": ">=3",
|
|
820
820
|
"@ai-sdk/google": ">=3",
|
|
@@ -163,9 +163,21 @@ checkout, or the expected worktree is missing, create one
|
|
|
163
163
|
to stop.
|
|
164
164
|
|
|
165
165
|
Window: roots posted in the last 5 days (or since the timestamp or permalink
|
|
166
|
-
the invocation gives), for new reports and open items alike.
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
the invocation gives), for new reports and open items alike. An older thread
|
|
167
|
+
is in the window too when we have already replied in it and a person has
|
|
168
|
+
replied since the window began: a channel read only shows roots, so search for
|
|
169
|
+
recent thread replies (`in:<#channel> is:thread after:<date>`) to find them.
|
|
170
|
+
On 10/29 a teammate's vote and question sat unanswered under a 3-week-old
|
|
171
|
+
root. Other older threads are left as they are, except reports listed under
|
|
172
|
+
`Reports` in a sweep PR opened or merged in that window: those always get
|
|
173
|
+
their close-out.
|
|
174
|
+
|
|
175
|
+
Reading a source is a good job for a helper: give each source below its own
|
|
176
|
+
helper on the cheapest model (Luna in Codex, Haiku in Claude Code), ask for a
|
|
177
|
+
short list of candidates with links, and close it as soon as it reports. On
|
|
178
|
+
10/29 the three source reads cost $0.44 together; reusing those same helpers
|
|
179
|
+
for fixes afterwards cost $6.36, because each new job paid for its whole
|
|
180
|
+
growing history.
|
|
169
181
|
|
|
170
182
|
- **Read the channels.** Use `slack_read_channel` with
|
|
171
183
|
`response_format: detailed` (paginate) back 5 days. Its output shows
|
|
@@ -250,8 +262,9 @@ apart from Steve's own 👀.
|
|
|
250
262
|
## 3. Fix as many as you can
|
|
251
263
|
|
|
252
264
|
- Group related reports so one cause gets one fix. Give each independent
|
|
253
|
-
group a subagent on
|
|
254
|
-
|
|
265
|
+
group a fresh subagent on your own model and effort, with disjoint files,
|
|
266
|
+
or fix it in the main thread. Never hand a finished helper a new job; start
|
|
267
|
+
a fresh one. The main thread plans, reviews diffs, and integrates.
|
|
255
268
|
- **Reproduce before you edit.** Get the failure on screen first: a test
|
|
256
269
|
that fails, the action returning the wrong thing, a stack trace, or the
|
|
257
270
|
flow broken in a signed-in local app. Reading code is not an attempt:
|
|
@@ -274,9 +287,12 @@ apart from Steve's own 👀.
|
|
|
274
287
|
green, stop editing and capture the real failure first (stack, logs, the
|
|
275
288
|
reporter's actual data). If that doesn't settle it within about 30
|
|
276
289
|
minutes, it becomes 🎫 with one line on what you learned.
|
|
277
|
-
- **Second opinion before the PR.** Give a fresh subagent
|
|
278
|
-
text, the diff, and the proof, and ask: does
|
|
279
|
-
reporter saw,
|
|
290
|
+
- **Second opinion before the PR, every time.** Give a fresh subagent on
|
|
291
|
+
your own model only the report text, the diff, and the proof, and ask: does
|
|
292
|
+
the check exercise what the reporter saw, is this the cause or a symptom,
|
|
293
|
+
and what edge case breaks it? Fix what it finds before you open the PR. The
|
|
294
|
+
10/29 run skipped this, and PR review found the edge cases one round at a
|
|
295
|
+
time instead.
|
|
280
296
|
- **Keep fixes small.** Each report's fix goes in its own commit so a bad
|
|
281
297
|
one can be reverted alone. A fix that grows past about 300 lines, or into
|
|
282
298
|
a new subsystem (timeouts, cancellation, retries) the reporter didn't ask
|
|
@@ -293,6 +309,19 @@ PR per item. End the PR body with a
|
|
|
293
309
|
Slack thread, or the Sentry, Analytics, or GitHub issue. That list is the
|
|
294
310
|
only set of threads a later `/ship` may close out as fixed.
|
|
295
311
|
|
|
312
|
+
Wait for CI with one blocking command, such as
|
|
313
|
+
`gh pr checks <number> --watch --required --interval 60`, and don't post a
|
|
314
|
+
status line while it runs: every turn re-sends your whole context, and on
|
|
315
|
+
10/28 polling CI was half the main thread's cost.
|
|
316
|
+
|
|
317
|
+
Fix each review round's findings in one batch. If a second round still finds
|
|
318
|
+
a problem in the same fix, take that fix out of the PR, remove its whole entry
|
|
319
|
+
from the PR's `Reports` section: the link and its `fix-proof:` and `visual:`
|
|
320
|
+
lines (close-out marks every listed report fixed, and a stray evidence line
|
|
321
|
+
counts toward the report above it). Then 🎫 its
|
|
322
|
+
report with what review found, and merge the rest. Close the PR only when nothing verified
|
|
323
|
+
is left in it.
|
|
324
|
+
|
|
296
325
|
Merge it the way this repo merges PRs. In a Factory workspace, that means
|
|
297
326
|
the workflow's merge step after its merge gate, never a direct merge.
|
|
298
327
|
|