experimental-a2 0.17.0 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +1 -1
  3. package/dist/{actor-DBbe5xeE.d.ts → actor-C7b-1arn.d.ts} +5 -5
  4. package/dist/{actor-DBbe5xeE.d.ts.map → actor-C7b-1arn.d.ts.map} +1 -1
  5. package/dist/actor-client.d.ts +1 -1
  6. package/dist/actor-react.d.ts +3 -3
  7. package/dist/actor-react.js +1 -1
  8. package/dist/actor.d.ts +1 -1
  9. package/dist/actor.js +2 -2
  10. package/dist/{ai-vpGtcaCB.d.ts → ai-BMLlI2Ff.d.ts} +3 -3
  11. package/dist/{ai-vpGtcaCB.d.ts.map → ai-BMLlI2Ff.d.ts.map} +1 -1
  12. package/dist/{ai-UrWfKeuv.js → ai-D6mGlO8j.js} +2 -2
  13. package/dist/{ai-UrWfKeuv.js.map → ai-D6mGlO8j.js.map} +1 -1
  14. package/dist/ai-client.d.ts +2 -2
  15. package/dist/ai-client.js +2 -2
  16. package/dist/ai-fx.browser.d.ts +1 -0
  17. package/dist/ai-fx.browser.js +6 -0
  18. package/dist/ai-fx.browser.js.map +1 -0
  19. package/dist/ai-fx.d.ts +10 -0
  20. package/dist/ai-fx.d.ts.map +1 -0
  21. package/dist/ai-fx.js +692 -0
  22. package/dist/ai-fx.js.map +1 -0
  23. package/dist/ai-harness-B2suP2Qh.d.ts +26 -0
  24. package/dist/ai-harness-B2suP2Qh.d.ts.map +1 -0
  25. package/dist/ai-harness-BuLh_EYi.js +273 -0
  26. package/dist/ai-harness-BuLh_EYi.js.map +1 -0
  27. package/dist/ai-pi.browser.d.ts +1 -0
  28. package/dist/ai-pi.browser.js +6 -0
  29. package/dist/ai-pi.browser.js.map +1 -0
  30. package/dist/ai-pi.d.ts +17 -0
  31. package/dist/ai-pi.d.ts.map +1 -0
  32. package/dist/ai-pi.js +950 -0
  33. package/dist/ai-pi.js.map +1 -0
  34. package/dist/ai-react.d.ts +5 -5
  35. package/dist/ai-react.js +2 -2
  36. package/dist/ai-server.d.ts +47 -25
  37. package/dist/ai-server.d.ts.map +1 -1
  38. package/dist/ai-server.js +113 -40
  39. package/dist/ai-server.js.map +1 -1
  40. package/dist/ai-tool-input-DmSqMUQi.js +40 -0
  41. package/dist/ai-tool-input-DmSqMUQi.js.map +1 -0
  42. package/dist/ai.d.ts +1 -1
  43. package/dist/ai.js +1 -1
  44. package/dist/bounded-cache-CPHWF-8h.js +41 -0
  45. package/dist/bounded-cache-CPHWF-8h.js.map +1 -0
  46. package/dist/{client-COaiaDub.js → client-BhHLoNKF.js} +3 -3
  47. package/dist/{client-COaiaDub.js.map → client-BhHLoNKF.js.map} +1 -1
  48. package/dist/{client-qRnRUzBS.d.ts → client-h_DKFAjj.d.ts} +3 -3
  49. package/dist/{client-qRnRUzBS.d.ts.map → client-h_DKFAjj.d.ts.map} +1 -1
  50. package/dist/client.d.ts +3 -3
  51. package/dist/client.js +1 -1
  52. package/dist/index.d.ts +5 -5
  53. package/dist/{initial-snapshot-BrLso5x_.d.ts → initial-snapshot-Bx-c0pDP.d.ts} +2 -2
  54. package/dist/{initial-snapshot-BrLso5x_.d.ts.map → initial-snapshot-Bx-c0pDP.d.ts.map} +1 -1
  55. package/dist/{internal-CbVvEwad.js → internal-CscSY7K_.js} +11 -3
  56. package/dist/internal-CscSY7K_.js.map +1 -0
  57. package/dist/otel.d.ts +1 -1
  58. package/dist/{react-BbJ-g6Uu.d.ts → react-BBXgHWFc.d.ts} +4 -4
  59. package/dist/{react-BbJ-g6Uu.d.ts.map → react-BBXgHWFc.d.ts.map} +1 -1
  60. package/dist/react.d.ts +1 -1
  61. package/dist/react.js +1 -1
  62. package/dist/reducer-BAXc8JyF.js.map +1 -1
  63. package/dist/{reducer-BYu6DT7h.d.ts → reducer-CqA59Q6U.d.ts} +2 -2
  64. package/dist/{reducer-BYu6DT7h.d.ts.map → reducer-CqA59Q6U.d.ts.map} +1 -1
  65. package/dist/scheduler-qstash.d.ts +2 -2
  66. package/dist/scheduler-qstash.js +3 -3
  67. package/dist/scheduler-qstash.js.map +1 -1
  68. package/dist/scheduler-vercel.d.ts +7 -7
  69. package/dist/scheduler-vercel.d.ts.map +1 -1
  70. package/dist/scheduler-vercel.js +9 -10
  71. package/dist/scheduler-vercel.js.map +1 -1
  72. package/dist/{server-Rj64fNvX.js → server-D-Y4pqwu.js} +126 -67
  73. package/dist/server-D-Y4pqwu.js.map +1 -0
  74. package/dist/{server-CGM8WzRG.d.ts → server-DYAATFuT.d.ts} +42 -7
  75. package/dist/server-DYAATFuT.d.ts.map +1 -0
  76. package/dist/server.d.ts +4 -4
  77. package/dist/server.js +1 -1
  78. package/dist/{session-clear-Dshpuhff.d.ts → session-clear-C-QwTXV1.d.ts} +2 -2
  79. package/dist/session-clear-C-QwTXV1.d.ts.map +1 -0
  80. package/dist/{store-Gpkq7WBo.d.ts → store-CyLUy86v.d.ts} +53 -5
  81. package/dist/store-CyLUy86v.d.ts.map +1 -0
  82. package/dist/store-N8PXxDAS.js.map +1 -1
  83. package/dist/store-memory.d.ts +1 -1
  84. package/dist/store-memory.js +56 -11
  85. package/dist/store-memory.js.map +1 -1
  86. package/dist/{store-polling-4_y8lETm.js → store-polling-7WJV0YWP.js} +2 -2
  87. package/dist/{store-polling-4_y8lETm.js.map → store-polling-7WJV0YWP.js.map} +1 -1
  88. package/dist/store-postgres.d.ts +1 -1
  89. package/dist/store-postgres.d.ts.map +1 -1
  90. package/dist/store-postgres.js +106 -25
  91. package/dist/store-postgres.js.map +1 -1
  92. package/dist/{store-presence-polling-Q1C-k2dd.js → store-presence-polling-B1ixeqIS.js} +3 -3
  93. package/dist/{store-presence-polling-Q1C-k2dd.js.map → store-presence-polling-B1ixeqIS.js.map} +1 -1
  94. package/dist/store-redis-http.d.ts +1 -1
  95. package/dist/store-redis-http.js +3 -3
  96. package/dist/{store-redis-notify-tqWNnMRu.js → store-redis-notify-CM0AfLY0.js} +271 -101
  97. package/dist/store-redis-notify-CM0AfLY0.js.map +1 -0
  98. package/dist/store-redis.d.ts +1 -1
  99. package/dist/store-redis.js +1 -1
  100. package/dist/store-sqlite.d.ts +1 -1
  101. package/dist/store-sqlite.js +66 -21
  102. package/dist/store-sqlite.js.map +1 -1
  103. package/dist/{telemetry-cZH-cibj.d.ts → telemetry-Cyfqo6Qt.d.ts} +2 -2
  104. package/dist/telemetry-Cyfqo6Qt.d.ts.map +1 -0
  105. package/dist/{wire-DjfHOvdW.js → wire-BKxH1vbP.js} +2 -2
  106. package/dist/{wire-DjfHOvdW.js.map → wire-BKxH1vbP.js.map} +1 -1
  107. package/docs/01-quickstart.mdx +49 -83
  108. package/docs/{guides/07-examples.mdx → 02-examples.mdx} +10 -20
  109. package/docs/actors/01-introduction.mdx +48 -86
  110. package/docs/actors/02-concurrency.mdx +43 -70
  111. package/docs/actors/03-timers.mdx +28 -42
  112. package/docs/actors/04-routes.mdx +110 -150
  113. package/docs/actors/meta.ts +1 -1
  114. package/docs/agents/01-introduction.mdx +257 -0
  115. package/docs/agents/02-tools.mdx +247 -0
  116. package/docs/agents/03-conversations.mdx +538 -0
  117. package/docs/agents/04-harnesses.mdx +136 -0
  118. package/docs/agents/meta.ts +1 -0
  119. package/docs/client/01-react.mdx +294 -0
  120. package/docs/client/02-transports.mdx +86 -0
  121. package/docs/client/03-presence.mdx +224 -0
  122. package/docs/client/meta.ts +1 -0
  123. package/docs/contract/01-events.mdx +57 -0
  124. package/docs/contract/02-state.mdx +142 -0
  125. package/docs/contract/03-sessions.mdx +175 -0
  126. package/docs/index.mdx +109 -145
  127. package/docs/reference/01-core.mdx +139 -0
  128. package/docs/reference/02-server.mdx +860 -0
  129. package/docs/reference/03-client.mdx +301 -0
  130. package/docs/reference/04-ai.mdx +731 -0
  131. package/docs/reference/05-adapters.mdx +351 -0
  132. package/docs/reference/06-errors.mdx +138 -0
  133. package/docs/reference/meta.ts +1 -1
  134. package/docs/server/01-handlers.mdx +200 -0
  135. package/docs/server/02-timers.mdx +130 -0
  136. package/docs/server/03-cancellation.mdx +142 -0
  137. package/docs/server/04-routes.mdx +243 -0
  138. package/docs/server/05-production.mdx +323 -0
  139. package/docs/server/06-guarantees.mdx +132 -0
  140. package/examples/playground/DEPLOY.md +3 -5
  141. package/examples/playground/app/a0/[appId]/page.tsx +12 -13
  142. package/examples/playground/app/a0/app-list.tsx +9 -2
  143. package/examples/playground/app/a0/app-view.tsx +9 -1
  144. package/examples/playground/app/a0/apps/[appId]/route.ts +10 -5
  145. package/examples/playground/app/a0/apps.test.ts +12 -0
  146. package/examples/playground/app/a0/apps.ts +22 -7
  147. package/examples/playground/app/a0/chat.tsx +47 -1
  148. package/examples/playground/app/a0/devtools.tsx +2 -8
  149. package/examples/playground/app/a0/fx/events/route.ts +9 -0
  150. package/examples/playground/app/a0/fx/scheduler/route.ts +7 -0
  151. package/examples/playground/app/a0/fx/short/events/route.ts +11 -0
  152. package/examples/playground/app/a0/model.test.ts +18 -1
  153. package/examples/playground/app/a0/model.ts +47 -10
  154. package/examples/playground/app/a0/no-photon.cjs +4 -0
  155. package/examples/playground/app/a0/no-quickjs.cjs +3 -0
  156. package/examples/playground/app/a0/pi/events/route.ts +9 -0
  157. package/examples/playground/app/a0/pi/scheduler/route.ts +7 -0
  158. package/examples/playground/app/a0/pi/short/events/route.ts +11 -0
  159. package/examples/playground/app/a0/sandbox-log.ts +10 -4
  160. package/examples/playground/app/a0/sandbox-session.ts +152 -0
  161. package/examples/playground/app/a0/scheduler/route.ts +2 -2
  162. package/examples/playground/app/a0/server.ts +98 -54
  163. package/examples/playground/app/a0/session.ts +17 -5
  164. package/examples/playground/app/a0/shell.tsx +11 -3
  165. package/examples/playground/app/agent/ingress.test.ts +6 -3
  166. package/examples/playground/app/agent/server.ts +9 -6
  167. package/examples/playground/app/agent/telemetry.test.ts +71 -50
  168. package/examples/playground/app/canvas/[canvasId]/canvas-client.tsx +1 -1
  169. package/examples/playground/app/chat/server.test.ts +30 -26
  170. package/examples/playground/app/chat/server.ts +46 -46
  171. package/examples/playground/next.config.ts +17 -5
  172. package/examples/playground/package.json +4 -1
  173. package/examples/playground/vercel.json +18 -0
  174. package/package.json +27 -3
  175. package/src/ai-agent.ts +271 -90
  176. package/src/ai-fx.browser.ts +5 -0
  177. package/src/ai-fx.ts +912 -0
  178. package/src/ai-harness.ts +518 -0
  179. package/src/ai-model-metadata.ts +11 -6
  180. package/src/ai-pi.browser.ts +5 -0
  181. package/src/ai-pi.ts +1322 -0
  182. package/src/ai-sdk-step.ts +2 -2
  183. package/src/ai-server.ts +3 -1
  184. package/src/ai-tool-input.ts +45 -0
  185. package/src/internal.ts +13 -0
  186. package/src/libfx.d.ts +34 -0
  187. package/src/reducer.ts +1 -1
  188. package/src/scheduler-qstash.ts +5 -5
  189. package/src/scheduler-vercel.ts +14 -15
  190. package/src/server.ts +233 -29
  191. package/src/store-memory.ts +92 -16
  192. package/src/store-postgres.ts +156 -25
  193. package/src/store-redis-core.ts +322 -110
  194. package/src/store-redis-notify.ts +2 -0
  195. package/src/store-sqlite.ts +121 -28
  196. package/src/store.ts +55 -3
  197. package/src/telemetry.ts +1 -0
  198. package/dist/internal-CbVvEwad.js.map +0 -1
  199. package/dist/server-CGM8WzRG.d.ts.map +0 -1
  200. package/dist/server-Rj64fNvX.js.map +0 -1
  201. package/dist/session-clear-Dshpuhff.d.ts.map +0 -1
  202. package/dist/store-Gpkq7WBo.d.ts.map +0 -1
  203. package/dist/store-redis-notify-tqWNnMRu.js.map +0 -1
  204. package/dist/telemetry-cZH-cibj.d.ts.map +0 -1
  205. package/docs/concepts/01-contracts.mdx +0 -237
  206. package/docs/concepts/02-handlers.mdx +0 -284
  207. package/docs/concepts/03-durability.mdx +0 -314
  208. package/docs/concepts/04-state.mdx +0 -209
  209. package/docs/guides/01-timers.mdx +0 -193
  210. package/docs/guides/02-cancellation.mdx +0 -161
  211. package/docs/guides/03-react.mdx +0 -324
  212. package/docs/guides/04-local-first.mdx +0 -47
  213. package/docs/guides/05-production.mdx +0 -534
  214. package/docs/guides/06-ai-agents.mdx +0 -1408
  215. package/docs/guides/08-application-data.mdx +0 -113
  216. package/docs/guides/09-presence.mdx +0 -262
  217. package/docs/guides/10-transports.mdx +0 -221
  218. package/docs/reference/01-api.mdx +0 -2358
  219. package/docs/reference/02-errors.mdx +0 -150
  220. /package/docs/{concepts → contract}/meta.ts +0 -0
  221. /package/docs/{guides → server}/meta.ts +0 -0
package/dist/ai-server.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import { i as A2Error } from "./session-clear-DGI4jTQ5.js";
2
2
  import { a as reducer, s as validateSync } from "./reducer-BAXc8JyF.js";
3
- import { m as installAmbientToolScopeStorage, p as consumeSchedulerSendFailure } from "./internal-CbVvEwad.js";
4
- import { a as CONSOLE_TELEMETRY, l as boundedCache, o as setServerFetchHooks, t as createServer } from "./server-Rj64fNvX.js";
5
- import { A as interruptUIMessage, C as reduceToolActivity, D as flattenProgressBatches, E as upsertResponse, M as assertMessageBase, N as restoreMessageBase, O as progressBatches, S as projectedMessage, T as upsertMessage, _ as applyControlChanges, a as events, b as findMessage, d as appSlice, f as isAgentContract, g as initialControlState, h as aiEventId, j as pauseUIMessage, k as progressOwnedBy, m as AI_EVENT_ID_PREFIX, n as agentContract, p as withAIStorage, u as appReducerOf, v as controlCommit, w as retainMessageBase, y as advanceProjection } from "./ai-UrWfKeuv.js";
3
+ import { h as installAmbientToolScopeStorage, m as failedPreviousAttempt, p as consumeSchedulerSendFailure } from "./internal-CscSY7K_.js";
4
+ import { t as boundedCache } from "./bounded-cache-CPHWF-8h.js";
5
+ import { a as CONSOLE_TELEMETRY, o as setServerFetchHooks, t as createServer } from "./server-D-Y4pqwu.js";
6
+ import { A as interruptUIMessage, C as reduceToolActivity, D as flattenProgressBatches, E as upsertResponse, M as assertMessageBase, N as restoreMessageBase, O as progressBatches, S as projectedMessage, T as upsertMessage, _ as applyControlChanges, a as events, b as findMessage, d as appSlice, f as isAgentContract, g as initialControlState, h as aiEventId, j as pauseUIMessage, k as progressOwnedBy, m as AI_EVENT_ID_PREFIX, n as agentContract, p as withAIStorage, u as appReducerOf, v as controlCommit, w as retainMessageBase, y as advanceProjection } from "./ai-D6mGlO8j.js";
7
+ import { a as harnessDriver, o as harnessLog, s as harnessStates, u as registerHarnessStates } from "./ai-harness-BuLh_EYi.js";
6
8
  import { AsyncLocalStorage } from "node:async_hooks";
7
9
  import { createHash } from "node:crypto";
8
10
  import { asSchema, convertToModelMessages, isToolUIPart, stepCountIs, streamText, toUIMessageStream } from "ai";
@@ -1441,9 +1443,15 @@ const catalogUrl = "https://ai-gateway.vercel.sh/v1/models";
1441
1443
  const catalogLifetimeMs = 36e5;
1442
1444
  const catalogTimeoutMs = 5e3;
1443
1445
  let catalog;
1446
+ /**
1447
+ * The model's AI Gateway ID: the model string, unless an AI SDK global
1448
+ * provider resolves it to a model that is not Gateway's.
1449
+ */
1444
1450
  const gatewayModelId = (model) => {
1445
- if (typeof model === "string") return globalThis.AI_SDK_DEFAULT_PROVIDER === void 0 ? model : void 0;
1446
- return model.provider === "gateway" ? model.modelId : void 0;
1451
+ const provider = globalThis.AI_SDK_DEFAULT_PROVIDER;
1452
+ if (provider === void 0) return model;
1453
+ if (typeof provider.languageModel !== "function") return void 0;
1454
+ return provider.languageModel(model).provider === "gateway" ? model : void 0;
1447
1455
  };
1448
1456
  const readCatalog = () => {
1449
1457
  if (catalog && catalog.expiresAt > Date.now()) return catalog.promise;
@@ -1581,11 +1589,7 @@ const withModelSettings = (options) => {
1581
1589
  } }
1582
1590
  };
1583
1591
  };
1584
- const modelName = (model) => {
1585
- if (typeof model === "string") return model;
1586
- if ("modelId" in model && typeof model.modelId === "string") return model.modelId;
1587
- return "custom";
1588
- };
1592
+ const instructionTexts = (instructions) => instructions === void 0 ? [] : typeof instructions === "string" ? [instructions] : (Array.isArray(instructions) ? instructions : [instructions]).map((message) => message.content);
1589
1593
  const errorMessage = (error) => error instanceof Error ? error.message : String(error);
1590
1594
  const toolScopeStorage = installAmbientToolScopeStorage(() => new AsyncLocalStorage());
1591
1595
  /** Run `fn` with `ctx` as the ambient tool handler context, for direct tool tests. */
@@ -1707,7 +1711,12 @@ async function* consumeGeneration(options) {
1707
1711
  chunks: mergeDeltas(pending.splice(0))
1708
1712
  });
1709
1713
  const reader = options.source.stream.getReader();
1710
- let pendingChunk = reader.read();
1714
+ const readAhead = () => {
1715
+ const read = reader.read();
1716
+ read.catch(() => {});
1717
+ return read;
1718
+ };
1719
+ let pendingChunk = readAhead();
1711
1720
  try {
1712
1721
  for (;;) {
1713
1722
  let result;
@@ -1726,7 +1735,7 @@ async function* consumeGeneration(options) {
1726
1735
  pending.push(chunk);
1727
1736
  if (chunk.type === "finish") streamedFinishReason = chunk.finishReason;
1728
1737
  if (chunk.type === "error") streamedError = chunk.errorText;
1729
- pendingChunk = reader.read();
1738
+ pendingChunk = readAhead();
1730
1739
  if (pending.length >= maxChunks || isBoundaryChunk(pending.at(-1))) {
1731
1740
  yield batch();
1732
1741
  lastFlush = Date.now();
@@ -1736,7 +1745,6 @@ async function* consumeGeneration(options) {
1736
1745
  if (pending.length > 0) yield batch();
1737
1746
  throw error;
1738
1747
  } finally {
1739
- pendingChunk.catch(() => {});
1740
1748
  try {
1741
1749
  await reader.cancel();
1742
1750
  } catch {} finally {
@@ -1887,7 +1895,7 @@ const lifecycleEvents = async (options) => {
1887
1895
  ...chunk.title === void 0 ? {} : { title: chunk.title }
1888
1896
  };
1889
1897
  take(payload.toolCallId);
1890
- const classification = approvalClassification(options.tools, options.generation, chunk.toolName);
1898
+ const classification = options.approvals === false ? "automatic" : approvalClassification(options.tools, options.generation, chunk.toolName);
1891
1899
  if (classification === "automatic") result.push(await toolCalledEvent(payload));
1892
1900
  else pending.push({
1893
1901
  call: payload,
@@ -2028,19 +2036,50 @@ const validateCompaction = (options) => {
2028
2036
  }
2029
2037
  return compaction;
2030
2038
  };
2039
+ const AI_SDK_HARNESS_OPTIONS = [
2040
+ "generation",
2041
+ "generate",
2042
+ "compaction",
2043
+ "messageMetadata"
2044
+ ];
2045
+ const assertNoLoopOptions = (options) => {
2046
+ const harness = options.harness?.type ?? "ai-sdk";
2047
+ for (const key of AI_SDK_HARNESS_OPTIONS) {
2048
+ if (!Object.hasOwn(options, key)) continue;
2049
+ throw new TypeError(harness === "ai-sdk" ? `${key} belongs to the harness: agent({ harness: { type: 'ai-sdk', ${key} } })` : `${key} is an option of the AI SDK harness; ${harness}() runs its own loop`);
2050
+ }
2051
+ };
2031
2052
  function createHandlers(options) {
2032
2053
  if (options.model === void 0) throw new TypeError("agent requires model");
2033
2054
  if (options.progress?.maxChunks !== void 0 && (!Number.isInteger(options.progress.maxChunks) || options.progress.maxChunks < 1)) throw new TypeError("progress.maxChunks must be a positive integer");
2034
2055
  if (options.progress?.maxDelayMs !== void 0 && (!Number.isFinite(options.progress.maxDelayMs) || options.progress.maxDelayMs < 0)) throw new TypeError("progress.maxDelayMs must be a non-negative number");
2035
2056
  if (options.maxSteps !== void 0 && options.maxSteps !== Number.POSITIVE_INFINITY && (!Number.isInteger(options.maxSteps) || options.maxSteps < 1)) throw new TypeError("maxSteps must be a positive integer or Infinity");
2036
- const configuredCompaction = options.compaction ?? (options.generate === void 0 ? {} : false);
2057
+ assertNoLoopOptions(options);
2058
+ const configured = options.harness;
2059
+ const loop = configured?.type === "ai-sdk" ? configured : {};
2060
+ const harness = configured === void 0 || configured.type === "ai-sdk" ? void 0 : harnessDriver(configured);
2061
+ const states = options.harnessStates ?? harnessStates();
2062
+ if (harness !== void 0) for (const [name, tool] of Object.entries(options.tools ?? {})) {
2063
+ const needsApproval = tool.needsApproval;
2064
+ if (needsApproval !== void 0 && needsApproval !== false) throw new TypeError(`a harness runs tools without approval; '${name}' sets needsApproval`);
2065
+ }
2066
+ const configuredCompaction = loop.compaction ?? (loop.generate === void 0 && harness === void 0 ? {} : false);
2037
2067
  const staticCompaction = typeof configuredCompaction === "function" ? void 0 : validateCompaction({
2038
2068
  compaction: configuredCompaction,
2039
- explicit: options.compaction !== void 0,
2040
- generation: typeof options.generation === "function" ? void 0 : options.generation,
2069
+ explicit: loop.compaction !== void 0,
2070
+ generation: typeof loop.generation === "function" ? void 0 : loop.generation,
2041
2071
  tools: options.tools
2042
2072
  });
2043
- const tools = options.tools ?? {};
2073
+ const tools = harness === void 0 ? options.tools ?? {} : {
2074
+ ...harness.tools,
2075
+ ...options.tools
2076
+ };
2077
+ const toolRecovery = options.toolRecovery ?? {};
2078
+ for (const [name, recovery] of Object.entries(toolRecovery)) {
2079
+ if (!Object.hasOwn(tools, name)) throw new TypeError(`toolRecovery names '${name}', which is not one of the agent's tools`);
2080
+ if (typeof tools[name].execute !== "function") throw new TypeError(`toolRecovery names '${name}', which has no execute function`);
2081
+ if (recovery !== "rerun" && recovery !== "report") throw new TypeError(`toolRecovery for '${name}' must be 'rerun' or 'report'`);
2082
+ }
2044
2083
  const telemetry = options.telemetry ?? CONSOLE_TELEMETRY;
2045
2084
  const maxSteps = options.maxSteps ?? Number.POSITIVE_INFINITY;
2046
2085
  const control = createControlRuntime({
@@ -2126,13 +2165,14 @@ function createHandlers(options) {
2126
2165
  if (schedulerFailure === "retryable") throw error;
2127
2166
  return resultEvent(call, `${ctx.event.id}:execution:error`, { error: errorMessage(error) });
2128
2167
  };
2129
- const runToolExecution = async (ctx, call, execute, messages) => {
2168
+ const runToolExecution = async (ctx, call, execute, messages, sandbox) => {
2130
2169
  let output;
2131
2170
  try {
2132
2171
  output = await execute(call.input, {
2133
2172
  toolCallId: call.toolCallId,
2134
2173
  messages,
2135
- abortSignal: ctx.signal
2174
+ abortSignal: ctx.signal,
2175
+ ...sandbox === void 0 ? {} : { experimental_sandbox: sandbox }
2136
2176
  });
2137
2177
  } catch (error) {
2138
2178
  return toolExecutionFailure(ctx, call, error);
@@ -2183,13 +2223,27 @@ function createHandlers(options) {
2183
2223
  const { ctx, call } = input;
2184
2224
  const execute = tools[call.toolName]?.execute;
2185
2225
  if (execute === void 0) return resultEvent(call, `${ctx.event.id}:execution:error`, { error: `Tool '${call.toolName}' has no server executor` });
2226
+ const report = toolRecovery[call.toolName] === "report";
2227
+ const interrupted = () => resultEvent(call, `${ctx.event.id}:execution:error`, { error: `Tool '${call.toolName}' was interrupted and may have partly run.` });
2228
+ if (report && ctx.attempt > 1 && !failedPreviousAttempt.has(ctx)) return interrupted();
2186
2229
  const messages = await promptMessages(input);
2230
+ const sandbox = harness?.sandbox === void 0 ? void 0 : await resolve(harness.sandbox, {
2231
+ session: { id: ctx.session.id },
2232
+ signal: ctx.signal
2233
+ });
2187
2234
  if (checkAbort(ctx.signal)) return;
2188
2235
  const scope = {
2189
2236
  contract: options.contract,
2190
2237
  context: ctx
2191
2238
  };
2192
- return toolScopeStorage.run(scope, () => runToolExecution(ctx, call, execute, messages));
2239
+ const run = () => toolScopeStorage.run(scope, () => runToolExecution(ctx, call, execute, messages, sandbox));
2240
+ if (!report) return run();
2241
+ try {
2242
+ return await run() ?? await interrupted();
2243
+ } catch {
2244
+ checkAbort(ctx.signal);
2245
+ return interrupted();
2246
+ }
2193
2247
  };
2194
2248
  const handleToolExecution = async (ctx) => {
2195
2249
  try {
@@ -2304,7 +2358,7 @@ function createHandlers(options) {
2304
2358
  generationId,
2305
2359
  responseMessageId,
2306
2360
  attempt,
2307
- ...model === void 0 ? {} : { model: modelName(model) },
2361
+ ...model === void 0 ? {} : { model },
2308
2362
  promptThroughIndex: snapshot.index
2309
2363
  });
2310
2364
  let resolvedModel;
@@ -2313,23 +2367,23 @@ function createHandlers(options) {
2313
2367
  try {
2314
2368
  const choice = await resolve(options.model, resolverContext);
2315
2369
  if (choice === void 0) throw new TypeError("the model resolver returned undefined");
2316
- const settings = typeof choice === "string" || "specificationVersion" in choice ? { model: choice } : choice;
2370
+ const settings = typeof choice === "string" ? { model: choice } : choice;
2317
2371
  const model = settings.model;
2318
- if (typeof model !== "string" && (typeof model !== "object" || model === null)) throw new TypeError("the model resolver must return a model");
2372
+ if (typeof model !== "string" || model === "") throw new TypeError("the model must be an AI Gateway model ID");
2319
2373
  resolvedModel = model;
2320
2374
  if (checkAbort(ctx.signal)) return;
2321
2375
  const resolvedInstructions = options.instructions === void 0 ? void 0 : await resolve(options.instructions, resolverContext);
2322
2376
  if (checkAbort(ctx.signal)) return;
2323
- const resolvedGeneration = await resolve(options.generation ?? {}, resolverContext);
2377
+ const resolvedGeneration = await resolve(loop.generation ?? {}, resolverContext);
2324
2378
  if (checkAbort(ctx.signal)) return;
2325
2379
  if (resolvedGeneration === null || typeof resolvedGeneration !== "object" || Array.isArray(resolvedGeneration)) throw new TypeError("the generation resolver must return settings");
2326
2380
  const generation = withModelSettings({
2327
2381
  generation: resolvedGeneration,
2328
2382
  settings
2329
2383
  });
2330
- const compaction = typeof configuredCompaction === "function" || typeof options.generation === "function" ? validateCompaction({
2384
+ const compaction = typeof configuredCompaction === "function" || typeof loop.generation === "function" ? validateCompaction({
2331
2385
  compaction: typeof configuredCompaction === "function" ? await resolve(configuredCompaction, resolverContext) : staticCompaction,
2332
- explicit: options.compaction !== void 0,
2386
+ explicit: loop.compaction !== void 0,
2333
2387
  generation,
2334
2388
  tools: options.tools
2335
2389
  }) : staticCompaction;
@@ -2393,7 +2447,7 @@ function createHandlers(options) {
2393
2447
  });
2394
2448
  const inputTokens = measuredInputTokens({
2395
2449
  estimate: inputTokenEstimate,
2396
- model: modelName(resolvedModel),
2450
+ model: resolvedModel,
2397
2451
  calibration: coordinatorState.calibration
2398
2452
  });
2399
2453
  const threshold = policy.thresholdTokens ?? (limits === void 0 ? void 0 : Math.floor(Math.min(limits.contextWindow * .75, limits.contextWindow - (generation.maxOutputTokens ?? 0))));
@@ -2500,13 +2554,30 @@ function createHandlers(options) {
2500
2554
  messages: generationMessages,
2501
2555
  modelMessages
2502
2556
  };
2503
- const custom = options.generate !== void 0;
2504
2557
  const updates = consumeGeneration({
2505
- source: options.generate === void 0 ? await generateWithAISDK({
2558
+ source: harness !== void 0 ? await harness.step({
2559
+ agentName: options.contract.name,
2560
+ sessionId: ctx.event.sessionId,
2561
+ requestIndex: ctx.event.index,
2562
+ generationId,
2563
+ responseMessageId,
2564
+ throughIndex: snapshot.index,
2565
+ messages: generationMessages,
2566
+ model,
2567
+ ...settings.reasoning === void 0 ? {} : { reasoning: settings.reasoning },
2568
+ ...settings.speed === void 0 ? {} : { speed: settings.speed },
2569
+ instructions: instructionTexts(resolvedInstructions),
2570
+ tools,
2571
+ log: harnessLog({
2572
+ states,
2573
+ session: ctx.session
2574
+ }),
2575
+ signal: ctx.signal
2576
+ }) : loop.generate === void 0 ? await generateWithAISDK({
2506
2577
  agentName: options.contract.name,
2507
2578
  context: generateContext,
2508
- messageMetadata: options.messageMetadata
2509
- }) : { stream: await options.generate(generateContext) },
2579
+ messageMetadata: loop.messageMetadata
2580
+ }) : { stream: await loop.generate(generateContext) },
2510
2581
  ...options.progress === void 0 ? {} : { progress: options.progress }
2511
2582
  });
2512
2583
  let sequence = 0;
@@ -2530,7 +2601,7 @@ function createHandlers(options) {
2530
2601
  pending: pendingToolCalls,
2531
2602
  tools,
2532
2603
  generation,
2533
- custom
2604
+ approvals: harness === void 0
2534
2605
  });
2535
2606
  pendingToolCalls = lifecycle.pending;
2536
2607
  await control.append({
@@ -2559,9 +2630,9 @@ function createHandlers(options) {
2559
2630
  id: await aiEventId("a2.ai.completed", generationId),
2560
2631
  payload: completed
2561
2632
  };
2562
- const unresolved = options.generate ? pendingToolCalls.filter((pending) => pending.classification !== "automatic") : [];
2633
+ const unresolved = loop.generate ? pendingToolCalls.filter((pending) => pending.classification !== "automatic") : [];
2563
2634
  if (unresolved.length > 0) throw new Error(`generation ended with unresolved tool authorization for '${unresolved[0].call.toolName}'`);
2564
- const pendingEvents = await Promise.all(pendingToolCalls.filter((pending) => pending.classification === "automatic" || options.generate === void 0 && pending.classification === "unknown").map((pending) => toolCalledEvent(pending.call)));
2635
+ const pendingEvents = await Promise.all(pendingToolCalls.filter((pending) => pending.classification === "automatic" || loop.generate === void 0 && pending.classification === "unknown").map((pending) => toolCalledEvent(pending.call)));
2565
2636
  if (finish.finishReason === "tool-calls") return [...pendingEvents, completionEvent];
2566
2637
  forgetPrompt(ctx.event.sessionId, generationId);
2567
2638
  return [
@@ -2691,7 +2762,8 @@ function createHandlers(options) {
2691
2762
  };
2692
2763
  }
2693
2764
  function agent(options) {
2694
- const { model, tools, instructions, generation, maxSteps, messageMetadata, generate, compaction, progress, toolLane, handlers, ...rest } = options;
2765
+ assertNoLoopOptions(options);
2766
+ const { model, tools, instructions, maxSteps, harness, toolRecovery, progress, toolLane, handlers, ...rest } = options;
2695
2767
  let contract;
2696
2768
  let serverOptions;
2697
2769
  if ("contract" in rest) {
@@ -2709,17 +2781,17 @@ function agent(options) {
2709
2781
  });
2710
2782
  serverOptions = remaining;
2711
2783
  }
2784
+ const states = harnessStates();
2712
2785
  const builtIns = createHandlers({
2713
2786
  contract,
2714
2787
  model,
2788
+ harnessStates: states,
2715
2789
  ...serverOptions.telemetry === void 0 ? {} : { telemetry: serverOptions.telemetry },
2716
2790
  ...tools === void 0 ? {} : { tools },
2717
2791
  ...instructions === void 0 ? {} : { instructions },
2718
- ...generation === void 0 ? {} : { generation },
2719
2792
  ...maxSteps === void 0 ? {} : { maxSteps },
2720
- ...messageMetadata === void 0 ? {} : { messageMetadata },
2721
- ...generate === void 0 ? {} : { generate },
2722
- ...compaction === void 0 ? {} : { compaction },
2793
+ ...harness === void 0 ? {} : { harness },
2794
+ ...toolRecovery === void 0 ? {} : { toolRecovery },
2723
2795
  ...progress === void 0 ? {} : { progress },
2724
2796
  ...toolLane === void 0 ? {} : { toolLane }
2725
2797
  });
@@ -2732,6 +2804,7 @@ function agent(options) {
2732
2804
  ...handlers
2733
2805
  }
2734
2806
  });
2807
+ registerHarnessStates(server, states);
2735
2808
  const applicationEvents = "contract" in rest;
2736
2809
  setServerFetchHooks(server, { validateIngress: (context) => validateAgentIngress({
2737
2810
  context,