@agent-native/core 0.209.0 → 0.209.1-nightly-20261015093558

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 (234) hide show
  1. package/dist/a2a/task-store.d.ts +1 -0
  2. package/dist/a2a/task-store.js +63 -62
  3. package/dist/action-call-classification.d.ts +15 -0
  4. package/dist/action-call-classification.js +24 -0
  5. package/dist/action-input-coercion.d.ts +10 -0
  6. package/dist/action-input-coercion.js +77 -0
  7. package/dist/action.d.ts +19 -1
  8. package/dist/action.js +37 -74
  9. package/dist/agent/engine/ai-sdk-engine.js +21 -4
  10. package/dist/agent/engine/continuation-dispatch-retry.d.ts +3 -0
  11. package/dist/agent/engine/continuation-dispatch-retry.js +53 -6
  12. package/dist/agent/harness/store.d.ts +1 -0
  13. package/dist/agent/harness/store.js +14 -16
  14. package/dist/agent/observational-memory/store.d.ts +1 -0
  15. package/dist/agent/observational-memory/store.js +28 -24
  16. package/dist/agent/production-agent.d.ts +16 -1
  17. package/dist/agent/production-agent.js +63 -10
  18. package/dist/agent/run-store.d.ts +1 -0
  19. package/dist/agent/run-store.js +61 -56
  20. package/dist/agent/tool-approval-store.d.ts +2 -0
  21. package/dist/agent/tool-approval-store.js +31 -29
  22. package/dist/app-config/migration.d.ts +1 -0
  23. package/dist/app-config/migration.js +4 -0
  24. package/dist/app-config/schema.d.ts +1 -0
  25. package/dist/application-state/store.d.ts +1 -0
  26. package/dist/application-state/store.js +36 -25
  27. package/dist/audit/store.d.ts +1 -0
  28. package/dist/audit/store.js +26 -28
  29. package/dist/browser-sessions/store.d.ts +1 -0
  30. package/dist/browser-sessions/store.js +15 -17
  31. package/dist/chat-threads/store.d.ts +1 -0
  32. package/dist/chat-threads/store.js +26 -19
  33. package/dist/checkpoints/store.d.ts +1 -0
  34. package/dist/checkpoints/store.js +19 -18
  35. package/dist/client/agent-sidebar-state.d.ts +1 -1
  36. package/dist/client/agent-sidebar-state.js +97 -5
  37. package/dist/coding-tools/run-code.js +5 -2
  38. package/dist/coding-tools/sandbox/executions-store.d.ts +1 -0
  39. package/dist/coding-tools/sandbox/executions-store.js +29 -30
  40. package/dist/collab/awareness-store.d.ts +1 -0
  41. package/dist/collab/awareness-store.js +15 -19
  42. package/dist/collab/routes.d.ts +1 -1
  43. package/dist/collab/storage.d.ts +1 -0
  44. package/dist/collab/storage.js +25 -24
  45. package/dist/data-programs/store.d.ts +1 -0
  46. package/dist/data-programs/store.js +25 -24
  47. package/dist/db/client.d.ts +1 -1
  48. package/dist/db/client.js +10 -30
  49. package/dist/db/ddl-guard.js +11 -3
  50. package/dist/db/index.d.ts +1 -1
  51. package/dist/db/index.js +1 -1
  52. package/dist/db/migration-policy.d.ts +2 -0
  53. package/dist/db/migration-policy.js +4 -0
  54. package/dist/db/runtime-facts.d.ts +11 -0
  55. package/dist/db/runtime-facts.js +41 -0
  56. package/dist/db/schema-catalog.d.ts +17 -0
  57. package/dist/db/schema-catalog.js +156 -0
  58. package/dist/db/store-registry.d.ts +85 -0
  59. package/dist/db/store-registry.generated.d.ts +2 -0
  60. package/dist/db/store-registry.generated.js +273 -0
  61. package/dist/db/store-registry.js +354 -0
  62. package/dist/db/widen-columns.js +7 -2
  63. package/dist/email-catalog/log.d.ts +1 -0
  64. package/dist/email-catalog/log.js +37 -25
  65. package/dist/extensions/slots/store.d.ts +1 -0
  66. package/dist/extensions/slots/store.js +20 -21
  67. package/dist/extensions/store.d.ts +1 -0
  68. package/dist/extensions/store.js +41 -26
  69. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  70. package/dist/guards/identity-columns-registered.js +5 -0
  71. package/dist/guards/release-schema-complete.d.ts +7 -13
  72. package/dist/guards/release-schema-complete.js +67 -32
  73. package/dist/guards/store-migrations-lock.d.ts +18 -0
  74. package/dist/guards/store-migrations-lock.js +49 -0
  75. package/dist/guards/store-registry-codegen.d.ts +16 -0
  76. package/dist/guards/store-registry-codegen.js +90 -0
  77. package/dist/history/store.d.ts +1 -0
  78. package/dist/history/store.js +20 -18
  79. package/dist/identity/retired-emails.d.ts +1 -0
  80. package/dist/identity/retired-emails.js +14 -13
  81. package/dist/integrations/a2a-continuations-store.d.ts +1 -0
  82. package/dist/integrations/a2a-continuations-store.js +46 -33
  83. package/dist/integrations/awaiting-input-store.d.ts +1 -0
  84. package/dist/integrations/awaiting-input-store.js +15 -19
  85. package/dist/integrations/computer-supervision-store.d.ts +1 -0
  86. package/dist/integrations/computer-supervision-store.js +15 -21
  87. package/dist/integrations/config-store.d.ts +1 -0
  88. package/dist/integrations/config-store.js +14 -16
  89. package/dist/integrations/controls-store.d.ts +1 -0
  90. package/dist/integrations/controls-store.js +15 -16
  91. package/dist/integrations/identity-links-store.d.ts +1 -0
  92. package/dist/integrations/identity-links-store.js +14 -21
  93. package/dist/integrations/installations-store.d.ts +1 -0
  94. package/dist/integrations/installations-store.js +15 -23
  95. package/dist/integrations/integration-campaigns-store.d.ts +1 -0
  96. package/dist/integrations/integration-campaigns-store.js +16 -23
  97. package/dist/integrations/pending-tasks-store.d.ts +1 -0
  98. package/dist/integrations/pending-tasks-store.js +16 -18
  99. package/dist/integrations/remote-commands-store.d.ts +1 -0
  100. package/dist/integrations/remote-commands-store.js +14 -16
  101. package/dist/integrations/remote-devices-store.d.ts +1 -0
  102. package/dist/integrations/remote-devices-store.js +39 -38
  103. package/dist/integrations/remote-push-store.d.ts +1 -0
  104. package/dist/integrations/remote-push-store.js +25 -24
  105. package/dist/integrations/remote-run-events-store.d.ts +1 -0
  106. package/dist/integrations/remote-run-events-store.js +17 -16
  107. package/dist/integrations/scope-store.d.ts +1 -0
  108. package/dist/integrations/scope-store.js +18 -36
  109. package/dist/integrations/thread-mapping-store.d.ts +1 -0
  110. package/dist/integrations/thread-mapping-store.js +25 -24
  111. package/dist/integrations/usage-budget-store.d.ts +1 -0
  112. package/dist/integrations/usage-budget-store.js +40 -49
  113. package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
  114. package/dist/jobs/automation-work-evidence.js +7 -3
  115. package/dist/jobs/run-history.d.ts +1 -0
  116. package/dist/jobs/run-history.js +38 -40
  117. package/dist/jobs/scheduler-health.d.ts +1 -0
  118. package/dist/jobs/scheduler-health.js +28 -30
  119. package/dist/mcp/approval-store.d.ts +1 -0
  120. package/dist/mcp/approval-store.js +23 -24
  121. package/dist/mcp/connect-store.d.ts +1 -0
  122. package/dist/mcp/connect-store.js +50 -49
  123. package/dist/mcp/oauth-store.d.ts +1 -0
  124. package/dist/mcp/oauth-store.js +24 -23
  125. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  126. package/dist/mcp-client/oauth-routes.js +20 -13
  127. package/dist/notifications/routes.d.ts +1 -1
  128. package/dist/notifications/store.d.ts +1 -0
  129. package/dist/notifications/store.js +14 -16
  130. package/dist/oauth-tokens/store.d.ts +1 -0
  131. package/dist/oauth-tokens/store.js +45 -31
  132. package/dist/observability/store.d.ts +1 -0
  133. package/dist/observability/store.js +24 -26
  134. package/dist/org/index.d.ts +1 -1
  135. package/dist/org/service-principal-policy.d.ts +1 -0
  136. package/dist/org/service-principal-policy.js +29 -28
  137. package/dist/progress/routes.d.ts +1 -1
  138. package/dist/progress/store.d.ts +1 -0
  139. package/dist/progress/store.js +27 -29
  140. package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
  141. package/dist/provider-api/actions/provider-api.d.ts +14 -9
  142. package/dist/provider-api/actions/provider-api.js +16 -1
  143. package/dist/provider-api/actions/staged-datasets.js +10 -2
  144. package/dist/provider-api/corpus-jobs-store.d.ts +1 -0
  145. package/dist/provider-api/corpus-jobs-store.js +81 -79
  146. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  147. package/dist/provider-api/corpus-jobs.js +43 -6
  148. package/dist/provider-api/custom-registry.d.ts +1 -0
  149. package/dist/provider-api/custom-registry.js +23 -17
  150. package/dist/provider-api/index.js +34 -2
  151. package/dist/provider-api/quota-governor.d.ts +1 -0
  152. package/dist/provider-api/quota-governor.js +33 -26
  153. package/dist/provider-api/staged-datasets-store.d.ts +57 -0
  154. package/dist/provider-api/staged-datasets-store.js +311 -149
  155. package/dist/provider-api/staging.js +14 -4
  156. package/dist/resource-changes/store.d.ts +1 -0
  157. package/dist/resource-changes/store.js +8 -7
  158. package/dist/resources/handlers.d.ts +1 -1
  159. package/dist/resources/store.d.ts +1 -0
  160. package/dist/resources/store.js +92 -56
  161. package/dist/review/store.d.ts +1 -0
  162. package/dist/review/store.js +27 -25
  163. package/dist/review/suggestions/store.d.ts +1 -0
  164. package/dist/review/suggestions/store.js +56 -50
  165. package/dist/search/index-store.d.ts +2 -2
  166. package/dist/search/index-store.js +6 -7
  167. package/dist/secrets/storage.d.ts +1 -0
  168. package/dist/secrets/storage.js +18 -17
  169. package/dist/server/action-discovery.js +6 -0
  170. package/dist/server/agent-chat/action-filters-a2a.js +11 -0
  171. package/dist/server/agent-chat/framework-prompts.js +6 -2
  172. package/dist/server/agent-chat-plugin.js +8 -16
  173. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  174. package/dist/server/agent-engine-default-model-route.d.ts +1 -1
  175. package/dist/server/agent-engine-ollama-models-route.d.ts +2 -2
  176. package/dist/server/agent-teams-run-queue.d.ts +1 -0
  177. package/dist/server/agent-teams-run-queue.js +21 -20
  178. package/dist/server/auth.d.ts +1 -0
  179. package/dist/server/auth.js +20 -17
  180. package/dist/server/embed-session.d.ts +1 -0
  181. package/dist/server/embed-session.js +34 -33
  182. package/dist/server/filesystem-action-entry.d.ts +7 -0
  183. package/dist/server/filesystem-action-entry.js +35 -0
  184. package/dist/server/google-oauth.d.ts +8 -0
  185. package/dist/server/google-oauth.js +8 -5
  186. package/dist/server/identity-sso-store.d.ts +1 -0
  187. package/dist/server/identity-sso-store.js +18 -27
  188. package/dist/server/poll.d.ts +2 -0
  189. package/dist/server/poll.js +74 -29
  190. package/dist/server/realtime-token.d.ts +1 -1
  191. package/dist/server/recap-image-store.d.ts +1 -0
  192. package/dist/server/recap-image-store.js +15 -14
  193. package/dist/server/release-migrations.js +54 -49
  194. package/dist/server/release-schema.d.ts +8 -27
  195. package/dist/server/release-schema.js +41 -314
  196. package/dist/server/request-context.d.ts +3 -0
  197. package/dist/server/self-dispatch.d.ts +9 -0
  198. package/dist/server/self-dispatch.js +20 -1
  199. package/dist/settings/store.d.ts +1 -0
  200. package/dist/settings/store.js +33 -23
  201. package/dist/shared/analytics-events.js +1 -0
  202. package/dist/sharing/access-request-store.d.ts +1 -0
  203. package/dist/sharing/access-request-store.js +17 -16
  204. package/dist/sharing/indexes.js +1 -0
  205. package/dist/templates/chat/.agents/skills/storing-data/SKILL.md +2 -2
  206. package/dist/templates/default/.agents/skills/storing-data/SKILL.md +2 -2
  207. package/dist/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +5 -0
  208. package/dist/templates/factory/.agents/skills/review-latest-feedback/references/chat-run-health.md +50 -0
  209. package/dist/templates/headless/.agents/skills/storing-data/SKILL.md +2 -2
  210. package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +2 -2
  211. package/dist/triggers/actions/manage-automation.d.ts +2 -2
  212. package/dist/triggers/event-queue.js +1 -0
  213. package/dist/triggers/webhook-store.d.ts +1 -0
  214. package/dist/triggers/webhook-store.js +14 -18
  215. package/dist/usage/alerts-store.d.ts +1 -0
  216. package/dist/usage/alerts-store.js +47 -48
  217. package/dist/usage/store.d.ts +1 -0
  218. package/dist/usage/store.js +67 -59
  219. package/dist/workspace-connections/groups.d.ts +1 -0
  220. package/dist/workspace-connections/groups.js +30 -42
  221. package/dist/workspace-connections/store.d.ts +1 -0
  222. package/dist/workspace-connections/store.js +17 -19
  223. package/docs/content/create-with-an-agent.mdx +160 -0
  224. package/docs/content/getting-started.mdx +3 -0
  225. package/docs/content/integrations.mdx +6 -2
  226. package/docs/content/template-clips-features.mdx +1 -1
  227. package/docs/content/tracking.mdx +1 -1
  228. package/package.json +4 -4
  229. package/src/templates/chat/.agents/skills/storing-data/SKILL.md +2 -2
  230. package/src/templates/default/.agents/skills/storing-data/SKILL.md +2 -2
  231. package/src/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +5 -0
  232. package/src/templates/factory/.agents/skills/review-latest-feedback/references/chat-run-health.md +50 -0
  233. package/src/templates/headless/.agents/skills/storing-data/SKILL.md +2 -2
  234. package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +2 -2
@@ -6,6 +6,7 @@ export interface A2ATaskListCursor {
6
6
  createdAt: number;
7
7
  id: string;
8
8
  }
9
+ export declare const a2aTasksStore: import("../db/store-registry.js").Store;
9
10
  export declare function ensureTable(): Promise<void>;
10
11
  export interface A2AApprovalRecord {
11
12
  id: string;
@@ -1,9 +1,8 @@
1
1
  import crypto from "crypto";
2
2
  import { getDbExec } from "../db/client.js";
3
3
  import { ensureTableExists, ensureColumnExists, ensureIndexExists, } from "../db/ddl-guard.js";
4
- import { retainRequestDbPoolScope } from "../db/request-pool-context.js";
4
+ import { defineStore } from "../db/store-registry.js";
5
5
  import { assertA2APersistablePayload } from "./persistence-safety.js";
6
- let _initPromise;
7
6
  export const MAX_A2A_IDEMPOTENCY_KEY_CHARS = 128;
8
7
  const A2A_IDEMPOTENCY_INDEX = "idx_a2a_tasks_owner_scope_idempotency";
9
8
  const A2A_ORG_IDEMPOTENCY_INDEX = "idx_a2a_tasks_org_scope_idempotency";
@@ -11,66 +10,68 @@ const A2A_RECOVERY_INDEX = "idx_a2a_tasks_recovery_created";
11
10
  export const A2A_PERSONAL_OWNER_SCOPE = "__personal__";
12
11
  export const A2A_ORG_ID_OWNER_SCOPE_PREFIX = "__a2a_org_id__:";
13
12
  const MAX_TASK_LIST_PAGE_SIZE = 100;
14
- export async function ensureTable() {
15
- if (!_initPromise) {
16
- const _initPromiseWithRequestDbPoolScope = (async () => {
17
- const createSql = `
18
- CREATE TABLE IF NOT EXISTS a2a_tasks (
19
- id TEXT PRIMARY KEY,
20
- context_id TEXT,
21
- status_state TEXT NOT NULL DEFAULT 'submitted',
22
- status_message TEXT,
23
- status_timestamp TEXT NOT NULL,
24
- history TEXT NOT NULL DEFAULT '[]',
25
- artifacts TEXT NOT NULL DEFAULT '[]',
26
- metadata TEXT,
27
- owner_email TEXT,
28
- owner_scope TEXT NOT NULL DEFAULT '',
29
- idempotency_key TEXT,
30
- created_at BIGINT NOT NULL,
31
- updated_at BIGINT NOT NULL
32
- )
33
- `;
34
- const createIdempotencyIndexSql = `CREATE UNIQUE INDEX IF NOT EXISTS ${A2A_IDEMPOTENCY_INDEX} ` +
35
- `ON a2a_tasks(owner_email, owner_scope, idempotency_key)`;
36
- const createOrgIdempotencyIndexSql = `CREATE UNIQUE INDEX IF NOT EXISTS ${A2A_ORG_IDEMPOTENCY_INDEX} ` +
37
- "ON a2a_tasks(owner_scope, idempotency_key) " +
38
- "WHERE owner_email IS NULL AND idempotency_key IS NOT NULL";
39
- const createRecoveryIndexSql = `CREATE INDEX IF NOT EXISTS ${A2A_RECOVERY_INDEX} ` +
40
- "ON a2a_tasks(created_at) " +
41
- "WHERE status_state IN ('submitted', 'working', 'processing')";
42
- const createApprovalsSql = `
43
- CREATE TABLE IF NOT EXISTS a2a_approvals (
44
- id TEXT PRIMARY KEY,
45
- task_id TEXT NOT NULL UNIQUE,
46
- owner_email TEXT NOT NULL,
47
- org_id TEXT,
48
- tool_name TEXT NOT NULL,
49
- tool_input TEXT NOT NULL,
50
- approval_key TEXT NOT NULL,
51
- call_id TEXT NOT NULL,
52
- status TEXT NOT NULL DEFAULT 'pending',
53
- result TEXT,
54
- expires_at BIGINT NOT NULL,
55
- created_at BIGINT NOT NULL,
56
- updated_at BIGINT NOT NULL
57
- )
58
- `;
59
- await ensureTableExists("a2a_tasks", createSql);
60
- await ensureColumnExists("a2a_tasks", "owner_email", `ALTER TABLE a2a_tasks ADD COLUMN IF NOT EXISTS owner_email TEXT`);
61
- await ensureColumnExists("a2a_tasks", "owner_scope", `ALTER TABLE a2a_tasks ADD COLUMN IF NOT EXISTS owner_scope TEXT NOT NULL DEFAULT ''`);
62
- await ensureColumnExists("a2a_tasks", "idempotency_key", `ALTER TABLE a2a_tasks ADD COLUMN IF NOT EXISTS idempotency_key TEXT`);
63
- await ensureIndexExists(A2A_IDEMPOTENCY_INDEX, createIdempotencyIndexSql);
64
- await ensureIndexExists(A2A_ORG_IDEMPOTENCY_INDEX, createOrgIdempotencyIndexSql);
65
- await ensureIndexExists(A2A_RECOVERY_INDEX, createRecoveryIndexSql);
66
- await ensureTableExists("a2a_approvals", createApprovalsSql);
67
- })().catch((err) => {
68
- _initPromise = undefined;
69
- throw err;
70
- });
71
- _initPromise = retainRequestDbPoolScope(_initPromiseWithRequestDbPoolScope);
72
- }
73
- return _initPromise;
13
+ export const a2aTasksStore = defineStore({
14
+ id: "a2a_tasks",
15
+ migrations: [
16
+ {
17
+ name: "baseline",
18
+ run: async () => {
19
+ const createSql = `
20
+ CREATE TABLE IF NOT EXISTS a2a_tasks (
21
+ id TEXT PRIMARY KEY,
22
+ context_id TEXT,
23
+ status_state TEXT NOT NULL DEFAULT 'submitted',
24
+ status_message TEXT,
25
+ status_timestamp TEXT NOT NULL,
26
+ history TEXT NOT NULL DEFAULT '[]',
27
+ artifacts TEXT NOT NULL DEFAULT '[]',
28
+ metadata TEXT,
29
+ owner_email TEXT,
30
+ owner_scope TEXT NOT NULL DEFAULT '',
31
+ idempotency_key TEXT,
32
+ created_at BIGINT NOT NULL,
33
+ updated_at BIGINT NOT NULL
34
+ )
35
+ `;
36
+ const createIdempotencyIndexSql = `CREATE UNIQUE INDEX IF NOT EXISTS ${A2A_IDEMPOTENCY_INDEX} ` +
37
+ `ON a2a_tasks(owner_email, owner_scope, idempotency_key)`;
38
+ const createOrgIdempotencyIndexSql = `CREATE UNIQUE INDEX IF NOT EXISTS ${A2A_ORG_IDEMPOTENCY_INDEX} ` +
39
+ "ON a2a_tasks(owner_scope, idempotency_key) " +
40
+ "WHERE owner_email IS NULL AND idempotency_key IS NOT NULL";
41
+ const createRecoveryIndexSql = `CREATE INDEX IF NOT EXISTS ${A2A_RECOVERY_INDEX} ` +
42
+ "ON a2a_tasks(created_at) " +
43
+ "WHERE status_state IN ('submitted', 'working', 'processing')";
44
+ const createApprovalsSql = `
45
+ CREATE TABLE IF NOT EXISTS a2a_approvals (
46
+ id TEXT PRIMARY KEY,
47
+ task_id TEXT NOT NULL UNIQUE,
48
+ owner_email TEXT NOT NULL,
49
+ org_id TEXT,
50
+ tool_name TEXT NOT NULL,
51
+ tool_input TEXT NOT NULL,
52
+ approval_key TEXT NOT NULL,
53
+ call_id TEXT NOT NULL,
54
+ status TEXT NOT NULL DEFAULT 'pending',
55
+ result TEXT,
56
+ expires_at BIGINT NOT NULL,
57
+ created_at BIGINT NOT NULL,
58
+ updated_at BIGINT NOT NULL
59
+ )
60
+ `;
61
+ await ensureTableExists("a2a_tasks", createSql);
62
+ await ensureColumnExists("a2a_tasks", "owner_email", `ALTER TABLE a2a_tasks ADD COLUMN IF NOT EXISTS owner_email TEXT`);
63
+ await ensureColumnExists("a2a_tasks", "owner_scope", `ALTER TABLE a2a_tasks ADD COLUMN IF NOT EXISTS owner_scope TEXT NOT NULL DEFAULT ''`);
64
+ await ensureColumnExists("a2a_tasks", "idempotency_key", `ALTER TABLE a2a_tasks ADD COLUMN IF NOT EXISTS idempotency_key TEXT`);
65
+ await ensureIndexExists(A2A_IDEMPOTENCY_INDEX, createIdempotencyIndexSql);
66
+ await ensureIndexExists(A2A_ORG_IDEMPOTENCY_INDEX, createOrgIdempotencyIndexSql);
67
+ await ensureIndexExists(A2A_RECOVERY_INDEX, createRecoveryIndexSql);
68
+ await ensureTableExists("a2a_approvals", createApprovalsSql);
69
+ },
70
+ },
71
+ ],
72
+ });
73
+ export function ensureTable() {
74
+ return a2aTasksStore.ready();
74
75
  }
75
76
  async function withDbTransaction(client, fn) {
76
77
  if (client.transaction)
@@ -1,8 +1,23 @@
1
1
  import type { ActionChangeResource, ActionPlanModeConfig } from "./action.js";
2
+ import type { ActionTool } from "./agent/types.js";
2
3
  export declare function actionCallIsReadOnly(entry: {
3
4
  readOnly?: boolean;
4
5
  planMode?: ActionPlanModeConfig<any>;
5
6
  }, params: unknown, fallback: boolean): boolean;
7
+ /**
8
+ * Whether re-running this call after an error or a lost result is safe. An
9
+ * action opts in with `retrySafe`; an undeclared action is not, so an
10
+ * ambiguous write keeps blocking the run. A predicate sees the arguments after
11
+ * the same gateway-string repair schema validation applies (`"true"` already
12
+ * `true`), never the raw model input a stringified flag could slip past a
13
+ * strict comparison in.
14
+ */
15
+ export declare function actionCallIsRetrySafe(entry: {
16
+ retrySafe?: boolean | ((input: any) => boolean);
17
+ tool?: {
18
+ parameters?: ActionTool["parameters"];
19
+ };
20
+ }, params: unknown): boolean;
6
21
  /**
7
22
  * Whether a successful call should publish an `action` change event.
8
23
  *
@@ -1,3 +1,4 @@
1
+ import { coerceGatewayStringifiedArgs } from "./action-input-coercion.js";
1
2
  export function actionCallIsReadOnly(entry, params, fallback) {
2
3
  const effect = entry.planMode?.effect;
3
4
  if (typeof effect === "string")
@@ -15,6 +16,29 @@ export function actionCallIsReadOnly(entry, params, fallback) {
15
16
  return entry.readOnly;
16
17
  return fallback;
17
18
  }
19
+ /**
20
+ * Whether re-running this call after an error or a lost result is safe. An
21
+ * action opts in with `retrySafe`; an undeclared action is not, so an
22
+ * ambiguous write keeps blocking the run. A predicate sees the arguments after
23
+ * the same gateway-string repair schema validation applies (`"true"` already
24
+ * `true`), never the raw model input a stringified flag could slip past a
25
+ * strict comparison in.
26
+ */
27
+ export function actionCallIsRetrySafe(entry, params) {
28
+ const { retrySafe } = entry;
29
+ if (typeof retrySafe === "boolean")
30
+ return retrySafe;
31
+ if (typeof retrySafe !== "function")
32
+ return false;
33
+ try {
34
+ return (retrySafe(coerceGatewayStringifiedArgs(params, entry.tool?.parameters)) === true);
35
+ }
36
+ catch {
37
+ // coercion-ok: a throwing predicate declares nothing, so the call stays
38
+ // conservative (blocked) rather than being treated as safe to replay.
39
+ return false;
40
+ }
41
+ }
18
42
  /**
19
43
  * Whether a successful call should publish an `action` change event.
20
44
  *
@@ -0,0 +1,10 @@
1
+ import type { ActionTool } from "./agent/types.js";
2
+ /**
3
+ * The repair a tool call's arguments get before schema validation: a gateway
4
+ * that stringifies `true`, `3`, or a JSON array/object is undone per the
5
+ * declared parameter type. Anything that reads a call's input to decide what
6
+ * the handler will do (`retrySafe`) must see this form, not the raw model
7
+ * input, or a stringified flag passes a strict comparison and still runs as
8
+ * `true`.
9
+ */
10
+ export declare function coerceGatewayStringifiedArgs(args: unknown, parameters?: ActionTool["parameters"]): unknown;
@@ -0,0 +1,77 @@
1
+ const NO_COERCE = Symbol("no-coerce");
2
+ function coerceStringToSchemaType(raw, types) {
3
+ const trimmed = raw.trim();
4
+ if (types.includes("boolean")) {
5
+ if (trimmed === "true")
6
+ return true;
7
+ if (trimmed === "false")
8
+ return false;
9
+ }
10
+ if ((types.includes("array") &&
11
+ trimmed.startsWith("[") &&
12
+ trimmed.endsWith("]")) ||
13
+ (types.includes("object") &&
14
+ trimmed.startsWith("{") &&
15
+ trimmed.endsWith("}"))) {
16
+ try {
17
+ const parsed = JSON.parse(trimmed);
18
+ if (types.includes("array") && Array.isArray(parsed))
19
+ return parsed;
20
+ if (types.includes("object") &&
21
+ parsed &&
22
+ typeof parsed === "object" &&
23
+ !Array.isArray(parsed)) {
24
+ return parsed;
25
+ }
26
+ // coercion-ok: unparseable text stays a string and schema validation rejects it
27
+ }
28
+ catch {
29
+ // fall through — leave the original so validation reports the real error
30
+ }
31
+ }
32
+ if ((types.includes("number") || types.includes("integer")) &&
33
+ trimmed !== "" &&
34
+ Number.isFinite(Number(trimmed))) {
35
+ const n = Number(trimmed);
36
+ if (types.includes("number") || Number.isInteger(n))
37
+ return n;
38
+ }
39
+ return NO_COERCE;
40
+ }
41
+ /**
42
+ * The repair a tool call's arguments get before schema validation: a gateway
43
+ * that stringifies `true`, `3`, or a JSON array/object is undone per the
44
+ * declared parameter type. Anything that reads a call's input to decide what
45
+ * the handler will do (`retrySafe`) must see this form, not the raw model
46
+ * input, or a stringified flag passes a strict comparison and still runs as
47
+ * `true`.
48
+ */
49
+ export function coerceGatewayStringifiedArgs(args, parameters) {
50
+ const properties = parameters?.properties;
51
+ if (!properties)
52
+ return args;
53
+ if (!args || typeof args !== "object" || Array.isArray(args))
54
+ return args;
55
+ let out = null;
56
+ for (const [key, raw] of Object.entries(args)) {
57
+ if (typeof raw !== "string")
58
+ continue;
59
+ const spec = properties[key];
60
+ if (!spec)
61
+ continue;
62
+ const types = Array.isArray(spec.type)
63
+ ? spec.type
64
+ : spec.type
65
+ ? [spec.type]
66
+ : [];
67
+ if (types.length === 0 || types.includes("string"))
68
+ continue;
69
+ const coerced = coerceStringToSchemaType(raw, types);
70
+ if (coerced === NO_COERCE)
71
+ continue;
72
+ if (!out)
73
+ out = { ...args };
74
+ out[key] = coerced;
75
+ }
76
+ return out ?? args;
77
+ }
package/dist/action.d.ts CHANGED
@@ -3,6 +3,11 @@ import { type ActionChatUIConfig } from "./action-ui.js";
3
3
  import type { ActionTool, AgentChatAttachment, AgentChatEvent } from "./agent/types.js";
4
4
  import type { ActionAuditConfig } from "./audit/types.js";
5
5
  import { type ActionAccessConfig } from "./authorization/action-access-runtime.js";
6
+ /**
7
+ * Carries an action's execution-frame key across `{ ...entry, run }` wrappers
8
+ * and the registry rebuilds that copy named fields (`preserveActionFlags`).
9
+ */
10
+ export declare const ACTION_EXECUTION_KEY: unique symbol;
6
11
  export type ActionCaller = "tool" | "http" | "frontend" | "mcp-widget" | "mcp-widget-write" | "cli" | "mcp" | "webmcp" | "a2a" | "automation";
7
12
  export interface ActionAutomationContext {
8
13
  triggerId: string;
@@ -308,6 +313,16 @@ interface DefineActionWithSchema<TSchema extends StandardSchemaV1, TReturn = any
308
313
  * names); return `null` when the call touches no resource or changed nothing. */
309
314
  changeResource?: (input: StandardSchemaV1.InferInput<TSchema>, result: TReturn) => ActionChangeResource | null | undefined;
310
315
  parallelSafe?: boolean;
316
+ /**
317
+ * Re-running this write after an error or a lost result cannot duplicate or
318
+ * corrupt data: it validates before it writes, or it sets an end state
319
+ * (replace-by-id, search-and-replace that fails loudly on a second run). The
320
+ * agent loop then lets the model correct its arguments and retry instead of
321
+ * ending the run as `write_tool_outcome_unknown`. Pass a predicate when only
322
+ * some inputs qualify. Do not set it on an action that appends, sends, or
323
+ * charges.
324
+ */
325
+ retrySafe?: boolean | ((input: StandardSchemaV1.InferInput<TSchema>) => boolean);
311
326
  endsTurn?: boolean;
312
327
  dedupe?: boolean;
313
328
  toolCallable?: boolean;
@@ -373,6 +388,8 @@ interface DefineActionWithParams<TParams extends Record<string, ParameterSchema>
373
388
  persistInBrowser?: boolean;
374
389
  changeResource?: (input: InferParams<TParams>, result: TReturn) => ActionChangeResource | null | undefined;
375
390
  parallelSafe?: boolean;
391
+ /** See `ActionDefinition.retrySafe`. */
392
+ retrySafe?: boolean | ((input: InferParams<TParams>) => boolean);
376
393
  endsTurn?: boolean;
377
394
  dedupe?: boolean;
378
395
  toolCallable?: boolean;
@@ -409,6 +426,7 @@ export interface ActionDefinition<TInput, TReturn> {
409
426
  readonly persistInBrowser?: boolean;
410
427
  readonly changeResource?: (input: TInput, result: TReturn) => ActionChangeResource | null | undefined;
411
428
  readonly parallelSafe?: boolean;
429
+ readonly retrySafe?: boolean | ((input: TInput) => boolean);
412
430
  readonly endsTurn?: boolean;
413
431
  readonly dedupe?: boolean;
414
432
  readonly toolCallable?: boolean;
@@ -449,6 +467,6 @@ type ActionExecutionRun = (args: any, ctx?: ActionRunContext) => Promise<any>;
449
467
  /** @internal Observe one public action invocation without transferring child refusals. */
450
468
  export declare function runActionWithExecutionOutcome(run: ActionExecutionRun, args: unknown, ctx: ActionRunContext | undefined, outcome: {
451
469
  refused: boolean;
452
- }): Promise<any>;
470
+ }, entry?: object): Promise<any>;
453
471
  export declare function validateActionArgs(schema: StandardSchemaV1, args: unknown, toolParameters?: ActionTool["parameters"], ctx?: object): Promise<any>;
454
472
  export {};
package/dist/action.js CHANGED
@@ -1,9 +1,15 @@
1
+ import { coerceGatewayStringifiedArgs } from "./action-input-coercion.js";
1
2
  import { normalizeActionChatUIConfig, } from "./action-ui.js";
2
3
  import { normalizeAuditConfig, resolveAuditAttach } from "./audit/config.js";
3
4
  import { assertRegisteredActionAccess, } from "./authorization/action-access-runtime.js";
4
5
  import { parseServiceIdentityEmail } from "./org/service-identity.js";
5
6
  import { getAsyncLocalStorageCtor } from "./shared/optional-node-builtins.js";
6
7
  import { wrapRunWithActionTracking } from "./tracking/action-lifecycle.js";
8
+ /**
9
+ * Carries an action's execution-frame key across `{ ...entry, run }` wrappers
10
+ * and the registry rebuilds that copy named fields (`preserveActionFlags`).
11
+ */
12
+ export const ACTION_EXECUTION_KEY = Symbol.for("agent-native.action.executionKey");
7
13
  export class ActionContractError extends Error {
8
14
  actionContractError = true;
9
15
  errorCode;
@@ -175,6 +181,10 @@ export function defineAction(options) {
175
181
  const parallelSafe = typeof options.parallelSafe === "boolean"
176
182
  ? options.parallelSafe
177
183
  : undefined;
184
+ const retrySafe = typeof options.retrySafe === "boolean" ||
185
+ typeof options.retrySafe === "function"
186
+ ? options.retrySafe
187
+ : undefined;
178
188
  const endsTurn = typeof options.endsTurn === "boolean" ? options.endsTurn : undefined;
179
189
  const dedupe = typeof options.dedupe === "boolean" ? options.dedupe : undefined;
180
190
  const publicAgent = options.publicAgent &&
@@ -204,7 +214,7 @@ export function defineAction(options) {
204
214
  return undefined;
205
215
  })();
206
216
  const chatUI = normalizeActionChatUIConfig(options.chatUI);
207
- return {
217
+ const entry = {
208
218
  tool: {
209
219
  ...(typeof options.title === "string" && options.title.trim()
210
220
  ? { title: options.title.trim() }
@@ -252,6 +262,7 @@ export function defineAction(options) {
252
262
  ? { changeResource: options.changeResource }
253
263
  : {}),
254
264
  ...(typeof parallelSafe === "boolean" ? { parallelSafe } : {}),
265
+ ...(retrySafe !== undefined ? { retrySafe } : {}),
255
266
  ...(typeof endsTurn === "boolean" ? { endsTurn } : {}),
256
267
  ...(typeof dedupe === "boolean" ? { dedupe } : {}),
257
268
  ...(typeof toolCallable === "boolean" ? { toolCallable } : {}),
@@ -288,6 +299,15 @@ export function defineAction(options) {
288
299
  ...(auditConfig ? { audit: auditConfig } : {}),
289
300
  ...(options.access ? { access: options.access } : {}),
290
301
  };
302
+ // Enumerable on purpose: an app that wraps `run` with `{ ...entry, run }`
303
+ // keeps the key, so the loop can still tell a pre-handler refusal from a
304
+ // handler failure. Without it the wrapper's own frame never becomes the
305
+ // action's frame and every validation error reads as an unknown write.
306
+ Object.defineProperty(entry, ACTION_EXECUTION_KEY, {
307
+ value: executionKey,
308
+ enumerable: true,
309
+ });
310
+ return entry;
291
311
  }
292
312
  export function isActionExposedToExternalAgents(entry) {
293
313
  if (entry.uiOnly === true)
@@ -671,74 +691,6 @@ function zodDefToJsonSchema(def) {
671
691
  }
672
692
  return { type: "string" };
673
693
  }
674
- const NO_COERCE = Symbol("no-coerce");
675
- function coerceStringToSchemaType(raw, types) {
676
- const trimmed = raw.trim();
677
- if (types.includes("boolean")) {
678
- if (trimmed === "true")
679
- return true;
680
- if (trimmed === "false")
681
- return false;
682
- }
683
- if ((types.includes("array") &&
684
- trimmed.startsWith("[") &&
685
- trimmed.endsWith("]")) ||
686
- (types.includes("object") &&
687
- trimmed.startsWith("{") &&
688
- trimmed.endsWith("}"))) {
689
- try {
690
- const parsed = JSON.parse(trimmed);
691
- if (types.includes("array") && Array.isArray(parsed))
692
- return parsed;
693
- if (types.includes("object") &&
694
- parsed &&
695
- typeof parsed === "object" &&
696
- !Array.isArray(parsed)) {
697
- return parsed;
698
- }
699
- }
700
- catch {
701
- // fall through — leave the original so validation reports the real error
702
- }
703
- }
704
- if ((types.includes("number") || types.includes("integer")) &&
705
- trimmed !== "" &&
706
- Number.isFinite(Number(trimmed))) {
707
- const n = Number(trimmed);
708
- if (types.includes("number") || Number.isInteger(n))
709
- return n;
710
- }
711
- return NO_COERCE;
712
- }
713
- function coerceGatewayStringifiedArgs(args, parameters) {
714
- const properties = parameters?.properties;
715
- if (!properties)
716
- return args;
717
- if (!args || typeof args !== "object" || Array.isArray(args))
718
- return args;
719
- let out = null;
720
- for (const [key, raw] of Object.entries(args)) {
721
- if (typeof raw !== "string")
722
- continue;
723
- const spec = properties[key];
724
- if (!spec)
725
- continue;
726
- const types = Array.isArray(spec.type)
727
- ? spec.type
728
- : spec.type
729
- ? [spec.type]
730
- : [];
731
- if (types.length === 0 || types.includes("string"))
732
- continue;
733
- const coerced = coerceStringToSchemaType(raw, types);
734
- if (coerced === NO_COERCE)
735
- continue;
736
- if (!out)
737
- out = { ...args };
738
- out[key] = coerced;
739
- }
740
- return out ?? args;
741
- }
742
694
  const MAX_SIGNATURE_DEPTH = 4;
743
695
  const MAX_SIGNATURE_LENGTH = 1200;
744
696
  function describeSchemaType(spec, depth) {
@@ -799,7 +751,8 @@ function wrapRunWithExecutionBoundary(run, key) {
799
751
  if (!actionExecutionStorage)
800
752
  return run(args, ctx);
801
753
  const parent = actionExecutionStorage.getStore();
802
- const frame = parent?.frame?.boundaryPending && parent.frame.run === boundaryRun
754
+ const frame = parent?.frame?.boundaryPending &&
755
+ (parent.frame.run === boundaryRun || parent.frame.key === key)
803
756
  ? parent.frame
804
757
  : {
805
758
  key,
@@ -830,14 +783,19 @@ function wrapRunWithExecutionBoundary(run, key) {
830
783
  return boundaryRun;
831
784
  }
832
785
  /** @internal Observe one public action invocation without transferring child refusals. */
833
- export async function runActionWithExecutionOutcome(run, args, ctx, outcome) {
786
+ export async function runActionWithExecutionOutcome(run, args, ctx, outcome, entry) {
834
787
  outcome.refused = false;
835
788
  // A mutable async stack cannot safely attribute overlapping invocations.
836
789
  if (!actionExecutionStorage)
837
790
  return run(args, ctx);
838
791
  const parent = actionExecutionStorage.getStore();
792
+ const entryKey = entry
793
+ ? entry[ACTION_EXECUTION_KEY]
794
+ : undefined;
839
795
  const frame = {
840
- key: {},
796
+ // The entry's own key lets its boundary adopt this frame when an app has
797
+ // wrapped `run`; an unkeyed entry gets a placeholder nothing can match.
798
+ key: entryKey !== null && typeof entryKey === "object" ? entryKey : {},
841
799
  run,
842
800
  parent: parent?.frame,
843
801
  handlerEntered: true,
@@ -857,10 +815,15 @@ export async function runActionWithExecutionOutcome(run, args, ctx, outcome) {
857
815
  ? state.failures.get(error)
858
816
  : undefined;
859
817
  // Error types cannot prove non-execution once the handler has entered.
818
+ // A keyed entry whose boundary was never entered threw in an app
819
+ // wrapper around `run`, before any handler could start.
860
820
  outcome.refused =
861
821
  !frame.descendantWriteEntered &&
862
- !frame.handlerEntered &&
863
- failure === frame;
822
+ ((!frame.handlerEntered && failure === frame) ||
823
+ (frame.key !== undefined &&
824
+ frame.boundaryPending === true &&
825
+ entryKey !== null &&
826
+ typeof entryKey === "object"));
864
827
  throw error;
865
828
  }
866
829
  });
@@ -1,6 +1,6 @@
1
1
  import { ssrfSafeFetch } from "../../extensions/url-safety.js";
2
2
  import { clearProviderCredentialAuthFailure, readDeployCredentialEnv, recordProviderCredentialAuthFailure, } from "../../server/credential-provider.js";
3
- import { allowsSamplingParams, anthropicManualThinkingBudget, normalizeReasoningEffortForModel, supportsClaudeAdaptiveThinking, } from "../../shared/reasoning-effort.js";
3
+ import { allowsSamplingParams, anthropicManualThinkingBudget, isGPTReasoningModel, normalizeReasoningEffortForModel, supportsClaudeAdaptiveThinking, } from "../../shared/reasoning-effort.js";
4
4
  import { isNodeRuntime } from "../../shared/runtime.js";
5
5
  import { AI_SDK_MODEL_CONFIG } from "../model-config.js";
6
6
  import { LLM_MISSING_CREDENTIALS_ERROR_CODE, LLM_MISSING_CREDENTIALS_MESSAGE, } from "./credential-errors.js";
@@ -364,6 +364,18 @@ class AISDKEngine {
364
364
  };
365
365
  }
366
366
  }
367
+ // @ai-sdk/openai infers reasoning models from its own id prefixes, which
368
+ // miss gpt-6-*. Without forceReasoning, Chat Completions sends max_tokens,
369
+ // which OpenAI rejects for reasoning models. isGPTReasoningModel also
370
+ // matches gpt-5-chat-*, which is not a reasoning model.
371
+ if (this.usesOpenAiChatCompletions() &&
372
+ isGPTReasoningModel(opts.model) &&
373
+ !/^(openai\/)?gpt-5-chat/i.test(opts.model)) {
374
+ providerOpts.openai = {
375
+ ...(providerOpts.openai ?? {}),
376
+ forceReasoning: true,
377
+ };
378
+ }
367
379
  const samplingAllowed = allowsSamplingParams({
368
380
  model: opts.model,
369
381
  thinkingEnabled: this.provider === "anthropic" &&
@@ -482,6 +494,13 @@ class AISDKEngine {
482
494
  firstEventAbort.cleanup();
483
495
  }
484
496
  }
497
+ // Provider construction and the OpenAI reasoning options must agree on the
498
+ // endpoint shape, so both read this one decision.
499
+ usesOpenAiChatCompletions() {
500
+ return (this.provider === "openai" &&
501
+ !this.forceResponses &&
502
+ isCustomOpenAiBaseUrl(this.baseUrl));
503
+ }
485
504
  async createProviderModel(model) {
486
505
  const pkg = PROVIDER_PACKAGES[this.provider];
487
506
  let providerModule;
@@ -511,9 +530,7 @@ class AISDKEngine {
511
530
  config.appUrl = this.appUrl;
512
531
  }
513
532
  const provider = createFn(config);
514
- return this.provider === "openai" &&
515
- !this.forceResponses &&
516
- isCustomOpenAiBaseUrl(this.baseUrl)
533
+ return this.usesOpenAiChatCompletions()
517
534
  ? provider.chat(model)
518
535
  : provider(model);
519
536
  }
@@ -12,6 +12,9 @@ export declare function attemptContinuationDispatch(params: {
12
12
  isLoopProtectionDispatchError: (err: unknown) => boolean;
13
13
  maxNestedSelfDispatchDepth: number;
14
14
  deps: ContinuationDispatchRetryDeps;
15
+ random?: () => number;
16
+ /** Wall clock for the overload budget; injectable so specs need no timers. */
17
+ now?: () => number;
15
18
  }): Promise<{
16
19
  dispatched: boolean;
17
20
  lastDispatchErr: unknown;