@agent-native/core 0.119.5 → 0.119.6

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 (89) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +6 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/durable-background.ts +1 -0
  5. package/corpus/core/src/deploy/build.ts +144 -2
  6. package/corpus/core/src/deploy/workspace-deploy.ts +123 -1
  7. package/corpus/core/src/integrations/integration-durable-dispatch-config.ts +22 -0
  8. package/corpus/core/src/integrations/integration-durable-dispatch.ts +190 -0
  9. package/corpus/core/src/integrations/pending-tasks-retry-job.ts +175 -87
  10. package/corpus/core/src/integrations/pending-tasks-store.ts +114 -11
  11. package/corpus/core/src/integrations/plugin.ts +113 -60
  12. package/corpus/core/src/integrations/task-queue-stats.ts +68 -15
  13. package/corpus/core/src/integrations/webhook-handler.ts +21 -46
  14. package/corpus/core/src/server/auth.ts +6 -0
  15. package/corpus/core/src/templates/default/.agents/skills/integration-webhooks/SKILL.md +63 -22
  16. package/corpus/core/src/templates/headless/.agents/skills/integration-webhooks/SKILL.md +63 -22
  17. package/corpus/core/src/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +63 -22
  18. package/corpus/templates/dispatch/changelog/2026-07-21-recover-stalled-slack-agent-work.md +6 -0
  19. package/dist/agent/durable-background.d.ts +1 -0
  20. package/dist/agent/durable-background.d.ts.map +1 -1
  21. package/dist/agent/durable-background.js +1 -0
  22. package/dist/agent/durable-background.js.map +1 -1
  23. package/dist/collab/routes.d.ts +1 -1
  24. package/dist/collab/struct-routes.d.ts +1 -1
  25. package/dist/deploy/build.d.ts +3 -0
  26. package/dist/deploy/build.d.ts.map +1 -1
  27. package/dist/deploy/build.js +106 -3
  28. package/dist/deploy/build.js.map +1 -1
  29. package/dist/deploy/workspace-deploy.d.ts.map +1 -1
  30. package/dist/deploy/workspace-deploy.js +103 -2
  31. package/dist/deploy/workspace-deploy.js.map +1 -1
  32. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  33. package/dist/integrations/integration-durable-dispatch-config.d.ts +7 -0
  34. package/dist/integrations/integration-durable-dispatch-config.d.ts.map +1 -0
  35. package/dist/integrations/integration-durable-dispatch-config.js +16 -0
  36. package/dist/integrations/integration-durable-dispatch-config.js.map +1 -0
  37. package/dist/integrations/integration-durable-dispatch.d.ts +23 -0
  38. package/dist/integrations/integration-durable-dispatch.d.ts.map +1 -0
  39. package/dist/integrations/integration-durable-dispatch.js +115 -0
  40. package/dist/integrations/integration-durable-dispatch.js.map +1 -0
  41. package/dist/integrations/pending-tasks-retry-job.d.ts +13 -1
  42. package/dist/integrations/pending-tasks-retry-job.d.ts.map +1 -1
  43. package/dist/integrations/pending-tasks-retry-job.js +133 -74
  44. package/dist/integrations/pending-tasks-retry-job.js.map +1 -1
  45. package/dist/integrations/pending-tasks-store.d.ts +14 -2
  46. package/dist/integrations/pending-tasks-store.d.ts.map +1 -1
  47. package/dist/integrations/pending-tasks-store.js +75 -11
  48. package/dist/integrations/pending-tasks-store.js.map +1 -1
  49. package/dist/integrations/plugin.d.ts.map +1 -1
  50. package/dist/integrations/plugin.js +88 -55
  51. package/dist/integrations/plugin.js.map +1 -1
  52. package/dist/integrations/task-queue-stats.d.ts +15 -3
  53. package/dist/integrations/task-queue-stats.d.ts.map +1 -1
  54. package/dist/integrations/task-queue-stats.js +45 -15
  55. package/dist/integrations/task-queue-stats.js.map +1 -1
  56. package/dist/integrations/webhook-handler.d.ts +1 -1
  57. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  58. package/dist/integrations/webhook-handler.js +18 -42
  59. package/dist/integrations/webhook-handler.js.map +1 -1
  60. package/dist/notifications/routes.d.ts +3 -3
  61. package/dist/observability/routes.d.ts +5 -5
  62. package/dist/progress/routes.d.ts +1 -1
  63. package/dist/provider-api/actions/custom-provider-registration.d.ts +5 -5
  64. package/dist/provider-api/actions/provider-api.d.ts +4 -4
  65. package/dist/resources/handlers.d.ts +1 -1
  66. package/dist/secrets/routes.d.ts +3 -3
  67. package/dist/server/auth.d.ts.map +1 -1
  68. package/dist/server/auth.js +5 -0
  69. package/dist/server/auth.js.map +1 -1
  70. package/dist/server/realtime-token.d.ts +1 -1
  71. package/dist/server/transcribe-voice.d.ts +1 -1
  72. package/dist/templates/default/.agents/skills/integration-webhooks/SKILL.md +63 -22
  73. package/dist/templates/headless/.agents/skills/integration-webhooks/SKILL.md +63 -22
  74. package/dist/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +63 -22
  75. package/package.json +1 -1
  76. package/src/agent/durable-background.ts +1 -0
  77. package/src/deploy/build.ts +144 -2
  78. package/src/deploy/workspace-deploy.ts +123 -1
  79. package/src/integrations/integration-durable-dispatch-config.ts +22 -0
  80. package/src/integrations/integration-durable-dispatch.ts +190 -0
  81. package/src/integrations/pending-tasks-retry-job.ts +175 -87
  82. package/src/integrations/pending-tasks-store.ts +114 -11
  83. package/src/integrations/plugin.ts +113 -60
  84. package/src/integrations/task-queue-stats.ts +68 -15
  85. package/src/integrations/webhook-handler.ts +21 -46
  86. package/src/server/auth.ts +6 -0
  87. package/src/templates/default/.agents/skills/integration-webhooks/SKILL.md +63 -22
  88. package/src/templates/headless/.agents/skills/integration-webhooks/SKILL.md +63 -22
  89. package/src/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +63 -22
@@ -1 +1 @@
1
- {"version":3,"file":"durable-background.js","sourceRoot":"","sources":["../../src/agent/durable-background.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Durable background agent-chat runs (Netlify background functions).\n *\n * Off by default. When enabled, a long in-app agent-chat turn is dispatched\n * into a Netlify *background* function (15-min budget) instead of completing\n * synchronously under the ~40s soft-timeout. The foreground POST claims the\n * run slot, inserts the run row, fires an HMAC-signed self-dispatch to\n * `AGENT_CHAT_PROCESS_RUN_PATH`, and returns the existing SSE subscription so\n * the client streams the same events (via the cross-isolate SQL-poll path)\n * with no client change.\n *\n * This module owns ONLY the gating decision + shared constants so both the\n * HTTP handler (`production-agent.ts`) and the processor route\n * (`agent-chat-plugin.ts`) agree on when the path is active without a circular\n * import. The actual run machinery is reused verbatim from run-manager /\n * run-store / self-dispatch / internal-token.\n *\n * GUARDRAIL: when `isAgentChatDurableBackgroundEnabled()` returns false, the\n * agent-chat handler must behave byte-for-byte like the current synchronous\n * path. The gate is true only when ALL of these hold:\n * 1. `AGENT_CHAT_DURABLE_BACKGROUND` env is explicitly enabled, or a\n * workspace app's agent-chat plugin opts in with `durableBackgroundRuns`\n * where the workspace deploy emits a per-app background function by\n * default. Single-template Netlify deploys must set the env flag because\n * that same flag controls whether `server-agent-background` is emitted.\n * 2. The runtime is hosted/serverless (local dev keeps the inline path so SSE\n * stays a single live stream and no second function is needed).\n * 3. `A2A_SECRET` is configured (the HMAC handoff is required to authenticate\n * the background dispatch; without it the dispatch can't be trusted).\n *\n * Opt-in keeps the blast radius small while the worker path is still being\n * proven. And even when enabled, a *dispatch failure degrades to an inline run*:\n * if the self-dispatch self-POST can't be delivered (fast connection error or\n * fast non-2xx), the foreground handler runs the turn synchronously instead of\n * erroring (see `production-agent.ts` — the inline fallback claims the run row\n * atomically so a delayed delivery can never double-execute). So an app where\n * durable dispatch happens to fail still gets a working chat, just without the\n * 15-min budget.\n */\nimport {\n hasConfiguredA2ASecret,\n isTrustedLocalRuntime,\n} from \"../a2a/auth-policy.js\";\nimport {\n extractBearerToken,\n verifyInternalToken,\n} from \"../integrations/internal-token.js\";\n\n/**\n * Framework route the background function actually runs — sibling to\n * `AGENT_TEAM_PROCESS_RUN_PATH`. Reached *through* the Netlify background\n * function, so it inherits the 15-min budget.\n */\nexport const AGENT_CHAT_PROCESS_RUN_PATH =\n \"/_agent-native/agent-chat/_process-run\";\n\n/**\n * Name of the standalone Netlify background function the build emits (see\n * `emitSingleTemplateNetlifyBackgroundFunction` in deploy/build.ts). Shared so\n * the emit and the dispatch-path helper below can never drift on the name.\n *\n * MUST end in `-background` — both because that is the conventional Netlify\n * async-function suffix and because `isInBackgroundFunctionRuntime()` reads the\n * `AWS_LAMBDA_FUNCTION_NAME` `-background` suffix as a secondary runtime signal.\n */\nexport const AGENT_BACKGROUND_FUNCTION_NAME = \"server-agent-background\";\n\n/**\n * Default function URL of the background function on Netlify. Every Netlify\n * function is reachable at `/.netlify/functions/<name>` BY DEFAULT; that default\n * url is removed ONLY if the function declares a custom `config.path`. The\n * emitted background function declares NO custom `config.path` (it sets\n * `background: true` and nothing else routing-related), so it KEEPS this default\n * url — and the Nitro `server` function already excludes `/.netlify/*` from its\n * `/*` catch-all, so this namespace is never shadowed. The foreground therefore\n * dispatches HERE on hosted Netlify (see `resolveAgentChatProcessRunDispatchPath`).\n */\nexport const AGENT_BACKGROUND_FUNCTION_URL_PATH = `/.netlify/functions/${AGENT_BACKGROUND_FUNCTION_NAME}`;\n\n/**\n * Marker carried in a Netlify background-function body when the shared\n * long-running worker should route to a processor other than agent chat.\n * The emitted wrapper defaults to the normal agent-chat `_process-run` route;\n * A2A uses this marker to reuse the same 15-minute function for async tasks.\n */\nexport const AGENT_BACKGROUND_PROCESSOR_FIELD = \"__agentNativeProcessor\";\nexport const AGENT_BACKGROUND_PROCESSOR_A2A = \"a2a\";\nexport const AGENT_BACKGROUND_PROCESSOR_ROUTE = \"route\";\nexport const AGENT_BACKGROUND_PROCESSOR_ROUTE_FIELD =\n \"__agentNativeProcessorRoute\";\n\n/**\n * The per-app workspace background function URL path. Workspace deploy emits one\n * background function per app named `<app>-agent-background`, reachable at its\n * DEFAULT url `/.netlify/functions/<app>-agent-background` (no custom\n * `config.path`). The foreground resolves the current workspace app id from\n * `AGENT_NATIVE_WORKSPACE_APP_ID` (set by the workspace function entry) so it can\n * dispatch to the right per-app function url. Returns `null` when no workspace\n * app id is configured (single-template deploy).\n */\nfunction resolveWorkspaceBackgroundFunctionUrlPath(): string | null {\n const raw = process.env.AGENT_NATIVE_WORKSPACE_APP_ID;\n if (typeof raw !== \"string\") return null;\n // Mirror the workspace app-id normalization (resources/store.ts): take the\n // first path segment and accept only the safe slug shape used for function\n // names. Anything else falls back to the single-template name.\n const candidate = raw.trim().replace(/^\\/+/, \"\").split(\"/\")[0] ?? \"\";\n if (!/^[a-z0-9][a-z0-9-]{0,127}$/.test(candidate)) return null;\n return `/.netlify/functions/${candidate}-agent-background`;\n}\n\nfunction isNetlifyHostedRuntimeForDispatch(): boolean {\n if (process.env.NETLIFY_LOCAL === \"true\") return false;\n if (process.env.NETLIFY === \"false\") return false;\n if (process.env.NETLIFY && process.env.NETLIFY !== \"false\") return true;\n // Netlify sets AWS Lambda runtime env on deployed Functions, but the build-time\n // NETLIFY flag is not always present in the runtime isolate. Treat Lambda as\n // Netlify here unless Netlify was explicitly disabled above; non-Netlify AWS\n // falls back inline if the /.netlify/functions dispatch fast-fails.\n return Boolean(process.env.AWS_LAMBDA_FUNCTION_NAME);\n}\n\n/**\n * Resolve the path the foreground POST should self-dispatch the chat background\n * worker to.\n *\n * GROUNDED IN THE REAL NETLIFY BUILD OUTPUT + THE NETLIFY DOCS DEFAULT-URL RULE:\n * the background function is emitted INTO the scanned dir\n * (`.netlify/functions-internal/server-agent-background`, or per-app\n * `<app>-agent-background` for workspaces) with `export const config = {\n * background: true, ... }` and NO custom `config.path`. Because it has no custom\n * path, Netlify keeps its DEFAULT function url `/.netlify/functions/<name>`, and\n * `background: true` makes any invocation of that url ASYNC (immediate 202,\n * 15-min budget). The Nitro `server` function already excludes `/.netlify/*`\n * from its `/*` catch-all, so the default-url namespace is NEVER shadowed by the\n * synchronous function.\n *\n * Therefore on hosted Netlify the foreground dispatches to the function's DEFAULT\n * url (`/.netlify/functions/<name>`); the function entry then rewrites the\n * incoming pathname to `AGENT_CHAT_PROCESS_RUN_PATH` (base-path-prefixed for\n * workspaces) before delegating to the Nitro router, so the `_process-run`\n * plugin runs with the async 15-min budget. Everywhere else (local dev, `netlify\n * dev`, non-Netlify hosts where no second function exists) there is no second\n * function, so the foreground dispatches to the framework route\n * `AGENT_CHAT_PROCESS_RUN_PATH` and the same in-process catch-all handles it\n * inline. The HMAC token (signed over the runId) is unchanged either way.\n *\n * NOTE: this is the DOC-CORRECT approach. An earlier attempt gave the function a\n * custom `config.path` + a catch-all `excludedPath` patch; the custom path was\n * NOT honored as a route in prod (probe → 404). Using the default function url\n * (no custom path) is what Netlify documents and is simpler — there is nothing\n * to shadow because `/.netlify/*` is already excluded from the `server` catch-all.\n */\nexport function resolveAgentChatProcessRunDispatchPath(): string {\n if (isNetlifyHostedRuntimeForDispatch()) {\n return (\n resolveWorkspaceBackgroundFunctionUrlPath() ??\n AGENT_BACKGROUND_FUNCTION_URL_PATH\n );\n }\n return AGENT_CHAT_PROCESS_RUN_PATH;\n}\n\nexport function resolveDurableBackgroundDispatchPath(\n fallbackPath: string,\n): string {\n if (isNetlifyHostedRuntimeForDispatch()) {\n return (\n resolveWorkspaceBackgroundFunctionUrlPath() ??\n AGENT_BACKGROUND_FUNCTION_URL_PATH\n );\n }\n return fallbackPath;\n}\n\nexport function dispatchPathTargetsNetlifyBackgroundFunction(\n dispatchPath: string,\n): boolean {\n return dispatchPath.startsWith(\"/.netlify/functions/\");\n}\n\n/**\n * Env flag for durable background runs. DEFAULT-OFF (opt-in): unset means\n * disabled; an app opts IN with an explicit truthy value (`true`/`1`/`yes`/`on`).\n */\nexport const AGENT_CHAT_DURABLE_BACKGROUND_ENV =\n \"AGENT_CHAT_DURABLE_BACKGROUND\";\n\n/**\n * Body field the foreground handler injects when self-dispatching to the\n * background processor. Its presence is how the re-entered handler knows it is\n * the background worker (run inline with the background soft-timeout; do NOT\n * re-claim the slot or re-dispatch). Untrusted on its own — the route also\n * verifies the HMAC token before invoking the handler.\n */\nexport const AGENT_CHAT_BACKGROUND_RUN_FIELD = \"__backgroundRun\";\n\n/**\n * Mirror of run-manager's private `isHostedRuntime`. Kept in sync deliberately:\n * the durable-background gate must agree with the soft-timeout regime about\n * what \"hosted\" means.\n */\nexport function isHostedRuntimeForDurableBackground(): boolean {\n if (\n process.env.NETLIFY &&\n process.env.NETLIFY !== \"false\" &&\n process.env.NETLIFY_LOCAL !== \"true\"\n ) {\n return true;\n }\n if (\n process.env.AWS_LAMBDA_FUNCTION_NAME &&\n process.env.NETLIFY_LOCAL !== \"true\"\n ) {\n return true;\n }\n return Boolean(\n process.env.CF_PAGES ||\n process.env.VERCEL ||\n process.env.VERCEL_ENV ||\n process.env.RENDER ||\n process.env.FLY_APP_NAME ||\n process.env.K_SERVICE,\n );\n}\n\n/**\n * True when THIS process is actually executing inside a Netlify *background*\n * function (the long, 15-min-budget async function whose deployed name ends in\n * `-background`). Netlify runs functions on AWS Lambda and sets\n * `AWS_LAMBDA_FUNCTION_NAME` to the function's name, so a `-background` suffix is\n * the runtime proof that the ~60s synchronous wall does NOT apply here.\n *\n * This is the SAFETY GUARD for the soft-timeout regime. The `_process-run`\n * self-dispatch worker (`isBackgroundWorker`) is NOT enough on its own: if the\n * `-background` function was never emitted (deploy gate off, or Netlify routed\n * the path to the synchronous function), the self-POST lands on the regular\n * ~60s `server` function. A worker there MUST use the 40s soft-timeout and\n * checkpoint before the 60s wall — using the ~13min budget would overshoot the\n * hard wall and get killed at 60s, then re-dispatch/resume in a wasteful loop.\n * So the 13-min budget is taken ONLY when this returns true.\n *\n * The PRIMARY signal is a `globalThis` marker the emitted background function's\n * entry sets at cold start — the deployed Lambda name is not guaranteed to end\n * in `-background` on Netlify, so the entry marks its own runtime. A `globalThis`\n * flag (not `process.env`) keeps the no-env-mutation guard satisfied and carries\n * no cross-request state (set once per isolate). The `AWS_LAMBDA_FUNCTION_NAME`\n * suffix and the explicit `AGENT_CHAT_FORCE_BACKGROUND_RUNTIME` env (truthy) are\n * additional signals — the latter an operator escape hatch. Off by default.\n */\nexport function isInBackgroundFunctionRuntime(): boolean {\n // Set by the emitted `-background` function entry at cold start (the primary,\n // most reliable signal — see the emit in deploy/build.ts).\n if (\n (globalThis as Record<string, unknown>)\n .__AGENT_NATIVE_BACKGROUND_RUNTIME__ === true\n ) {\n return true;\n }\n const lambdaName = process.env.AWS_LAMBDA_FUNCTION_NAME;\n if (\n typeof lambdaName === \"string\" &&\n lambdaName.toLowerCase().endsWith(\"-background\")\n ) {\n return true;\n }\n const forced = process.env.AGENT_CHAT_FORCE_BACKGROUND_RUNTIME;\n if (forced != null) {\n const v = forced.trim().toLowerCase();\n return v === \"1\" || v === \"true\" || v === \"yes\" || v === \"on\";\n }\n return false;\n}\n\nexport function backgroundRunMarkerExpectsBackgroundRuntime(\n marker: unknown,\n): boolean {\n return (\n typeof marker === \"object\" &&\n marker !== null &&\n (marker as { backgroundFunctionRuntimeExpected?: unknown })\n .backgroundFunctionRuntimeExpected === true\n );\n}\n\nexport function shouldUseBackgroundFunctionTimeoutForWorker(\n _marker: unknown,\n): boolean {\n // The dispatch marker says which URL the foreground targeted, not where the\n // request actually landed. Only the worker runtime proof can safely lift the\n // hosted 40s clamp to the 15-minute background-function budget.\n return isInBackgroundFunctionRuntime();\n}\n\nexport function backgroundRuntimeDiagnosticDetail(marker: unknown): string {\n return [\n `markerExpected=${backgroundRunMarkerExpectsBackgroundRuntime(marker)}`,\n `runtimeDetected=${isInBackgroundFunctionRuntime()}`,\n `globalMarker=${(globalThis as Record<string, unknown>).__AGENT_NATIVE_BACKGROUND_RUNTIME__ === true}`,\n `lambdaNameEndsBackground=${typeof process.env.AWS_LAMBDA_FUNCTION_NAME === \"string\" && process.env.AWS_LAMBDA_FUNCTION_NAME.toLowerCase().endsWith(\"-background\")}`,\n `forceEnv=${typeof process.env.AGENT_CHAT_FORCE_BACKGROUND_RUNTIME === \"string\" && process.env.AGENT_CHAT_FORCE_BACKGROUND_RUNTIME.trim().length > 0}`,\n ].join(\" \");\n}\n\nfunction isFlagEnabled(): boolean {\n // Read the literal key (not `process.env[CONST]`) so guard:no-env-credentials\n // can statically verify it against the allowlisted `AGENT_*` prefix. Keep this\n // in sync with AGENT_CHAT_DURABLE_BACKGROUND_ENV.\n //\n // DEFAULT-OFF (opt-in): durable background runs are still being hardened. A\n // premature fleet-wide default-on caused real-user incidents (Assets/Analytics\n // hit \"Failed to dispatch\" + stalls, 2026-06-24) because the async background\n // worker path is not yet proven end-to-end and the deploy-time env opt-out is\n // not reliably baked into a given deploy. So an unset/empty/unknown flag means\n // OFF; an app opts IN only with an explicit truthy value\n // (AGENT_CHAT_DURABLE_BACKGROUND=true). This still composes with the hosted +\n // A2A_SECRET gates below. Flip back to default-on only after the 15-min\n // background-function worker is verified live in production (see the\n // project_durable_bg_prod_verified memory).\n const raw = process.env.AGENT_CHAT_DURABLE_BACKGROUND;\n if (raw == null) return false;\n const normalized = raw.trim().toLowerCase();\n return (\n normalized === \"1\" ||\n normalized === \"true\" ||\n normalized === \"yes\" ||\n normalized === \"on\"\n );\n}\n\nfunction isFlagExplicitlyDisabled(): boolean {\n const raw = process.env.AGENT_CHAT_DURABLE_BACKGROUND;\n if (raw == null) return false;\n const normalized = raw.trim().toLowerCase();\n return (\n normalized === \"0\" ||\n normalized === \"false\" ||\n normalized === \"no\" ||\n normalized === \"off\"\n );\n}\n\n/**\n * The single gate. True when the env flag is explicitly enabled, or a workspace\n * app opted in and has a per-app background-function target, AND the runtime is\n * hosted AND A2A_SECRET is configured. False otherwise — and false means the\n * current synchronous behavior is used unchanged. Single-template Netlify app\n * opt-ins deliberately require the env flag too because that flag controls\n * whether the `server-agent-background` function exists in the deploy output.\n */\nexport function isAgentChatDurableBackgroundEnabled(options?: {\n appOptIn?: boolean;\n}): boolean {\n // An app-level opt-out must win over a stale deploy-wide env flag. Netlify\n // environment variables can outlive the source config that originally set\n // them; allowing that flag to re-enable a worker an app explicitly disabled\n // recreates the missing-background-function failure this gate is meant to\n // prevent.\n if (options?.appOptIn === false) return false;\n const envOptIn = isFlagEnabled();\n const workspaceAppOptIn =\n options?.appOptIn === true &&\n !isFlagExplicitlyDisabled() &&\n resolveWorkspaceBackgroundFunctionUrlPath() !== null;\n return (\n (envOptIn || workspaceAppOptIn) &&\n isHostedRuntimeForDurableBackground() &&\n hasConfiguredA2ASecret()\n );\n}\n\n/**\n * Env flag for the FOREGROUND server-driven self-chain. DEFAULT-OFF: a hosted\n * app must explicitly opt in with a truthy value (`true`/`1`/`yes`/`on`). A\n * regular Netlify function has a fixed 60-second wall, and a self-dispatched\n * successor can otherwise be killed before it persists its next continuation.\n * Keep this separate from `AGENT_CHAT_DURABLE_BACKGROUND` so the experimental\n * regular-function chain can be enabled independently after its deployment is\n * proven safe.\n */\nexport const AGENT_CHAT_FOREGROUND_SELF_CHAIN_ENV =\n \"AGENT_CHAT_FOREGROUND_SELF_CHAIN\";\n\nfunction isForegroundSelfChainExplicitlyEnabled(): boolean {\n // Read the literal key (not `process.env[CONST]`) so guard:no-env-credentials\n // can statically verify it against the allowlisted `AGENT_*` prefix. Keep this\n // in sync with AGENT_CHAT_FOREGROUND_SELF_CHAIN_ENV.\n const raw = process.env.AGENT_CHAT_FOREGROUND_SELF_CHAIN;\n if (raw == null) return false;\n const normalized = raw.trim().toLowerCase();\n return (\n normalized === \"1\" ||\n normalized === \"true\" ||\n normalized === \"yes\" ||\n normalized === \"on\"\n );\n}\n\n/**\n * Gate for the foreground self-chain: a normal (non-durable-background)\n * agent-chat turn that hits its soft-timeout chunk boundary continues via a\n * server-side self-dispatch on the REGULAR function (not a Netlify\n * `-background` function) instead of depending on the client to re-POST\n * `auto_continue`. Composes exactly like `isAgentChatDurableBackgroundEnabled`:\n * true only when the env flag is explicitly truthy, the runtime is hosted, and\n * `A2A_SECRET` is configured (the HMAC handoff authenticates the dispatch).\n * False means the existing client-driven `auto_continue` re-POST path is used.\n *\n * Deliberately independent of `isAgentChatDurableBackgroundEnabled`: an app can\n * use this narrower capability without opting into the full 15-min\n * background-function worker path, and the two gates never need to agree.\n * When BOTH would be true for a given run, the durable-background dispatch\n * decision in `production-agent.ts` is evaluated first and takes precedence —\n * a run already dispatched to the durable background worker chains via the\n * existing `isBackgroundWorker` path, not this one.\n */\nexport function isAgentChatForegroundSelfChainEnabled(): boolean {\n return (\n isForegroundSelfChainExplicitlyEnabled() &&\n isHostedRuntimeForDurableBackground() &&\n hasConfiguredA2ASecret()\n );\n}\n\n/** Decision returned by `prepareProcessRunRequest`. */\nexport type ProcessRunPreparation =\n | {\n ok: true;\n /** The pre-claimed run id the background worker must reuse. */\n runId: string;\n /** Body to stash for the re-entered handler (marker guaranteed present). */\n body: Record<string, unknown>;\n }\n | {\n ok: false;\n /** HTTP status the route should return. */\n status: number;\n /** Error payload. */\n error: string;\n /**\n * The run id parsed from the body, when present. Carried even on failure\n * so the route can RECORD the auth/validation failure ONTO the run\n * (diag_stage) before returning the error status — otherwise a 401/503 in\n * the unreadable Netlify background function would leave the run to time\n * out with no clue why. Null when no run id could be parsed.\n */\n runId: string | null;\n };\n\n/**\n * Parse the run id from a `_process-run` request body without authenticating.\n * Mirrors the precedence in `prepareProcessRunRequest` (marker.runId, then\n * top-level taskId). Returns null when neither is a usable string. Used so the\n * route can attach a diagnostic to the run even on an auth/validation failure.\n */\nexport function extractProcessRunId(body: unknown): string | null {\n if (!body || typeof body !== \"object\") return null;\n const record = body as Record<string, unknown>;\n const marker = record[AGENT_CHAT_BACKGROUND_RUN_FIELD] as\n | { runId?: unknown }\n | undefined;\n if (marker && typeof marker.runId === \"string\" && marker.runId) {\n return marker.runId;\n }\n if (typeof record.taskId === \"string\" && record.taskId) {\n return record.taskId;\n }\n return null;\n}\n\n/**\n * Pure, transport-agnostic core of the `_process-run` route: validate the body,\n * authenticate the HMAC self-dispatch, and produce the body the re-entered\n * agent-chat handler should run as the background worker.\n *\n * Auth policy mirrors the agent-teams processor exactly:\n * - `A2A_SECRET` set → require a valid `verifyInternalToken(runId, token)`.\n * - no secret → require `isTrustedLocalRuntime({ loopback })` (see\n * auth-policy.ts): refuse (503) unless `A2A_ALLOW_UNSIGNED_INTERNAL=1` is\n * set. This function has no h3 `event` of its own, so callers that CAN\n * see the inbound socket peer (the route handler, which has the event)\n * should compute `loopback` from it and pass it through; callers that\n * can't determine the peer address should omit it (defaults to `false`\n * — never trust unsigned dispatch without an explicit opt-in).\n *\n * Extracted from the route handler so the auth + marker-prep decision is unit\n * testable without booting the whole Nitro plugin. The route only adds body\n * reading and the final handler invocation around this.\n */\nexport function prepareProcessRunRequest(\n body: unknown,\n authHeader: string | undefined,\n loopback: boolean = false,\n): ProcessRunPreparation {\n if (!body || typeof body !== \"object\") {\n return {\n ok: false,\n status: 400,\n error: \"Invalid request body\",\n runId: null,\n };\n }\n const record = body as Record<string, unknown>;\n const marker = record[AGENT_CHAT_BACKGROUND_RUN_FIELD] as\n | { runId?: unknown }\n | undefined;\n const runId =\n marker && typeof marker.runId === \"string\"\n ? marker.runId\n : typeof record.taskId === \"string\"\n ? (record.taskId as string)\n : \"\";\n if (!runId) {\n return { ok: false, status: 400, error: \"runId required\", runId: null };\n }\n\n if (hasConfiguredA2ASecret()) {\n const token = extractBearerToken(authHeader);\n if (!verifyInternalToken(runId, token ?? \"\")) {\n return {\n ok: false,\n status: 401,\n error: \"Invalid or expired processor token\",\n runId,\n };\n }\n } else if (!isTrustedLocalRuntime({ loopback })) {\n // Callers that can see the h3 `event` (the route handler) pass the real\n // loopback signal; callers without one default to non-loopback. Unsigned\n // dispatch is still allowed via A2A_ALLOW_UNSIGNED_INTERNAL=1 for trusted\n // local/dev setups; see auth-policy.ts `isTrustedLocalRuntime`.\n return {\n ok: false,\n status: 503,\n error:\n \"Agent chat background processor not configured — set A2A_SECRET on this deployment (or A2A_ALLOW_UNSIGNED_INTERNAL=1 for trusted local dev).\",\n runId,\n };\n }\n\n // Ensure the marker is present so the re-entered handler runs as the\n // background worker (reuses runId/turnId, no re-claim, no re-dispatch).\n if (!marker || typeof marker.runId !== \"string\") {\n record[AGENT_CHAT_BACKGROUND_RUN_FIELD] = { runId };\n }\n return { ok: true, runId, body: record };\n}\n"]}
1
+ {"version":3,"file":"durable-background.js","sourceRoot":"","sources":["../../src/agent/durable-background.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Durable background agent-chat runs (Netlify background functions).\n *\n * Off by default. When enabled, a long in-app agent-chat turn is dispatched\n * into a Netlify *background* function (15-min budget) instead of completing\n * synchronously under the ~40s soft-timeout. The foreground POST claims the\n * run slot, inserts the run row, fires an HMAC-signed self-dispatch to\n * `AGENT_CHAT_PROCESS_RUN_PATH`, and returns the existing SSE subscription so\n * the client streams the same events (via the cross-isolate SQL-poll path)\n * with no client change.\n *\n * This module owns ONLY the gating decision + shared constants so both the\n * HTTP handler (`production-agent.ts`) and the processor route\n * (`agent-chat-plugin.ts`) agree on when the path is active without a circular\n * import. The actual run machinery is reused verbatim from run-manager /\n * run-store / self-dispatch / internal-token.\n *\n * GUARDRAIL: when `isAgentChatDurableBackgroundEnabled()` returns false, the\n * agent-chat handler must behave byte-for-byte like the current synchronous\n * path. The gate is true only when ALL of these hold:\n * 1. `AGENT_CHAT_DURABLE_BACKGROUND` env is explicitly enabled, or a\n * workspace app's agent-chat plugin opts in with `durableBackgroundRuns`\n * where the workspace deploy emits a per-app background function by\n * default. Single-template Netlify deploys must set the env flag because\n * that same flag controls whether `server-agent-background` is emitted.\n * 2. The runtime is hosted/serverless (local dev keeps the inline path so SSE\n * stays a single live stream and no second function is needed).\n * 3. `A2A_SECRET` is configured (the HMAC handoff is required to authenticate\n * the background dispatch; without it the dispatch can't be trusted).\n *\n * Opt-in keeps the blast radius small while the worker path is still being\n * proven. And even when enabled, a *dispatch failure degrades to an inline run*:\n * if the self-dispatch self-POST can't be delivered (fast connection error or\n * fast non-2xx), the foreground handler runs the turn synchronously instead of\n * erroring (see `production-agent.ts` — the inline fallback claims the run row\n * atomically so a delayed delivery can never double-execute). So an app where\n * durable dispatch happens to fail still gets a working chat, just without the\n * 15-min budget.\n */\nimport {\n hasConfiguredA2ASecret,\n isTrustedLocalRuntime,\n} from \"../a2a/auth-policy.js\";\nimport {\n extractBearerToken,\n verifyInternalToken,\n} from \"../integrations/internal-token.js\";\n\n/**\n * Framework route the background function actually runs — sibling to\n * `AGENT_TEAM_PROCESS_RUN_PATH`. Reached *through* the Netlify background\n * function, so it inherits the 15-min budget.\n */\nexport const AGENT_CHAT_PROCESS_RUN_PATH =\n \"/_agent-native/agent-chat/_process-run\";\n\n/**\n * Name of the standalone Netlify background function the build emits (see\n * `emitSingleTemplateNetlifyBackgroundFunction` in deploy/build.ts). Shared so\n * the emit and the dispatch-path helper below can never drift on the name.\n *\n * MUST end in `-background` — both because that is the conventional Netlify\n * async-function suffix and because `isInBackgroundFunctionRuntime()` reads the\n * `AWS_LAMBDA_FUNCTION_NAME` `-background` suffix as a secondary runtime signal.\n */\nexport const AGENT_BACKGROUND_FUNCTION_NAME = \"server-agent-background\";\n\n/**\n * Default function URL of the background function on Netlify. Every Netlify\n * function is reachable at `/.netlify/functions/<name>` BY DEFAULT; that default\n * url is removed ONLY if the function declares a custom `config.path`. The\n * emitted background function declares NO custom `config.path` (it sets\n * `background: true` and nothing else routing-related), so it KEEPS this default\n * url — and the Nitro `server` function already excludes `/.netlify/*` from its\n * `/*` catch-all, so this namespace is never shadowed. The foreground therefore\n * dispatches HERE on hosted Netlify (see `resolveAgentChatProcessRunDispatchPath`).\n */\nexport const AGENT_BACKGROUND_FUNCTION_URL_PATH = `/.netlify/functions/${AGENT_BACKGROUND_FUNCTION_NAME}`;\n\n/**\n * Marker carried in a Netlify background-function body when the shared\n * long-running worker should route to a processor other than agent chat.\n * The emitted wrapper defaults to the normal agent-chat `_process-run` route;\n * A2A uses this marker to reuse the same 15-minute function for async tasks.\n */\nexport const AGENT_BACKGROUND_PROCESSOR_FIELD = \"__agentNativeProcessor\";\nexport const AGENT_BACKGROUND_PROCESSOR_A2A = \"a2a\";\nexport const AGENT_BACKGROUND_PROCESSOR_INTEGRATION = \"integration\";\nexport const AGENT_BACKGROUND_PROCESSOR_ROUTE = \"route\";\nexport const AGENT_BACKGROUND_PROCESSOR_ROUTE_FIELD =\n \"__agentNativeProcessorRoute\";\n\n/**\n * The per-app workspace background function URL path. Workspace deploy emits one\n * background function per app named `<app>-agent-background`, reachable at its\n * DEFAULT url `/.netlify/functions/<app>-agent-background` (no custom\n * `config.path`). The foreground resolves the current workspace app id from\n * `AGENT_NATIVE_WORKSPACE_APP_ID` (set by the workspace function entry) so it can\n * dispatch to the right per-app function url. Returns `null` when no workspace\n * app id is configured (single-template deploy).\n */\nfunction resolveWorkspaceBackgroundFunctionUrlPath(): string | null {\n const raw = process.env.AGENT_NATIVE_WORKSPACE_APP_ID;\n if (typeof raw !== \"string\") return null;\n // Mirror the workspace app-id normalization (resources/store.ts): take the\n // first path segment and accept only the safe slug shape used for function\n // names. Anything else falls back to the single-template name.\n const candidate = raw.trim().replace(/^\\/+/, \"\").split(\"/\")[0] ?? \"\";\n if (!/^[a-z0-9][a-z0-9-]{0,127}$/.test(candidate)) return null;\n return `/.netlify/functions/${candidate}-agent-background`;\n}\n\nfunction isNetlifyHostedRuntimeForDispatch(): boolean {\n if (process.env.NETLIFY_LOCAL === \"true\") return false;\n if (process.env.NETLIFY === \"false\") return false;\n if (process.env.NETLIFY && process.env.NETLIFY !== \"false\") return true;\n // Netlify sets AWS Lambda runtime env on deployed Functions, but the build-time\n // NETLIFY flag is not always present in the runtime isolate. Treat Lambda as\n // Netlify here unless Netlify was explicitly disabled above; non-Netlify AWS\n // falls back inline if the /.netlify/functions dispatch fast-fails.\n return Boolean(process.env.AWS_LAMBDA_FUNCTION_NAME);\n}\n\n/**\n * Resolve the path the foreground POST should self-dispatch the chat background\n * worker to.\n *\n * GROUNDED IN THE REAL NETLIFY BUILD OUTPUT + THE NETLIFY DOCS DEFAULT-URL RULE:\n * the background function is emitted INTO the scanned dir\n * (`.netlify/functions-internal/server-agent-background`, or per-app\n * `<app>-agent-background` for workspaces) with `export const config = {\n * background: true, ... }` and NO custom `config.path`. Because it has no custom\n * path, Netlify keeps its DEFAULT function url `/.netlify/functions/<name>`, and\n * `background: true` makes any invocation of that url ASYNC (immediate 202,\n * 15-min budget). The Nitro `server` function already excludes `/.netlify/*`\n * from its `/*` catch-all, so the default-url namespace is NEVER shadowed by the\n * synchronous function.\n *\n * Therefore on hosted Netlify the foreground dispatches to the function's DEFAULT\n * url (`/.netlify/functions/<name>`); the function entry then rewrites the\n * incoming pathname to `AGENT_CHAT_PROCESS_RUN_PATH` (base-path-prefixed for\n * workspaces) before delegating to the Nitro router, so the `_process-run`\n * plugin runs with the async 15-min budget. Everywhere else (local dev, `netlify\n * dev`, non-Netlify hosts where no second function exists) there is no second\n * function, so the foreground dispatches to the framework route\n * `AGENT_CHAT_PROCESS_RUN_PATH` and the same in-process catch-all handles it\n * inline. The HMAC token (signed over the runId) is unchanged either way.\n *\n * NOTE: this is the DOC-CORRECT approach. An earlier attempt gave the function a\n * custom `config.path` + a catch-all `excludedPath` patch; the custom path was\n * NOT honored as a route in prod (probe → 404). Using the default function url\n * (no custom path) is what Netlify documents and is simpler — there is nothing\n * to shadow because `/.netlify/*` is already excluded from the `server` catch-all.\n */\nexport function resolveAgentChatProcessRunDispatchPath(): string {\n if (isNetlifyHostedRuntimeForDispatch()) {\n return (\n resolveWorkspaceBackgroundFunctionUrlPath() ??\n AGENT_BACKGROUND_FUNCTION_URL_PATH\n );\n }\n return AGENT_CHAT_PROCESS_RUN_PATH;\n}\n\nexport function resolveDurableBackgroundDispatchPath(\n fallbackPath: string,\n): string {\n if (isNetlifyHostedRuntimeForDispatch()) {\n return (\n resolveWorkspaceBackgroundFunctionUrlPath() ??\n AGENT_BACKGROUND_FUNCTION_URL_PATH\n );\n }\n return fallbackPath;\n}\n\nexport function dispatchPathTargetsNetlifyBackgroundFunction(\n dispatchPath: string,\n): boolean {\n return dispatchPath.startsWith(\"/.netlify/functions/\");\n}\n\n/**\n * Env flag for durable background runs. DEFAULT-OFF (opt-in): unset means\n * disabled; an app opts IN with an explicit truthy value (`true`/`1`/`yes`/`on`).\n */\nexport const AGENT_CHAT_DURABLE_BACKGROUND_ENV =\n \"AGENT_CHAT_DURABLE_BACKGROUND\";\n\n/**\n * Body field the foreground handler injects when self-dispatching to the\n * background processor. Its presence is how the re-entered handler knows it is\n * the background worker (run inline with the background soft-timeout; do NOT\n * re-claim the slot or re-dispatch). Untrusted on its own — the route also\n * verifies the HMAC token before invoking the handler.\n */\nexport const AGENT_CHAT_BACKGROUND_RUN_FIELD = \"__backgroundRun\";\n\n/**\n * Mirror of run-manager's private `isHostedRuntime`. Kept in sync deliberately:\n * the durable-background gate must agree with the soft-timeout regime about\n * what \"hosted\" means.\n */\nexport function isHostedRuntimeForDurableBackground(): boolean {\n if (\n process.env.NETLIFY &&\n process.env.NETLIFY !== \"false\" &&\n process.env.NETLIFY_LOCAL !== \"true\"\n ) {\n return true;\n }\n if (\n process.env.AWS_LAMBDA_FUNCTION_NAME &&\n process.env.NETLIFY_LOCAL !== \"true\"\n ) {\n return true;\n }\n return Boolean(\n process.env.CF_PAGES ||\n process.env.VERCEL ||\n process.env.VERCEL_ENV ||\n process.env.RENDER ||\n process.env.FLY_APP_NAME ||\n process.env.K_SERVICE,\n );\n}\n\n/**\n * True when THIS process is actually executing inside a Netlify *background*\n * function (the long, 15-min-budget async function whose deployed name ends in\n * `-background`). Netlify runs functions on AWS Lambda and sets\n * `AWS_LAMBDA_FUNCTION_NAME` to the function's name, so a `-background` suffix is\n * the runtime proof that the ~60s synchronous wall does NOT apply here.\n *\n * This is the SAFETY GUARD for the soft-timeout regime. The `_process-run`\n * self-dispatch worker (`isBackgroundWorker`) is NOT enough on its own: if the\n * `-background` function was never emitted (deploy gate off, or Netlify routed\n * the path to the synchronous function), the self-POST lands on the regular\n * ~60s `server` function. A worker there MUST use the 40s soft-timeout and\n * checkpoint before the 60s wall — using the ~13min budget would overshoot the\n * hard wall and get killed at 60s, then re-dispatch/resume in a wasteful loop.\n * So the 13-min budget is taken ONLY when this returns true.\n *\n * The PRIMARY signal is a `globalThis` marker the emitted background function's\n * entry sets at cold start — the deployed Lambda name is not guaranteed to end\n * in `-background` on Netlify, so the entry marks its own runtime. A `globalThis`\n * flag (not `process.env`) keeps the no-env-mutation guard satisfied and carries\n * no cross-request state (set once per isolate). The `AWS_LAMBDA_FUNCTION_NAME`\n * suffix and the explicit `AGENT_CHAT_FORCE_BACKGROUND_RUNTIME` env (truthy) are\n * additional signals — the latter an operator escape hatch. Off by default.\n */\nexport function isInBackgroundFunctionRuntime(): boolean {\n // Set by the emitted `-background` function entry at cold start (the primary,\n // most reliable signal — see the emit in deploy/build.ts).\n if (\n (globalThis as Record<string, unknown>)\n .__AGENT_NATIVE_BACKGROUND_RUNTIME__ === true\n ) {\n return true;\n }\n const lambdaName = process.env.AWS_LAMBDA_FUNCTION_NAME;\n if (\n typeof lambdaName === \"string\" &&\n lambdaName.toLowerCase().endsWith(\"-background\")\n ) {\n return true;\n }\n const forced = process.env.AGENT_CHAT_FORCE_BACKGROUND_RUNTIME;\n if (forced != null) {\n const v = forced.trim().toLowerCase();\n return v === \"1\" || v === \"true\" || v === \"yes\" || v === \"on\";\n }\n return false;\n}\n\nexport function backgroundRunMarkerExpectsBackgroundRuntime(\n marker: unknown,\n): boolean {\n return (\n typeof marker === \"object\" &&\n marker !== null &&\n (marker as { backgroundFunctionRuntimeExpected?: unknown })\n .backgroundFunctionRuntimeExpected === true\n );\n}\n\nexport function shouldUseBackgroundFunctionTimeoutForWorker(\n _marker: unknown,\n): boolean {\n // The dispatch marker says which URL the foreground targeted, not where the\n // request actually landed. Only the worker runtime proof can safely lift the\n // hosted 40s clamp to the 15-minute background-function budget.\n return isInBackgroundFunctionRuntime();\n}\n\nexport function backgroundRuntimeDiagnosticDetail(marker: unknown): string {\n return [\n `markerExpected=${backgroundRunMarkerExpectsBackgroundRuntime(marker)}`,\n `runtimeDetected=${isInBackgroundFunctionRuntime()}`,\n `globalMarker=${(globalThis as Record<string, unknown>).__AGENT_NATIVE_BACKGROUND_RUNTIME__ === true}`,\n `lambdaNameEndsBackground=${typeof process.env.AWS_LAMBDA_FUNCTION_NAME === \"string\" && process.env.AWS_LAMBDA_FUNCTION_NAME.toLowerCase().endsWith(\"-background\")}`,\n `forceEnv=${typeof process.env.AGENT_CHAT_FORCE_BACKGROUND_RUNTIME === \"string\" && process.env.AGENT_CHAT_FORCE_BACKGROUND_RUNTIME.trim().length > 0}`,\n ].join(\" \");\n}\n\nfunction isFlagEnabled(): boolean {\n // Read the literal key (not `process.env[CONST]`) so guard:no-env-credentials\n // can statically verify it against the allowlisted `AGENT_*` prefix. Keep this\n // in sync with AGENT_CHAT_DURABLE_BACKGROUND_ENV.\n //\n // DEFAULT-OFF (opt-in): durable background runs are still being hardened. A\n // premature fleet-wide default-on caused real-user incidents (Assets/Analytics\n // hit \"Failed to dispatch\" + stalls, 2026-06-24) because the async background\n // worker path is not yet proven end-to-end and the deploy-time env opt-out is\n // not reliably baked into a given deploy. So an unset/empty/unknown flag means\n // OFF; an app opts IN only with an explicit truthy value\n // (AGENT_CHAT_DURABLE_BACKGROUND=true). This still composes with the hosted +\n // A2A_SECRET gates below. Flip back to default-on only after the 15-min\n // background-function worker is verified live in production (see the\n // project_durable_bg_prod_verified memory).\n const raw = process.env.AGENT_CHAT_DURABLE_BACKGROUND;\n if (raw == null) return false;\n const normalized = raw.trim().toLowerCase();\n return (\n normalized === \"1\" ||\n normalized === \"true\" ||\n normalized === \"yes\" ||\n normalized === \"on\"\n );\n}\n\nfunction isFlagExplicitlyDisabled(): boolean {\n const raw = process.env.AGENT_CHAT_DURABLE_BACKGROUND;\n if (raw == null) return false;\n const normalized = raw.trim().toLowerCase();\n return (\n normalized === \"0\" ||\n normalized === \"false\" ||\n normalized === \"no\" ||\n normalized === \"off\"\n );\n}\n\n/**\n * The single gate. True when the env flag is explicitly enabled, or a workspace\n * app opted in and has a per-app background-function target, AND the runtime is\n * hosted AND A2A_SECRET is configured. False otherwise — and false means the\n * current synchronous behavior is used unchanged. Single-template Netlify app\n * opt-ins deliberately require the env flag too because that flag controls\n * whether the `server-agent-background` function exists in the deploy output.\n */\nexport function isAgentChatDurableBackgroundEnabled(options?: {\n appOptIn?: boolean;\n}): boolean {\n // An app-level opt-out must win over a stale deploy-wide env flag. Netlify\n // environment variables can outlive the source config that originally set\n // them; allowing that flag to re-enable a worker an app explicitly disabled\n // recreates the missing-background-function failure this gate is meant to\n // prevent.\n if (options?.appOptIn === false) return false;\n const envOptIn = isFlagEnabled();\n const workspaceAppOptIn =\n options?.appOptIn === true &&\n !isFlagExplicitlyDisabled() &&\n resolveWorkspaceBackgroundFunctionUrlPath() !== null;\n return (\n (envOptIn || workspaceAppOptIn) &&\n isHostedRuntimeForDurableBackground() &&\n hasConfiguredA2ASecret()\n );\n}\n\n/**\n * Env flag for the FOREGROUND server-driven self-chain. DEFAULT-OFF: a hosted\n * app must explicitly opt in with a truthy value (`true`/`1`/`yes`/`on`). A\n * regular Netlify function has a fixed 60-second wall, and a self-dispatched\n * successor can otherwise be killed before it persists its next continuation.\n * Keep this separate from `AGENT_CHAT_DURABLE_BACKGROUND` so the experimental\n * regular-function chain can be enabled independently after its deployment is\n * proven safe.\n */\nexport const AGENT_CHAT_FOREGROUND_SELF_CHAIN_ENV =\n \"AGENT_CHAT_FOREGROUND_SELF_CHAIN\";\n\nfunction isForegroundSelfChainExplicitlyEnabled(): boolean {\n // Read the literal key (not `process.env[CONST]`) so guard:no-env-credentials\n // can statically verify it against the allowlisted `AGENT_*` prefix. Keep this\n // in sync with AGENT_CHAT_FOREGROUND_SELF_CHAIN_ENV.\n const raw = process.env.AGENT_CHAT_FOREGROUND_SELF_CHAIN;\n if (raw == null) return false;\n const normalized = raw.trim().toLowerCase();\n return (\n normalized === \"1\" ||\n normalized === \"true\" ||\n normalized === \"yes\" ||\n normalized === \"on\"\n );\n}\n\n/**\n * Gate for the foreground self-chain: a normal (non-durable-background)\n * agent-chat turn that hits its soft-timeout chunk boundary continues via a\n * server-side self-dispatch on the REGULAR function (not a Netlify\n * `-background` function) instead of depending on the client to re-POST\n * `auto_continue`. Composes exactly like `isAgentChatDurableBackgroundEnabled`:\n * true only when the env flag is explicitly truthy, the runtime is hosted, and\n * `A2A_SECRET` is configured (the HMAC handoff authenticates the dispatch).\n * False means the existing client-driven `auto_continue` re-POST path is used.\n *\n * Deliberately independent of `isAgentChatDurableBackgroundEnabled`: an app can\n * use this narrower capability without opting into the full 15-min\n * background-function worker path, and the two gates never need to agree.\n * When BOTH would be true for a given run, the durable-background dispatch\n * decision in `production-agent.ts` is evaluated first and takes precedence —\n * a run already dispatched to the durable background worker chains via the\n * existing `isBackgroundWorker` path, not this one.\n */\nexport function isAgentChatForegroundSelfChainEnabled(): boolean {\n return (\n isForegroundSelfChainExplicitlyEnabled() &&\n isHostedRuntimeForDurableBackground() &&\n hasConfiguredA2ASecret()\n );\n}\n\n/** Decision returned by `prepareProcessRunRequest`. */\nexport type ProcessRunPreparation =\n | {\n ok: true;\n /** The pre-claimed run id the background worker must reuse. */\n runId: string;\n /** Body to stash for the re-entered handler (marker guaranteed present). */\n body: Record<string, unknown>;\n }\n | {\n ok: false;\n /** HTTP status the route should return. */\n status: number;\n /** Error payload. */\n error: string;\n /**\n * The run id parsed from the body, when present. Carried even on failure\n * so the route can RECORD the auth/validation failure ONTO the run\n * (diag_stage) before returning the error status — otherwise a 401/503 in\n * the unreadable Netlify background function would leave the run to time\n * out with no clue why. Null when no run id could be parsed.\n */\n runId: string | null;\n };\n\n/**\n * Parse the run id from a `_process-run` request body without authenticating.\n * Mirrors the precedence in `prepareProcessRunRequest` (marker.runId, then\n * top-level taskId). Returns null when neither is a usable string. Used so the\n * route can attach a diagnostic to the run even on an auth/validation failure.\n */\nexport function extractProcessRunId(body: unknown): string | null {\n if (!body || typeof body !== \"object\") return null;\n const record = body as Record<string, unknown>;\n const marker = record[AGENT_CHAT_BACKGROUND_RUN_FIELD] as\n | { runId?: unknown }\n | undefined;\n if (marker && typeof marker.runId === \"string\" && marker.runId) {\n return marker.runId;\n }\n if (typeof record.taskId === \"string\" && record.taskId) {\n return record.taskId;\n }\n return null;\n}\n\n/**\n * Pure, transport-agnostic core of the `_process-run` route: validate the body,\n * authenticate the HMAC self-dispatch, and produce the body the re-entered\n * agent-chat handler should run as the background worker.\n *\n * Auth policy mirrors the agent-teams processor exactly:\n * - `A2A_SECRET` set → require a valid `verifyInternalToken(runId, token)`.\n * - no secret → require `isTrustedLocalRuntime({ loopback })` (see\n * auth-policy.ts): refuse (503) unless `A2A_ALLOW_UNSIGNED_INTERNAL=1` is\n * set. This function has no h3 `event` of its own, so callers that CAN\n * see the inbound socket peer (the route handler, which has the event)\n * should compute `loopback` from it and pass it through; callers that\n * can't determine the peer address should omit it (defaults to `false`\n * — never trust unsigned dispatch without an explicit opt-in).\n *\n * Extracted from the route handler so the auth + marker-prep decision is unit\n * testable without booting the whole Nitro plugin. The route only adds body\n * reading and the final handler invocation around this.\n */\nexport function prepareProcessRunRequest(\n body: unknown,\n authHeader: string | undefined,\n loopback: boolean = false,\n): ProcessRunPreparation {\n if (!body || typeof body !== \"object\") {\n return {\n ok: false,\n status: 400,\n error: \"Invalid request body\",\n runId: null,\n };\n }\n const record = body as Record<string, unknown>;\n const marker = record[AGENT_CHAT_BACKGROUND_RUN_FIELD] as\n | { runId?: unknown }\n | undefined;\n const runId =\n marker && typeof marker.runId === \"string\"\n ? marker.runId\n : typeof record.taskId === \"string\"\n ? (record.taskId as string)\n : \"\";\n if (!runId) {\n return { ok: false, status: 400, error: \"runId required\", runId: null };\n }\n\n if (hasConfiguredA2ASecret()) {\n const token = extractBearerToken(authHeader);\n if (!verifyInternalToken(runId, token ?? \"\")) {\n return {\n ok: false,\n status: 401,\n error: \"Invalid or expired processor token\",\n runId,\n };\n }\n } else if (!isTrustedLocalRuntime({ loopback })) {\n // Callers that can see the h3 `event` (the route handler) pass the real\n // loopback signal; callers without one default to non-loopback. Unsigned\n // dispatch is still allowed via A2A_ALLOW_UNSIGNED_INTERNAL=1 for trusted\n // local/dev setups; see auth-policy.ts `isTrustedLocalRuntime`.\n return {\n ok: false,\n status: 503,\n error:\n \"Agent chat background processor not configured — set A2A_SECRET on this deployment (or A2A_ALLOW_UNSIGNED_INTERNAL=1 for trusted local dev).\",\n runId,\n };\n }\n\n // Ensure the marker is present so the re-entered handler runs as the\n // background worker (reuses runId/turnId, no re-claim, no re-dispatch).\n if (!marker || typeof marker.runId !== \"string\") {\n record[AGENT_CHAT_BACKGROUND_RUN_FIELD] = { runId };\n }\n return { ok: true, runId, body: record };\n}\n"]}
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
26
26
  * Body: { update: string (base64), requestSource?: string }
27
27
  */
28
28
  export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
29
- ok?: undefined;
30
29
  error: string;
30
+ ok?: undefined;
31
31
  } | {
32
32
  error?: undefined;
33
33
  ok: boolean;
@@ -13,8 +13,8 @@
13
13
  * Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
14
14
  */
15
15
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
16
- error: string;
17
16
  ok?: undefined;
17
+ error: string;
18
18
  } | {
19
19
  error?: undefined;
20
20
  ok: boolean;
@@ -90,6 +90,8 @@ export declare function findInstalledResvgPackages(nodeModulesRoots: string[]):
90
90
  * so a missing emit degrades to clean 40s-chunked runs rather than the loop.)
91
91
  */
92
92
  export declare function isDurableBackgroundDeployEnabled(): boolean;
93
+ export declare const NETLIFY_INTEGRATION_RECOVERY_FUNCTION_NAME = "server-integration-recovery";
94
+ export declare function isIntegrationDurableDispatchDeployEnabled(): boolean;
93
95
  /**
94
96
  * Emit a site-local Netlify Scheduled Function that wakes the public server
95
97
  * function and its database every minute. GitHub Actions schedules can be
@@ -160,6 +162,7 @@ export declare function emitSingleTemplateNetlifyKeepWarmFunction(projectCwd: st
160
162
  * inline 40s synchronous run (see production-agent.ts).
161
163
  */
162
164
  export declare function emitSingleTemplateNetlifyBackgroundFunction(projectCwd: string): void;
165
+ export declare function emitSingleTemplateNetlifyIntegrationRecoveryFunction(projectCwd: string): void;
163
166
  /**
164
167
  * Nitro receives the React Router SSR build as prebuilt chunks, so its normal
165
168
  * dependency resolver cannot reliably fold the preserved bare `yjs` imports
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/deploy/build.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/deploy/build.ts"],"names":[],"mappings":"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"}
@@ -17,7 +17,8 @@ import fs from "fs";
17
17
  import { createRequire } from "module";
18
18
  import path from "path";
19
19
  import { fileURLToPath } from "url";
20
- import { AGENT_BACKGROUND_FUNCTION_NAME, AGENT_BACKGROUND_PROCESSOR_A2A, AGENT_BACKGROUND_PROCESSOR_FIELD, AGENT_BACKGROUND_PROCESSOR_ROUTE, AGENT_BACKGROUND_PROCESSOR_ROUTE_FIELD, AGENT_CHAT_PROCESS_RUN_PATH, } from "../agent/durable-background.js";
20
+ import { AGENT_BACKGROUND_FUNCTION_NAME, AGENT_BACKGROUND_PROCESSOR_A2A, AGENT_BACKGROUND_PROCESSOR_FIELD, AGENT_BACKGROUND_PROCESSOR_INTEGRATION, AGENT_BACKGROUND_PROCESSOR_ROUTE, AGENT_BACKGROUND_PROCESSOR_ROUTE_FIELD, AGENT_CHAT_PROCESS_RUN_PATH, } from "../agent/durable-background.js";
21
+ import { INTEGRATION_RETRY_SWEEP_PATH, INTEGRATION_RETRY_SWEEP_TOKEN_SUBJECT, isIntegrationDurableDispatchConfigured, } from "../integrations/integration-durable-dispatch-config.js";
21
22
  import { normalizeAppBasePath } from "../server/app-base-path.js";
22
23
  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";
23
24
  import { mcpEmbedStaticAssetRouteRules } from "../shared/mcp-embed-headers.js";
@@ -1942,6 +1943,10 @@ export function isDurableBackgroundDeployEnabled() {
1942
1943
  const v = raw.trim().toLowerCase();
1943
1944
  return v === "1" || v === "true" || v === "yes" || v === "on";
1944
1945
  }
1946
+ export const NETLIFY_INTEGRATION_RECOVERY_FUNCTION_NAME = "server-integration-recovery";
1947
+ export function isIntegrationDurableDispatchDeployEnabled() {
1948
+ return isIntegrationDurableDispatchConfigured();
1949
+ }
1945
1950
  const NETLIFY_KEEP_WARM_FUNCTION_NAME = "agent-native-keep-warm";
1946
1951
  /**
1947
1952
  * Emit a site-local Netlify Scheduled Function that wakes the public server
@@ -2090,8 +2095,10 @@ export function emitSingleTemplateNetlifyBackgroundFunction(projectCwd) {
2090
2095
  fs.rmSync(path.join(dest, "server.mjs"), { force: true });
2091
2096
  const processRunPath = JSON.stringify(AGENT_CHAT_PROCESS_RUN_PATH);
2092
2097
  const a2aProcessTaskPath = JSON.stringify("/_agent-native/a2a/_process-task");
2098
+ const integrationProcessTaskPath = JSON.stringify("/_agent-native/integrations/process-task");
2093
2099
  const backgroundProcessorField = JSON.stringify(AGENT_BACKGROUND_PROCESSOR_FIELD);
2094
2100
  const backgroundProcessorA2A = JSON.stringify(AGENT_BACKGROUND_PROCESSOR_A2A);
2101
+ const backgroundProcessorIntegration = JSON.stringify(AGENT_BACKGROUND_PROCESSOR_INTEGRATION);
2095
2102
  const backgroundProcessorRoute = JSON.stringify(AGENT_BACKGROUND_PROCESSOR_ROUTE);
2096
2103
  const backgroundProcessorRouteField = JSON.stringify(AGENT_BACKGROUND_PROCESSOR_ROUTE_FIELD);
2097
2104
  const entry = `// Mark this isolate as the durable background runtime BEFORE the handler
@@ -2106,8 +2113,10 @@ globalThis.__AGENT_NATIVE_BACKGROUND_RUNTIME__ = true;
2106
2113
  // The framework route the Nitro router dispatches to (the _process-run plugin).
2107
2114
  const PROCESS_RUN_PATH = ${processRunPath};
2108
2115
  const A2A_PROCESS_TASK_PATH = ${a2aProcessTaskPath};
2116
+ const INTEGRATION_PROCESS_TASK_PATH = ${integrationProcessTaskPath};
2109
2117
  const BACKGROUND_PROCESSOR_FIELD = ${backgroundProcessorField};
2110
2118
  const BACKGROUND_PROCESSOR_A2A = ${backgroundProcessorA2A};
2119
+ const BACKGROUND_PROCESSOR_INTEGRATION = ${backgroundProcessorIntegration};
2111
2120
  const BACKGROUND_PROCESSOR_ROUTE = ${backgroundProcessorRoute};
2112
2121
  const BACKGROUND_PROCESSOR_ROUTE_FIELD = ${backgroundProcessorRouteField};
2113
2122
 
@@ -2118,6 +2127,12 @@ function processorPathFromBody(body) {
2118
2127
  if (parsed?.[BACKGROUND_PROCESSOR_FIELD] === BACKGROUND_PROCESSOR_A2A) {
2119
2128
  return A2A_PROCESS_TASK_PATH;
2120
2129
  }
2130
+ if (
2131
+ parsed?.[BACKGROUND_PROCESSOR_FIELD] ===
2132
+ BACKGROUND_PROCESSOR_INTEGRATION
2133
+ ) {
2134
+ return INTEGRATION_PROCESS_TASK_PATH;
2135
+ }
2121
2136
  const route = parsed?.[BACKGROUND_PROCESSOR_ROUTE_FIELD];
2122
2137
  if (
2123
2138
  parsed?.[BACKGROUND_PROCESSOR_FIELD] === BACKGROUND_PROCESSOR_ROUTE &&
@@ -2203,6 +2218,72 @@ export const config = {
2203
2218
  `verification of Netlify async (202) invocation — see ` +
2204
2219
  `docs/design/durable-agent-runs.md.`);
2205
2220
  }
2221
+ export function emitSingleTemplateNetlifyIntegrationRecoveryFunction(projectCwd) {
2222
+ const internalDir = path.join(projectCwd, ".netlify", "functions-internal");
2223
+ const serverDir = path.join(internalDir, "server");
2224
+ if (!fs.existsSync(path.join(serverDir, "main.mjs"))) {
2225
+ console.warn("[build] Integration recovery emit skipped: expected Nitro Netlify function " +
2226
+ "at .netlify/functions-internal/server/main.mjs was not found.");
2227
+ return;
2228
+ }
2229
+ const functionName = NETLIFY_INTEGRATION_RECOVERY_FUNCTION_NAME;
2230
+ const dest = path.join(internalDir, functionName);
2231
+ fs.rmSync(dest, { recursive: true, force: true });
2232
+ copyDir(serverDir, dest);
2233
+ fs.rmSync(path.join(dest, "server.mjs"), { force: true });
2234
+ const entry = `import { createHmac } from "node:crypto";
2235
+
2236
+ const SWEEP_PATH = ${JSON.stringify(INTEGRATION_RETRY_SWEEP_PATH)};
2237
+ const SWEEP_SUBJECT = ${JSON.stringify(INTEGRATION_RETRY_SWEEP_TOKEN_SUBJECT)};
2238
+
2239
+ function enabled() {
2240
+ const raw = process.env.AGENT_INTEGRATION_DURABLE_DISPATCH;
2241
+ if (!raw) return false;
2242
+ return ["1", "true", "yes", "on"].includes(raw.trim().toLowerCase());
2243
+ }
2244
+
2245
+ function token(secret) {
2246
+ const timestamp = Date.now();
2247
+ const signature = createHmac("sha256", secret)
2248
+ .update(\`${INTEGRATION_RETRY_SWEEP_TOKEN_SUBJECT}:\${timestamp}\`)
2249
+ .digest("hex");
2250
+ return \`\${timestamp}.\${signature}\`;
2251
+ }
2252
+
2253
+ let cachedHandler;
2254
+
2255
+ export default async function handler(request, context) {
2256
+ if (!enabled()) return new Response(null, { status: 204 });
2257
+ const secret = process.env.A2A_SECRET;
2258
+ if (!secret) {
2259
+ console.error("[integration-recovery] A2A_SECRET is required; sweep skipped");
2260
+ return new Response(null, { status: 204 });
2261
+ }
2262
+ cachedHandler ??= (await import("./main.mjs")).default;
2263
+ const url = new URL(request.url);
2264
+ url.pathname = SWEEP_PATH;
2265
+ const rewritten = new Request(url.toString(), {
2266
+ method: "POST",
2267
+ headers: {
2268
+ Authorization: \`Bearer \${token(secret)}\`,
2269
+ "Content-Type": "application/json",
2270
+ },
2271
+ body: JSON.stringify({ taskId: SWEEP_SUBJECT }),
2272
+ });
2273
+ return cachedHandler(rewritten, context);
2274
+ }
2275
+
2276
+ export const config = {
2277
+ name: "integration pending-task recovery",
2278
+ generator: "agent-native build",
2279
+ schedule: "* * * * *",
2280
+ nodeBundler: "none",
2281
+ includedFiles: ["**"],
2282
+ preferStatic: false,
2283
+ };
2284
+ `;
2285
+ fs.writeFileSync(path.join(dest, `${functionName}.mjs`), entry);
2286
+ }
2206
2287
  /**
2207
2288
  * Nitro's Netlify preset can emit a harmful fallback rewrite to
2208
2289
  * `/.netlify/functions/server`. With `config.path: "/*"`, that default URL is
@@ -2408,7 +2489,8 @@ export function assertSingleTemplateNetlifyBuildOutput(projectCwd) {
2408
2489
  if (bundledVitestRuntime.length > 0) {
2409
2490
  failures.push(`Netlify server bundle contains Vitest test runtime code: ${bundledVitestRuntime.join(", ")}`);
2410
2491
  }
2411
- if (isDurableBackgroundDeployEnabled()) {
2492
+ if (isDurableBackgroundDeployEnabled() ||
2493
+ isIntegrationDurableDispatchDeployEnabled()) {
2412
2494
  const backgroundDir = path.join(internalDir, AGENT_BACKGROUND_FUNCTION_NAME);
2413
2495
  const backgroundEntryPath = path.join(backgroundDir, `${AGENT_BACKGROUND_FUNCTION_NAME}.mjs`);
2414
2496
  if (!fs.existsSync(backgroundEntryPath)) {
@@ -2424,6 +2506,18 @@ export function assertSingleTemplateNetlifyBuildOutput(projectCwd) {
2424
2506
  }
2425
2507
  }
2426
2508
  }
2509
+ if (isIntegrationDurableDispatchDeployEnabled()) {
2510
+ const recoveryEntryPath = path.join(internalDir, NETLIFY_INTEGRATION_RECOVERY_FUNCTION_NAME, `${NETLIFY_INTEGRATION_RECOVERY_FUNCTION_NAME}.mjs`);
2511
+ if (!fs.existsSync(recoveryEntryPath)) {
2512
+ failures.push(`integration durable dispatch is enabled but ${path.relative(projectCwd, recoveryEntryPath)} was not emitted`);
2513
+ }
2514
+ else {
2515
+ const recoveryEntry = fs.readFileSync(recoveryEntryPath, "utf-8");
2516
+ if (!/\bschedule\s*:\s*["']\* \* \* \* \*["']/.test(recoveryEntry)) {
2517
+ failures.push(`integration recovery entry ${path.relative(projectCwd, recoveryEntryPath)} is missing the one-minute schedule`);
2518
+ }
2519
+ }
2520
+ }
2427
2521
  if (failures.length > 0) {
2428
2522
  throw new Error("[deploy] Netlify deploy guard failed; refusing to publish an output " +
2429
2523
  "that would likely serve Netlify 404s:\n" +
@@ -2969,7 +3063,8 @@ export default bundle;
2969
3063
  // bundle, so the chat `_process-run` POST lands on Netlify's async (15-min)
2970
3064
  // function. When not opted in this is a no-op and the single-function
2971
3065
  // deploy is byte-for-byte unchanged.
2972
- if (isDurableBackgroundDeployEnabled()) {
3066
+ if (isDurableBackgroundDeployEnabled() ||
3067
+ isIntegrationDurableDispatchDeployEnabled()) {
2973
3068
  try {
2974
3069
  emitSingleTemplateNetlifyBackgroundFunction(cwd);
2975
3070
  }
@@ -2977,6 +3072,14 @@ export default bundle;
2977
3072
  console.warn("[build] Failed to emit durable-background Netlify function (non-fatal):", err instanceof Error ? err.message : err);
2978
3073
  }
2979
3074
  }
3075
+ if (isIntegrationDurableDispatchDeployEnabled()) {
3076
+ try {
3077
+ emitSingleTemplateNetlifyIntegrationRecoveryFunction(cwd);
3078
+ }
3079
+ catch (err) {
3080
+ console.warn("[build] Failed to emit integration recovery Netlify function (non-fatal):", err instanceof Error ? err.message : err);
3081
+ }
3082
+ }
2980
3083
  writeSingleTemplateNetlifyRedirects(cwd);
2981
3084
  assertSingleTemplateNetlifyBuildOutput(cwd);
2982
3085
  }