@agent-native/core 0.75.0 → 0.75.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.
Files changed (48) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +46 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/durable-background.ts +71 -3
  5. package/corpus/core/src/agent/production-agent.ts +16 -3
  6. package/corpus/core/src/cli/skills.ts +15 -11
  7. package/corpus/core/src/deploy/build.ts +100 -30
  8. package/corpus/core/src/templates/default/_gitignore +1 -0
  9. package/corpus/core/src/templates/headless/_gitignore +1 -0
  10. package/corpus/core/src/templates/workspace-root/_gitignore +1 -0
  11. package/corpus/templates/analytics/actions/get-sql-dashboard.ts +0 -8
  12. package/corpus/templates/analytics/actions/update-dashboard.ts +3 -1
  13. package/corpus/templates/analytics/app/components/SqlEditor.tsx +57 -0
  14. package/corpus/templates/analytics/app/components/SqlHighlight.tsx +27 -28
  15. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +130 -8
  16. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +2 -3
  17. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/ViewSqlPopover.tsx +4 -4
  18. package/corpus/templates/analytics/changelog/2026-06-24-active-user-dashboard-panels-classify-templates-more-accurat.md +6 -0
  19. package/corpus/templates/analytics/changelog/2026-06-24-dashboard-panel-deletes-now-stay-deleted-after-refresh.md +6 -0
  20. package/corpus/templates/analytics/changelog/2026-06-24-sql-panel-editors-now-highlight-query-syntax-and-keep-one-cl.md +6 -0
  21. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +2 -2
  22. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +9 -11
  23. package/corpus/templates/clips/actions/list-recordings.ts +21 -0
  24. package/corpus/templates/clips/app/components/library/library-layout.tsx +21 -2
  25. package/corpus/templates/clips/app/hooks/use-library.ts +18 -0
  26. package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +7 -5
  27. package/dist/agent/durable-background.d.ts +51 -3
  28. package/dist/agent/durable-background.d.ts.map +1 -1
  29. package/dist/agent/durable-background.js +64 -3
  30. package/dist/agent/durable-background.js.map +1 -1
  31. package/dist/agent/production-agent.d.ts.map +1 -1
  32. package/dist/agent/production-agent.js +16 -3
  33. package/dist/agent/production-agent.js.map +1 -1
  34. package/dist/cli/skills.d.ts +1 -1
  35. package/dist/cli/skills.d.ts.map +1 -1
  36. package/dist/cli/skills.js +15 -11
  37. package/dist/cli/skills.js.map +1 -1
  38. package/dist/deploy/build.d.ts +38 -17
  39. package/dist/deploy/build.d.ts.map +1 -1
  40. package/dist/deploy/build.js +96 -29
  41. package/dist/deploy/build.js.map +1 -1
  42. package/dist/templates/default/_gitignore +1 -0
  43. package/dist/templates/headless/_gitignore +1 -0
  44. package/dist/templates/workspace-root/_gitignore +1 -0
  45. package/package.json +1 -1
  46. package/src/templates/default/_gitignore +1 -0
  47. package/src/templates/headless/_gitignore +1 -0
  48. package/src/templates/workspace-root/_gitignore +1 -0
@@ -58,25 +58,46 @@ export declare function findInstalledResvgPackages(nodeModulesRoots: string[]):
58
58
  */
59
59
  export declare function isDurableBackgroundDeployEnabled(): boolean;
60
60
  /**
61
- * Single-template Netlify build: emit a SECOND function whose name ends in
62
- * `-background`, re-exporting the same `main.mjs` handler bundle, so the chat
63
- * `_process-run` POST lands on Netlify's async (15-min) function instead of the
64
- * synchronous one. Additive + flag-gated (see `isDurableBackgroundDeployEnabled`).
61
+ * Single-template Netlify build: emit a STANDALONE async background function so
62
+ * the chat `_process-run` worker runs on Netlify's async (15-min) function
63
+ * reached at its DIRECT url, instead of the synchronous `/*` catch-all.
64
+ * Additive + flag-gated (see `isDurableBackgroundDeployEnabled`).
65
65
  *
66
- * Nitro's `netlify` preset emits a single function at
67
- * `.netlify/functions-internal/server` (`server.mjs` → `main.mjs`). We copy
68
- * that directory to a sibling `<...>-background` function and write an entry
69
- * with a `config.path` of the process-run route.
66
+ * Nitro's `netlify` preset emits a single synchronous function at
67
+ * `.netlify/functions-internal/server` (`server.mjs` → `main.mjs`, `config.path`
68
+ * `/*`). We copy that bundle to a STANDALONE function in the STANDARD functions
69
+ * dir `.netlify/functions/server-agent-background` and write an entry that:
70
+ * 1. Sets `globalThis.__AGENT_NATIVE_BACKGROUND_RUNTIME__ = true` at cold start
71
+ * (read back by `isInBackgroundFunctionRuntime()` so the worker takes the
72
+ * ~13-min soft-timeout). A `globalThis` flag — NOT `process.env` — keeps the
73
+ * no-env-mutation guard satisfied and carries no cross-request state.
74
+ * 2. Declares `export const config = { background: true }` with NO `path`. With
75
+ * no custom `path`, Netlify exposes the function at the DEFAULT url
76
+ * `/.netlify/functions/server-agent-background` and `background:true` makes
77
+ * it ASYNC (immediate HTTP 202 ack, 15-min budget). The foreground POST
78
+ * self-dispatches to that direct url
79
+ * (`resolveAgentChatProcessRunDispatchPath`), BYPASSING Nitro's `/*`
80
+ * catch-all entirely.
81
+ * 3. REWRITES the incoming request path to `AGENT_CHAT_PROCESS_RUN_PATH` before
82
+ * delegating to the Nitro handler (`./main.mjs` default export — a Netlify
83
+ * v2 / Web-standard `async (Request) => Response` handler), so the Nitro
84
+ * router dispatches it to the `_process-run` plugin. Method, ALL headers
85
+ * (critically the HMAC `Authorization: Bearer` the plugin verifies) and the
86
+ * body are preserved by cloning the incoming `Request` with only its URL
87
+ * pathname rewritten.
70
88
  *
71
- * ⚠️ REAL-DEPLOY VERIFICATION REQUIRED. Whether Netlify routes
72
- * `/_agent-native/agent-chat/_process-run` to this `-background` function (and
73
- * invokes it asynchronously with the 15-min budget) vs the synchronous Nitro
74
- * function cannot be verified in this environment — Nitro owns the primary
75
- * function's routing manifest, and the precedence between the two functions for
76
- * that path is a Netlify runtime behavior. If routing resolves to the
77
- * synchronous function, the run still completes via the existing 40s
78
- * soft-timeout path (no durable win, no regression). See
79
- * docs/design/durable-agent-runs.md (Open risks #1).
89
+ * WHY this replaced the previous `config.path` approach: a function with a custom
90
+ * `config.path` is reachable ONLY at that path (not at its default function url)
91
+ * and `functions-internal` is not exposed at the default url at all. In prod,
92
+ * Netlify routed `/_agent-native/agent-chat/_process-run` to the synchronous
93
+ * Nitro `server` catch-all, NOT to the background function verified live: a
94
+ * POST to the process-run path returned a SYNCHRONOUS 401 from the handler
95
+ * (the Nitro plugin ran) instead of a 202 async ack. A standalone function at
96
+ * its direct url cannot be shadowed by the catch-all.
97
+ *
98
+ * Safety net regardless of Netlify routing nuance: if the direct-url dispatch
99
+ * fast-fails (e.g. 404 when this function was not emitted), the foreground
100
+ * handler degrades to an inline 40s synchronous run (see production-agent.ts).
80
101
  */
81
102
  export declare function emitSingleTemplateNetlifyBackgroundFunction(projectCwd: string): void;
82
103
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/deploy/build.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;GAYG;AAOH,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AA4B7B,eAAO,MAAM,6BAA6B,UAiBzC,CAAC;AAuBF,wBAAgB,wCAAwC,CACtD,WAAW,EAAE,MAAM,EAAE,GACpB,MAAM,CAaR;AAgBD,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC,CAAC;AAgBvE,wBAAgB,yCAAyC,CACvD,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,EACjB,WAAW,SAAK,GACf,IAAI,CAQN;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,EAAE,EACzB,WAAW,EAAE,MAAM,EAAE,EACrB,kBAAkB,GAAE,MAAM,EAAO,EACjC,OAAO,GAAE,gBAAgB,EAAO,EAChC,aAAa,GAAE,oBAAoB,GAAG,IAAW,EACjD,mBAAmB,GAAE,MAAM,EAAO,EAClC,gBAAgB,SAAmC,GAClD,MAAM,CAskBR;AAyXD,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C;AAkHD,wBAAgB,OAAO,CACrB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,iBAAiB,cAAoB,QAoCtC;AAuBD,KAAK,0BAA0B,GAAG,OAAO,GAAG,KAAK,CAAC;AAQlD,wBAAgB,qCAAqC,CACnD,YAAY,GAAE,MAAM,CAAC,QAA2B,EAChD,QAAQ,GAAE,MAAM,CAAC,YAA2B,EAC5C,UAAU,GAAE,0BAA0B,GAAG,IAAgD,GACxF,OAAO,CAOT;AAqED,wBAAgB,gCAAgC,CAC9C,gBAAgB,EAAE,MAAM,EAAE,GACzB,MAAM,GAAG,IAAI,CA8Bf;AAED,wBAAgB,0BAA0B,CACxC,gBAAgB,EAAE,MAAM,EAAE,GACzB,KAAK,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAqCpD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gCAAgC,IAAI,OAAO,CAK1D;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,2CAA2C,CACzD,UAAU,EAAE,MAAM,GACjB,IAAI,CAyCN;AAkND;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,gBAAgB,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,UAAU,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,GAAG,CAAC;IACX,KAAK,EAAE,eAAe,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/deploy/build.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;GAYG;AAOH,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AA+B7B,eAAO,MAAM,6BAA6B,UAiBzC,CAAC;AAuBF,wBAAgB,wCAAwC,CACtD,WAAW,EAAE,MAAM,EAAE,GACpB,MAAM,CAaR;AAgBD,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC,CAAC;AAgBvE,wBAAgB,yCAAyC,CACvD,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,EACjB,WAAW,SAAK,GACf,IAAI,CAQN;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,EAAE,EACzB,WAAW,EAAE,MAAM,EAAE,EACrB,kBAAkB,GAAE,MAAM,EAAO,EACjC,OAAO,GAAE,gBAAgB,EAAO,EAChC,aAAa,GAAE,oBAAoB,GAAG,IAAW,EACjD,mBAAmB,GAAE,MAAM,EAAO,EAClC,gBAAgB,SAAmC,GAClD,MAAM,CAskBR;AAyXD,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C;AAkHD,wBAAgB,OAAO,CACrB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,iBAAiB,cAAoB,QAoCtC;AAuBD,KAAK,0BAA0B,GAAG,OAAO,GAAG,KAAK,CAAC;AAQlD,wBAAgB,qCAAqC,CACnD,YAAY,GAAE,MAAM,CAAC,QAA2B,EAChD,QAAQ,GAAE,MAAM,CAAC,YAA2B,EAC5C,UAAU,GAAE,0BAA0B,GAAG,IAAgD,GACxF,OAAO,CAOT;AAqED,wBAAgB,gCAAgC,CAC9C,gBAAgB,EAAE,MAAM,EAAE,GACzB,MAAM,GAAG,IAAI,CA8Bf;AAED,wBAAgB,0BAA0B,CACxC,gBAAgB,EAAE,MAAM,EAAE,GACzB,KAAK,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAqCpD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gCAAgC,IAAI,OAAO,CAK1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,2CAA2C,CACzD,UAAU,EAAE,MAAM,GACjB,IAAI,CAuFN;AAkND;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,gBAAgB,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,UAAU,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,GAAG,CAAC;IACX,KAAK,EAAE,eAAe,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
@@ -21,7 +21,7 @@ import { discoverApiRoutes, discoverPlugins, discoverActionFiles, getMissingDefa
21
21
  import { getWorkspaceCoreExports, } from "./workspace-core.js";
22
22
  import { generateActionRegistryForProject } from "../vite/action-types-plugin.js";
23
23
  import { mcpEmbedStaticAssetRouteRules } from "../shared/mcp-embed-headers.js";
24
- import { AGENT_CHAT_PROCESS_RUN_PATH } from "../agent/durable-background.js";
24
+ import { AGENT_BACKGROUND_FUNCTION_NAME, AGENT_CHAT_PROCESS_RUN_PATH, } from "../agent/durable-background.js";
25
25
  import { AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_CACHE_BUSTER, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, } from "../shared/social-meta.js";
26
26
  import { DEFAULT_SSR_CDN_CACHE_CONTROL, DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL, DEFAULT_SPECULATION_RULES_PATH, DEFAULT_SSR_CACHE_CONTROL, } from "../shared/cache-control.js";
27
27
  import { collectImmutableAssetPaths, IMMUTABLE_ASSET_CACHE_CONTROL, IMMUTABLE_ASSET_CACHE_HEADERS, prefixAssetPath, } from "./immutable-assets.js";
@@ -1252,29 +1252,50 @@ export function isDurableBackgroundDeployEnabled() {
1252
1252
  return !(v === "0" || v === "false" || v === "no" || v === "off");
1253
1253
  }
1254
1254
  /**
1255
- * Single-template Netlify build: emit a SECOND function whose name ends in
1256
- * `-background`, re-exporting the same `main.mjs` handler bundle, so the chat
1257
- * `_process-run` POST lands on Netlify's async (15-min) function instead of the
1258
- * synchronous one. Additive + flag-gated (see `isDurableBackgroundDeployEnabled`).
1255
+ * Single-template Netlify build: emit a STANDALONE async background function so
1256
+ * the chat `_process-run` worker runs on Netlify's async (15-min) function
1257
+ * reached at its DIRECT url, instead of the synchronous `/*` catch-all.
1258
+ * Additive + flag-gated (see `isDurableBackgroundDeployEnabled`).
1259
1259
  *
1260
- * Nitro's `netlify` preset emits a single function at
1261
- * `.netlify/functions-internal/server` (`server.mjs` → `main.mjs`). We copy
1262
- * that directory to a sibling `<...>-background` function and write an entry
1263
- * with a `config.path` of the process-run route.
1260
+ * Nitro's `netlify` preset emits a single synchronous function at
1261
+ * `.netlify/functions-internal/server` (`server.mjs` → `main.mjs`, `config.path`
1262
+ * `/*`). We copy that bundle to a STANDALONE function in the STANDARD functions
1263
+ * dir `.netlify/functions/server-agent-background` and write an entry that:
1264
+ * 1. Sets `globalThis.__AGENT_NATIVE_BACKGROUND_RUNTIME__ = true` at cold start
1265
+ * (read back by `isInBackgroundFunctionRuntime()` so the worker takes the
1266
+ * ~13-min soft-timeout). A `globalThis` flag — NOT `process.env` — keeps the
1267
+ * no-env-mutation guard satisfied and carries no cross-request state.
1268
+ * 2. Declares `export const config = { background: true }` with NO `path`. With
1269
+ * no custom `path`, Netlify exposes the function at the DEFAULT url
1270
+ * `/.netlify/functions/server-agent-background` and `background:true` makes
1271
+ * it ASYNC (immediate HTTP 202 ack, 15-min budget). The foreground POST
1272
+ * self-dispatches to that direct url
1273
+ * (`resolveAgentChatProcessRunDispatchPath`), BYPASSING Nitro's `/*`
1274
+ * catch-all entirely.
1275
+ * 3. REWRITES the incoming request path to `AGENT_CHAT_PROCESS_RUN_PATH` before
1276
+ * delegating to the Nitro handler (`./main.mjs` default export — a Netlify
1277
+ * v2 / Web-standard `async (Request) => Response` handler), so the Nitro
1278
+ * router dispatches it to the `_process-run` plugin. Method, ALL headers
1279
+ * (critically the HMAC `Authorization: Bearer` the plugin verifies) and the
1280
+ * body are preserved by cloning the incoming `Request` with only its URL
1281
+ * pathname rewritten.
1264
1282
  *
1265
- * ⚠️ REAL-DEPLOY VERIFICATION REQUIRED. Whether Netlify routes
1266
- * `/_agent-native/agent-chat/_process-run` to this `-background` function (and
1267
- * invokes it asynchronously with the 15-min budget) vs the synchronous Nitro
1268
- * function cannot be verified in this environment — Nitro owns the primary
1269
- * function's routing manifest, and the precedence between the two functions for
1270
- * that path is a Netlify runtime behavior. If routing resolves to the
1271
- * synchronous function, the run still completes via the existing 40s
1272
- * soft-timeout path (no durable win, no regression). See
1273
- * docs/design/durable-agent-runs.md (Open risks #1).
1283
+ * WHY this replaced the previous `config.path` approach: a function with a custom
1284
+ * `config.path` is reachable ONLY at that path (not at its default function url)
1285
+ * and `functions-internal` is not exposed at the default url at all. In prod,
1286
+ * Netlify routed `/_agent-native/agent-chat/_process-run` to the synchronous
1287
+ * Nitro `server` catch-all, NOT to the background function verified live: a
1288
+ * POST to the process-run path returned a SYNCHRONOUS 401 from the handler
1289
+ * (the Nitro plugin ran) instead of a 202 async ack. A standalone function at
1290
+ * its direct url cannot be shadowed by the catch-all.
1291
+ *
1292
+ * Safety net regardless of Netlify routing nuance: if the direct-url dispatch
1293
+ * fast-fails (e.g. 404 when this function was not emitted), the foreground
1294
+ * handler degrades to an inline 40s synchronous run (see production-agent.ts).
1274
1295
  */
1275
1296
  export function emitSingleTemplateNetlifyBackgroundFunction(projectCwd) {
1276
- const functionsDir = path.join(projectCwd, ".netlify", "functions-internal");
1277
- const serverDir = path.join(functionsDir, "server");
1297
+ const internalDir = path.join(projectCwd, ".netlify", "functions-internal");
1298
+ const serverDir = path.join(internalDir, "server");
1278
1299
  if (!fs.existsSync(path.join(serverDir, "main.mjs"))) {
1279
1300
  // Nitro output layout differs from what we expected — skip rather than
1280
1301
  // guess. The single-function deploy is unaffected.
@@ -1282,32 +1303,78 @@ export function emitSingleTemplateNetlifyBackgroundFunction(projectCwd) {
1282
1303
  "at .netlify/functions-internal/server/main.mjs was not found.");
1283
1304
  return;
1284
1305
  }
1285
- const backgroundName = "server-agent-background";
1306
+ const backgroundName = AGENT_BACKGROUND_FUNCTION_NAME;
1307
+ // Emit into the STANDARD functions dir (NOT functions-internal) so Netlify
1308
+ // exposes the function at its default url `/.netlify/functions/<name>`.
1309
+ const functionsDir = path.join(projectCwd, ".netlify", "functions");
1286
1310
  const dest = path.join(functionsDir, backgroundName);
1311
+ fs.mkdirSync(functionsDir, { recursive: true });
1287
1312
  fs.rmSync(dest, { recursive: true, force: true });
1288
1313
  copyDir(serverDir, dest);
1289
- // Drop the original Nitro entry so our background entry is the entrypoint.
1314
+ // Drop the original Nitro `/*` entry so our standalone entry is the entrypoint
1315
+ // and the copied bundle does NOT re-register the catch-all `config.path`.
1290
1316
  fs.rmSync(path.join(dest, "server.mjs"), { force: true });
1291
- const entry = `let cachedHandler;
1317
+ const processRunPath = JSON.stringify(AGENT_CHAT_PROCESS_RUN_PATH);
1318
+ const entry = `// Mark this isolate as the durable background runtime BEFORE the handler
1319
+ // bundle is imported, so isInBackgroundFunctionRuntime() reliably returns true
1320
+ // in this function. The deployed Lambda name is NOT guaranteed to end in
1321
+ // "-background" (Netlify may mangle/prefix it), so we cannot depend on
1322
+ // AWS_LAMBDA_FUNCTION_NAME alone. A globalThis flag (NOT process.env) avoids the
1323
+ // no-env-mutation guard and carries no cross-request state — it is a static,
1324
+ // set-once isolate marker read back by isInBackgroundFunctionRuntime().
1325
+ globalThis.__AGENT_NATIVE_BACKGROUND_RUNTIME__ = true;
1326
+
1327
+ // The framework route the Nitro router dispatches to (the _process-run plugin).
1328
+ const PROCESS_RUN_PATH = ${processRunPath};
1292
1329
 
1293
- export default async function handler(...args) {
1330
+ let cachedHandler;
1331
+
1332
+ // Netlify v2 invokes this as (request, context). The Nitro netlify handler is a
1333
+ // Web-standard \`async (Request) => Response\` (see nitro/presets/netlify/runtime).
1334
+ // We are reached at this function's DIRECT url
1335
+ // (/.netlify/functions/${backgroundName}); rewrite the path to PROCESS_RUN_PATH
1336
+ // so Nitro routes it to the _process-run plugin, preserving method, ALL headers
1337
+ // (the HMAC Authorization: Bearer MUST survive — the plugin verifies it) and the
1338
+ // body. We clone the incoming Request with only its URL pathname rewritten;
1339
+ // query + origin are preserved.
1340
+ export default async function handler(request) {
1294
1341
  cachedHandler ??= (await import("./main.mjs")).default;
1295
- return cachedHandler(...args);
1342
+ const url = new URL(request.url);
1343
+ url.pathname = PROCESS_RUN_PATH;
1344
+ // Read the body once and pass it through. GET/HEAD have no body.
1345
+ const method = request.method || "POST";
1346
+ const hasBody = method !== "GET" && method !== "HEAD";
1347
+ const body = hasBody ? await request.text() : undefined;
1348
+ const rewritten = new Request(url.toString(), {
1349
+ method,
1350
+ headers: request.headers,
1351
+ body,
1352
+ });
1353
+ return cachedHandler(rewritten);
1296
1354
  }
1297
1355
 
1298
1356
  export const config = {
1299
1357
  name: "agent background handler",
1300
1358
  generator: "agent-native build",
1301
- path: ${JSON.stringify([AGENT_CHAT_PROCESS_RUN_PATH])},
1359
+ // background: true makes Netlify invoke this ASYNCHRONOUSLY (immediate HTTP
1360
+ // 202 ack) with the 15-minute budget. NO custom \`path\`: that keeps the
1361
+ // function reachable at its DEFAULT url /.netlify/functions/${backgroundName},
1362
+ // which BYPASSES Nitro's /* catch-all. The previous version set a custom
1363
+ // \`config.path\` and Netlify routed the process-run path to the SYNCHRONOUS
1364
+ // catch-all instead (verified live: a synchronous 401 from the handler, not a
1365
+ // 202 async ack). See Netlify docs: build/functions/background-functions +
1366
+ // build/functions/configuration.
1367
+ background: true,
1302
1368
  nodeBundler: "none",
1303
1369
  includedFiles: ["**"],
1304
1370
  preferStatic: false,
1305
1371
  };
1306
1372
  `;
1307
1373
  fs.writeFileSync(path.join(dest, `${backgroundName}.mjs`), entry);
1308
- console.log(`[build] Emitted durable-background function "${backgroundName}" ` +
1309
- `(path ${AGENT_CHAT_PROCESS_RUN_PATH}). REQUIRES real-deploy verification ` +
1310
- `of Netlify async routing see docs/design/durable-agent-runs.md.`);
1374
+ console.log(`[build] Emitted standalone durable-background function "${backgroundName}" ` +
1375
+ `at /.netlify/functions/${backgroundName} (async, rewrites to ` +
1376
+ `${AGENT_CHAT_PROCESS_RUN_PATH}). REQUIRES real-deploy verification of ` +
1377
+ `Netlify async invocation — see docs/design/durable-agent-runs.md.`);
1311
1378
  }
1312
1379
  function copyInstalledLibsqlNativePackages(serverDir) {
1313
1380
  if (!serverDir || !fs.existsSync(serverDir))