@agent-native/core 0.158.10 → 0.159.1

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 (76) hide show
  1. package/corpus/templates/clips/app/components/recorder/recording-toolbar.tsx +2 -2
  2. package/corpus/templates/clips/app/i18n/en-US.ts +7 -2
  3. package/corpus/templates/clips/app/routes/record.tsx +147 -5
  4. package/dist/a2a/auth-policy.d.ts +0 -6
  5. package/dist/a2a/auth-policy.js +2 -1
  6. package/dist/a2a/client.js +10 -12
  7. package/dist/agent/durable-background.js +3 -2
  8. package/dist/agent/engine/registry.js +5 -4
  9. package/dist/agent/run-manager.js +8 -20
  10. package/dist/app-config/a2a.d.ts +14 -0
  11. package/dist/app-config/a2a.js +42 -0
  12. package/dist/app-config/agent.d.ts +18 -0
  13. package/dist/app-config/agent.js +69 -0
  14. package/dist/app-config/app.d.ts +33 -0
  15. package/dist/app-config/app.js +100 -0
  16. package/dist/app-config/describe.d.ts +26 -0
  17. package/dist/app-config/describe.js +61 -0
  18. package/dist/app-config/env-layer.d.ts +37 -0
  19. package/dist/app-config/env-layer.js +136 -0
  20. package/dist/app-config/index.d.ts +2 -0
  21. package/dist/app-config/index.js +2 -0
  22. package/dist/app-config/integrations.d.ts +5 -0
  23. package/dist/app-config/integrations.js +11 -0
  24. package/dist/app-config/private-blob.d.ts +14 -0
  25. package/dist/app-config/private-blob.js +19 -0
  26. package/dist/app-config/schema.d.ts +55 -0
  27. package/dist/app-config/schema.js +31 -0
  28. package/dist/app-config/store.d.ts +42 -0
  29. package/dist/app-config/store.js +104 -0
  30. package/dist/app-config/workspace.d.ts +21 -0
  31. package/dist/app-config/workspace.js +35 -0
  32. package/dist/cli/agent.js +2 -1
  33. package/dist/cli/code-agent-executor.js +5 -4
  34. package/dist/client/analytics.d.ts +9 -0
  35. package/dist/client/frame.js +11 -1
  36. package/dist/deploy/build.js +36 -0
  37. package/dist/integrations/a2a-continuation-processor.js +12 -9
  38. package/dist/integrations/adapters/email.js +2 -1
  39. package/dist/integrations/adapters/telegram.js +2 -1
  40. package/dist/integrations/adapters/whatsapp.js +2 -1
  41. package/dist/integrations/webhook-handler.d.ts +7 -2
  42. package/dist/integrations/webhook-handler.js +9 -31
  43. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  44. package/dist/notifications/routes.d.ts +3 -3
  45. package/dist/observability/routes.d.ts +6 -6
  46. package/dist/onboarding/app-profile.js +2 -4
  47. package/dist/onboarding/default-steps.js +4 -4
  48. package/dist/private-blob/registry.d.ts +5 -0
  49. package/dist/private-blob/registry.js +19 -8
  50. package/dist/provider-api/actions/custom-provider-registration.d.ts +13 -13
  51. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  52. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  53. package/dist/scripts/agent-engines/list-agent-engines.js +4 -2
  54. package/dist/secrets/routes.d.ts +3 -3
  55. package/dist/server/agent-chat/action-filters-a2a.js +5 -4
  56. package/dist/server/agent-chat/run-code-tools.js +3 -4
  57. package/dist/server/agent-chat-plugin.js +4 -3
  58. package/dist/server/agent-discovery.js +7 -5
  59. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  60. package/dist/server/app-origin-config.d.ts +23 -0
  61. package/dist/server/app-origin-config.js +43 -0
  62. package/dist/server/auth.js +2 -1
  63. package/dist/server/core-routes-plugin.js +3 -3
  64. package/dist/server/credential-provider.js +7 -8
  65. package/dist/server/embed-session.js +2 -1
  66. package/dist/server/identity-sso.js +6 -2
  67. package/dist/server/index.d.ts +1 -0
  68. package/dist/server/index.js +1 -0
  69. package/dist/server/oauth-public-origin.js +10 -14
  70. package/dist/server/oauth-return-url.js +5 -9
  71. package/dist/server/self-dispatch.js +5 -2
  72. package/dist/server/ssr-handler.js +2 -0
  73. package/dist/server/workspace-provider-oauth.js +2 -4
  74. package/dist/sharing/actions/create-agent-resource-link.js +2 -2
  75. package/dist/usage/metrics-store.js +2 -1
  76. package/package.json +1 -1
@@ -0,0 +1,21 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Workspace gateway.
4
+ *
5
+ * A workspace deploy puts one gateway in front of N apps, so these are a
6
+ * *different host* from this app's own URL — not another spelling of it.
7
+ * `deploy/workspace-deploy.ts` sets them on each app it launches.
8
+ *
9
+ * Each field lists the plain and `VITE_` spelling as aliases of one value. The
10
+ * prefix only ever meant "inline this into the browser bundle", which is a
11
+ * delivery question, not a second setting — the shell projection in
12
+ * `server/app-origin-config.ts` answers that now.
13
+ *
14
+ * Length-checked but not `.url()`-validated, for the same reason as `app.url`:
15
+ * a malformed value should fail where it is used, not take every config read
16
+ * in the process down with it.
17
+ */
18
+ export declare const workspaceConfig: z.ZodObject<{
19
+ gatewayUrl: z.ZodOptional<z.ZodString>;
20
+ oauthOrigin: z.ZodOptional<z.ZodString>;
21
+ }, z.core.$strip>;
@@ -0,0 +1,35 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Workspace gateway.
4
+ *
5
+ * A workspace deploy puts one gateway in front of N apps, so these are a
6
+ * *different host* from this app's own URL — not another spelling of it.
7
+ * `deploy/workspace-deploy.ts` sets them on each app it launches.
8
+ *
9
+ * Each field lists the plain and `VITE_` spelling as aliases of one value. The
10
+ * prefix only ever meant "inline this into the browser bundle", which is a
11
+ * delivery question, not a second setting — the shell projection in
12
+ * `server/app-origin-config.ts` answers that now.
13
+ *
14
+ * Length-checked but not `.url()`-validated, for the same reason as `app.url`:
15
+ * a malformed value should fail where it is used, not take every config read
16
+ * in the process down with it.
17
+ */
18
+ export const workspaceConfig = z.object({
19
+ gatewayUrl: z
20
+ .string()
21
+ .min(1)
22
+ .optional()
23
+ .meta({
24
+ env: ["WORKSPACE_GATEWAY_URL", "VITE_WORKSPACE_GATEWAY_URL"],
25
+ doc: "URL of the workspace gateway fronting this app.",
26
+ }),
27
+ oauthOrigin: z
28
+ .string()
29
+ .min(1)
30
+ .optional()
31
+ .meta({
32
+ env: ["WORKSPACE_OAUTH_ORIGIN", "VITE_WORKSPACE_OAUTH_ORIGIN"],
33
+ doc: "Shared origin workspace apps complete OAuth against.",
34
+ }),
35
+ });
package/dist/cli/agent.js CHANGED
@@ -4,6 +4,7 @@ import { DEFAULT_MODEL } from "../agent/default-model.js";
4
4
  import { registerBuiltinEngines, resolveEngine, } from "../agent/engine/index.js";
5
5
  import { actionsToEngineTools, } from "../agent/production-agent.js";
6
6
  import { runAgentLoopDirectWithSoftTimeout } from "../agent/run-loop-with-resume.js";
7
+ import { getAppConfig } from "../app-config/index.js";
7
8
  import { createGitHubRepoToolEntries } from "../provider-api/github-repo.js";
8
9
  import { resolveDevUserEmail } from "../scripts/dev-session.js";
9
10
  import { loadEnv } from "../scripts/utils.js";
@@ -143,7 +144,7 @@ async function runLocalAgentLoop(parsed) {
143
144
  const localActions = await autoDiscoverActions("auto");
144
145
  const builtinActions = await createHeadlessBuiltinActions();
145
146
  const repoActions = createGitHubRepoToolEntries({
146
- appId: process.env.AGENT_NATIVE_APP_ID ?? process.env.APP_ID ?? "app",
147
+ appId: getAppConfig().app.id ?? "app",
147
148
  });
148
149
  const actions = { ...builtinActions, ...localActions, ...repoActions };
149
150
  const tools = actionsToEngineTools(actions);
@@ -7,6 +7,7 @@ import { PROVIDER_ENV_VARS } from "../agent/engine/provider-env-vars.js";
7
7
  import { DEFAULT_AGENT_MAX_ITERATIONS } from "../agent/loop-settings.js";
8
8
  import { actionsToEngineTools, runAgentLoop, } from "../agent/production-agent.js";
9
9
  import { createToolSearchEntry, TOOL_SEARCH_ACTION_NAME, } from "../agent/tool-search.js";
10
+ import { getAppConfig } from "../app-config/index.js";
10
11
  import { formatPromptWithAttachments, } from "../code-agents/prompt-attachments.js";
11
12
  import { createCodingToolRegistry, isReadOnlyShellCommand, runCodingCommand, truncateBashOutput, truncateCodingOutput, } from "../coding-tools/index.js";
12
13
  import { buildMergedConfig, McpClientManager, mcpToolsToActionEntries, } from "../mcp-client/index.js";
@@ -103,7 +104,7 @@ export async function executeCodeAgentRun(options) {
103
104
  // Fall back to AGENT_ENGINE here too, mirroring resolveExecutorEngine below.
104
105
  // Without it, `AGENT_ENGINE=codex-cli` skips this Codex branch and is handed
105
106
  // to resolveEngine (LLM providers only), which throws `Unknown engine`.
106
- const requestedEngine = normalizeRequestedEngine(metadataString(existing, "engine") ?? process.env.AGENT_ENGINE);
107
+ const requestedEngine = normalizeRequestedEngine(metadataString(existing, "engine") ?? getAppConfig().agent.engine);
107
108
  if (requestedEngine === CODEX_CLI_ENGINE_NAME) {
108
109
  return executeCodexCliRun({
109
110
  run: existing,
@@ -178,7 +179,7 @@ export async function executeCodeAgentRun(options) {
178
179
  }
179
180
  const modelCandidate = options.model ??
180
181
  metadataString(existing, "model") ??
181
- process.env.AGENT_MODEL ??
182
+ getAppConfig().agent.model ??
182
183
  (await getStoredModelForEngine(engine).catch(() => undefined)) ??
183
184
  engine.defaultModel;
184
185
  const model = normalizeModelForEngine(engine, modelCandidate);
@@ -1794,11 +1795,11 @@ async function resolveExecutorEngine(requestedEngine) {
1794
1795
  if (!hasAnyProviderCredential())
1795
1796
  return null;
1796
1797
  return resolveEngine({
1797
- engineOption: requestedEngine ?? process.env.AGENT_ENGINE,
1798
+ engineOption: requestedEngine ?? getAppConfig().agent.engine,
1798
1799
  });
1799
1800
  }
1800
1801
  function hasAnyProviderCredential() {
1801
- if (process.env.AGENT_ENGINE)
1802
+ if (getAppConfig().agent.engine)
1802
1803
  return true;
1803
1804
  if (PROVIDER_ENV_VARS.some((key) => Boolean(process.env[key])))
1804
1805
  return true;
@@ -9,6 +9,15 @@ declare global {
9
9
  interface Window {
10
10
  gtag?: (...args: any[]) => void;
11
11
  __AGENT_NATIVE_CONFIG__?: {
12
+ /**
13
+ * This app's origins, projected by server/app-origin-config.ts. These
14
+ * replace the `VITE_` mirrors of APP_URL / WORKSPACE_* — the prefix only
15
+ * ever answered "how does this reach the browser", which the shell
16
+ * answers better. Impersonal, so safe in the CDN-cached shell.
17
+ */
18
+ appUrl?: string;
19
+ workspaceGatewayUrl?: string;
20
+ workspaceOAuthOrigin?: string;
12
21
  sentryDsn?: string;
13
22
  sentryEnvironment?: string;
14
23
  /**
@@ -186,7 +186,17 @@ function runtimeEnvValue(name) {
186
186
  : undefined;
187
187
  }
188
188
  function workspaceOAuthOrigin() {
189
- const raw = runtimeEnvValue("VITE_WORKSPACE_OAUTH_ORIGIN") ||
189
+ // The shell carries the server's declared values, so it answers first. The
190
+ // env lookups below are the pre-shell fallback and are kept for deployments
191
+ // built before the projection existed: in a browser only the `VITE_`
192
+ // spellings can ever resolve, and on the server only the plain ones are
193
+ // guaranteed — which is why the chain lists both and why it is not the
194
+ // primary path any more.
195
+ const shell = typeof window !== "undefined" ? window.__AGENT_NATIVE_CONFIG__ : undefined;
196
+ const raw = shell?.workspaceOAuthOrigin ||
197
+ shell?.appUrl ||
198
+ shell?.workspaceGatewayUrl ||
199
+ runtimeEnvValue("VITE_WORKSPACE_OAUTH_ORIGIN") ||
190
200
  runtimeEnvValue("WORKSPACE_OAUTH_ORIGIN") ||
191
201
  runtimeEnvValue("VITE_APP_URL") ||
192
202
  runtimeEnvValue("APP_URL") ||
@@ -964,6 +964,41 @@ function getRealtimeClientConfigScript() {
964
964
  );
965
965
  }
966
966
 
967
+ function getAppOriginClientConfigScript() {
968
+ // MUST stay consistent with resolvePublicAppOriginConfig in
969
+ // server/app-origin-config.ts, and with the alias order declared on
970
+ // app.url / workspace.* in app-config (worker bundles a string copy; it
971
+ // can't import them). Impersonal values only — this ships into the
972
+ // CDN-cached shell.
973
+ const env = globalThis.process?.env || {};
974
+ const appUrl = firstNonEmpty(
975
+ env.APP_URL,
976
+ env.VITE_APP_URL,
977
+ env.BETTER_AUTH_URL,
978
+ env.VITE_BETTER_AUTH_URL,
979
+ );
980
+ const workspaceGatewayUrl = firstNonEmpty(
981
+ env.WORKSPACE_GATEWAY_URL,
982
+ env.VITE_WORKSPACE_GATEWAY_URL,
983
+ );
984
+ const workspaceOAuthOrigin = firstNonEmpty(
985
+ env.WORKSPACE_OAUTH_ORIGIN,
986
+ env.VITE_WORKSPACE_OAUTH_ORIGIN,
987
+ );
988
+ const config = {
989
+ ...(appUrl ? { appUrl } : {}),
990
+ ...(workspaceGatewayUrl ? { workspaceGatewayUrl } : {}),
991
+ ...(workspaceOAuthOrigin ? { workspaceOAuthOrigin } : {}),
992
+ };
993
+ if (Object.keys(config).length === 0) return null;
994
+ return (
995
+ '<script data-agent-native-app-origin-config>' +
996
+ 'window.__AGENT_NATIVE_CONFIG__=Object.assign({},window.__AGENT_NATIVE_CONFIG__,' +
997
+ JSON.stringify(config) +
998
+ ");</script>"
999
+ );
1000
+ }
1001
+
967
1002
  function injectHeadScript(html, script) {
968
1003
  if (!script) return html;
969
1004
  const headCloseIdx = html.indexOf("</head>");
@@ -1105,6 +1140,7 @@ async function rewriteMountedResponse(response, basePath, pathname, request) {
1105
1140
  getSentryClientConfigScript(),
1106
1141
  getPostHogClientConfigScript(),
1107
1142
  getRealtimeClientConfigScript(),
1143
+ getAppOriginClientConfigScript(),
1108
1144
  ]
1109
1145
  .filter(Boolean)
1110
1146
  .join("") || null;
@@ -3,8 +3,10 @@ import { A2AClient, signA2AToken } from "../a2a/client.js";
3
3
  import { formatLlmCredentialErrorMessage, isLlmCredentialError, LLM_MISSING_CREDENTIALS_ERROR_CODE, } from "../agent/engine/credential-errors.js";
4
4
  import { extractThreadMeta } from "../agent/thread-data-builder.js";
5
5
  import { getThread, updateThreadData } from "../chat-threads/store.js";
6
+ import { resolveArtifactBaseUrl } from "../server/agent-chat/action-filters-a2a.js";
6
7
  import { withConfiguredAppBasePath } from "../server/app-base-path.js";
7
8
  import { FRAMEWORK_ROUTE_PREFIX } from "../server/core-routes-plugin.js";
9
+ import { resolveSelfDispatchBaseUrl } from "../server/self-dispatch.js";
8
10
  import { claimA2AContinuation, claimA2AContinuationDelivery, claimDueA2AContinuations, failA2AContinuationsForIntegrationTask, failA2AContinuation, finalizeA2ATerminalHistory, getA2AContinuation, getA2AContinuationTaskOutcome, hasOnlyLegacyFailedA2AContinuationsForIntegrationTask, hasPendingConfirmedA2ADeliveryForIntegrationTask, listRecoverableA2AIntegrationTasks, recoverDueA2AContinuationIds, recordA2ATerminalDeliveryReceipt, retainA2AUnconfirmedDeliveryClaim, rescheduleA2AContinuation, saveA2AVerifiedArtifactCheckpoint, } from "./a2a-continuations-store.js";
9
11
  import { completeIntegrationCampaignTaskAfterA2A, failDisabledIntegrationCampaignTask, failIntegrationCampaignTaskDeliveryContainment, getIntegrationCampaignForTask, } from "./integration-campaigns-store.js";
10
12
  import { dispatchPendingIntegrationTask, isIntegrationDurableDispatchEnabledForTask, } from "./integration-durable-dispatch.js";
@@ -37,12 +39,17 @@ function logA2AContinuationTransition(event, continuation) {
37
39
  });
38
40
  }
39
41
  export async function dispatchA2AContinuation(continuationId, webhookBaseUrl) {
42
+ // Self-dispatch: this POST has to land on the deployment that enqueued the
43
+ // continuation. It used to carry its own chain, which omitted
44
+ // DEPLOY_PRIME_URL — so a deploy preview dispatched to production — and
45
+ // silently fell back to localhost in production, where the request simply
46
+ // never arrives and the continuation is dropped with no error.
47
+ // `WEBHOOK_BASE_URL` stays ahead of it: this runs from a retry job with no
48
+ // inbound request, and a dev tunnel is reachable where the app's own address
49
+ // is not.
40
50
  const baseUrl = webhookBaseUrl ||
41
51
  process.env.WEBHOOK_BASE_URL ||
42
- process.env.APP_URL ||
43
- process.env.URL ||
44
- process.env.DEPLOY_URL ||
45
- `http://localhost:${process.env.PORT || 3000}`;
52
+ resolveSelfDispatchBaseUrl();
46
53
  const url = `${withConfiguredAppBasePath(baseUrl)}${PROCESSOR_PATH}`;
47
54
  const headers = {
48
55
  "Content-Type": "application/json",
@@ -897,11 +904,7 @@ function formatRecoverableArtifactFallbackText(text) {
897
904
  }
898
905
  function formatContinuationArtifactText(text, agentUrl) {
899
906
  const expandedText = expandRelativeUrls(text, agentUrl);
900
- return appendA2AArtifactLinks(expandedText, [{ tool: "call-agent", result: expandedText }], { baseUrl: resolveArtifactBaseUrl() });
901
- }
902
- function resolveArtifactBaseUrl() {
903
- const baseUrl = process.env.APP_URL || process.env.URL || process.env.DEPLOY_URL;
904
- return baseUrl ? withConfiguredAppBasePath(baseUrl) : undefined;
907
+ return appendA2AArtifactLinks(expandedText, [{ tool: "call-agent", result: expandedText }], { baseUrl: resolveArtifactBaseUrl(undefined) });
905
908
  }
906
909
  function expandRelativeUrls(text, agentUrl) {
907
910
  if (!text || !agentUrl)
@@ -1,5 +1,6 @@
1
1
  import { timingSafeEqual } from "node:crypto";
2
2
  import { getHeader, readRawBody as h3ReadRawBody } from "h3";
3
+ import { getAppConfig } from "../../app-config/index.js";
3
4
  import { getDbExec } from "../../db/client.js";
4
5
  import { resolveSecret } from "../../server/credential-provider.js";
5
6
  import { sendEmail, isEmailConfigured, getEmailProvider, } from "../../server/email.js";
@@ -30,7 +31,7 @@ function escapeLike(value) {
30
31
  * webhook security audit).
31
32
  */
32
33
  function shouldRefuseWhenSecretMissing() {
33
- if (process.env.AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS === "1")
34
+ if (getAppConfig().integrations.allowUnverifiedWebhooks)
34
35
  return false;
35
36
  return process.env.NODE_ENV === "production";
36
37
  }
@@ -1,4 +1,5 @@
1
1
  import { getHeader } from "h3";
2
+ import { getAppConfig } from "../../app-config/index.js";
2
3
  import { resolveSecret } from "../../server/credential-provider.js";
3
4
  import { readBody } from "../../server/h3-helpers.js";
4
5
  /** Telegram's max message length */
@@ -16,7 +17,7 @@ let _telegramUnverifiedWarned = false;
16
17
  * messages (C2 in the webhook security audit).
17
18
  */
18
19
  function shouldRefuseWhenSecretMissing() {
19
- if (process.env.AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS === "1")
20
+ if (getAppConfig().integrations.allowUnverifiedWebhooks)
20
21
  return false;
21
22
  return process.env.NODE_ENV === "production";
22
23
  }
@@ -1,4 +1,5 @@
1
1
  import { getQuery, getHeader, readRawBody as h3ReadRawBody } from "h3";
2
+ import { getAppConfig } from "../../app-config/index.js";
2
3
  import { resolveSecret } from "../../server/credential-provider.js";
3
4
  /** WhatsApp's max message length */
4
5
  const WHATSAPP_MAX_LENGTH = 4096;
@@ -15,7 +16,7 @@ let _whatsappUnverifiedWarned = false;
15
16
  * be verified (C2 in the webhook security audit).
16
17
  */
17
18
  function shouldRefuseWhenSecretMissing() {
18
- if (process.env.AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS === "1")
19
+ if (getAppConfig().integrations.allowUnverifiedWebhooks)
19
20
  return false;
20
21
  return process.env.NODE_ENV === "production";
21
22
  }
@@ -109,8 +109,13 @@ export declare function handleWebhook(event: H3Event, options: WebhookHandlerOpt
109
109
  }>;
110
110
  /**
111
111
  * Resolve the base URL we should dispatch the processor request to.
112
- * Prefers explicit env vars (most reliable on serverless), falls back to the
113
- * inbound request's headers.
112
+ *
113
+ * This is self-dispatch — the request has to land on *this* deployment — so it
114
+ * shares one resolver with the rest of the framework rather than keeping its
115
+ * own copy. The copy that used to live here preferred `APP_URL` over the
116
+ * platform's own deploy URLs and did not consult `DEPLOY_PRIME_URL` at all, so
117
+ * on a Netlify deploy preview it dispatched integration work to production
118
+ * while agent background work correctly stayed on the preview.
114
119
  */
115
120
  export declare function resolveBaseUrl(event: H3Event): string;
116
121
  /**
@@ -12,10 +12,10 @@ import { buildAssistantMessage, extractThreadMeta, threadDataToEngineMessages, }
12
12
  import { attachToolSearch } from "../agent/tool-search.js";
13
13
  import { createThread, getThread, grantThreadUserShare, setThreadSourceIfMissing, } from "../chat-threads/store.js";
14
14
  import { updateThreadData } from "../chat-threads/store.js";
15
- import { isLocalDatabase } from "../db/client.js";
16
15
  import { getOrgA2ASecret, resolveOrgIdForEmail } from "../org/context.js";
17
16
  import { withConfiguredAppBasePath } from "../server/app-base-path.js";
18
17
  import { runWithRequestContext } from "../server/request-context.js";
18
+ import { resolveSelfDispatchBaseUrl } from "../server/self-dispatch.js";
19
19
  import { normalizeReasoningEffortForRequest } from "../shared/reasoning-effort.js";
20
20
  import { A2A_CONTINUATION_QUEUED_MARKER } from "./a2a-continuation-marker.js";
21
21
  import { reconcileTerminalA2AParentIfDisabled } from "./a2a-continuation-processor.js";
@@ -360,38 +360,16 @@ async function enqueueAndDispatch(event, incoming, options, handlerStartedAt = D
360
360
  }
361
361
  /**
362
362
  * Resolve the base URL we should dispatch the processor request to.
363
- * Prefers explicit env vars (most reliable on serverless), falls back to the
364
- * inbound request's headers.
363
+ *
364
+ * This is self-dispatch — the request has to land on *this* deployment — so it
365
+ * shares one resolver with the rest of the framework rather than keeping its
366
+ * own copy. The copy that used to live here preferred `APP_URL` over the
367
+ * platform's own deploy URLs and did not consult `DEPLOY_PRIME_URL` at all, so
368
+ * on a Netlify deploy preview it dispatched integration work to production
369
+ * while agent background work correctly stayed on the preview.
365
370
  */
366
371
  export function resolveBaseUrl(event) {
367
- const fromEnv = process.env.APP_URL ||
368
- process.env.URL ||
369
- process.env.DEPLOY_URL ||
370
- process.env.BETTER_AUTH_URL;
371
- if (fromEnv)
372
- return withConfiguredAppBasePath(fromEnv);
373
- if (process.env.NODE_ENV === "production" || !isLocalDatabase()) {
374
- throw new Error("Integration self-dispatch requires APP_URL, URL, DEPLOY_URL, or BETTER_AUTH_URL in production/shared deployments.");
375
- }
376
- try {
377
- const headers = event.node?.req?.headers ?? event.headers;
378
- const get = (name) => {
379
- if (!headers)
380
- return undefined;
381
- if (typeof headers.get === "function") {
382
- return headers.get(name) ?? undefined;
383
- }
384
- const lower = String(name).toLowerCase();
385
- const map = headers;
386
- return map[name] ?? map[lower];
387
- };
388
- const proto = get("x-forwarded-proto") || "http";
389
- const host = get("host") || `localhost:${process.env.PORT || 3000}`;
390
- return withConfiguredAppBasePath(`${proto}://${host}`);
391
- }
392
- catch {
393
- return withConfiguredAppBasePath(`http://localhost:${process.env.PORT || 3000}`);
394
- }
372
+ return resolveSelfDispatchBaseUrl(event);
395
373
  }
396
374
  /**
397
375
  * Run the actual agent loop for a previously-enqueued task. Called by the
@@ -137,13 +137,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
137
137
  inputSchema: {
138
138
  type: string;
139
139
  properties: {
140
+ count?: undefined;
140
141
  query?: undefined;
141
142
  minutes?: undefined;
142
143
  limit?: undefined;
143
144
  clientHint?: undefined;
144
145
  timestamp?: undefined;
145
146
  chapterId?: undefined;
146
- count?: undefined;
147
147
  startAt?: undefined;
148
148
  endAt?: undefined;
149
149
  reason?: undefined;
@@ -159,6 +159,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
159
159
  inputSchema: {
160
160
  type: string;
161
161
  properties: {
162
+ count?: undefined;
162
163
  query: {
163
164
  type: string;
164
165
  description: string;
@@ -174,7 +175,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
174
175
  clientHint?: undefined;
175
176
  timestamp?: undefined;
176
177
  chapterId?: undefined;
177
- count?: undefined;
178
178
  startAt?: undefined;
179
179
  endAt?: undefined;
180
180
  reason?: undefined;
@@ -190,6 +190,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
190
190
  inputSchema: {
191
191
  type: string;
192
192
  properties: {
193
+ count?: undefined;
193
194
  minutes: {
194
195
  type: string;
195
196
  description: string;
@@ -199,7 +200,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
199
200
  clientHint?: undefined;
200
201
  timestamp?: undefined;
201
202
  chapterId?: undefined;
202
- count?: undefined;
203
203
  startAt?: undefined;
204
204
  endAt?: undefined;
205
205
  reason?: undefined;
@@ -216,6 +216,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
216
216
  type: string;
217
217
  required: string[];
218
218
  properties: {
219
+ count?: undefined;
219
220
  query: {
220
221
  type: string;
221
222
  description: string;
@@ -234,7 +235,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
234
235
  };
235
236
  timestamp?: undefined;
236
237
  chapterId?: undefined;
237
- count?: undefined;
238
238
  startAt?: undefined;
239
239
  endAt?: undefined;
240
240
  reason?: undefined;
@@ -250,6 +250,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
250
250
  type: string;
251
251
  required: string[];
252
252
  properties: {
253
+ count?: undefined;
253
254
  query?: undefined;
254
255
  minutes?: undefined;
255
256
  limit?: undefined;
@@ -263,7 +264,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
263
264
  description: string;
264
265
  };
265
266
  chapterId?: undefined;
266
- count?: undefined;
267
267
  startAt?: undefined;
268
268
  endAt?: undefined;
269
269
  includeMicrophone?: undefined;
@@ -314,13 +314,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
314
314
  type: string;
315
315
  required: string[];
316
316
  properties: {
317
+ count?: undefined;
317
318
  query?: undefined;
318
319
  minutes?: undefined;
319
320
  limit?: undefined;
320
321
  clientHint?: undefined;
321
322
  timestamp?: undefined;
322
323
  chapterId?: undefined;
323
- count?: undefined;
324
324
  startAt: {
325
325
  type: string;
326
326
  description: string;
@@ -349,13 +349,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
349
349
  type: string;
350
350
  required: string[];
351
351
  properties: {
352
+ count?: undefined;
352
353
  query?: undefined;
353
354
  minutes?: undefined;
354
355
  limit?: undefined;
355
356
  clientHint?: undefined;
356
357
  timestamp?: undefined;
357
358
  chapterId?: undefined;
358
- count?: undefined;
359
359
  startAt?: undefined;
360
360
  endAt?: undefined;
361
361
  reason?: undefined;
@@ -16,18 +16,18 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
16
16
  error?: undefined;
17
17
  ok?: undefined;
18
18
  } | {
19
+ count?: undefined;
19
20
  updated: number;
20
21
  error?: undefined;
21
22
  ok?: undefined;
22
- count?: undefined;
23
23
  } | {
24
+ count?: undefined;
24
25
  updated?: undefined;
25
26
  error: string;
26
27
  ok?: undefined;
27
- count?: undefined;
28
28
  } | {
29
+ count?: undefined;
29
30
  updated?: undefined;
30
31
  error?: undefined;
31
32
  ok: boolean;
32
- count?: undefined;
33
33
  }>>;
@@ -41,27 +41,27 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
41
41
  thumbsUpRate: number;
42
42
  avgEvalScore: number;
43
43
  } | {
44
- ok?: undefined;
45
- error?: undefined;
46
44
  summary: import("./types.js").TraceSummary;
47
45
  spans: import("./types.js").TraceSpan[];
48
46
  id?: undefined;
49
- } | {
50
- ok?: undefined;
51
47
  error?: undefined;
48
+ ok?: undefined;
49
+ } | {
52
50
  summary?: undefined;
53
51
  spans?: undefined;
54
52
  id: string;
55
- } | {
53
+ error?: undefined;
56
54
  ok?: undefined;
55
+ } | {
57
56
  summary?: undefined;
58
57
  spans?: undefined;
59
58
  id?: undefined;
60
59
  error: any;
60
+ ok?: undefined;
61
61
  } | {
62
- error?: undefined;
63
62
  summary?: undefined;
64
63
  spans?: undefined;
65
64
  id?: undefined;
65
+ error?: undefined;
66
66
  ok: boolean;
67
67
  }>>;
@@ -1,3 +1,4 @@
1
+ import { getAppConfig } from "../app-config/index.js";
1
2
  const LLM_CAPABILITY = {
2
3
  id: "llm",
3
4
  label: "AI model",
@@ -382,10 +383,7 @@ function normalizeAppId(value) {
382
383
  .replace(/^-|-$/g, "") || "app");
383
384
  }
384
385
  export function resolveOnboardingAppId(explicit) {
385
- return normalizeAppId(explicit ??
386
- process.env.AGENT_NATIVE_APP_ID ??
387
- process.env.APP_ID ??
388
- process.env.npm_package_name);
386
+ return normalizeAppId(explicit ?? getAppConfig().app.id ?? getAppConfig().app.packageName);
389
387
  }
390
388
  export function getOnboardingAppProfile(appId) {
391
389
  const resolvedId = resolveOnboardingAppId(appId);
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import { PROVIDER_ENV_META, PROVIDER_ENV_VARS, } from "../agent/engine/provider-env-vars.js";
9
9
  import { detectEngineFromUserSecrets, isAgentEngineSettingConfigured, } from "../agent/engine/registry.js";
10
+ import { getAppConfig } from "../app-config/index.js";
10
11
  import { getActiveFileUploadProviderForRequest, registerFileUploadProvider, } from "../file-upload/registry.js";
11
12
  import { s3FileUploadProvider } from "../file-upload/s3.js";
12
13
  import { canUseDeployCredentialFallbackForRequest, readDeployCredentialEnv, resolveSecret, } from "../server/credential-provider.js";
@@ -323,10 +324,9 @@ const githubRepositoryStep = {
323
324
  try {
324
325
  const { resolveWorkspaceConnectionCredentialForApp } = await import("../workspace-connections/index.js");
325
326
  const result = await resolveWorkspaceConnectionCredentialForApp({
326
- appId: process.env.AGENT_NATIVE_APP_ID ||
327
- process.env.APP_ID ||
328
- process.env.npm_package_name ||
329
- "app",
327
+ // Deliberately not `resolveOnboardingAppId()` — that normalizes, and
328
+ // this id is matched against a stored workspace connection grant.
329
+ appId: getAppConfig().app.id ?? getAppConfig().app.packageName ?? "app",
330
330
  provider: "github",
331
331
  key: "GITHUB_TOKEN",
332
332
  userEmail,
@@ -3,6 +3,11 @@ export declare function registerPrivateBlobProvider(provider: PrivateBlobProvide
3
3
  export declare function unregisterPrivateBlobProvider(id: string): void;
4
4
  export declare function listPrivateBlobProviders(): PrivateBlobProvider[];
5
5
  export declare function getActivePrivateBlobProvider(): PrivateBlobProvider | null;
6
+ /**
7
+ * @deprecated Use `defineAppConfig({ privateBlob: { publicUploadFallback } })`
8
+ * instead. This writes the same value into the deprecated layer of the config
9
+ * ladder, so an explicit `defineAppConfig` call now wins over it.
10
+ */
6
11
  export declare function setPrivateBlobPublicUploadFallbackEnabled(enabled: boolean): void;
7
12
  export declare function putPrivateBlob(input: PrivateBlobPutInput): Promise<PrivateBlobHandle | null>;
8
13
  export declare function readPrivateBlob(handle: PrivateBlobHandle): Promise<PrivateBlobReadResult>;
@@ -1,13 +1,12 @@
1
1
  import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
2
+ import { getAppConfig } from "../app-config/index.js";
3
+ import { setAppConfigLayer } from "../app-config/store.js";
2
4
  import { uploadFile } from "../file-upload/index.js";
3
5
  import { decryptSecretValue, encryptSecretValue, getSecretEncryptionKey, } from "../secrets/crypto.js";
4
6
  const PUBLIC_UPLOAD_HANDLE_PREFIX = "public-upload:v1:";
5
7
  const PUBLIC_UPLOAD_READ_RETRY_DELAYS_MS = [100, 250, 500];
6
8
  const globals = globalThis;
7
9
  const providers = (globals.__agentNativePrivateBlobProviders ??= new Map());
8
- const publicUploadFallbackRef = (globals.__agentNativePrivateBlobPublicUploadFallback ??= {
9
- enabled: true,
10
- });
11
10
  function toBytes(data) {
12
11
  return data instanceof Uint8Array ? data : new Uint8Array(data);
13
12
  }
@@ -171,24 +170,36 @@ export function listPrivateBlobProviders() {
171
170
  return [...providers.values()];
172
171
  }
173
172
  export function getActivePrivateBlobProvider() {
173
+ const selected = getAppConfig().privateBlob.provider;
174
+ if (selected) {
175
+ const provider = providers.get(selected);
176
+ if (!provider) {
177
+ throw new Error(`Private blob provider "${selected}" is selected in app config but no provider with that id is registered`);
178
+ }
179
+ return provider;
180
+ }
174
181
  for (const provider of providers.values()) {
175
182
  if (provider.isConfigured())
176
183
  return provider;
177
184
  }
178
185
  return null;
179
186
  }
187
+ /**
188
+ * @deprecated Use `defineAppConfig({ privateBlob: { publicUploadFallback } })`
189
+ * instead. This writes the same value into the deprecated layer of the config
190
+ * ladder, so an explicit `defineAppConfig` call now wins over it.
191
+ */
180
192
  export function setPrivateBlobPublicUploadFallbackEnabled(enabled) {
181
- publicUploadFallbackRef.enabled = enabled;
193
+ setAppConfigLayer("legacy", {
194
+ privateBlob: { publicUploadFallback: enabled },
195
+ });
182
196
  }
183
197
  export async function putPrivateBlob(input) {
184
198
  const provider = getActivePrivateBlobProvider();
185
199
  if (provider)
186
200
  return provider.put(input);
187
- if (!publicUploadFallbackRef.enabled)
201
+ if (!getAppConfig().privateBlob.publicUploadFallback)
188
202
  return null;
189
- if (process.env.AGENT_NATIVE_PRIVATE_BLOB_PUBLIC_UPLOAD_FALLBACK === "0") {
190
- return null;
191
- }
192
203
  return putViaEncryptedPublicUpload(input);
193
204
  }
194
205
  export async function readPrivateBlob(handle) {