@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
@@ -1,20 +1,50 @@
1
+ import { SelfDispatchHttpError } from "../../server/self-dispatch.js";
2
+ // These statuses mean the endpoint is shedding load, not that the handoff is
3
+ // dead. They are waited out with jittered backoff instead of spending the short
4
+ // fixed attempt cap, which deferred the chunk to the sweep's multi-minute gap.
5
+ const OVERLOAD_STATUSES = new Set([429, 502, 503, 504, 520]);
6
+ const OVERLOAD_BACKOFF_BASE_MS = 1_000;
7
+ const OVERLOAD_BACKOFF_CAP_MS = 30_000;
8
+ const RETRY_AFTER_CLAMP_MS = 60_000;
9
+ // Full jitter can draw ~0 forever, so the wait budget alone never drains.
10
+ const MAX_OVERLOAD_RETRIES = 8;
11
+ /** Delay before the next try, or null when waiting any longer is pointless. */
12
+ function overloadBackoffMs(err, retriesSoFar, waitedMs, budgetMs, random) {
13
+ if (retriesSoFar >= MAX_OVERLOAD_RETRIES)
14
+ return null;
15
+ const remainingMs = budgetMs - waitedMs;
16
+ if (remainingMs <= 0)
17
+ return null;
18
+ const retryAfterMs = Math.min(err.retryAfterMs ?? 0, RETRY_AFTER_CLAMP_MS);
19
+ // The server asked for longer than this run can wait; the sweep owns it.
20
+ if (retryAfterMs > remainingMs)
21
+ return null;
22
+ const ceilingMs = Math.min(OVERLOAD_BACKOFF_CAP_MS, OVERLOAD_BACKOFF_BASE_MS * 2 ** retriesSoFar);
23
+ return Math.min(Math.max(random() * ceilingMs, retryAfterMs), remainingMs);
24
+ }
1
25
  export async function attemptContinuationDispatch(params) {
2
- const { event, backgroundContinuationCount, nextRunId, nextRowInserted, continuationDispatchPath, dispatchBody, dispatchBudget, isLoopProtectionDispatchError, maxNestedSelfDispatchDepth, deps: d, } = params;
26
+ const { event, backgroundContinuationCount, nextRunId, nextRowInserted, continuationDispatchPath, dispatchBody, dispatchBudget, isLoopProtectionDispatchError, maxNestedSelfDispatchDepth, deps: d, random = Math.random, now = Date.now, } = params;
3
27
  const maxDispatchAttempts = dispatchBudget.maxDispatchAttempts;
4
28
  const dispatchResponseTimeoutMs = dispatchBudget.dispatchResponseTimeoutMs;
29
+ const overloadWaitBudgetMs = dispatchBudget.overloadWaitBudgetMs;
5
30
  let dispatched = false;
6
31
  let lastDispatchErr;
7
32
  const nestedDepthExceeded = backgroundContinuationCount >= maxNestedSelfDispatchDepth;
8
33
  if (nestedDepthExceeded) {
9
34
  lastDispatchErr = new Error(`proactive nested-dispatch depth cap reached (backgroundContinuationCount=${backgroundContinuationCount} >= MAX_NESTED_SELF_DISPATCH_DEPTH=${maxNestedSelfDispatchDepth}) — deferring to the unclaimed-background-run sweep instead of risking Netlify loop protection`);
10
35
  }
11
- for (let attempt = 0; !nestedDepthExceeded && attempt < maxDispatchAttempts && !dispatched; attempt++) {
36
+ const startedAt = now();
37
+ // Overload retries are paid for by the wait budget, not the attempt cap.
38
+ let overloadRetries = 0;
39
+ let overloadWaitedMs = 0;
40
+ let failedAttempts = 0;
41
+ let nextBackoffMs = 0;
42
+ for (let attempt = 0; !nestedDepthExceeded &&
43
+ attempt < maxDispatchAttempts + overloadRetries &&
44
+ !dispatched; attempt++) {
12
45
  try {
13
46
  if (attempt > 0) {
14
- const backoffMs = Number.isFinite(dispatchBudget.backoffCapMs)
15
- ? Math.min(500 * 2 ** (attempt - 1), dispatchBudget.backoffCapMs)
16
- : 500 * 2 ** attempt;
17
- await d.sleep(backoffMs);
47
+ await d.sleep(nextBackoffMs);
18
48
  if (nextRowInserted) {
19
49
  await d.updateRunHeartbeat(nextRunId).catch(() => { });
20
50
  }
@@ -46,6 +76,23 @@ export async function attemptContinuationDispatch(params) {
46
76
  if (isLoopProtectionDispatchError(dispatchErr)) {
47
77
  break;
48
78
  }
79
+ if (dispatchErr instanceof SelfDispatchHttpError &&
80
+ OVERLOAD_STATUSES.has(dispatchErr.httpStatus)) {
81
+ const backoffMs = overloadBackoffMs(dispatchErr, overloadRetries,
82
+ // Slow overload responses spend the same host time as the sleeps.
83
+ Math.max(overloadWaitedMs, now() - startedAt), overloadWaitBudgetMs, random);
84
+ if (backoffMs === null)
85
+ break;
86
+ overloadRetries++;
87
+ overloadWaitedMs += backoffMs;
88
+ nextBackoffMs = backoffMs;
89
+ }
90
+ else {
91
+ failedAttempts++;
92
+ nextBackoffMs = Number.isFinite(dispatchBudget.backoffCapMs)
93
+ ? Math.min(500 * 2 ** (failedAttempts - 1), dispatchBudget.backoffCapMs)
94
+ : 500 * 2 ** failedAttempts;
95
+ }
49
96
  }
50
97
  }
51
98
  return { dispatched, lastDispatchErr, nestedDepthExceeded };
@@ -38,6 +38,7 @@ export interface SaveAgentHarnessSessionInput {
38
38
  expectedGeneration?: number;
39
39
  existingSession?: StoredAgentHarnessSession | null;
40
40
  }
41
+ export declare const agentHarnessSessionsStore: import("../../db/store-registry.js").Store;
41
42
  export declare function ensureAgentHarnessSessionTables(): Promise<void>;
42
43
  export declare function saveAgentHarnessSession(input: SaveAgentHarnessSessionInput): Promise<StoredAgentHarnessSession>;
43
44
  export declare function updateAgentHarnessSession(id: string, patch: Partial<Omit<SaveAgentHarnessSessionInput, "id">>): Promise<StoredAgentHarnessSession | null>;
@@ -1,6 +1,6 @@
1
1
  import { getDbExec } from "../../db/client.js";
2
2
  import { ensureColumnExists, ensureIndexExists, ensureTableExists, } from "../../db/ddl-guard.js";
3
- import { retainRequestDbPoolScope } from "../../db/request-pool-context.js";
3
+ import { defineStore } from "../../db/store-registry.js";
4
4
  export class AgentHarnessSessionConflictError extends Error {
5
5
  constructor(sessionId) {
6
6
  super(`Harness session ${sessionId} changed concurrently; retry the operation.`);
@@ -12,11 +12,13 @@ export function isAgentHarnessSessionConflictError(error) {
12
12
  (error instanceof Error &&
13
13
  error.name === "AgentHarnessSessionConflictError"));
14
14
  }
15
- let initPromise;
16
- export async function ensureAgentHarnessSessionTables() {
17
- if (!initPromise) {
18
- const initPromiseWithRequestDbPoolScope = (async () => {
19
- const createSql = `
15
+ export const agentHarnessSessionsStore = defineStore({
16
+ id: "agent_harness_sessions",
17
+ migrations: [
18
+ {
19
+ name: "baseline",
20
+ run: async () => {
21
+ const createSql = `
20
22
  CREATE TABLE IF NOT EXISTS agent_harness_sessions (
21
23
  id TEXT PRIMARY KEY,
22
24
  harness_name TEXT NOT NULL,
@@ -36,7 +38,6 @@ export async function ensureAgentHarnessSessionTables() {
36
38
  stopped_at BIGINT
37
39
  )
38
40
  `;
39
- {
40
41
  await ensureTableExists("agent_harness_sessions", createSql);
41
42
  for (const col of [
42
43
  "run_id",
@@ -55,15 +56,12 @@ export async function ensureAgentHarnessSessionTables() {
55
56
  await ensureIndexExists("idx_agent_harness_sessions_thread", `CREATE INDEX IF NOT EXISTS idx_agent_harness_sessions_thread ON agent_harness_sessions(thread_id, updated_at)`);
56
57
  await ensureIndexExists("idx_agent_harness_sessions_status", `CREATE INDEX IF NOT EXISTS idx_agent_harness_sessions_status ON agent_harness_sessions(status, updated_at)`);
57
58
  await ensureIndexExists("idx_agent_harness_sessions_owner", `CREATE INDEX IF NOT EXISTS idx_agent_harness_sessions_owner ON agent_harness_sessions(owner_email, updated_at)`);
58
- return;
59
- }
60
- })().catch((err) => {
61
- initPromise = undefined;
62
- throw err;
63
- });
64
- initPromise = retainRequestDbPoolScope(initPromiseWithRequestDbPoolScope);
65
- }
66
- return initPromise;
59
+ },
60
+ },
61
+ ],
62
+ });
63
+ export function ensureAgentHarnessSessionTables() {
64
+ return agentHarnessSessionsStore.ready();
67
65
  }
68
66
  export async function saveAgentHarnessSession(input) {
69
67
  await ensureAgentHarnessSessionTables();
@@ -12,6 +12,7 @@
12
12
  * runtime even before the migration plugin is registered.
13
13
  */
14
14
  import type { ObservationalMemoryEntry, ObservationalMemoryOwner, ObservationalMemoryTier } from "./types.js";
15
+ export declare const observationalMemoryStore: import("../../db/store-registry.js").Store;
15
16
  export declare function ensureTable(): Promise<void>;
16
17
  export declare function __resetObservationalMemoryTableCache(): void;
17
18
  export interface InsertObservationalMemoryInput extends ObservationalMemoryOwner {
@@ -13,15 +13,16 @@
13
13
  */
14
14
  import { getDbExec } from "../../db/client.js";
15
15
  import { ensureTableExists, ensureIndexExists } from "../../db/ddl-guard.js";
16
- import { retainRequestDbPoolScope } from "../../db/request-pool-context.js";
16
+ import { defineStore } from "../../db/store-registry.js";
17
17
  import { widenIntColumnsToBigInt } from "../../db/widen-columns.js";
18
- let tableReady = null;
19
- export async function ensureTable() {
20
- if (tableReady)
21
- return tableReady;
22
- tableReady = retainRequestDbPoolScope((async () => {
23
- const integerType = "BIGINT";
24
- const createSql = `CREATE TABLE IF NOT EXISTS observational_memory (
18
+ export const observationalMemoryStore = defineStore({
19
+ id: "observational_memory",
20
+ migrations: [
21
+ {
22
+ name: "baseline",
23
+ run: async () => {
24
+ const integerType = "BIGINT";
25
+ const createSql = `CREATE TABLE IF NOT EXISTS observational_memory (
25
26
  id TEXT PRIMARY KEY,
26
27
  thread_id TEXT NOT NULL,
27
28
  tier TEXT NOT NULL,
@@ -36,26 +37,29 @@ export async function ensureTable() {
36
37
  org_id TEXT,
37
38
  visibility TEXT NOT NULL DEFAULT 'private'
38
39
  )`;
39
- {
40
- await ensureTableExists("observational_memory", createSql);
41
- await widenIntColumnsToBigInt("observational_memory", [
42
- "created_at",
43
- "updated_at",
44
- ]);
45
- await ensureIndexExists("observational_memory_thread_tier_idx", `CREATE INDEX IF NOT EXISTS observational_memory_thread_tier_idx
40
+ await ensureTableExists("observational_memory", createSql);
41
+ await ensureIndexExists("observational_memory_thread_tier_idx", `CREATE INDEX IF NOT EXISTS observational_memory_thread_tier_idx
46
42
  ON observational_memory(thread_id, tier, created_at)`);
47
- await ensureIndexExists("observational_memory_thread_owner_idx", `CREATE INDEX IF NOT EXISTS observational_memory_thread_owner_idx
43
+ await ensureIndexExists("observational_memory_thread_owner_idx", `CREATE INDEX IF NOT EXISTS observational_memory_thread_owner_idx
48
44
  ON observational_memory(thread_id, owner_email)`);
49
- return;
50
- }
51
- })().catch((err) => {
52
- tableReady = null;
53
- throw err;
54
- }));
55
- return tableReady;
45
+ },
46
+ },
47
+ {
48
+ name: "widen-bigint",
49
+ run: async () => {
50
+ await widenIntColumnsToBigInt("observational_memory", [
51
+ "created_at",
52
+ "updated_at",
53
+ ]);
54
+ },
55
+ },
56
+ ],
57
+ });
58
+ export function ensureTable() {
59
+ return observationalMemoryStore.ready();
56
60
  }
57
61
  export function __resetObservationalMemoryTableCache() {
58
- tableReady = null;
62
+ observationalMemoryStore.reset();
59
63
  }
60
64
  function entryId() {
61
65
  return `om-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
@@ -187,6 +187,8 @@ export interface ActionEntry {
187
187
  persistInBrowser?: boolean;
188
188
  changeResource?: (input: any, result: any) => import("../action.js").ActionChangeResource | null | undefined;
189
189
  parallelSafe?: boolean;
190
+ /** See `ActionDefinition.retrySafe`. */
191
+ retrySafe?: boolean | ((input: any) => boolean);
190
192
  dedupe?: boolean;
191
193
  toolCallable?: boolean;
192
194
  agentDiscoveryAvailable?: (context?: import("../action.js").ActionRunContext) => boolean | Promise<boolean>;
@@ -357,7 +359,12 @@ export interface ProductionAgentOptions {
357
359
  runNoProgressTimeoutMs?: number;
358
360
  durableBackgroundRuns?: boolean;
359
361
  onRunStart?: (send: (event: AgentChatEvent) => void, threadId: string, runId: string) => void | Promise<void>;
360
- onEngineResolved?: (engine: AgentEngine, model: string) => void;
362
+ /**
363
+ * Called when the run's engine, model, and effort resolve, and again before
364
+ * each model call, because a call can run on a rate-limit fallback model or
365
+ * at the lower effort an empty-response retry steps down to.
366
+ */
367
+ onEngineResolved?: (engine: AgentEngine, model: string, reasoningEffort: ReasoningEffort | undefined) => void;
361
368
  resolveOwnerEmail?: (event: any) => string | Promise<string>;
362
369
  finalResponseGuard?: AgentLoopFinalResponseGuard;
363
370
  skipFilesContext?: boolean;
@@ -674,6 +681,12 @@ export declare function runAgentLoop(opts: {
674
681
  unknownWriteToolNames?: Set<string>;
675
682
  internalContinuation?: boolean;
676
683
  onModelInput?: ModelInputObserver;
684
+ /**
685
+ * The model and effort each model call uses. Either can change mid-run: a
686
+ * rate limit falls back to another model, and an empty response steps effort
687
+ * down.
688
+ */
689
+ onModelSettings?: (model: string, reasoningEffort: ReasoningEffort | undefined) => void;
677
690
  onUsage?: (usage: AgentLoopUsage) => void;
678
691
  onOutcome?: (outcome: AgentLoopOutcome) => void;
679
692
  ownerEmail?: string | null;
@@ -864,6 +877,8 @@ export interface ContinuationDispatchBudget {
864
877
  maxDispatchAttempts: number;
865
878
  dispatchResponseTimeoutMs: number;
866
879
  backoffCapMs: number;
880
+ /** Total sleep allowed while the target answers 429/502/503/504/520. */
881
+ overloadWaitBudgetMs: number;
867
882
  }
868
883
  export declare function resolveContinuationDispatchBudget(opts: {
869
884
  chainViaDurableBackground: boolean;
@@ -5,7 +5,7 @@ import Ajv2020 from "ajv/dist/2020.js";
5
5
  import { defineEventHandler, getHeader, setResponseHeader, setResponseStatus, getMethod, } from "h3";
6
6
  import "../authorization/check-action.js";
7
7
  import { parseA2AAgentActivityPart } from "../a2a/activity.js";
8
- import { actionCallEmitsChange, actionCallIsReadOnly, actionChangeResource, } from "../action-call-classification.js";
8
+ import { actionCallEmitsChange, actionCallIsReadOnly, actionCallIsRetrySafe, actionChangeResource, } from "../action-call-classification.js";
9
9
  import { ACTION_CHAT_UI_RECORD_CHANGE_RENDERER, normalizeActionChangeResult, } from "../action-ui.js";
10
10
  import { AgentConnectionRequiredError, describeToolParameterSignature, isActionContractError, runActionWithExecutionOutcome, isActionHiddenFromEveryAgentSurface, isAgentActionStopError, isAgentConnectionRequiredError, stripUnsupportedSchemaKeywords, } from "../action.js";
11
11
  import { getAppConfig } from "../app-config/index.js";
@@ -4584,6 +4584,7 @@ export async function runAgentLoop(opts) {
4584
4584
  : effectiveReasoningEffort,
4585
4585
  providerOptions,
4586
4586
  };
4587
+ opts.onModelSettings?.(model, effectiveReasoningEffort);
4587
4588
  usage.llmCalls = (usage.llmCalls ?? 0) + 1;
4588
4589
  notifyModelInputObserver(opts.onModelInput, engineMessages);
4589
4590
  const eventStream = engine.stream(streamOpts);
@@ -4952,7 +4953,7 @@ export async function runAgentLoop(opts) {
4952
4953
  fallbackModelAttempted = true;
4953
4954
  send({
4954
4955
  type: "activity",
4955
- label: `${model} is rate limited — switching to ${fallbackModel}`,
4956
+ label: "Model is rate limited — switching to a backup model",
4956
4957
  });
4957
4958
  send({ type: "clear" });
4958
4959
  model = fallbackModel;
@@ -4961,7 +4962,9 @@ export async function runAgentLoop(opts) {
4961
4962
  usage.cacheReadTokens = 0;
4962
4963
  usage.cacheWriteTokens = 0;
4963
4964
  usage.model = fallbackModel;
4964
- retry = -1;
4965
+ // The sibling shares the throttled quota, so it gets this one
4966
+ // attempt; a fresh retry budget only re-hits the same limit.
4967
+ retry = maxRetriesForError(err) - 1;
4965
4968
  continue;
4966
4969
  }
4967
4970
  }
@@ -5322,6 +5325,9 @@ export async function runAgentLoop(opts) {
5322
5325
  const actionIsReadOnly = actionEntry
5323
5326
  ? actionCallIsReadOnly(actionEntry, toolCall.input, false)
5324
5327
  : false;
5328
+ const actionRetrySafe = actionEntry
5329
+ ? actionCallIsRetrySafe(actionEntry, toolCall.input)
5330
+ : false;
5325
5331
  const repeatGuardStopFromThisCall = noteRepeatedToolCall(toolCall.name, toolCall.input, toolCall.id);
5326
5332
  const rollbackRepeatedToolCall = () => {
5327
5333
  const repeatKey = toolCallCacheKey(toolCall.name, toolCall.input);
@@ -5355,6 +5361,14 @@ export async function runAgentLoop(opts) {
5355
5361
  const emitToolDone = (event) => {
5356
5362
  if (event.outcomeUnknown) {
5357
5363
  unknownWriteToolNames.add(toolCall.name);
5364
+ }
5365
+ // A write that errored after it was invoked may still have committed,
5366
+ // retry-safe or not, so cached reads of its target are stale.
5367
+ if (event.outcomeUnknown ||
5368
+ (event.isError &&
5369
+ actionInvoked &&
5370
+ !actionIsReadOnly &&
5371
+ !actionRefused)) {
5358
5372
  readOnlyToolResultCache.clear();
5359
5373
  duplicateReadOnlyToolCalls.clear();
5360
5374
  }
@@ -5784,8 +5798,8 @@ export async function runAgentLoop(opts) {
5784
5798
  });
5785
5799
  recordToolResult(result, true);
5786
5800
  requestedActionStop ??= {
5787
- message: `I stopped because the ${toolCall.name} action was interrupted ${priorInterruptions} time(s) and its result is unknown. ` +
5788
- `Check whether it completed before asking me to retry.`,
5801
+ message: `I stopped before running ${toolCall.name} again. ${priorInterruptions === 1 ? "An earlier attempt" : `${priorInterruptions} earlier attempts`} may have already saved changes and I could not confirm the result. ` +
5802
+ `Check what was saved, then reply "continue" and I will verify it before doing anything else.`,
5789
5803
  errorCode: "write_tool_outcome_unknown",
5790
5804
  };
5791
5805
  return {
@@ -5930,6 +5944,10 @@ export async function runAgentLoop(opts) {
5930
5944
  let result;
5931
5945
  let chatUIResult;
5932
5946
  let isError = false;
5947
+ // A deadline or abort after invocation leaves a zombie that may still
5948
+ // commit, so a retry-safe action stays blocked for it; an error the
5949
+ // handler returned does not.
5950
+ let toolResultLost = false;
5933
5951
  let toolErrorCode;
5934
5952
  let mcpApp;
5935
5953
  let toolResultImages;
@@ -6001,7 +6019,7 @@ export async function runAgentLoop(opts) {
6001
6019
  ...(opts.turnId ? { turnId: opts.turnId } : {}),
6002
6020
  };
6003
6021
  actionInvoked = true;
6004
- return runActionWithExecutionOutcome(actionEntry.run, toolCall.input, actionContext, actionExecutionOutcome);
6022
+ return runActionWithExecutionOutcome(actionEntry.run, toolCall.input, actionContext, actionExecutionOutcome, actionEntry);
6005
6023
  };
6006
6024
  const actionPromise = Promise.resolve(runWithRequestContext({
6007
6025
  ...(requestContext ?? {}),
@@ -6179,6 +6197,9 @@ export async function runAgentLoop(opts) {
6179
6197
  }
6180
6198
  catch (err) {
6181
6199
  actionRefused = actionExecutionOutcome.refused;
6200
+ toolResultLost =
6201
+ signal.aborted ||
6202
+ isToolCallTimeoutResult(String(err?.message ?? err));
6182
6203
  toolErrorCode = isActionContractError(err)
6183
6204
  ? err.errorCode
6184
6205
  : undefined;
@@ -6286,7 +6307,10 @@ export async function runAgentLoop(opts) {
6286
6307
  ...(isError ? { isError: true } : {}),
6287
6308
  ...(toolErrorCode ? { errorCode: toolErrorCode } : {}),
6288
6309
  ...(isError
6289
- ? actionInvoked && !actionIsReadOnly && !actionRefused
6310
+ ? actionInvoked &&
6311
+ !actionIsReadOnly &&
6312
+ !actionRefused &&
6313
+ (!actionRetrySafe || toolResultLost)
6290
6314
  ? { outcomeUnknown: true }
6291
6315
  : { completedSideEffect: false }
6292
6316
  : receipt
@@ -7389,6 +7413,9 @@ export function resolveContinuationDispatchBudget(opts) {
7389
7413
  maxDispatchAttempts: 3,
7390
7414
  dispatchResponseTimeoutMs: 15_000,
7391
7415
  backoffCapMs: Infinity,
7416
+ // Durable-background chaining is entered from the foreground function,
7417
+ // which a host kills about 60s in, so it waits no longer than that tier.
7418
+ overloadWaitBudgetMs: 10_000,
7392
7419
  };
7393
7420
  }
7394
7421
  if (opts.workerProvenInBackgroundFunction) {
@@ -7396,12 +7423,17 @@ export function resolveContinuationDispatchBudget(opts) {
7396
7423
  maxDispatchAttempts: 5,
7397
7424
  dispatchResponseTimeoutMs: 15_000,
7398
7425
  backoffCapMs: 4_000,
7426
+ // The chain starts 2 minutes before the 15-minute background budget;
7427
+ // five hung dispatches plus backoff already take about 82s of that.
7428
+ overloadWaitBudgetMs: 30_000,
7399
7429
  };
7400
7430
  }
7431
+ // A hosted foreground function is killed soon after its soft timeout.
7401
7432
  return {
7402
7433
  maxDispatchAttempts: 2,
7403
7434
  dispatchResponseTimeoutMs: 10_000,
7404
7435
  backoffCapMs: Infinity,
7436
+ overloadWaitBudgetMs: 10_000,
7405
7437
  };
7406
7438
  }
7407
7439
  export function isLoopProtectionDispatchError(err) {
@@ -8539,7 +8571,7 @@ export function createProductionAgentHandler(options) {
8539
8571
  configuredEffort: options.reasoningEffort,
8540
8572
  });
8541
8573
  const modelSupportsVision = isAgentModelVisionCapable(effectiveModel, engine.capabilities.vision === true);
8542
- options.onEngineResolved?.(engine, effectiveModel);
8574
+ options.onEngineResolved?.(engine, effectiveModel, reasoningEffort);
8543
8575
  console.log(`[agent-chat] resolved engine=${engine.name} model=${effectiveModel} requestModel=${requestModel ?? "(none)"} requestEngine=${requestEngine ?? "(none)"} modelSource=${modelSelectionSource} engineDefault=${engine.defaultModel} effort=${reasoningEffort ?? "unset"} turnId=${requestTurnId ?? "(none)"}`);
8544
8576
  if (!(await isResolvedEngineUsableForRequest(engine, {
8545
8577
  apiKey: effectiveApiKey,
@@ -9792,9 +9824,26 @@ export function createProductionAgentHandler(options) {
9792
9824
  : "") +
9793
9825
  `\n</custom-agent-profile>`;
9794
9826
  let responseText = "";
9795
- const subUsage = await runAgentLoop({
9827
+ // A profile is its own model conversation running beside
9828
+ // others, so it gets its own run context: its model and effort
9829
+ // never stand in for another loop's, and it starts with
9830
+ // nothing read, since the run's reads are what the run's
9831
+ // model saw. New per-conversation fields reset here too.
9832
+ const profileRun = {
9833
+ ...getRequestRunContext(),
9834
+ model: profile.model ?? model,
9835
+ reasoningEffort,
9836
+ toolSearchReads: undefined,
9837
+ extensionContentReads: undefined,
9838
+ extensionExcerptReads: undefined,
9839
+ };
9840
+ const profileLoopOpts = {
9796
9841
  engine,
9797
9842
  model: profile.model ?? model,
9843
+ onModelSettings: (loopModel, effort) => {
9844
+ profileRun.model = loopModel;
9845
+ profileRun.reasoningEffort = effort;
9846
+ },
9798
9847
  systemPrompt: profilePrompt,
9799
9848
  tools: requestTools,
9800
9849
  availableTools: availableRequestTools,
@@ -9848,7 +9897,8 @@ export function createProductionAgentHandler(options) {
9848
9897
  ...(resolvedRunSoftTimeoutMs > 0
9849
9898
  ? { runSoftTimeoutMs: resolvedRunSoftTimeoutMs }
9850
9899
  : {}),
9851
- });
9900
+ };
9901
+ const subUsage = await runWithRequestContext({ ...getRequestContext(), run: profileRun }, () => runAgentLoop(profileLoopOpts));
9852
9902
  await control.flushEvents();
9853
9903
  try {
9854
9904
  const ownerEmail = options.resolveOwnerEmail
@@ -9968,6 +10018,9 @@ export function createProductionAgentHandler(options) {
9968
10018
  const agentLoopOpts = {
9969
10019
  engine,
9970
10020
  model: effectiveModel,
10021
+ // Custom agent profile loops report into their own run context
10022
+ // copies, so only this loop sets the run's model and effort.
10023
+ onModelSettings: (model, effort) => options.onEngineResolved?.(engine, model, effort),
9971
10024
  runId,
9972
10025
  followUpSuggestions: true,
9973
10026
  systemPrompt: requestSystemPrompt,
@@ -97,6 +97,7 @@ export declare class AgentTurnInitiatorMismatchError extends Error {
97
97
  export declare class AgentTurnInitiatorUnavailableError extends Error {
98
98
  constructor(threadId: string, turnId: string);
99
99
  }
100
+ export declare const agentRunsStore: import("../db/store-registry.js").Store;
100
101
  export declare function ensureRunTables(): Promise<void>;
101
102
  /**
102
103
  * Persist a zombie tool-call completion to the ledger. Called by the detached