@loopingai/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +279 -0
  3. package/dist/a2a/agent-stub.d.ts +61 -0
  4. package/dist/a2a/agent-stub.d.ts.map +1 -0
  5. package/dist/a2a/agent-stub.js +2 -0
  6. package/dist/a2a/agent-stub.js.map +1 -0
  7. package/dist/a2a/card.d.ts +119 -0
  8. package/dist/a2a/card.d.ts.map +1 -0
  9. package/dist/a2a/card.js +115 -0
  10. package/dist/a2a/card.js.map +1 -0
  11. package/dist/a2a/context.d.ts +14 -0
  12. package/dist/a2a/context.d.ts.map +1 -0
  13. package/dist/a2a/context.js +55 -0
  14. package/dist/a2a/context.js.map +1 -0
  15. package/dist/a2a/executor.d.ts +85 -0
  16. package/dist/a2a/executor.d.ts.map +1 -0
  17. package/dist/a2a/executor.js +107 -0
  18. package/dist/a2a/executor.js.map +1 -0
  19. package/dist/a2a/index.d.ts +18 -0
  20. package/dist/a2a/index.d.ts.map +1 -0
  21. package/dist/a2a/index.js +17 -0
  22. package/dist/a2a/index.js.map +1 -0
  23. package/dist/a2a/notify.d.ts +75 -0
  24. package/dist/a2a/notify.d.ts.map +1 -0
  25. package/dist/a2a/notify.js +161 -0
  26. package/dist/a2a/notify.js.map +1 -0
  27. package/dist/a2a/parts.d.ts +46 -0
  28. package/dist/a2a/parts.d.ts.map +1 -0
  29. package/dist/a2a/parts.js +95 -0
  30. package/dist/a2a/parts.js.map +1 -0
  31. package/dist/a2a/task-store.d.ts +45 -0
  32. package/dist/a2a/task-store.d.ts.map +1 -0
  33. package/dist/a2a/task-store.js +100 -0
  34. package/dist/a2a/task-store.js.map +1 -0
  35. package/dist/a2a/task.d.ts +86 -0
  36. package/dist/a2a/task.d.ts.map +1 -0
  37. package/dist/a2a/task.js +16 -0
  38. package/dist/a2a/task.js.map +1 -0
  39. package/dist/a2a/verify.d.ts +64 -0
  40. package/dist/a2a/verify.d.ts.map +1 -0
  41. package/dist/a2a/verify.js +122 -0
  42. package/dist/a2a/verify.js.map +1 -0
  43. package/dist/agent/budget.d.ts +47 -0
  44. package/dist/agent/budget.d.ts.map +1 -0
  45. package/dist/agent/budget.js +43 -0
  46. package/dist/agent/budget.js.map +1 -0
  47. package/dist/agent/control.d.ts +110 -0
  48. package/dist/agent/control.d.ts.map +1 -0
  49. package/dist/agent/control.js +115 -0
  50. package/dist/agent/control.js.map +1 -0
  51. package/dist/agent/final-reply.d.ts +49 -0
  52. package/dist/agent/final-reply.d.ts.map +1 -0
  53. package/dist/agent/final-reply.js +52 -0
  54. package/dist/agent/final-reply.js.map +1 -0
  55. package/dist/agent/history.d.ts +83 -0
  56. package/dist/agent/history.d.ts.map +1 -0
  57. package/dist/agent/history.js +117 -0
  58. package/dist/agent/history.js.map +1 -0
  59. package/dist/agent/index.d.ts +17 -0
  60. package/dist/agent/index.d.ts.map +1 -0
  61. package/dist/agent/index.js +17 -0
  62. package/dist/agent/index.js.map +1 -0
  63. package/dist/agent/inference.d.ts +52 -0
  64. package/dist/agent/inference.d.ts.map +1 -0
  65. package/dist/agent/inference.js +79 -0
  66. package/dist/agent/inference.js.map +1 -0
  67. package/dist/agent/model.d.ts +75 -0
  68. package/dist/agent/model.d.ts.map +1 -0
  69. package/dist/agent/model.js +62 -0
  70. package/dist/agent/model.js.map +1 -0
  71. package/dist/agent/session.d.ts +92 -0
  72. package/dist/agent/session.d.ts.map +1 -0
  73. package/dist/agent/session.js +80 -0
  74. package/dist/agent/session.js.map +1 -0
  75. package/dist/config.d.ts +159 -0
  76. package/dist/config.d.ts.map +1 -0
  77. package/dist/config.js +92 -0
  78. package/dist/config.js.map +1 -0
  79. package/dist/contract/index.d.ts +10 -0
  80. package/dist/contract/index.d.ts.map +1 -0
  81. package/dist/contract/index.js +9 -0
  82. package/dist/contract/index.js.map +1 -0
  83. package/dist/contract/plugin.d.ts +163 -0
  84. package/dist/contract/plugin.d.ts.map +1 -0
  85. package/dist/contract/plugin.js +39 -0
  86. package/dist/contract/plugin.js.map +1 -0
  87. package/dist/contract/recipe.d.ts +170 -0
  88. package/dist/contract/recipe.d.ts.map +1 -0
  89. package/dist/contract/recipe.js +2 -0
  90. package/dist/contract/recipe.js.map +1 -0
  91. package/dist/contract/validation.d.ts +86 -0
  92. package/dist/contract/validation.d.ts.map +1 -0
  93. package/dist/contract/validation.js +76 -0
  94. package/dist/contract/validation.js.map +1 -0
  95. package/dist/db/db.d.ts +131 -0
  96. package/dist/db/db.d.ts.map +1 -0
  97. package/dist/db/db.js +91 -0
  98. package/dist/db/db.js.map +1 -0
  99. package/dist/db/index.d.ts +9 -0
  100. package/dist/db/index.d.ts.map +1 -0
  101. package/dist/db/index.js +9 -0
  102. package/dist/db/index.js.map +1 -0
  103. package/dist/db/migrations/index.d.ts +21 -0
  104. package/dist/db/migrations/index.d.ts.map +1 -0
  105. package/dist/db/migrations/index.js +54 -0
  106. package/dist/db/migrations/index.js.map +1 -0
  107. package/dist/db/models/subtasks.d.ts +102 -0
  108. package/dist/db/models/subtasks.d.ts.map +1 -0
  109. package/dist/db/models/subtasks.js +285 -0
  110. package/dist/db/models/subtasks.js.map +1 -0
  111. package/dist/db/models/tasks.d.ts +92 -0
  112. package/dist/db/models/tasks.d.ts.map +1 -0
  113. package/dist/db/models/tasks.js +212 -0
  114. package/dist/db/models/tasks.js.map +1 -0
  115. package/dist/db/schema.d.ts +488 -0
  116. package/dist/db/schema.d.ts.map +1 -0
  117. package/dist/db/schema.js +91 -0
  118. package/dist/db/schema.js.map +1 -0
  119. package/dist/env.d.ts +46 -0
  120. package/dist/env.d.ts.map +1 -0
  121. package/dist/env.js +40 -0
  122. package/dist/env.js.map +1 -0
  123. package/dist/index.d.ts +20 -0
  124. package/dist/index.d.ts.map +1 -0
  125. package/dist/index.js +18 -0
  126. package/dist/index.js.map +1 -0
  127. package/dist/platform.d.ts +47 -0
  128. package/dist/platform.d.ts.map +1 -0
  129. package/dist/platform.js +47 -0
  130. package/dist/platform.js.map +1 -0
  131. package/dist/runtime/index.d.ts +86 -0
  132. package/dist/runtime/index.d.ts.map +1 -0
  133. package/dist/runtime/index.js +123 -0
  134. package/dist/runtime/index.js.map +1 -0
  135. package/dist/runtime/tool-families.d.ts +33 -0
  136. package/dist/runtime/tool-families.d.ts.map +1 -0
  137. package/dist/runtime/tool-families.js +62 -0
  138. package/dist/runtime/tool-families.js.map +1 -0
  139. package/dist/subagent/fingerprint.d.ts +38 -0
  140. package/dist/subagent/fingerprint.d.ts.map +1 -0
  141. package/dist/subagent/fingerprint.js +97 -0
  142. package/dist/subagent/fingerprint.js.map +1 -0
  143. package/dist/subagent/index.d.ts +147 -0
  144. package/dist/subagent/index.d.ts.map +1 -0
  145. package/dist/subagent/index.js +299 -0
  146. package/dist/subagent/index.js.map +1 -0
  147. package/dist/subagent/prompt.d.ts +34 -0
  148. package/dist/subagent/prompt.d.ts.map +1 -0
  149. package/dist/subagent/prompt.js +46 -0
  150. package/dist/subagent/prompt.js.map +1 -0
  151. package/dist/subagent/run.d.ts +151 -0
  152. package/dist/subagent/run.d.ts.map +1 -0
  153. package/dist/subagent/run.js +491 -0
  154. package/dist/subagent/run.js.map +1 -0
  155. package/dist/subagent/workspace.d.ts +65 -0
  156. package/dist/subagent/workspace.d.ts.map +1 -0
  157. package/dist/subagent/workspace.js +53 -0
  158. package/dist/subagent/workspace.js.map +1 -0
  159. package/dist/subtasks/catalog.d.ts +40 -0
  160. package/dist/subtasks/catalog.d.ts.map +1 -0
  161. package/dist/subtasks/catalog.js +36 -0
  162. package/dist/subtasks/catalog.js.map +1 -0
  163. package/dist/subtasks/decomposition.d.ts +90 -0
  164. package/dist/subtasks/decomposition.d.ts.map +1 -0
  165. package/dist/subtasks/decomposition.js +205 -0
  166. package/dist/subtasks/decomposition.js.map +1 -0
  167. package/dist/subtasks/delegate.d.ts +77 -0
  168. package/dist/subtasks/delegate.d.ts.map +1 -0
  169. package/dist/subtasks/delegate.js +102 -0
  170. package/dist/subtasks/delegate.js.map +1 -0
  171. package/dist/subtasks/index.d.ts +11 -0
  172. package/dist/subtasks/index.d.ts.map +1 -0
  173. package/dist/subtasks/index.js +11 -0
  174. package/dist/subtasks/index.js.map +1 -0
  175. package/dist/subtasks/scheduler.d.ts +49 -0
  176. package/dist/subtasks/scheduler.d.ts.map +1 -0
  177. package/dist/subtasks/scheduler.js +48 -0
  178. package/dist/subtasks/scheduler.js.map +1 -0
  179. package/dist/subtasks/subtask-types.d.ts +100 -0
  180. package/dist/subtasks/subtask-types.d.ts.map +1 -0
  181. package/dist/subtasks/subtask-types.js +111 -0
  182. package/dist/subtasks/subtask-types.js.map +1 -0
  183. package/dist/subtasks/types.d.ts +321 -0
  184. package/dist/subtasks/types.d.ts.map +1 -0
  185. package/dist/subtasks/types.js +16 -0
  186. package/dist/subtasks/types.js.map +1 -0
  187. package/dist/testing/auth.d.ts +12 -0
  188. package/dist/testing/auth.d.ts.map +1 -0
  189. package/dist/testing/auth.js +25 -0
  190. package/dist/testing/auth.js.map +1 -0
  191. package/dist/testing/do.d.ts +30 -0
  192. package/dist/testing/do.d.ts.map +1 -0
  193. package/dist/testing/do.js +26 -0
  194. package/dist/testing/do.js.map +1 -0
  195. package/dist/testing/fake-session.d.ts +27 -0
  196. package/dist/testing/fake-session.d.ts.map +1 -0
  197. package/dist/testing/fake-session.js +38 -0
  198. package/dist/testing/fake-session.js.map +1 -0
  199. package/dist/testing/fixtures.d.ts +27 -0
  200. package/dist/testing/fixtures.d.ts.map +1 -0
  201. package/dist/testing/fixtures.js +67 -0
  202. package/dist/testing/fixtures.js.map +1 -0
  203. package/dist/testing/index.d.ts +31 -0
  204. package/dist/testing/index.d.ts.map +1 -0
  205. package/dist/testing/index.js +31 -0
  206. package/dist/testing/index.js.map +1 -0
  207. package/dist/testing/mock-model.d.ts +43 -0
  208. package/dist/testing/mock-model.d.ts.map +1 -0
  209. package/dist/testing/mock-model.js +62 -0
  210. package/dist/testing/mock-model.js.map +1 -0
  211. package/dist/testing/node.d.ts +24 -0
  212. package/dist/testing/node.d.ts.map +1 -0
  213. package/dist/testing/node.js +24 -0
  214. package/dist/testing/node.js.map +1 -0
  215. package/dist/testing/vcr-global-setup.d.ts +3 -0
  216. package/dist/testing/vcr-global-setup.d.ts.map +1 -0
  217. package/dist/testing/vcr-global-setup.js +9 -0
  218. package/dist/testing/vcr-global-setup.js.map +1 -0
  219. package/dist/testing/vcr-shared.d.ts +21 -0
  220. package/dist/testing/vcr-shared.d.ts.map +1 -0
  221. package/dist/testing/vcr-shared.js +21 -0
  222. package/dist/testing/vcr-shared.js.map +1 -0
  223. package/dist/testing/vcr-spec.d.ts +17 -0
  224. package/dist/testing/vcr-spec.d.ts.map +1 -0
  225. package/dist/testing/vcr-spec.js +72 -0
  226. package/dist/testing/vcr-spec.js.map +1 -0
  227. package/dist/testing/vcr.d.ts +81 -0
  228. package/dist/testing/vcr.d.ts.map +1 -0
  229. package/dist/testing/vcr.js +211 -0
  230. package/dist/testing/vcr.js.map +1 -0
  231. package/dist/worker/index.d.ts +62 -0
  232. package/dist/worker/index.d.ts.map +1 -0
  233. package/dist/worker/index.js +194 -0
  234. package/dist/worker/index.js.map +1 -0
  235. package/eslint-rules/index.js +31 -0
  236. package/eslint-rules/no-deprecated-object-properties.js +81 -0
  237. package/package.json +147 -0
  238. package/scripts/generate-keys.mjs +53 -0
@@ -0,0 +1,52 @@
1
+ import type { StepResult, ToolSet } from "ai";
2
+ /**
3
+ * Shared Workers-AI plumbing for the agent's inference operations — the pieces
4
+ * every model call needs regardless of *which* operation it belongs to.
5
+ *
6
+ * The two loops themselves are deliberately separate, not layered on a common
7
+ * one: the main agent's Session-coupled round lives in
8
+ * {@link file://./turn.ts turn.ts}, and the Session-less subagent loop in
9
+ * {@link file://../subagent/run.ts run.ts}. They share error classification and
10
+ * progress streaming; their control flow has nothing in common worth abstracting.
11
+ */
12
+ /**
13
+ * Called with each **intermediate** assistant content message — text the model
14
+ * emits in a step that also makes tool calls (`finishReason:"tool-calls"`), i.e.
15
+ * before the final reply. Used to stream those messages out live; the final reply
16
+ * is the operation's return value, not an `onContent` call. `stepIndex` is the
17
+ * 0-based step ordinal (stable enough across a primary→fallback re-run for the
18
+ * gateway to dedupe on). Best-effort — the caller must swallow its own failures.
19
+ */
20
+ export type OnContent = (text: string, stepIndex: number) => void | Promise<void>;
21
+ /**
22
+ * Whether an error is a transient availability condition rather than a
23
+ * deterministic bad-output one.
24
+ *
25
+ * The distinction decides who handles it: transient throws out of the attempt loop
26
+ * so the Workflow step retries the whole round, while everything else burns the
27
+ * model slot and hands over to the fallback. Classifying a capacity blip as
28
+ * deterministic is the expensive mistake — it spends both slots on an outage and
29
+ * fails a Task that would have succeeded a second later.
30
+ *
31
+ * Structured signals first: the SDK's own `APICallError.isRetryable`, then the
32
+ * status code, then `RetryError` (raised once the SDK's internal backoff is
33
+ * exhausted). The message fragments stay as the last resort for the Workers-AI
34
+ * error codes, which arrive as prose on a plain `Error`.
35
+ */
36
+ export declare function isTransientAiError(err: unknown): boolean;
37
+ /**
38
+ * Returns a fresh `onStepEnd` callback for one `generateText` attempt.
39
+ * Fires `onContent` for each intermediate step (text that accompanies tool
40
+ * calls); the final step is skipped because its text is the operation's return
41
+ * value. A fresh handler per attempt resets the 0-based `stepIndex` counter so a
42
+ * primary→fallback re-run reuses the same indices and the gateway dedupes.
43
+ *
44
+ * `terminalToolNames` are the loop's **halting** control tools (e.g. the main
45
+ * agent's `delegate`): a step that calls one still has `finishReason:"tool-calls"`,
46
+ * but it is the round's *final* step, and its accompanying text is the round's
47
+ * acknowledgment — which the caller publishes separately as a milestone. Streaming
48
+ * it here too would double-post the same text under a second messageId, so those
49
+ * steps are skipped. Default `[]` (the subagent loop has no control tools).
50
+ */
51
+ export declare function buildIntermediateContentHandler(onContent: OnContent, terminalToolNames?: string[]): (step: StepResult<ToolSet>) => Promise<void>;
52
+ //# sourceMappingURL=inference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inference.d.ts","sourceRoot":"","sources":["../../src/agent/inference.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,UAAU,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAG5D;;;;;;;;;GASG;AAEH;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG,CACtB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,KACd,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAoB1B;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAWxD;AAOD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,SAAS,EACpB,iBAAiB,GAAE,MAAM,EAAO,GAC/B,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAU9C"}
@@ -0,0 +1,79 @@
1
+ import { APICallError, RetryError } from "ai";
2
+ /** Workers-AI error codes and message fragments that mean "try again later". */
3
+ const TRANSIENT_MESSAGE_FRAGMENTS = [
4
+ "3040",
5
+ "3046",
6
+ "capacity temporarily exceeded",
7
+ "request timeout",
8
+ "rate limit",
9
+ "too many requests",
10
+ "overloaded",
11
+ "service unavailable"
12
+ ];
13
+ /** HTTP statuses worth another attempt: timeout, conflict, throttle, any 5xx. */
14
+ function isRetryableStatus(status) {
15
+ if (status === undefined)
16
+ return false;
17
+ return status === 408 || status === 409 || status === 429 || status >= 500;
18
+ }
19
+ /**
20
+ * Whether an error is a transient availability condition rather than a
21
+ * deterministic bad-output one.
22
+ *
23
+ * The distinction decides who handles it: transient throws out of the attempt loop
24
+ * so the Workflow step retries the whole round, while everything else burns the
25
+ * model slot and hands over to the fallback. Classifying a capacity blip as
26
+ * deterministic is the expensive mistake — it spends both slots on an outage and
27
+ * fails a Task that would have succeeded a second later.
28
+ *
29
+ * Structured signals first: the SDK's own `APICallError.isRetryable`, then the
30
+ * status code, then `RetryError` (raised once the SDK's internal backoff is
31
+ * exhausted). The message fragments stay as the last resort for the Workers-AI
32
+ * error codes, which arrive as prose on a plain `Error`.
33
+ */
34
+ export function isTransientAiError(err) {
35
+ if (APICallError.isInstance(err)) {
36
+ if (err.isRetryable)
37
+ return true;
38
+ if (isRetryableStatus(err.statusCode))
39
+ return true;
40
+ }
41
+ if (RetryError.isInstance(err))
42
+ return true;
43
+ if (!(err instanceof Error))
44
+ return false;
45
+ const message = err.message.toLowerCase();
46
+ return TRANSIENT_MESSAGE_FRAGMENTS.some((fragment) => message.includes(fragment));
47
+ }
48
+ /** A step is "intermediate" when it makes tool calls — more content follows. */
49
+ function isIntermediateStep(step) {
50
+ return step.finishReason === "tool-calls";
51
+ }
52
+ /**
53
+ * Returns a fresh `onStepEnd` callback for one `generateText` attempt.
54
+ * Fires `onContent` for each intermediate step (text that accompanies tool
55
+ * calls); the final step is skipped because its text is the operation's return
56
+ * value. A fresh handler per attempt resets the 0-based `stepIndex` counter so a
57
+ * primary→fallback re-run reuses the same indices and the gateway dedupes.
58
+ *
59
+ * `terminalToolNames` are the loop's **halting** control tools (e.g. the main
60
+ * agent's `delegate`): a step that calls one still has `finishReason:"tool-calls"`,
61
+ * but it is the round's *final* step, and its accompanying text is the round's
62
+ * acknowledgment — which the caller publishes separately as a milestone. Streaming
63
+ * it here too would double-post the same text under a second messageId, so those
64
+ * steps are skipped. Default `[]` (the subagent loop has no control tools).
65
+ */
66
+ export function buildIntermediateContentHandler(onContent, terminalToolNames = []) {
67
+ let stepIndex = 0;
68
+ return async (step) => {
69
+ const i = stepIndex++;
70
+ if (!isIntermediateStep(step))
71
+ return;
72
+ if (step.toolCalls.some((c) => terminalToolNames.includes(c.toolName)))
73
+ return;
74
+ const content = step.text.trim();
75
+ if (content)
76
+ await onContent(content, i);
77
+ };
78
+ }
79
+ //# sourceMappingURL=inference.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inference.js","sourceRoot":"","sources":["../../src/agent/inference.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AA0B9C,gFAAgF;AAChF,MAAM,2BAA2B,GAAG;IAClC,MAAM;IACN,MAAM;IACN,+BAA+B;IAC/B,iBAAiB;IACjB,YAAY;IACZ,mBAAmB;IACnB,YAAY;IACZ,qBAAqB;CACtB,CAAC;AAEF,iFAAiF;AACjF,SAAS,iBAAiB,CAAC,MAA0B;IACnD,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACvC,OAAO,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,IAAI,GAAG,CAAC;AAC7E,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAY;IAC7C,IAAI,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACjC,IAAI,GAAG,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QACjC,IAAI,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,OAAO,IAAI,CAAC;IACrD,CAAC;IACD,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5C,IAAI,CAAC,CAAC,GAAG,YAAY,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IAC1C,OAAO,2BAA2B,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAC3B,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,SAAS,kBAAkB,CAAC,IAAoC;IAC9D,OAAO,IAAI,CAAC,YAAY,KAAK,YAAY,CAAC;AAC5C,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,+BAA+B,CAC7C,SAAoB,EACpB,oBAA8B,EAAE;IAEhC,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,OAAO,KAAK,EAAE,IAAI,EAAE,EAAE;QACpB,MAAM,CAAC,GAAG,SAAS,EAAE,CAAC;QACtB,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC;YAAE,OAAO;QACtC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YACpE,OAAO;QACT,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACjC,IAAI,OAAO;YAAE,MAAM,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC3C,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,75 @@
1
+ import type { LanguageModel } from "ai";
2
+ import type { ModelConfig } from "../config.js";
3
+ /**
4
+ * The Workers-AI model pair every loop runs on, built per agent instance.
5
+ *
6
+ * The predecessor read `env.AI` and five config constants as module-level
7
+ * imports. Neither survives packaging: `env` does not exist at module scope on
8
+ * Workers, and a module constant cannot be overridden by a consumer. So this is
9
+ * a factory over an injected binding and an injected {@link ModelConfig}.
10
+ */
11
+ /**
12
+ * Embed a batch of texts for episodic recall. Uses the same Workers-AI + AI
13
+ * Gateway path as the chat models so embeddings get the same gateway
14
+ * observability/caching. The output dimension must match the Vectorize index.
15
+ */
16
+ export type Embed = (texts: string[]) => Promise<number[][]>;
17
+ /**
18
+ * Custom metadata attached to the AI Gateway log for every call a pair makes.
19
+ * The gateway's own `metadata` is otherwise `null`, so a model call can only be
20
+ * tied back to its task by timestamp; stamping `{ taskId, round }` (a turn) or
21
+ * `{ taskId, subtaskId }` (a chunk) makes correlation exact. Values are limited
22
+ * to the gateway's accepted scalar set.
23
+ */
24
+ export type GatewayMetadata = Record<string, number | string | boolean>;
25
+ export interface ModelOverrides {
26
+ /** Test override for the primary slot. */
27
+ model?: LanguageModel;
28
+ /** Test override for the fallback slot. */
29
+ fallbackModel?: LanguageModel;
30
+ /**
31
+ * Workers-AI id for the primary slot (a recipe's, already code-validated
32
+ * against the allowlist by `validateRecipe`). Defaults to the configured
33
+ * `chatModelId`.
34
+ */
35
+ primaryModelId?: string;
36
+ /**
37
+ * Workers-AI id for the fallback slot (already code-validated). Defaults to
38
+ * the configured `fallbackChatModelId`.
39
+ */
40
+ fallbackModelId?: string;
41
+ /** AI Gateway log metadata for correlation — see {@link GatewayMetadata}. */
42
+ metadata?: GatewayMetadata;
43
+ }
44
+ /** The primary/fallback models (lazily memoized) plus their ids for logging. */
45
+ export interface ModelPair {
46
+ primary: () => LanguageModel;
47
+ fallback: () => LanguageModel;
48
+ primaryId: () => string;
49
+ fallbackId: () => string;
50
+ }
51
+ export interface ModelRuntime {
52
+ /**
53
+ * Lazily build + memoize a primary/fallback model pair (overridable in tests,
54
+ * id-parameterized for recipes). No allowlisting happens here —
55
+ * `validateRecipe` is the single validation owner for recipe-supplied ids.
56
+ */
57
+ createModelPair(overrides?: ModelOverrides): ModelPair;
58
+ embedTexts: Embed;
59
+ }
60
+ export interface ModelRuntimeDeps {
61
+ /** The `AI` binding. Read lazily — see {@link createModelRuntime}. */
62
+ ai: Ai;
63
+ config: ModelConfig;
64
+ }
65
+ /**
66
+ * Build the model runtime for one agent instance.
67
+ *
68
+ * The provider is constructed on first *use*, not here. During `wrangler deploy`
69
+ * Cloudflare evaluates module scope to validate the new version, and bindings
70
+ * are not populated at that point — constructing eagerly makes `createWorkersAI`
71
+ * throw "you must provide either a binding or credentials". The same laziness
72
+ * protects a consumer who builds their runtime early.
73
+ */
74
+ export declare function createModelRuntime(deps: ModelRuntimeDeps): ModelRuntime;
75
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/agent/model.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAExC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;;;;;;GAOG;AAEH;;;;GAIG;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAE7D;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;AAExE,MAAM,WAAW,cAAc;IAC7B,0CAA0C;IAC1C,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,2CAA2C;IAC3C,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,gFAAgF;AAChF,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,aAAa,CAAC;IAC7B,QAAQ,EAAE,MAAM,aAAa,CAAC;IAC9B,SAAS,EAAE,MAAM,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,eAAe,CAAC,SAAS,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACvD,UAAU,EAAE,KAAK,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,EAAE,EAAE,EAAE,CAAC;IACP,MAAM,EAAE,WAAW,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,YAAY,CAuDvE"}
@@ -0,0 +1,62 @@
1
+ import { createWorkersAI } from "workers-ai-provider";
2
+ import { embedMany } from "ai";
3
+ /**
4
+ * Build the model runtime for one agent instance.
5
+ *
6
+ * The provider is constructed on first *use*, not here. During `wrangler deploy`
7
+ * Cloudflare evaluates module scope to validate the new version, and bindings
8
+ * are not populated at that point — constructing eagerly makes `createWorkersAI`
9
+ * throw "you must provide either a binding or credentials". The same laziness
10
+ * protects a consumer who builds their runtime early.
11
+ */
12
+ export function createModelRuntime(deps) {
13
+ const { config } = deps;
14
+ let provider;
15
+ const workersai = () => (provider ??= createWorkersAI({
16
+ binding: deps.ai,
17
+ gateway: { id: config.aiGatewayId }
18
+ }));
19
+ /**
20
+ * Per-model Workers-AI settings: pin the gateway id (so per-call metadata does
21
+ * not drop the gateway route), attach correlation metadata when supplied, and
22
+ * set the reasoning budget.
23
+ *
24
+ * Always returns a settings object, even with no metadata: `reasoning_effort`
25
+ * has to reach the binding on every call, and an `undefined` return drops it.
26
+ */
27
+ const chatSettings = (metadata) => ({
28
+ gateway: { id: config.aiGatewayId, ...(metadata ? { metadata } : {}) },
29
+ reasoning_effort: config.reasoningEffort
30
+ });
31
+ return {
32
+ createModelPair(overrides = {}) {
33
+ const primaryId = overrides.primaryModelId ?? config.chatModelId;
34
+ const fallbackId = overrides.fallbackModelId ?? config.fallbackChatModelId;
35
+ let primary;
36
+ let fallback;
37
+ const settings = chatSettings(overrides.metadata);
38
+ return {
39
+ primary: () => (primary ??= overrides.model ?? workersai()(primaryId, settings)),
40
+ fallback: () => (fallback ??=
41
+ overrides.fallbackModel ??
42
+ overrides.model ??
43
+ workersai()(fallbackId, settings)),
44
+ primaryId: () => primaryId,
45
+ fallbackId: () => fallbackId
46
+ };
47
+ },
48
+ async embedTexts(texts) {
49
+ if (texts.length === 0)
50
+ return [];
51
+ const { embeddings } = await embedMany({
52
+ model: workersai().embedding(config.embeddingModelId),
53
+ values: texts,
54
+ // Failures surface to the caller (best-effort archival swallows them);
55
+ // the SDK's retry/backoff would only add latency on a hard failure.
56
+ maxRetries: 0
57
+ });
58
+ return embeddings;
59
+ }
60
+ };
61
+ }
62
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/agent/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAwE/B;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAsB;IACvD,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACxB,IAAI,QAAwD,CAAC;IAC7D,MAAM,SAAS,GAAG,GAAG,EAAE,CACrB,CAAC,QAAQ,KAAK,eAAe,CAAC;QAC5B,OAAO,EAAE,IAAI,CAAC,EAAE;QAChB,OAAO,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,WAAW,EAAE;KACpC,CAAC,CAAC,CAAC;IAEN;;;;;;;OAOG;IACH,MAAM,YAAY,GAAG,CAAC,QAA0B,EAAE,EAAE,CAAC,CAAC;QACpD,OAAO,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,WAAW,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;QACtE,gBAAgB,EAAE,MAAM,CAAC,eAAe;KACzC,CAAC,CAAC;IAEH,OAAO;QACL,eAAe,CAAC,YAA4B,EAAE;YAC5C,MAAM,SAAS,GAAG,SAAS,CAAC,cAAc,IAAI,MAAM,CAAC,WAAW,CAAC;YACjE,MAAM,UAAU,GACd,SAAS,CAAC,eAAe,IAAI,MAAM,CAAC,mBAAmB,CAAC;YAC1D,IAAI,OAAkC,CAAC;YACvC,IAAI,QAAmC,CAAC;YACxC,MAAM,QAAQ,GAAG,YAAY,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAClD,OAAO;gBACL,OAAO,EAAE,GAAG,EAAE,CACZ,CAAC,OAAO,KAAK,SAAS,CAAC,KAAK,IAAI,SAAS,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;gBACnE,QAAQ,EAAE,GAAG,EAAE,CACb,CAAC,QAAQ;oBACP,SAAS,CAAC,aAAa;wBACvB,SAAS,CAAC,KAAK;wBACf,SAAS,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;gBACtC,SAAS,EAAE,GAAG,EAAE,CAAC,SAAS;gBAC1B,UAAU,EAAE,GAAG,EAAE,CAAC,UAAU;aAC7B,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,UAAU,CAAC,KAAe;YAC9B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;YAClC,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,SAAS,CAAC;gBACrC,KAAK,EAAE,SAAS,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,gBAAgB,CAAC;gBACrD,MAAM,EAAE,KAAK;gBACb,uEAAuE;gBACvE,oEAAoE;gBACpE,UAAU,EAAE,CAAC;aACd,CAAC,CAAC;YACH,OAAO,UAAU,CAAC;QACpB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,92 @@
1
+ import type { LanguageModel, ToolSet } from "ai";
2
+ import { Session } from "agents/experimental/memory/session";
3
+ import type { SessionMessage } from "agents/experimental/memory/session";
4
+ import { createCompactFunction } from "agents/experimental/memory/utils";
5
+ /**
6
+ * The one continuous {@link Session} an agent Durable Object owns. Ported from
7
+ * the looping-gateway admin agent's `shared/session.ts` (single Session per DO —
8
+ * soul + memory + compaction). Recall (Vectorize) archival is Phase 3: the
9
+ * `onArchive` seam is present but left unwired for now.
10
+ */
11
+ /**
12
+ * The SQLite-backed host the Sessions API needs — satisfied by the Agents SDK
13
+ * `Agent` (`this.sql`).
14
+ */
15
+ export interface SessionHost {
16
+ sql<T = Record<string, string | number | boolean | null>>(strings: TemplateStringsArray, ...values: (string | number | boolean | null)[]): T[];
17
+ }
18
+ /** The subset of `Session` the agent loop drives — lets tests inject a fake. */
19
+ export interface SessionLike {
20
+ appendMessage(message: SessionMessage, parentId?: string | null): Promise<unknown> | unknown;
21
+ getHistory(): Promise<SessionMessage[]>;
22
+ /**
23
+ * Read one message by id, or null. Reads the **raw stored row**, so it is
24
+ * unaffected by compaction overlays — a message folded into a summary is still
25
+ * readable here. That is what makes {@link appendOnce}'s read-back a reliable
26
+ * recovery path for a phase whose Workflow step re-ran.
27
+ */
28
+ getMessage(id: string): Promise<SessionMessage | null>;
29
+ refreshSystemPrompt(): Promise<string>;
30
+ tools(): Promise<ToolSet>;
31
+ /** Compaction overlays so far — non-empty ⇒ an episodic archive exists. */
32
+ getCompactions(): Promise<unknown[]>;
33
+ }
34
+ /**
35
+ * Append a message with a deterministic id exactly once, and return the text that
36
+ * is **durably stored** under that id.
37
+ *
38
+ * `Session.appendMessage` is already idempotent by id: appending an id that
39
+ * exists is a no-op. The read-back is what matters for a re-run phase — if the
40
+ * step crashed after appending and the retry re-inferred a *different* reply, the
41
+ * append no-ops and this returns the original, durable text. The Session and the
42
+ * value the caller goes on to deliver therefore never disagree.
43
+ *
44
+ * Falls back to the message's own text if the read-back returns null (it cannot,
45
+ * having just been appended) rather than failing a phase over a missing echo.
46
+ */
47
+ export declare function appendOnce(session: SessionLike, message: SessionMessage): Promise<string>;
48
+ export interface AgentSessionOptions {
49
+ /** Read-only identity block injected into the system prompt every turn. */
50
+ soul: () => string | Promise<string>;
51
+ /** Description of the writable SQLite `"memory"` scratchpad the model self-edits. */
52
+ memoryDescription: string;
53
+ /** Soft cap (tokens) for the `"memory"` block. */
54
+ memoryMaxTokens: number;
55
+ /** History token threshold that triggers compaction. */
56
+ compactAfterTokens: number;
57
+ /**
58
+ * Tokens of recent history compaction keeps verbatim. Coupled to
59
+ * {@link compactAfterTokens} — see `SessionConfig.compactTailTokens` for the
60
+ * invariant that binds them, which `resolveConfig` enforces.
61
+ */
62
+ compactTailTokens: number;
63
+ /**
64
+ * Output-token ceiling for the summarizer call. An unbounded summary is not
65
+ * the risk; a silently truncated one is — it becomes this caller's memory of
66
+ * everything that scrolled out, with no way to tell it was cut short.
67
+ */
68
+ maxOutputTokens: number;
69
+ /**
70
+ * Archive the raw messages displaced by each compaction (episodic recall).
71
+ * Best-effort: a throw here must never abort compaction. (Wired in Phase 3.)
72
+ */
73
+ onArchive?: (messages: SessionMessage[]) => Promise<void>;
74
+ }
75
+ type CompactFn = ReturnType<typeof createCompactFunction>;
76
+ /**
77
+ * Wrap a compaction function so the raw messages it folds into a summary are
78
+ * also handed to `onArchive` (which embeds them for later recall). The displaced
79
+ * range is `fromMessageId..toMessageId` of the result, sliced from the `history`
80
+ * the compaction saw. Archival failure is swallowed — compaction must still
81
+ * shorten history even if the recall store is briefly unavailable.
82
+ */
83
+ export declare function archivingCompaction(base: CompactFn, onArchive?: (messages: SessionMessage[]) => Promise<void>): CompactFn;
84
+ /**
85
+ * Build the one continuous `Session` an agent Durable Object owns: a read-only
86
+ * `"soul"` identity block + a writable `"memory"` scratchpad, with history
87
+ * compaction summarized by the same model. All of a caller's turns (any channel
88
+ * or thread) accumulate into this single conversation.
89
+ */
90
+ export declare function buildAgentSession(agent: SessionHost, model: LanguageModel, opts: AgentSessionOptions): Session;
91
+ export {};
92
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/agent/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAEjD,OAAO,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAGzE;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,EACtD,OAAO,EAAE,oBAAoB,EAC7B,GAAG,MAAM,EAAE,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,EAAE,GAC9C,CAAC,EAAE,CAAC;CACR;AAED,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B,aAAa,CACX,OAAO,EAAE,cAAc,EACvB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GACvB,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAC9B,UAAU,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IACxC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACvD,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACvC,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,2EAA2E;IAC3E,cAAc,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;CACtC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,IAAI,EAAE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC,qFAAqF;IACrF,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kDAAkD;IAClD,eAAe,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;AAED,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE1D;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,SAAS,EACf,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GACxD,SAAS,CAiBX;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE,mBAAmB,GACxB,OAAO,CA2BT"}
@@ -0,0 +1,80 @@
1
+ import { generateText } from "ai";
2
+ import { Session } from "agents/experimental/memory/session";
3
+ import { createCompactFunction } from "agents/experimental/memory/utils";
4
+ import { sessionText } from "./history.js";
5
+ /**
6
+ * Append a message with a deterministic id exactly once, and return the text that
7
+ * is **durably stored** under that id.
8
+ *
9
+ * `Session.appendMessage` is already idempotent by id: appending an id that
10
+ * exists is a no-op. The read-back is what matters for a re-run phase — if the
11
+ * step crashed after appending and the retry re-inferred a *different* reply, the
12
+ * append no-ops and this returns the original, durable text. The Session and the
13
+ * value the caller goes on to deliver therefore never disagree.
14
+ *
15
+ * Falls back to the message's own text if the read-back returns null (it cannot,
16
+ * having just been appended) rather than failing a phase over a missing echo.
17
+ */
18
+ export async function appendOnce(session, message) {
19
+ await session.appendMessage(message);
20
+ const stored = await session.getMessage(message.id);
21
+ return stored ? sessionText(stored) : sessionText(message);
22
+ }
23
+ /**
24
+ * Wrap a compaction function so the raw messages it folds into a summary are
25
+ * also handed to `onArchive` (which embeds them for later recall). The displaced
26
+ * range is `fromMessageId..toMessageId` of the result, sliced from the `history`
27
+ * the compaction saw. Archival failure is swallowed — compaction must still
28
+ * shorten history even if the recall store is briefly unavailable.
29
+ */
30
+ export function archivingCompaction(base, onArchive) {
31
+ if (!onArchive)
32
+ return base;
33
+ return async (history, options) => {
34
+ const result = await base(history, options);
35
+ if (result) {
36
+ const from = history.findIndex((m) => m.id === result.fromMessageId);
37
+ const to = history.findIndex((m) => m.id === result.toMessageId);
38
+ if (from !== -1 && to !== -1) {
39
+ try {
40
+ await onArchive(history.slice(from, to + 1));
41
+ }
42
+ catch (err) {
43
+ console.error("[recall] archive on compaction failed", err);
44
+ }
45
+ }
46
+ }
47
+ return result;
48
+ };
49
+ }
50
+ /**
51
+ * Build the one continuous `Session` an agent Durable Object owns: a read-only
52
+ * `"soul"` identity block + a writable `"memory"` scratchpad, with history
53
+ * compaction summarized by the same model. All of a caller's turns (any channel
54
+ * or thread) accumulate into this single conversation.
55
+ */
56
+ export function buildAgentSession(agent, model, opts) {
57
+ const compact = archivingCompaction(createCompactFunction({
58
+ // The one boundary worth owning. `protectHead` (3) and `minTailMessages`
59
+ // (2) keep the SDK defaults: the head is the conversation's opening and is
60
+ // cheap, and the tail floor is a safety net rather than a budget.
61
+ tailTokenBudget: opts.compactTailTokens,
62
+ // Bounded like every other call: an unbounded summary is not the risk, a
63
+ // silently truncated one is — it becomes this caller's memory of everything
64
+ // that scrolled out, with no way to tell it was cut short.
65
+ summarize: (prompt) => generateText({
66
+ model,
67
+ prompt,
68
+ maxOutputTokens: opts.maxOutputTokens
69
+ }).then((r) => r.text)
70
+ }), opts.onArchive);
71
+ return Session.create(agent)
72
+ .withContext("soul", { provider: { get: async () => opts.soul() } })
73
+ .withContext("memory", {
74
+ description: opts.memoryDescription,
75
+ maxTokens: opts.memoryMaxTokens
76
+ })
77
+ .onCompaction(compact)
78
+ .compactAfter(opts.compactAfterTokens);
79
+ }
80
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/agent/session.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAE7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAwC3C;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,OAAoB,EACpB,OAAuB;IAEvB,MAAM,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AAC7D,CAAC;AAgCD;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAe,EACf,SAAyD;IAEzD,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAC5B,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;QAChC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC5C,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,aAAa,CAAC,CAAC;YACrE,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,WAAW,CAAC,CAAC;YACjE,IAAI,IAAI,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;gBAC7B,IAAI,CAAC;oBACH,MAAM,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC/C,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAC;gBAC9D,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAkB,EAClB,KAAoB,EACpB,IAAyB;IAEzB,MAAM,OAAO,GAAG,mBAAmB,CACjC,qBAAqB,CAAC;QACpB,yEAAyE;QACzE,2EAA2E;QAC3E,kEAAkE;QAClE,eAAe,EAAE,IAAI,CAAC,iBAAiB;QACvC,yEAAyE;QACzE,4EAA4E;QAC5E,2DAA2D;QAC3D,SAAS,EAAE,CAAC,MAAM,EAAE,EAAE,CACpB,YAAY,CAAC;YACX,KAAK;YACL,MAAM;YACN,eAAe,EAAE,IAAI,CAAC,eAAe;SACtC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;KACzB,CAAC,EACF,IAAI,CAAC,SAAS,CACf,CAAC;IACF,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;SACzB,WAAW,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC;SACnE,WAAW,CAAC,QAAQ,EAAE;QACrB,WAAW,EAAE,IAAI,CAAC,iBAAiB;QACnC,SAAS,EAAE,IAAI,CAAC,eAAe;KAChC,CAAC;SACD,YAAY,CAAC,OAAO,CAAC;SACrB,YAAY,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,159 @@
1
+ /**
2
+ * The shapes of everything an agent tunes, plus a working set of defaults.
3
+ *
4
+ * In the predecessor repos this file held bare `export const`s that ~12 modules
5
+ * imported directly. That is what this package cannot do: a module-level constant
6
+ * read at import time is not overridable by a consumer, and it freezes the value
7
+ * into the module graph before `env` exists. So core owns the *shapes* and a
8
+ * baseline; a consuming agent passes overrides to {@link resolveConfig} once, at
9
+ * DO start, and the resolved object is threaded through explicitly.
10
+ *
11
+ * The distinction against {@link file://./platform.ts} stays sharp: nothing here
12
+ * is a platform fact, and nothing there is tunable.
13
+ */
14
+ /** Model ids and per-call generation settings. */
15
+ export interface ModelConfig {
16
+ /** Workers AI model for the tool loop. Must support function calling. */
17
+ chatModelId: string;
18
+ /**
19
+ * Tried when the primary throws. Should be a *different vendor and family* —
20
+ * a same-family fallback shares the failure mode you are falling back from.
21
+ */
22
+ fallbackChatModelId: string;
23
+ /** AI Gateway slug; `"default"` auto-provisions on first request. */
24
+ aiGatewayId: string;
25
+ /**
26
+ * Output-token ceiling for every chat call. Left unset, the binding applies a
27
+ * per-model default which a reasoning model spends on `reasoning_content`
28
+ * before emitting the tool call — a truncated round that reads as a clean
29
+ * answer. Generous on purpose: it bounds a runaway, it does not ration.
30
+ */
31
+ maxOutputTokens: number;
32
+ /** Reasoning budget forwarded on the binding's `inputs` by workers-ai-provider. */
33
+ reasoningEffort: "low" | "medium" | "high";
34
+ /**
35
+ * Embedding model backing recall. Its dimension/metric must match the
36
+ * Vectorize index (1024-dim, cosine); changing it means recreating the index.
37
+ */
38
+ embeddingModelId: string;
39
+ }
40
+ /**
41
+ * An execution budget, in the only two currencies that mean anything: **turns**
42
+ * (what it costs) and **wall clock** (how long it can run away for).
43
+ *
44
+ * Rounds, chunks and steps are *mechanics*, not budgets — a round is the
45
+ * delegate/answer loop, a chunk is a durable slice sized by the Workers step
46
+ * timeout. None of them is tunable and none belongs here. Conflating the two is
47
+ * what once made an overnight runaway look healthy to every cap in the system.
48
+ *
49
+ * Reaching either ceiling does the same thing at either level: one final call
50
+ * with **no tools** — "you have spent your budget, answer now from what you
51
+ * have". A ceiling yields an answer; it never drops the work.
52
+ */
53
+ export interface AgentLimits {
54
+ /**
55
+ * Tool-loop steps, summed across every round *and* across the
56
+ * primary→fallback attempt within a round — a fallback attempt is real spend.
57
+ */
58
+ maxTurns: number;
59
+ /**
60
+ * Measured from the first durable step. Note for whoever implements
61
+ * escalation: this must be **rebased** after a `step.waitForEvent(...)`
62
+ * returns, or a human's thinking time is charged to the agent and a task that
63
+ * asks a question at minute 5 is dead before the answer arrives. Turns need no
64
+ * such care — waiting costs none.
65
+ */
66
+ maxWallMs: number;
67
+ }
68
+ /** Session memory + compaction tuning. */
69
+ export interface SessionConfig {
70
+ /** Soft cap (tokens) for the self-edited `"memory"` scratchpad block. */
71
+ memoryMaxTokens: number;
72
+ /** Live-history token threshold that triggers automatic compaction. */
73
+ compactAfterTokens: number;
74
+ /**
75
+ * Tokens of the most recent history compaction keeps **verbatim**.
76
+ *
77
+ * Read this together with {@link compactAfterTokens}; neither means anything
78
+ * alone. After a compaction the floor is `system + protectHead + summary +
79
+ * tail`, so the conversation that must accumulate before compaction fires
80
+ * again is `Δ = compactAfterTokens − floor`, and the SDK sizes each summary at
81
+ * 20% of the middle it folded, so at equilibrium `S ≈ 0.2Δ`.
82
+ *
83
+ * INVARIANT: `compactAfterTokens − compactTailTokens >= 10_000`, asserted in
84
+ * `session.spec.ts`. Below it the fixed floor eats the gap and compaction
85
+ * fires on nearly every append, each firing spending a summarizer call on a
86
+ * near-empty middle. Never lower the threshold without lowering the tail too.
87
+ */
88
+ compactTailTokens: number;
89
+ /** One-line description shown to the model for the writable `"memory"` block. */
90
+ memoryDescription: string;
91
+ }
92
+ /** Episodic-recall (Vectorize) tuning. */
93
+ export interface RecallConfig {
94
+ /** Default number of archived messages one `recall` query returns. */
95
+ topK: number;
96
+ /**
97
+ * Max chars of a message's text stored in its vector metadata. Keeps each
98
+ * vector under Vectorize's ~10 KiB/vector limit; recall returns this snippet
99
+ * plus provenance, not the full original message.
100
+ */
101
+ metadataTextMax: number;
102
+ }
103
+ export interface CoreConfig {
104
+ model: ModelConfig;
105
+ /** What bounds the MAIN agent across every round of one task. */
106
+ mainAgentLimits: AgentLimits;
107
+ /**
108
+ * The baseline every subagent branch runs under. A recipe may override either
109
+ * field — to any positive integer, larger included — and inherits the baseline
110
+ * for whatever it does not validly declare. A default, not a ceiling.
111
+ */
112
+ subagentLimits: AgentLimits;
113
+ /**
114
+ * How many of the most recent assistant turns keep their tool **results** in a
115
+ * subagent's rolling window. Older results are stubbed; the tool *calls* and
116
+ * the model's own text always survive the full `historyWindow`, because that
117
+ * is where a recipe's model keeps whatever it wrote down for itself.
118
+ *
119
+ * A mechanic of the window, not a property of a domain — which is why it is
120
+ * deliberately not a recipe field: recipe fields are fingerprinted, and
121
+ * changing a fingerprint strands every in-flight run behind a mismatch that
122
+ * costs it its whole history.
123
+ */
124
+ toolOutputWindow: number;
125
+ /**
126
+ * Upper bound on subtasks per **round** — a core invariant: a delegating round
127
+ * emits `1..maxSubtasks` subtasks, which is also what bounds its fan-out (all
128
+ * dependency-ready subtasks run concurrently, with no other concurrency cap).
129
+ *
130
+ * Not a budget but a shape: it is what the delegation schema offers the model,
131
+ * and the data layer re-checks it as the durable guard.
132
+ */
133
+ maxSubtasks: number;
134
+ session: SessionConfig;
135
+ recall: RecallConfig;
136
+ }
137
+ /**
138
+ * A working baseline. Every value is overridable; none is a ceiling. These are
139
+ * the values both predecessor agents converged on in production, so they are a
140
+ * reasonable place to start rather than an opinion about your domain.
141
+ */
142
+ export declare const DEFAULT_CORE_CONFIG: CoreConfig;
143
+ /** One level of optionality per nested group — enough for a config this shallow. */
144
+ export type CoreConfigOverrides = {
145
+ [K in keyof CoreConfig]?: CoreConfig[K] extends object ? Partial<CoreConfig[K]> : CoreConfig[K];
146
+ };
147
+ export declare class ConfigError extends Error {
148
+ constructor(message: string);
149
+ }
150
+ /**
151
+ * Merge overrides onto {@link DEFAULT_CORE_CONFIG} and check the invariants that
152
+ * are cheap to get wrong and expensive to notice.
153
+ *
154
+ * Called once, at DO start, and the result threaded explicitly from there. Do
155
+ * not call it per-request: the point of resolving is that every module downstream
156
+ * reads the same object.
157
+ */
158
+ export declare function resolveConfig(overrides?: CoreConfigOverrides): CoreConfig;
159
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,kDAAkD;AAClD,MAAM,WAAW,WAAW;IAC1B,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAC5B,qEAAqE;IACrE,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,mFAAmF;IACnF,eAAe,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC3C;;;OAGG;IACH,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,0CAA0C;AAC1C,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,eAAe,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;;;;;;;;;;;;OAaG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iFAAiF;IACjF,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,0CAA0C;AAC1C,MAAM,WAAW,YAAY;IAC3B,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,WAAW,CAAC;IACnB,iEAAiE;IACjE,eAAe,EAAE,WAAW,CAAC;IAC7B;;;;OAIG;IACH,cAAc,EAAE,WAAW,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;;;OAOG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,UAsBjC,CAAC;AAEF,oFAAoF;AACpF,MAAM,MAAM,mBAAmB,GAAG;KAC/B,CAAC,IAAI,MAAM,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,SAAS,MAAM,GAClD,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GACtB,UAAU,CAAC,CAAC,CAAC;CAClB,CAAC;AAEF,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,SAAS,GAAE,mBAAwB,GAAG,UAAU,CA4C7E"}