@agent-native/core 0.204.1-nightly-20261008153353 → 0.205.0

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 (45) hide show
  1. package/dist/a2a/caller-auth.d.ts +1 -0
  2. package/dist/a2a/caller-auth.js +9 -3
  3. package/dist/a2a/client.d.ts +1 -0
  4. package/dist/a2a/client.js +1 -1
  5. package/dist/a2a/index.d.ts +2 -1
  6. package/dist/a2a/index.js +2 -1
  7. package/dist/agent/engine/ai-sdk-engine.js +3 -8
  8. package/dist/agent/engine/builder-engine.d.ts +1 -1
  9. package/dist/agent/engine/openrouter-tool-fetch.d.ts +1 -0
  10. package/dist/agent/engine/openrouter-tool-fetch.js +20 -0
  11. package/dist/agent/engine/translate-ai-sdk.d.ts +1 -1
  12. package/dist/agent/engine/translate-ai-sdk.js +3 -2
  13. package/dist/agent/model-config.d.ts +2 -2
  14. package/dist/agent/model-config.js +2 -0
  15. package/dist/app-config/observability.js +8 -1
  16. package/dist/client/analytics-session.js +25 -7
  17. package/dist/client/chat/agentkit-protocol.js +13 -2
  18. package/dist/client/url-scrub.js +5 -2
  19. package/dist/deploy/build.js +11 -0
  20. package/dist/file-upload/actions/upload-image.d.ts +3 -3
  21. package/dist/jobs/background-automation-runner.js +13 -2
  22. package/dist/mcp/build-server.js +7 -4
  23. package/dist/mcp/connect-route.js +16 -11
  24. package/dist/notifications/routes.d.ts +2 -2
  25. package/dist/observability/routes.d.ts +6 -6
  26. package/dist/observability/sentiment.d.ts +1 -1
  27. package/dist/observability/sentiment.js +30 -6
  28. package/dist/org/index.d.ts +1 -1
  29. package/dist/progress/routes.d.ts +1 -1
  30. package/dist/secrets/routes.d.ts +11 -11
  31. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  32. package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
  33. package/dist/server/attribution.d.ts +4 -6
  34. package/dist/server/attribution.js +20 -6
  35. package/dist/server/better-auth-instance.d.ts +2 -1
  36. package/dist/server/better-auth-instance.js +5 -1
  37. package/dist/server/magic-link-attribution.d.ts +1 -0
  38. package/dist/server/magic-link-attribution.js +5 -0
  39. package/dist/shared/analytics-session-id.d.ts +5 -0
  40. package/dist/shared/analytics-session-id.js +21 -0
  41. package/dist/triggers/actions/manage-automation.d.ts +3 -3
  42. package/dist/vite/sentry-source-maps.d.ts +1 -0
  43. package/dist/vite/sentry-source-maps.js +48 -22
  44. package/docs/content/actions-access-control.mdx +67 -21
  45. package/package.json +4 -4
@@ -11,4 +11,5 @@ export declare function resolveA2ACallerAuth(options?: {
11
11
  expiresIn?: string | number;
12
12
  includeGoogleToken?: boolean;
13
13
  audience?: string | string[];
14
+ userIdentityOnly?: boolean;
14
15
  }): Promise<A2ACallerAuth>;
@@ -26,14 +26,20 @@ export async function resolveA2ACallerAuth(options) {
26
26
  if (userEmail &&
27
27
  options?.audience &&
28
28
  globalSecret &&
29
- (!orgId || orgDomain?.trim())) {
30
- addApiKeyAttempt(await signA2AToken(userEmail, orgDomain, undefined, {
29
+ (options?.userIdentityOnly || !orgId || orgDomain?.trim())) {
30
+ addApiKeyAttempt(await signA2AToken(userEmail, options?.userIdentityOnly ? undefined : orgDomain, undefined, {
31
31
  expiresIn: options?.expiresIn ?? DEFAULT_A2A_CALLER_TOKEN_TTL,
32
32
  preferGlobalSecret: true,
33
33
  audience: options?.audience,
34
+ ...(options?.userIdentityOnly && orgId
35
+ ? { extraClaims: { org_id: orgId } }
36
+ : {}),
34
37
  }));
35
38
  }
36
- if (orgDomain && options?.audience && (orgSecret || globalSecret)) {
39
+ if (!options?.userIdentityOnly &&
40
+ orgDomain &&
41
+ options?.audience &&
42
+ (orgSecret || globalSecret)) {
37
43
  addApiKeyAttempt(await signA2AOrganizationToken(orgDomain, orgSecret, undefined, {
38
44
  expiresIn: options?.expiresIn ?? DEFAULT_A2A_CALLER_TOKEN_TTL,
39
45
  audience: options?.audience,
@@ -135,6 +135,7 @@ export declare class A2AClient {
135
135
  private postJson;
136
136
  private transportHeadersFor;
137
137
  }
138
+ export declare function assertCredentialedA2AUrl(url: string, credentialed: boolean): void;
138
139
  export declare function callAgent(url: string, text: string, opts?: {
139
140
  apiKey?: string;
140
141
  apiKeyFallbacks?: string[];
@@ -842,7 +842,7 @@ function hasA2ACredentials(apiKeys, headers) {
842
842
  }
843
843
  return Object.keys(headers ?? {}).some((name) => /^(authorization|api[-_]key|x-api[-_]key|x-api[-_]token)$/i.test(name));
844
844
  }
845
- function assertCredentialedA2AUrl(url, credentialed) {
845
+ export function assertCredentialedA2AUrl(url, credentialed) {
846
846
  if (!credentialed)
847
847
  return;
848
848
  let parsed;
@@ -2,8 +2,9 @@ export { mountA2A, verifyA2AToken } from "./server.js";
2
2
  export type { A2ATokenPayload } from "./server.js";
3
3
  export { generateAgentCard } from "./agent-card.js";
4
4
  export { A2A_AGENT_ACTIVITY_KIND, A2A_AGENT_ACTIVITY_VERSION, MAX_A2A_ACTIVITY_REASONING_CHARS, MAX_A2A_ACTIVITY_REASONING_SEGMENTS, MAX_A2A_ACTIVITY_RESPONSE_CHARS, MAX_A2A_ACTIVITY_TOOL_CALLS, MAX_A2A_ACTIVITY_TOTAL_CHARS, MAX_A2A_ACTIVITY_TOOL_ID_CHARS, MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS, MAX_A2A_ACTIVITY_TOOL_NAME_CHARS, MAX_A2A_ACTIVITY_TOOL_PAYLOAD_CHARS, MAX_A2A_ACTIVITY_TOOL_RESULT_CHARS, applyA2AAgentActivityEvent, buildA2AAgentActivityPart, buildA2AAgentActivitySnapshot, createA2AAgentActivityState, parseA2AAgentActivityPart, } from "./activity.js";
5
- export { A2AClient, A2AJsonRpcResponseError, A2AMissingJsonRpcResponseError, A2ANoJsonRpcInterfaceError, A2AProtocolError, callAction, callAgent, clearA2ACardCache, getGlobalA2ASecret, signA2AOrganizationToken, signA2AToken, } from "./client.js";
5
+ export { A2AClient, A2AJsonRpcResponseError, A2AMissingJsonRpcResponseError, A2ANoJsonRpcInterfaceError, A2AProtocolError, assertCredentialedA2AUrl, callAction, callAgent, clearA2ACardCache, getGlobalA2ASecret, signA2AOrganizationToken, signA2AToken, } from "./client.js";
6
6
  export type { A2AProtocolErrorCode } from "./client.js";
7
+ export { workspacePrivateOrigins } from "./workspace-private-origins.js";
7
8
  export { clearRemoteAgentTokenCache, RemoteAgentAuthError, RemoteAgentCredentialRejectedError, resolveRemoteAgentToken, } from "./remote-agent-auth.js";
8
9
  export type { RemoteAgentAuthErrorCode, RemoteAgentCredentialContext, } from "./remote-agent-auth.js";
9
10
  export { canonicalA2AAudience } from "./audience.js";
package/dist/a2a/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  export { mountA2A, verifyA2AToken } from "./server.js";
2
2
  export { generateAgentCard } from "./agent-card.js";
3
3
  export { A2A_AGENT_ACTIVITY_KIND, A2A_AGENT_ACTIVITY_VERSION, MAX_A2A_ACTIVITY_REASONING_CHARS, MAX_A2A_ACTIVITY_REASONING_SEGMENTS, MAX_A2A_ACTIVITY_RESPONSE_CHARS, MAX_A2A_ACTIVITY_TOOL_CALLS, MAX_A2A_ACTIVITY_TOTAL_CHARS, MAX_A2A_ACTIVITY_TOOL_ID_CHARS, MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS, MAX_A2A_ACTIVITY_TOOL_NAME_CHARS, MAX_A2A_ACTIVITY_TOOL_PAYLOAD_CHARS, MAX_A2A_ACTIVITY_TOOL_RESULT_CHARS, applyA2AAgentActivityEvent, buildA2AAgentActivityPart, buildA2AAgentActivitySnapshot, createA2AAgentActivityState, parseA2AAgentActivityPart, } from "./activity.js";
4
- export { A2AClient, A2AJsonRpcResponseError, A2AMissingJsonRpcResponseError, A2ANoJsonRpcInterfaceError, A2AProtocolError, callAction, callAgent, clearA2ACardCache, getGlobalA2ASecret, signA2AOrganizationToken, signA2AToken, } from "./client.js";
4
+ export { A2AClient, A2AJsonRpcResponseError, A2AMissingJsonRpcResponseError, A2ANoJsonRpcInterfaceError, A2AProtocolError, assertCredentialedA2AUrl, callAction, callAgent, clearA2ACardCache, getGlobalA2ASecret, signA2AOrganizationToken, signA2AToken, } from "./client.js";
5
+ export { workspacePrivateOrigins } from "./workspace-private-origins.js";
5
6
  export { clearRemoteAgentTokenCache, RemoteAgentAuthError, RemoteAgentCredentialRejectedError, resolveRemoteAgentToken, } from "./remote-agent-auth.js";
6
7
  export { canonicalA2AAudience } from "./audience.js";
7
8
  export { resolveA2ACallerAuth } from "./caller-auth.js";
@@ -8,6 +8,7 @@ import { classifyProviderError, describeErrorWithCauses, } from "./error-detail.
8
8
  import { createFirstEventAbortController } from "./first-event-timeout.js";
9
9
  import { limitProviderTools } from "./limit-provider-tools.js";
10
10
  import { isCustomOpenAiBaseUrl } from "./openai-compatible-endpoint.js";
11
+ import { createOpenRouterToolFetch } from "./openrouter-tool-fetch.js";
11
12
  import { clampThinkingBudgetTokens, resolveMaxOutputTokensForEngine, } from "./output-tokens.js";
12
13
  import { createProviderToolNameMap } from "./tool-name.js";
13
14
  import { engineToolsToAISDK, engineMessagesToAISDK, aiSdkPartToEngineEvents, aiSdkStepToAssistantContent, } from "./translate-ai-sdk.js";
@@ -279,15 +280,8 @@ class AISDKEngine {
279
280
  }
280
281
  const toolNameMap = createProviderToolNameMap(opts.tools, opts.messages);
281
282
  const providerTools = limitProviderTools(opts.tools);
282
- // The Responses API treats an omitted `strict` as strict mode and rewrites
283
- // every optional parameter as required, so the model must invent a value
284
- // ("" or a guessed id) for each one. Action schemas use omission to mean
285
- // "not this mode", so those fillers turn a valid call into a mixed one
286
- // that validation rejects on every retry.
287
- const usesResponsesApi = this.provider === "openai" &&
288
- (this.forceResponses || !isCustomOpenAiBaseUrl(this.baseUrl));
289
283
  const aiSdkTools = providerTools.length > 0
290
- ? engineToolsToAISDK(providerTools, jsonSchema, toolNameMap, usesResponsesApi ? false : undefined)
284
+ ? engineToolsToAISDK(providerTools, jsonSchema, toolNameMap)
291
285
  : undefined;
292
286
  const messages = engineMessagesToAISDK(opts.messages, {
293
287
  toolResultImages: this.capabilities.vision,
@@ -510,6 +504,7 @@ class AISDKEngine {
510
504
  if (this.requestFetch)
511
505
  config.fetch = this.requestFetch;
512
506
  if (this.provider === "openrouter") {
507
+ config.fetch = createOpenRouterToolFetch(this.requestFetch);
513
508
  if (this.appName)
514
509
  config.appName = this.appName;
515
510
  if (this.appUrl)
@@ -1,7 +1,7 @@
1
1
  import { type BuilderGatewayLane } from "../../server/credential-provider.js";
2
2
  import type { AgentEngine, EngineCapabilities } from "./types.js";
3
3
  export declare const BUILDER_CAPABILITIES: EngineCapabilities;
4
- export declare const BUILDER_SUPPORTED_MODELS: readonly ["auto", "claude-haiku-4-5", "claude-sonnet-5", "claude-opus-5-5", "gpt-5-4", "gpt-5-5", "gpt-5-4-mini", "gpt-5-1-codex-mini", "gpt-6.1-sol", "gpt-5-6-terra", "gpt-6-luna", "gemini-3-1-pro", "gemini-3-8-flash", "gemini-3-5-flash-lite", "gemini-3-1-flash-lite", "qwen3-coder", "kimi-k2-5", "deepseek-v3-1", "z-ai-glm-4-5", "z-ai-glm-5-1"];
4
+ export declare const BUILDER_SUPPORTED_MODELS: readonly ["auto", "claude-haiku-4-5", "claude-sonnet-5", "claude-opus-5-5", "gpt-5-4", "gpt-5-5", "gpt-5-4-mini", "gpt-5-1-codex-mini", "gpt-6.1-sol", "gpt-5-6-terra", "gpt-6-luna", "gemini-3-1-pro", "gemini-3-8-flash", "gemini-3-5-flash-lite", "gemini-3-1-flash-lite", "qwen3-coder", "kimi-k2-5", "deepseek-v3-1", "deepseek-v4-1-flash", "z-ai-glm-4-5", "z-ai-glm-5-1", "z-ai-glm-5-3-flash"];
5
5
  export declare const BUILDER_MODEL_UNAUTHORIZED_ERROR_CODE = "builder_model_unauthorized";
6
6
  /**
7
7
  * A truncated stream, not a rejected request: the client continues the partial
@@ -0,0 +1 @@
1
+ export declare function createOpenRouterToolFetch(requestFetch?: typeof fetch): typeof fetch;
@@ -0,0 +1,20 @@
1
+ export function createOpenRouterToolFetch(requestFetch = globalThis.fetch) {
2
+ return (input, init) => {
3
+ if (typeof init?.body !== "string")
4
+ return requestFetch(input, init);
5
+ const body = JSON.parse(init.body);
6
+ if (!body.tools?.length)
7
+ return requestFetch(input, init);
8
+ // Temporary adapter until OpenRouter's SDK forwards the standard tool.strict
9
+ // flag (still dropped in v3.1.0). Keep the wire regression when removing this.
10
+ return requestFetch(input, {
11
+ ...init,
12
+ body: JSON.stringify({
13
+ ...body,
14
+ tools: body.tools.map((tool) => tool.type === "function" && tool.function
15
+ ? { ...tool, function: { ...tool.function, strict: false } }
16
+ : tool),
17
+ }),
18
+ });
19
+ };
20
+ }
@@ -1,6 +1,6 @@
1
1
  import { type ProviderToolNameMap } from "./tool-name.js";
2
2
  import type { EngineTool, EngineMessage, EngineContentPart, EngineEvent } from "./types.js";
3
- export declare function engineToolsToAISDK(tools: EngineTool[], jsonSchema?: (schema: Record<string, unknown>) => unknown, toolNameMap?: ProviderToolNameMap, strict?: boolean): Record<string, any>;
3
+ export declare function engineToolsToAISDK(tools: EngineTool[], jsonSchema?: (schema: Record<string, unknown>) => unknown, toolNameMap?: ProviderToolNameMap): Record<string, any>;
4
4
  export interface EngineToAISDKOptions {
5
5
  toolResultImages?: boolean;
6
6
  toolNameMap?: ProviderToolNameMap;
@@ -2,7 +2,7 @@ import { classifyProviderError, describeErrorWithCauses, } from "./error-detail.
2
2
  import { flattenComposedRootSchema } from "./flatten-composed-root-schema.js";
3
3
  import { createProviderToolNameMap, toEngineToolName, toProviderToolName, } from "./tool-name.js";
4
4
  import { backfillEngineMessagesToolResults } from "./translate-anthropic.js";
5
- export function engineToolsToAISDK(tools, jsonSchema, toolNameMap = createProviderToolNameMap(tools), strict) {
5
+ export function engineToolsToAISDK(tools, jsonSchema, toolNameMap = createProviderToolNameMap(tools)) {
6
6
  const result = {};
7
7
  for (const tool of tools) {
8
8
  const inputSchema = flattenComposedRootSchema(tool.inputSchema);
@@ -16,7 +16,8 @@ export function engineToolsToAISDK(tools, jsonSchema, toolNameMap = createProvid
16
16
  result[providerName] = {
17
17
  description: tool.description,
18
18
  inputSchema: jsonSchema ? jsonSchema(rawSchema) : rawSchema,
19
- ...(strict === undefined ? {} : { strict }),
19
+ // Gateways may normalize an omitted flag into required optional fields.
20
+ strict: false,
20
21
  };
21
22
  }
22
23
  return result;
@@ -21,7 +21,7 @@ export declare const BUILDER_CLAUDE_SONNET_MODEL_LABEL = "Claude Sonnet 5";
21
21
  export declare const AGENT_MODEL_CONFIG: {
22
22
  readonly builder: {
23
23
  readonly defaultModel: "gpt-6-luna";
24
- readonly supportedModels: readonly ["auto", "claude-haiku-4-5", "claude-sonnet-5", "claude-opus-5-5", "gpt-5-4", "gpt-5-5", "gpt-5-4-mini", "gpt-5-1-codex-mini", "gpt-6.1-sol", "gpt-5-6-terra", "gpt-6-luna", "gemini-3-1-pro", "gemini-3-8-flash", "gemini-3-5-flash-lite", "gemini-3-1-flash-lite", "qwen3-coder", "kimi-k2-5", "deepseek-v3-1", "z-ai-glm-4-5", "z-ai-glm-5-1"];
24
+ readonly supportedModels: readonly ["auto", "claude-haiku-4-5", "claude-sonnet-5", "claude-opus-5-5", "gpt-5-4", "gpt-5-5", "gpt-5-4-mini", "gpt-5-1-codex-mini", "gpt-6.1-sol", "gpt-5-6-terra", "gpt-6-luna", "gemini-3-1-pro", "gemini-3-8-flash", "gemini-3-5-flash-lite", "gemini-3-1-flash-lite", "qwen3-coder", "kimi-k2-5", "deepseek-v3-1", "deepseek-v4-1-flash", "z-ai-glm-4-5", "z-ai-glm-5-1", "z-ai-glm-5-3-flash"];
25
25
  };
26
26
  readonly anthropic: {
27
27
  readonly defaultModel: "claude-sonnet-5-5";
@@ -64,7 +64,7 @@ export declare const AGENT_MODEL_CONFIG: {
64
64
  };
65
65
  export declare const BUILDER_MODEL_CONFIG: {
66
66
  readonly defaultModel: "gpt-6-luna";
67
- readonly supportedModels: readonly ["auto", "claude-haiku-4-5", "claude-sonnet-5", "claude-opus-5-5", "gpt-5-4", "gpt-5-5", "gpt-5-4-mini", "gpt-5-1-codex-mini", "gpt-6.1-sol", "gpt-5-6-terra", "gpt-6-luna", "gemini-3-1-pro", "gemini-3-8-flash", "gemini-3-5-flash-lite", "gemini-3-1-flash-lite", "qwen3-coder", "kimi-k2-5", "deepseek-v3-1", "z-ai-glm-4-5", "z-ai-glm-5-1"];
67
+ readonly supportedModels: readonly ["auto", "claude-haiku-4-5", "claude-sonnet-5", "claude-opus-5-5", "gpt-5-4", "gpt-5-5", "gpt-5-4-mini", "gpt-5-1-codex-mini", "gpt-6.1-sol", "gpt-5-6-terra", "gpt-6-luna", "gemini-3-1-pro", "gemini-3-8-flash", "gemini-3-5-flash-lite", "gemini-3-1-flash-lite", "qwen3-coder", "kimi-k2-5", "deepseek-v3-1", "deepseek-v4-1-flash", "z-ai-glm-4-5", "z-ai-glm-5-1", "z-ai-glm-5-3-flash"];
68
68
  };
69
69
  export declare const ANTHROPIC_MODEL_CONFIG: {
70
70
  readonly defaultModel: "claude-sonnet-5-5";
@@ -177,8 +177,10 @@ export const AGENT_MODEL_CONFIG = {
177
177
  "qwen3-coder",
178
178
  "kimi-k2-5",
179
179
  "deepseek-v3-1",
180
+ "deepseek-v4-1-flash",
180
181
  "z-ai-glm-4-5",
181
182
  "z-ai-glm-5-1",
183
+ "z-ai-glm-5-3-flash",
182
184
  ],
183
185
  },
184
186
  anthropic: {
@@ -1,4 +1,7 @@
1
1
  import { z } from "zod";
2
+ // Typed against the Builder catalog: the classifier runs on the gateway, so a
3
+ // retired id must break the build instead of every classification.
4
+ const DEFAULT_INFERRED_SENTIMENT_MODEL = "gpt-6-luna";
2
5
  export const observabilityConfig = z.object({
3
6
  release: z
4
7
  .string()
@@ -101,7 +104,11 @@ export const observabilityConfig = z.object({
101
104
  inferredSentimentSampleRate: z.number().min(0).max(1).optional().meta({
102
105
  doc: "Deterministic fraction of eligible user messages to classify, 0 to 1.",
103
106
  }),
104
- inferredSentimentModel: z.string().min(1).default("gpt-5-6-luna").meta({
107
+ inferredSentimentModel: z
108
+ .string()
109
+ .min(1)
110
+ .default(DEFAULT_INFERRED_SENTIMENT_MODEL)
111
+ .meta({
105
112
  doc: "Model used by the managed sentiment classifier.",
106
113
  }),
107
114
  });
@@ -1,11 +1,10 @@
1
1
  import { serializeAnalyticsAnonymousIdCookie } from "../shared/analytics-anonymous-id.js";
2
+ import { ANALYTICS_SESSION_ID_COOKIE_NAME, ANALYTICS_SESSION_ID_MAX_LENGTH, normalizeAnalyticsSessionId, serializeAnalyticsSessionIdCookie, } from "../shared/analytics-session-id.js";
2
3
  const ANONYMOUS_ID_STORAGE_KEY = "agent-native.anonymous_id";
3
4
  const SESSION_ID_STORAGE_KEY = "agent-native.session_id";
4
5
  const SESSION_ID_PIN_STORAGE_KEY = "agent-native.session_id_pin";
5
6
  const SESSION_LAST_ACTIVITY_STORAGE_KEY = "agent-native.session_last_activity";
6
7
  const SESSION_IDLE_TIMEOUT_MS = 30 * 60 * 1000;
7
- const MAX_SESSION_ID_LENGTH = 127;
8
- const SAFE_SESSION_ID = /^[!-~]+$/;
9
8
  function generateVisitorId() {
10
9
  try {
11
10
  if (typeof crypto !== "undefined" &&
@@ -56,6 +55,17 @@ function syncAnalyticsAnonymousIdCookie(id) {
56
55
  // remains the browser-side source of truth in that case.
57
56
  }
58
57
  }
58
+ function syncAnalyticsSessionIdCookie(id) {
59
+ try {
60
+ const cookie = serializeAnalyticsSessionIdCookie(id);
61
+ if (cookie)
62
+ document.cookie = cookie;
63
+ }
64
+ catch {
65
+ // coercion-ok: cookie access is optional and cannot block analytics.
66
+ // Local storage remains the browser-side source of truth when cookies are unavailable.
67
+ }
68
+ }
59
69
  let pageLoadId;
60
70
  /** One id for this page load, shared by every pageview until it reloads. */
61
71
  export function getAnalyticsPageLoadId() {
@@ -74,17 +84,16 @@ export function getOrCreateAnalyticsAnonymousId() {
74
84
  return id;
75
85
  }
76
86
  export function setAnalyticsSessionId(sessionId) {
77
- const trimmed = typeof sessionId === "string" ? sessionId.trim() : "";
78
- if (!trimmed ||
79
- trimmed.length > MAX_SESSION_ID_LENGTH ||
80
- !SAFE_SESSION_ID.test(trimmed)) {
81
- throw new Error(`Invalid analytics session id: expected 1-${MAX_SESSION_ID_LENGTH} printable ASCII characters with no whitespace`);
87
+ const trimmed = normalizeAnalyticsSessionId(sessionId);
88
+ if (!trimmed) {
89
+ throw new Error(`Invalid analytics session id: expected 1-${ANALYTICS_SESSION_ID_MAX_LENGTH} printable ASCII characters with no whitespace`);
82
90
  }
83
91
  if (typeof window === "undefined")
84
92
  return undefined;
85
93
  safeStorageSet(SESSION_ID_PIN_STORAGE_KEY, trimmed);
86
94
  safeStorageSet(SESSION_ID_STORAGE_KEY, trimmed);
87
95
  safeStorageSet(SESSION_LAST_ACTIVITY_STORAGE_KEY, String(Date.now()));
96
+ syncAnalyticsSessionIdCookie(trimmed);
88
97
  return trimmed;
89
98
  }
90
99
  export function clearAnalyticsSessionId() {
@@ -93,6 +102,13 @@ export function clearAnalyticsSessionId() {
93
102
  safeStorageRemove(SESSION_ID_PIN_STORAGE_KEY);
94
103
  safeStorageRemove(SESSION_ID_STORAGE_KEY);
95
104
  safeStorageRemove(SESSION_LAST_ACTIVITY_STORAGE_KEY);
105
+ try {
106
+ document.cookie = `${ANALYTICS_SESSION_ID_COOKIE_NAME}=; path=/; max-age=0; SameSite=Lax`;
107
+ }
108
+ catch {
109
+ // coercion-ok: cookie access is optional and cannot block analytics.
110
+ // Local storage remains the browser-side source of truth when cookies are unavailable.
111
+ }
96
112
  }
97
113
  export function getOrCreateAnalyticsSessionId() {
98
114
  if (typeof window === "undefined")
@@ -102,6 +118,7 @@ export function getOrCreateAnalyticsSessionId() {
102
118
  if (pinned) {
103
119
  safeStorageSet(SESSION_ID_STORAGE_KEY, pinned);
104
120
  safeStorageSet(SESSION_LAST_ACTIVITY_STORAGE_KEY, String(now));
121
+ syncAnalyticsSessionIdCookie(pinned);
105
122
  return pinned;
106
123
  }
107
124
  const lastActivityRaw = safeStorageGet(SESSION_LAST_ACTIVITY_STORAGE_KEY);
@@ -117,5 +134,6 @@ export function getOrCreateAnalyticsSessionId() {
117
134
  safeStorageSet(SESSION_ID_STORAGE_KEY, id);
118
135
  }
119
136
  safeStorageSet(SESSION_LAST_ACTIVITY_STORAGE_KEY, String(now));
137
+ syncAnalyticsSessionIdCookie(id);
120
138
  return id;
121
139
  }
@@ -166,6 +166,15 @@ function setRuntimeRunIdMetadata(metadata, runtimeRunId) {
166
166
  else
167
167
  observability.runtimeRunId = runtimeRunId;
168
168
  }
169
+ function setRuntimeTurnIdMetadata(metadata, runtimeTurnId) {
170
+ const observability = agentNativeMetadata(metadata)?.observability;
171
+ if (!observability)
172
+ return;
173
+ if (runtimeTurnId === undefined)
174
+ delete observability.turnId;
175
+ else
176
+ observability.turnId = runtimeTurnId;
177
+ }
169
178
  function objectReference(value) {
170
179
  const object = asRecord(value);
171
180
  if (!object ||
@@ -1215,13 +1224,14 @@ export function createAgentKitProtocolAdapter(runtime, options = {}) {
1215
1224
  ...(turn.runId === undefined ? {} : { runtimeRunId: turn.runId }),
1216
1225
  runtimeId: runtime.id,
1217
1226
  sessionId: session.id,
1218
- turnId: turn.id,
1227
+ ...(turn.id === undefined ? {} : { turnId: turn.id }),
1219
1228
  threadId,
1220
1229
  ...observability,
1221
1230
  },
1222
1231
  },
1223
1232
  });
1224
1233
  setRuntimeRunIdMetadata(runMetadata, turn.runId);
1234
+ setRuntimeTurnIdMetadata(runMetadata, turn.id);
1225
1235
  const run = {
1226
1236
  runId,
1227
1237
  threadId,
@@ -3056,13 +3066,14 @@ export function createAgentKitProtocolAdapter(runtime, options = {}) {
3056
3066
  : { runtimeRunId: nextTurn.runId }),
3057
3067
  runtimeId: runtime.id,
3058
3068
  sessionId: run.session.id,
3059
- turnId: nextTurn.id,
3069
+ ...(nextTurn.id === undefined ? {} : { turnId: nextTurn.id }),
3060
3070
  threadId: input.threadId,
3061
3071
  interruptedRunId: run.runId,
3062
3072
  },
3063
3073
  },
3064
3074
  });
3065
3075
  setRuntimeRunIdMetadata(replacementMetadata, nextTurn.runId);
3076
+ setRuntimeTurnIdMetadata(replacementMetadata, nextTurn.id);
3066
3077
  const replacementRun = {
3067
3078
  runId: nextRunId,
3068
3079
  threadId: input.threadId,
@@ -1,8 +1,10 @@
1
+ import { AGENT_ACCESS_PARAM } from "../shared/agent-access.js";
1
2
  /**
2
3
  * Query parameters that may carry sensitive values in the URL bar. Browser
3
4
  * telemetry and feedback integrations must not copy OAuth codes, share tokens,
4
- * password params, email-confirm tokens, or similar secrets into downstream
5
- * systems. Callers may opt into additional app-specific query parameters.
5
+ * password params, email-confirm tokens, signed agent-access links, or similar
6
+ * secrets into downstream systems. Callers may opt into additional
7
+ * app-specific query parameters.
6
8
  */
7
9
  const SENSITIVE_QUERY_PARAMS = new Set([
8
10
  "password",
@@ -13,6 +15,7 @@ const SENSITIVE_QUERY_PARAMS = new Set([
13
15
  "share",
14
16
  "share_token",
15
17
  "bridge",
18
+ AGENT_ACCESS_PARAM,
16
19
  ]);
17
20
  export function scrubUrl(url, additionalSensitiveParams = []) {
18
21
  if (!url || typeof url !== "string")
@@ -26,6 +26,7 @@ import { AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_CACHE_BUSTER,
26
26
  import { workspaceAppAudienceFromEnv, workspaceAppAudienceFromPackageJson, workspaceAppRouteAccessFromEnv, workspaceAppRouteAccessFromPackageJson, } from "../shared/workspace-app-audience.js";
27
27
  import { generateActionRegistryForProject } from "../vite/action-types-plugin.js";
28
28
  import { createAgentNativeConfigContext, loadResolvedAgentNativeConfig, readAgentNativeBuildConfigMarker, resolveFirstRunOnboardingBuildReplacement, resolveHarnessBuildReplacement, } from "../vite/agent-native-config-loader.js";
29
+ import { createSentryServerSourceMapUploadPlugins } from "../vite/sentry-source-maps.js";
29
30
  import { cloneServerBundleForFunction, copyDir, pruneSsrIslandFromRewritingClone, readPackageManifest, SERVERLESS_BROWSER_RUNTIME_PACKAGES, } from "./function-bundle.js";
30
31
  import { collectImmutableAssetPaths, IMMUTABLE_ASSET_CACHE_CONTROL, IMMUTABLE_ASSET_CACHE_HEADERS, prefixAssetPath, } from "./immutable-assets.js";
31
32
  import { writeNetlifyStaticHeaders } from "./netlify-static-headers.js";
@@ -4240,6 +4241,7 @@ export default bundle;
4240
4241
  const providedPluginsNitroPlugin = await writeProvidedPluginsNitroPlugin();
4241
4242
  const awsLambdaStreaming = isAwsLambdaStreamingBuild(preset, nitroEnvironment);
4242
4243
  const nitroServerCodeSplittingConfig = nitroServerCodeSplittingConfigForPreset(preset);
4244
+ const sentryServerSourceMapPlugins = await createSentryServerSourceMapUploadPlugins(nitroEnvironment);
4243
4245
  const nitroVirtual = {
4244
4246
  "virtual:agents-bundle": agentsBundleModuleSource,
4245
4247
  };
@@ -4260,6 +4262,14 @@ export default bundle;
4260
4262
  ...(isAwsLambdaPreset(preset) ? { awsLambda: { streaming: false } } : {}),
4261
4263
  baseURL: appBasePath || "/",
4262
4264
  minify: true,
4265
+ ...(sentryServerSourceMapPlugins.length > 0
4266
+ ? {
4267
+ sourcemap: "hidden",
4268
+ // Nitro strips sourcesContent by default; the maps never ship, so
4269
+ // keep it for Sentry to show source context.
4270
+ experimental: { sourcemapMinify: false },
4271
+ }
4272
+ : {}),
4263
4273
  serverDir: "./server",
4264
4274
  ignore: NITRO_RUNTIME_IGNORE_PATTERNS,
4265
4275
  alias: {
@@ -4286,6 +4296,7 @@ export default bundle;
4286
4296
  ? [createCloudflareModuleStubPlugin()]
4287
4297
  : []),
4288
4298
  createBrowserOnlyServerStubPlugin(),
4299
+ ...sentryServerSourceMapPlugins,
4289
4300
  ...(enterpriseAuthAdaptersEnabled
4290
4301
  ? []
4291
4302
  : [createEnterpriseAuthAdapterStubPlugin(false)]),
@@ -33,20 +33,20 @@ declare const _default: import("../../action.js").ActionDefinition<{
33
33
  idempotencyKey: string;
34
34
  deleted: boolean;
35
35
  } | {
36
+ id?: undefined;
36
37
  error: string;
37
38
  url?: undefined;
38
- id?: undefined;
39
39
  provider?: undefined;
40
40
  configured?: undefined;
41
41
  } | {
42
42
  url: string;
43
43
  id: string;
44
44
  provider: string;
45
- error?: undefined;
46
45
  configured?: undefined;
46
+ error?: undefined;
47
47
  } | {
48
- url?: undefined;
49
48
  id?: undefined;
49
+ url?: undefined;
50
50
  provider?: undefined;
51
51
  error: string;
52
52
  configured: boolean;
@@ -6,6 +6,7 @@ import { actionsToEngineTools, filterInitialEngineTools, resolveOwnerEngineApiKe
6
6
  import { runAgentLoopDirectWithSoftTimeout } from "../agent/run-loop-with-resume.js";
7
7
  import { abortRun, resolveBackgroundAutomationSoftTimeoutMs, resolveBackgroundRunHardTimeoutMs, startRun, } from "../agent/run-manager.js";
8
8
  import { claimBackgroundRun, insertRun } from "../agent/run-store.js";
9
+ import { buildCurrentTimeUserContext, buildRuntimeContextPrompt, } from "../agent/runtime-context.js";
9
10
  import { buildAssistantMessage, buildUserMessage, extractThreadMeta, foldAssistantTurn, upsertUserMessage, } from "../agent/thread-data-builder.js";
10
11
  import { attachToolSearch } from "../agent/tool-search.js";
11
12
  import { lookupOwnerAccount, resolveAutomationExecutionIdentity, } from "../automations/service.js";
@@ -19,6 +20,7 @@ import { runWithRequestContext, } from "../server/request-context.js";
19
20
  import { normalizeReasoningEffortForRequest } from "../shared/reasoning-effort.js";
20
21
  import automationNoOpAction, { AUTOMATION_NO_OP_TOOL, automationNoOpSchema, } from "./actions/automation-no-op.js";
21
22
  import { applyAutomationFailure, automationOwnerKind, classifyAutomationFailure, CONFIG_INVALID_ERROR_CODE, MISSING_TOOLS_ERROR_CODE, OWNER_MISSING_ERROR_CODE, pausedMessage, withDeliveryNote, } from "./automation-outcome.js";
23
+ import { effectiveTimezone } from "./cron.js";
22
24
  import { recoveredFactoryOwnerOrgId, } from "./frontmatter.js";
23
25
  import { attachAutomationRunThread, finishAutomationRun, startAutomationRun, } from "./run-history.js";
24
26
  export const BACKGROUND_RUN_HARD_TIMEOUT_MS = 10 * 60_000;
@@ -645,16 +647,25 @@ async function executeBackgroundAutomation(options, deps, historyId, runIdRef) {
645
647
  : Math.max(1, options.hardDeadlineAt - Date.now()));
646
648
  await new Promise((resolve, reject) => {
647
649
  const activeRun = startRun(runId, thread.id, async (send, signal, control) => {
650
+ const runtimeContext = {
651
+ now: new Date(),
652
+ timezone: effectiveTimezone(automation.meta.timezone),
653
+ };
648
654
  const loopOpts = {
649
655
  engine,
650
656
  model,
651
- systemPrompt,
657
+ systemPrompt: systemPrompt + buildRuntimeContextPrompt(runtimeContext),
652
658
  tools,
653
659
  availableTools,
654
660
  messages: [
655
661
  {
656
662
  role: "user",
657
- content: [{ type: "text", text: prompt }],
663
+ content: [
664
+ {
665
+ type: "text",
666
+ text: prompt + buildCurrentTimeUserContext(runtimeContext),
667
+ },
668
+ ],
658
669
  },
659
670
  ],
660
671
  actions,
@@ -2584,6 +2584,9 @@ async function verifyA2AJwtForMcp(token, resourceUrl) {
2584
2584
  if (globalSecret) {
2585
2585
  const payload = await verifyWithSecret(globalSecret);
2586
2586
  if (payload) {
2587
+ const tokenScope = typeof payload.scope === "string" ? payload.scope : undefined;
2588
+ const firstPartyMcp = payload.agent_native_first_party_mcp === true;
2589
+ const locallyIssuedConnectToken = tokenScope === MCP_CONNECT_SCOPE && !firstPartyMcp;
2587
2590
  if (orgDomain) {
2588
2591
  let organization;
2589
2592
  try {
@@ -2594,17 +2597,17 @@ async function verifyA2AJwtForMcp(token, resourceUrl) {
2594
2597
  catch (error) {
2595
2598
  throw new McpIdentityVerificationUnavailableError(error);
2596
2599
  }
2597
- if (organization?.secret.trim() === globalSecret) {
2600
+ // Locally issued connect identities are admitted below only after
2601
+ // their active JTI row confirms the stored owner and organization.
2602
+ if (organization?.secret.trim() === globalSecret &&
2603
+ !locallyIssuedConnectToken) {
2598
2604
  return organizationPrincipalClaims(payload, organization);
2599
2605
  }
2600
2606
  }
2601
- const tokenScope = typeof payload.scope === "string" ? payload.scope : undefined;
2602
- const firstPartyMcp = payload.agent_native_first_party_mcp === true;
2603
2607
  const hasOrganizationClaim = Object.prototype.hasOwnProperty.call(payload, "org_id") &&
2604
2608
  payload.org_id !== null;
2605
2609
  const hasOrganizationDomainClaim = Object.prototype.hasOwnProperty.call(payload, "org_domain") &&
2606
2610
  payload.org_domain !== null;
2607
- const locallyIssuedConnectToken = tokenScope === MCP_CONNECT_SCOPE && !firstPartyMcp;
2608
2611
  const unclaimedFirstPartyToken = firstPartyMcp && !hasOrganizationClaim && !hasOrganizationDomainClaim;
2609
2612
  if (locallyIssuedConnectToken || unclaimedFirstPartyToken) {
2610
2613
  return payload;
@@ -533,9 +533,9 @@ function renderConnectPage(params) {
533
533
  .advanced { margin: 0 0 1rem; }
534
534
  .advanced > summary {
535
535
  list-style: none; cursor: pointer; user-select: none;
536
- display: flex; align-items: center; justify-content: center; gap: 0.35rem;
536
+ display: flex; align-items: center; justify-content: space-between; gap: 0.35rem;
537
537
  color: var(--subtle); font-size: 0.8rem; font-weight: 500;
538
- padding: 0.5rem 0; text-align: center;
538
+ padding: 0.65rem 0; text-align: left;
539
539
  }
540
540
  .advanced > summary::-webkit-details-marker { display: none; }
541
541
  .advanced > summary:hover { color: var(--muted); }
@@ -544,7 +544,8 @@ function renderConnectPage(params) {
544
544
  .advanced > summary .chev {
545
545
  width: 7px; height: 7px; border-right: 1.5px solid currentColor;
546
546
  border-bottom: 1.5px solid currentColor; transform: rotate(45deg);
547
- transition: transform 0.15s ease; margin-top: -3px;
547
+ transition: transform 0.15s ease; margin: -3px 0.25rem 0 auto;
548
+ flex: 0 0 auto;
548
549
  }
549
550
  .advanced[open] > summary .chev { transform: rotate(225deg); margin-top: 2px; }
550
551
  .advanced-body {
@@ -577,13 +578,13 @@ function renderConnectPage(params) {
577
578
  box-shadow: 0 0 0 3px rgba(250,250,250,0.12);
578
579
  }
579
580
  .connections {
580
- margin-top: 1.1rem; border-top: 1px solid var(--border);
581
- padding-top: 0.35rem;
581
+ margin-top: 0; border-top: 1px solid var(--border);
582
582
  }
583
583
  .connections > summary {
584
584
  list-style: none; cursor: pointer; user-select: none;
585
585
  display: flex; align-items: center; gap: 0.55rem;
586
- min-height: 2.2rem; color: var(--muted); font-size: 0.82rem;
586
+ min-height: 2.75rem; padding: 0.65rem 0;
587
+ color: var(--muted); font-size: 0.82rem;
587
588
  }
588
589
  .connections > summary::-webkit-details-marker { display: none; }
589
590
  .connections > summary:focus-visible {
@@ -597,8 +598,12 @@ function renderConnectPage(params) {
597
598
  .connections .chev {
598
599
  width: 7px; height: 7px; border-right: 1.5px solid currentColor;
599
600
  border-bottom: 1.5px solid currentColor; transform: rotate(45deg);
600
- transition: transform 0.15s ease; margin: -3px 0 0 0.15rem;
601
+ transition: transform 0.15s ease; margin: -3px 0 0 auto;
601
602
  }
603
+ .connections > summary > .connections-state:not(.hidden) + .chev {
604
+ margin-left: 0.15rem;
605
+ }
606
+ .connections > summary > .chev { margin-right: 0.25rem; }
602
607
  .connections[open] .chev { transform: rotate(225deg); margin-top: 2px; }
603
608
  .token-list { padding-top: 0.4rem; }
604
609
  .tok { display: flex; align-items: center; justify-content: space-between;
@@ -663,13 +668,13 @@ function renderConnectPage(params) {
663
668
  }
664
669
  .url-row .ghost { flex: 0 0 auto; }
665
670
  .hosts {
666
- margin: 0 0 1rem; border-top: 1px solid var(--border);
667
- border-bottom: 1px solid var(--border); padding: 0.35rem 0;
671
+ margin: 0; border-top: 1px solid var(--border);
668
672
  }
669
673
  .hosts > summary {
670
674
  list-style: none; cursor: pointer; user-select: none;
671
675
  display: flex; align-items: center; gap: 0.55rem;
672
- min-height: 2.2rem; color: var(--muted); font-size: 0.82rem;
676
+ min-height: 2.75rem; padding: 0.65rem 0;
677
+ color: var(--muted); font-size: 0.82rem;
673
678
  }
674
679
  .hosts > summary::-webkit-details-marker { display: none; }
675
680
  .hosts > summary:focus-visible {
@@ -678,7 +683,7 @@ function renderConnectPage(params) {
678
683
  .hosts > summary .chev {
679
684
  width: 7px; height: 7px; border-right: 1.5px solid currentColor;
680
685
  border-bottom: 1.5px solid currentColor; transform: rotate(45deg);
681
- transition: transform 0.15s ease; margin: -3px 0 0 0.15rem;
686
+ transition: transform 0.15s ease; margin: -3px 0.25rem 0 0.15rem;
682
687
  }
683
688
  .hosts[open] > summary .chev { transform: rotate(225deg); margin-top: 2px; }
684
689
  .hosts-body { padding: 0.15rem 0 0.25rem; }
@@ -1,13 +1,13 @@
1
1
  export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
2
2
  count: number;
3
3
  updated?: undefined;
4
- error?: undefined;
5
4
  ok?: undefined;
5
+ error?: undefined;
6
6
  } | {
7
7
  count?: undefined;
8
8
  updated: number;
9
- error?: undefined;
10
9
  ok?: undefined;
10
+ error?: undefined;
11
11
  } | {
12
12
  count?: undefined;
13
13
  updated?: undefined;