@agent-native/core 0.75.1 → 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 (30) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +30 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/durable-background.ts +56 -0
  5. package/corpus/core/src/agent/production-agent.ts +16 -3
  6. package/corpus/core/src/deploy/build.ts +87 -40
  7. package/corpus/templates/analytics/actions/get-sql-dashboard.ts +0 -8
  8. package/corpus/templates/analytics/actions/update-dashboard.ts +3 -1
  9. package/corpus/templates/analytics/app/components/SqlEditor.tsx +57 -0
  10. package/corpus/templates/analytics/app/components/SqlHighlight.tsx +27 -28
  11. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +130 -8
  12. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +2 -3
  13. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/ViewSqlPopover.tsx +4 -4
  14. package/corpus/templates/analytics/changelog/2026-06-24-active-user-dashboard-panels-classify-templates-more-accurat.md +6 -0
  15. package/corpus/templates/analytics/changelog/2026-06-24-dashboard-panel-deletes-now-stay-deleted-after-refresh.md +6 -0
  16. package/corpus/templates/analytics/changelog/2026-06-24-sql-panel-editors-now-highlight-query-syntax-and-keep-one-cl.md +6 -0
  17. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +2 -2
  18. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +9 -11
  19. package/dist/agent/durable-background.d.ts +44 -0
  20. package/dist/agent/durable-background.d.ts.map +1 -1
  21. package/dist/agent/durable-background.js +51 -0
  22. package/dist/agent/durable-background.js.map +1 -1
  23. package/dist/agent/production-agent.d.ts.map +1 -1
  24. package/dist/agent/production-agent.js +16 -3
  25. package/dist/agent/production-agent.js.map +1 -1
  26. package/dist/deploy/build.d.ts +37 -21
  27. package/dist/deploy/build.d.ts.map +1 -1
  28. package/dist/deploy/build.js +84 -40
  29. package/dist/deploy/build.js.map +1 -1
  30. package/package.json +1 -1
@@ -58,30 +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
- * The function declares `background: true` so Netlify invokes it ASYNC (HTTP
72
- * 202 ack) with the 15-min budget, and a `config.path` of the process-run route
73
- * so the `_process-run` self-dispatch lands on it. The earlier version set the
74
- * path but omitted `background: true` and relied on the legacy `-background`
75
- * filename which the `config` object overrides so Netlify served it
76
- * SYNCHRONOUSLY (~60s) and the durable worker never got the 15-min budget
77
- * (confirmed live: a POST to the process-run path returned a synchronous 401
78
- * from the handler instead of a 202 async ack).
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 functionverified 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.
79
97
  *
80
- * ⚠️ One Netlify runtime behavior still resolves only on a real deploy: the
81
- * routing precedence between this function's `config.path` and Nitro's catch-all
82
- * for that exact path. If the catch-all wins, the run still completes via the
83
- * 40s soft-timeout path on the sync function (no durable win, no regression).
84
- * See docs/design/durable-agent-runs.md (Open risks #1).
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).
85
101
  */
86
102
  export declare function emitSingleTemplateNetlifyBackgroundFunction(projectCwd: string): void;
87
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;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,2CAA2C,CACzD,UAAU,EAAE,MAAM,GACjB,IAAI,CA2DN;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,34 +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
- * The function declares `background: true` so Netlify invokes it ASYNC (HTTP
1266
- * 202 ack) with the 15-min budget, and a `config.path` of the process-run route
1267
- * so the `_process-run` self-dispatch lands on it. The earlier version set the
1268
- * path but omitted `background: true` and relied on the legacy `-background`
1269
- * filename which the `config` object overrides so Netlify served it
1270
- * SYNCHRONOUSLY (~60s) and the durable worker never got the 15-min budget
1271
- * (confirmed live: a POST to the process-run path returned a synchronous 401
1272
- * from the handler instead of a 202 async ack).
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 functionverified 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.
1273
1291
  *
1274
- * ⚠️ One Netlify runtime behavior still resolves only on a real deploy: the
1275
- * routing precedence between this function's `config.path` and Nitro's catch-all
1276
- * for that exact path. If the catch-all wins, the run still completes via the
1277
- * 40s soft-timeout path on the sync function (no durable win, no regression).
1278
- * See docs/design/durable-agent-runs.md (Open risks #1).
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).
1279
1295
  */
1280
1296
  export function emitSingleTemplateNetlifyBackgroundFunction(projectCwd) {
1281
- const functionsDir = path.join(projectCwd, ".netlify", "functions-internal");
1282
- const serverDir = path.join(functionsDir, "server");
1297
+ const internalDir = path.join(projectCwd, ".netlify", "functions-internal");
1298
+ const serverDir = path.join(internalDir, "server");
1283
1299
  if (!fs.existsSync(path.join(serverDir, "main.mjs"))) {
1284
1300
  // Nitro output layout differs from what we expected — skip rather than
1285
1301
  // guess. The single-function deploy is unaffected.
@@ -1287,12 +1303,18 @@ export function emitSingleTemplateNetlifyBackgroundFunction(projectCwd) {
1287
1303
  "at .netlify/functions-internal/server/main.mjs was not found.");
1288
1304
  return;
1289
1305
  }
1290
- 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");
1291
1310
  const dest = path.join(functionsDir, backgroundName);
1311
+ fs.mkdirSync(functionsDir, { recursive: true });
1292
1312
  fs.rmSync(dest, { recursive: true, force: true });
1293
1313
  copyDir(serverDir, dest);
1294
- // 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`.
1295
1316
  fs.rmSync(path.join(dest, "server.mjs"), { force: true });
1317
+ const processRunPath = JSON.stringify(AGENT_CHAT_PROCESS_RUN_PATH);
1296
1318
  const entry = `// Mark this isolate as the durable background runtime BEFORE the handler
1297
1319
  // bundle is imported, so isInBackgroundFunctionRuntime() reliably returns true
1298
1320
  // in this function. The deployed Lambda name is NOT guaranteed to end in
@@ -1302,35 +1324,57 @@ export function emitSingleTemplateNetlifyBackgroundFunction(projectCwd) {
1302
1324
  // set-once isolate marker read back by isInBackgroundFunctionRuntime().
1303
1325
  globalThis.__AGENT_NATIVE_BACKGROUND_RUNTIME__ = true;
1304
1326
 
1327
+ // The framework route the Nitro router dispatches to (the _process-run plugin).
1328
+ const PROCESS_RUN_PATH = ${processRunPath};
1329
+
1305
1330
  let cachedHandler;
1306
1331
 
1307
- export default async function handler(...args) {
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) {
1308
1341
  cachedHandler ??= (await import("./main.mjs")).default;
1309
- 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);
1310
1354
  }
1311
1355
 
1312
1356
  export const config = {
1313
1357
  name: "agent background handler",
1314
1358
  generator: "agent-native build",
1315
- // background: true is what actually makes Netlify invoke this ASYNCHRONOUSLY
1316
- // (immediate HTTP 202 ack) with the 15-minute budget. Without it, a function
1317
- // that declares a custom \`path\` is served SYNCHRONOUSLY (~60s) even when its
1318
- // file name ends in "-background" the \`config\` object overrides the legacy
1319
- // filename convention. That omission is why the durable worker was capped at
1320
- // ~60s in prod (verified live: POST to the process-run path returned a
1321
- // synchronous 401 from the handler, not a 202 async ack). See Netlify docs:
1322
- // build/functions/background-functions + build/functions/configuration.
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.
1323
1367
  background: true,
1324
- path: ${JSON.stringify([AGENT_CHAT_PROCESS_RUN_PATH])},
1325
1368
  nodeBundler: "none",
1326
1369
  includedFiles: ["**"],
1327
1370
  preferStatic: false,
1328
1371
  };
1329
1372
  `;
1330
1373
  fs.writeFileSync(path.join(dest, `${backgroundName}.mjs`), entry);
1331
- console.log(`[build] Emitted durable-background function "${backgroundName}" ` +
1332
- `(path ${AGENT_CHAT_PROCESS_RUN_PATH}). REQUIRES real-deploy verification ` +
1333
- `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.`);
1334
1378
  }
1335
1379
  function copyInstalledLibsqlNativePackages(serverDir) {
1336
1380
  if (!serverDir || !fs.existsSync(serverDir))