@namzu/sdk 36.0.0 → 37.0.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 (308) hide show
  1. package/CHANGELOG.md +180 -0
  2. package/README.md +68 -41
  3. package/dist/bridge/a2a/mapper.d.ts.map +1 -1
  4. package/dist/bridge/a2a/mapper.js +2 -0
  5. package/dist/bridge/a2a/mapper.js.map +1 -1
  6. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  7. package/dist/bridge/sse/mapper.js +2 -0
  8. package/dist/bridge/sse/mapper.js.map +1 -1
  9. package/dist/compaction/extractor.d.ts +1 -1
  10. package/dist/compaction/extractor.d.ts.map +1 -1
  11. package/dist/compaction/extractor.js +15 -7
  12. package/dist/compaction/extractor.js.map +1 -1
  13. package/dist/compaction/manager.d.ts +2 -0
  14. package/dist/compaction/manager.d.ts.map +1 -1
  15. package/dist/compaction/manager.js +12 -1
  16. package/dist/compaction/manager.js.map +1 -1
  17. package/dist/compaction/verifier.d.ts.map +1 -1
  18. package/dist/compaction/verifier.js +82 -15
  19. package/dist/compaction/verifier.js.map +1 -1
  20. package/dist/contracts/schemas.d.ts +10 -10
  21. package/dist/eval/harness-verification.d.ts +63 -0
  22. package/dist/eval/harness-verification.d.ts.map +1 -0
  23. package/dist/eval/harness-verification.js +165 -0
  24. package/dist/eval/harness-verification.js.map +1 -0
  25. package/dist/eval/index.d.ts +2 -0
  26. package/dist/eval/index.d.ts.map +1 -1
  27. package/dist/eval/index.js +1 -0
  28. package/dist/eval/index.js.map +1 -1
  29. package/dist/execution/code-runtime/json-value.d.ts +10 -0
  30. package/dist/execution/code-runtime/json-value.d.ts.map +1 -0
  31. package/dist/execution/code-runtime/json-value.js +89 -0
  32. package/dist/execution/code-runtime/json-value.js.map +1 -0
  33. package/dist/execution/code-runtime/worker-program.d.ts +8 -0
  34. package/dist/execution/code-runtime/worker-program.d.ts.map +1 -0
  35. package/dist/execution/code-runtime/worker-program.js +240 -0
  36. package/dist/execution/code-runtime/worker-program.js.map +1 -0
  37. package/dist/execution/code-runtime/worker.d.ts +22 -0
  38. package/dist/execution/code-runtime/worker.d.ts.map +1 -1
  39. package/dist/execution/code-runtime/worker.js +148 -111
  40. package/dist/execution/code-runtime/worker.js.map +1 -1
  41. package/dist/manager/agent/lifecycle.d.ts +12 -0
  42. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  43. package/dist/manager/agent/lifecycle.js +306 -37
  44. package/dist/manager/agent/lifecycle.js.map +1 -1
  45. package/dist/manager/run/persistence.d.ts +2 -0
  46. package/dist/manager/run/persistence.d.ts.map +1 -1
  47. package/dist/manager/run/persistence.js +6 -0
  48. package/dist/manager/run/persistence.js.map +1 -1
  49. package/dist/provider/capabilities.d.ts +3 -1
  50. package/dist/provider/capabilities.d.ts.map +1 -1
  51. package/dist/provider/capabilities.js +13 -0
  52. package/dist/provider/capabilities.js.map +1 -1
  53. package/dist/provider/fallback.d.ts.map +1 -1
  54. package/dist/provider/fallback.js +2 -0
  55. package/dist/provider/fallback.js.map +1 -1
  56. package/dist/public-runtime.d.ts +3 -1
  57. package/dist/public-runtime.d.ts.map +1 -1
  58. package/dist/public-runtime.js +2 -1
  59. package/dist/public-runtime.js.map +1 -1
  60. package/dist/public-tools.d.ts +1 -1
  61. package/dist/public-tools.d.ts.map +1 -1
  62. package/dist/public-tools.js +1 -1
  63. package/dist/public-tools.js.map +1 -1
  64. package/dist/public-types.d.ts +1 -0
  65. package/dist/public-types.d.ts.map +1 -1
  66. package/dist/registry/tool/execute.d.ts +3 -0
  67. package/dist/registry/tool/execute.d.ts.map +1 -1
  68. package/dist/registry/tool/execute.js +11 -80
  69. package/dist/registry/tool/execute.js.map +1 -1
  70. package/dist/run/command-gate.d.ts.map +1 -1
  71. package/dist/run/command-gate.js +65 -12
  72. package/dist/run/command-gate.js.map +1 -1
  73. package/dist/run/index.d.ts +2 -0
  74. package/dist/run/index.d.ts.map +1 -1
  75. package/dist/run/index.js +1 -0
  76. package/dist/run/index.js.map +1 -1
  77. package/dist/run/memory-promoter.d.ts +3 -35
  78. package/dist/run/memory-promoter.d.ts.map +1 -1
  79. package/dist/run/memory-promoter.js +32 -40
  80. package/dist/run/memory-promoter.js.map +1 -1
  81. package/dist/run/memory-recall.d.ts +25 -0
  82. package/dist/run/memory-recall.d.ts.map +1 -0
  83. package/dist/run/memory-recall.js +228 -0
  84. package/dist/run/memory-recall.js.map +1 -0
  85. package/dist/run/reporter.d.ts.map +1 -1
  86. package/dist/run/reporter.js +1 -0
  87. package/dist/run/reporter.js.map +1 -1
  88. package/dist/run/token-budget.d.ts +2 -0
  89. package/dist/run/token-budget.d.ts.map +1 -1
  90. package/dist/run/token-budget.js +4 -0
  91. package/dist/run/token-budget.js.map +1 -1
  92. package/dist/run/workspace-fingerprint.d.ts +10 -3
  93. package/dist/run/workspace-fingerprint.d.ts.map +1 -1
  94. package/dist/run/workspace-fingerprint.js +17 -8
  95. package/dist/run/workspace-fingerprint.js.map +1 -1
  96. package/dist/runtime/query/checkpoint.d.ts +14 -0
  97. package/dist/runtime/query/checkpoint.d.ts.map +1 -1
  98. package/dist/runtime/query/checkpoint.js +82 -1
  99. package/dist/runtime/query/checkpoint.js.map +1 -1
  100. package/dist/runtime/query/executor.d.ts +5 -0
  101. package/dist/runtime/query/executor.d.ts.map +1 -1
  102. package/dist/runtime/query/executor.js +70 -14
  103. package/dist/runtime/query/executor.js.map +1 -1
  104. package/dist/runtime/query/index.d.ts +5 -8
  105. package/dist/runtime/query/index.d.ts.map +1 -1
  106. package/dist/runtime/query/index.js +54 -7
  107. package/dist/runtime/query/index.js.map +1 -1
  108. package/dist/runtime/query/iteration/index.d.ts +10 -0
  109. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  110. package/dist/runtime/query/iteration/index.js +325 -36
  111. package/dist/runtime/query/iteration/index.js.map +1 -1
  112. package/dist/runtime/query/iteration/native-output.d.ts +10 -0
  113. package/dist/runtime/query/iteration/native-output.d.ts.map +1 -0
  114. package/dist/runtime/query/iteration/native-output.js +32 -0
  115. package/dist/runtime/query/iteration/native-output.js.map +1 -0
  116. package/dist/runtime/query/iteration/phases/advisory.d.ts.map +1 -1
  117. package/dist/runtime/query/iteration/phases/advisory.js +18 -13
  118. package/dist/runtime/query/iteration/phases/advisory.js.map +1 -1
  119. package/dist/runtime/query/iteration/phases/compaction.d.ts +2 -0
  120. package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
  121. package/dist/runtime/query/iteration/phases/compaction.js +32 -11
  122. package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
  123. package/dist/runtime/query/iteration/phases/context.d.ts +9 -0
  124. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  125. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  126. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  127. package/dist/runtime/query/iteration/phases/tool-review.js +1 -1
  128. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  129. package/dist/runtime/query/iteration/phases/working-memory.d.ts +1 -1
  130. package/dist/runtime/query/iteration/phases/working-memory.d.ts.map +1 -1
  131. package/dist/runtime/query/iteration/phases/working-memory.js +23 -6
  132. package/dist/runtime/query/iteration/phases/working-memory.js.map +1 -1
  133. package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
  134. package/dist/runtime/query/iteration/stream-turn.js +2 -0
  135. package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
  136. package/dist/runtime/query/steering.d.ts +6 -2
  137. package/dist/runtime/query/steering.d.ts.map +1 -1
  138. package/dist/runtime/query/steering.js +17 -2
  139. package/dist/runtime/query/steering.js.map +1 -1
  140. package/dist/runtime/query/tool-call-budget.d.ts +19 -0
  141. package/dist/runtime/query/tool-call-budget.d.ts.map +1 -0
  142. package/dist/runtime/query/tool-call-budget.js +110 -0
  143. package/dist/runtime/query/tool-call-budget.js.map +1 -0
  144. package/dist/runtime/query/tooling.d.ts +2 -0
  145. package/dist/runtime/query/tooling.d.ts.map +1 -1
  146. package/dist/runtime/query/tooling.js +4 -0
  147. package/dist/runtime/query/tooling.js.map +1 -1
  148. package/dist/scheduler/local.d.ts.map +1 -1
  149. package/dist/scheduler/local.js +1 -0
  150. package/dist/scheduler/local.js.map +1 -1
  151. package/dist/session/handoff/capacity.d.ts +2 -2
  152. package/dist/session/handoff/capacity.d.ts.map +1 -1
  153. package/dist/session/handoff/capacity.js +3 -2
  154. package/dist/session/handoff/capacity.js.map +1 -1
  155. package/dist/store/memory/disk.d.ts +6 -2
  156. package/dist/store/memory/disk.d.ts.map +1 -1
  157. package/dist/store/memory/disk.js +42 -25
  158. package/dist/store/memory/disk.js.map +1 -1
  159. package/dist/store/memory/index.d.ts +4 -0
  160. package/dist/store/memory/index.d.ts.map +1 -1
  161. package/dist/store/memory/index.js +55 -19
  162. package/dist/store/memory/index.js.map +1 -1
  163. package/dist/store/memory/memory.d.ts +3 -2
  164. package/dist/store/memory/memory.d.ts.map +1 -1
  165. package/dist/store/memory/memory.js +11 -2
  166. package/dist/store/memory/memory.js.map +1 -1
  167. package/dist/store/memory/operation-lock.d.ts +11 -0
  168. package/dist/store/memory/operation-lock.d.ts.map +1 -0
  169. package/dist/store/memory/operation-lock.js +94 -0
  170. package/dist/store/memory/operation-lock.js.map +1 -0
  171. package/dist/tools/builtins/computer-use.d.ts.map +1 -1
  172. package/dist/tools/builtins/computer-use.js +60 -10
  173. package/dist/tools/builtins/computer-use.js.map +1 -1
  174. package/dist/tools/builtins/run-code.d.ts +6 -0
  175. package/dist/tools/builtins/run-code.d.ts.map +1 -1
  176. package/dist/tools/builtins/run-code.js +15 -4
  177. package/dist/tools/builtins/run-code.js.map +1 -1
  178. package/dist/tools/builtins/search-tools.d.ts.map +1 -1
  179. package/dist/tools/builtins/search-tools.js +14 -2
  180. package/dist/tools/builtins/search-tools.js.map +1 -1
  181. package/dist/tools/defineTool.d.ts +2 -0
  182. package/dist/tools/defineTool.d.ts.map +1 -1
  183. package/dist/tools/defineTool.js +3 -0
  184. package/dist/tools/defineTool.js.map +1 -1
  185. package/dist/tools/memory/delete.d.ts +4 -0
  186. package/dist/tools/memory/delete.d.ts.map +1 -0
  187. package/dist/tools/memory/delete.js +26 -0
  188. package/dist/tools/memory/delete.js.map +1 -0
  189. package/dist/tools/memory/index.d.ts +2 -0
  190. package/dist/tools/memory/index.d.ts.map +1 -1
  191. package/dist/tools/memory/index.js +6 -0
  192. package/dist/tools/memory/index.js.map +1 -1
  193. package/dist/tools/memory/save.d.ts.map +1 -1
  194. package/dist/tools/memory/save.js +3 -2
  195. package/dist/tools/memory/save.js.map +1 -1
  196. package/dist/tools/memory/search.d.ts.map +1 -1
  197. package/dist/tools/memory/search.js +12 -5
  198. package/dist/tools/memory/search.js.map +1 -1
  199. package/dist/tools/memory/update.d.ts +4 -0
  200. package/dist/tools/memory/update.d.ts.map +1 -0
  201. package/dist/tools/memory/update.js +47 -0
  202. package/dist/tools/memory/update.js.map +1 -0
  203. package/dist/types/agent/scheduler.d.ts +5 -0
  204. package/dist/types/agent/scheduler.d.ts.map +1 -1
  205. package/dist/types/agent/task.d.ts +10 -0
  206. package/dist/types/agent/task.d.ts.map +1 -1
  207. package/dist/types/computer-use/index.d.ts +6 -0
  208. package/dist/types/computer-use/index.d.ts.map +1 -1
  209. package/dist/types/computer-use/index.js.map +1 -1
  210. package/dist/types/errors/catalog.js +1 -1
  211. package/dist/types/errors/catalog.js.map +1 -1
  212. package/dist/types/hitl/index.d.ts +11 -1
  213. package/dist/types/hitl/index.d.ts.map +1 -1
  214. package/dist/types/hitl/index.js.map +1 -1
  215. package/dist/types/memory/index.d.ts +14 -1
  216. package/dist/types/memory/index.d.ts.map +1 -1
  217. package/dist/types/project/entity.d.ts +1 -0
  218. package/dist/types/project/entity.d.ts.map +1 -1
  219. package/dist/types/provider/config.d.ts +2 -0
  220. package/dist/types/provider/config.d.ts.map +1 -1
  221. package/dist/types/provider/model.d.ts +4 -0
  222. package/dist/types/provider/model.d.ts.map +1 -1
  223. package/dist/types/run/answer-review.d.ts +2 -0
  224. package/dist/types/run/answer-review.d.ts.map +1 -1
  225. package/dist/types/run/events.d.ts +9 -0
  226. package/dist/types/run/events.d.ts.map +1 -1
  227. package/dist/types/run/events.js.map +1 -1
  228. package/dist/types/run/prepare-step.d.ts +19 -1
  229. package/dist/types/run/prepare-step.d.ts.map +1 -1
  230. package/dist/types/structured-output/index.d.ts +8 -2
  231. package/dist/types/structured-output/index.d.ts.map +1 -1
  232. package/dist/types/tool/index.d.ts +15 -0
  233. package/dist/types/tool/index.d.ts.map +1 -1
  234. package/dist/types/tool/index.js.map +1 -1
  235. package/dist/utils/json-snapshot.d.ts +3 -0
  236. package/dist/utils/json-snapshot.d.ts.map +1 -0
  237. package/dist/utils/json-snapshot.js +79 -0
  238. package/dist/utils/json-snapshot.js.map +1 -0
  239. package/package.json +4 -2
  240. package/src/bridge/a2a/mapper.ts +2 -0
  241. package/src/bridge/sse/mapper.ts +2 -0
  242. package/src/compaction/extractor.ts +21 -8
  243. package/src/compaction/manager.ts +11 -1
  244. package/src/compaction/verifier.ts +80 -18
  245. package/src/eval/harness-verification.ts +270 -0
  246. package/src/eval/index.ts +10 -0
  247. package/src/execution/code-runtime/json-value.ts +82 -0
  248. package/src/execution/code-runtime/worker-program.ts +239 -0
  249. package/src/execution/code-runtime/worker.ts +164 -111
  250. package/src/manager/agent/lifecycle.ts +340 -45
  251. package/src/manager/run/persistence.ts +7 -0
  252. package/src/provider/capabilities.ts +25 -1
  253. package/src/provider/fallback.ts +2 -0
  254. package/src/public-runtime.ts +4 -0
  255. package/src/public-tools.ts +5 -1
  256. package/src/public-types.ts +1 -0
  257. package/src/registry/tool/execute.ts +17 -79
  258. package/src/run/command-gate.ts +61 -13
  259. package/src/run/index.ts +2 -0
  260. package/src/run/memory-promoter.ts +32 -40
  261. package/src/run/memory-recall.ts +254 -0
  262. package/src/run/reporter.ts +1 -0
  263. package/src/run/token-budget.ts +4 -0
  264. package/src/run/workspace-fingerprint.ts +17 -8
  265. package/src/runtime/query/checkpoint.ts +96 -2
  266. package/src/runtime/query/executor.ts +77 -14
  267. package/src/runtime/query/index.ts +73 -16
  268. package/src/runtime/query/iteration/index.ts +377 -44
  269. package/src/runtime/query/iteration/native-output.ts +35 -0
  270. package/src/runtime/query/iteration/phases/advisory.ts +21 -11
  271. package/src/runtime/query/iteration/phases/compaction.ts +36 -14
  272. package/src/runtime/query/iteration/phases/context.ts +9 -0
  273. package/src/runtime/query/iteration/phases/tool-review.ts +5 -1
  274. package/src/runtime/query/iteration/phases/working-memory.ts +23 -5
  275. package/src/runtime/query/iteration/stream-turn.ts +2 -0
  276. package/src/runtime/query/steering.ts +19 -2
  277. package/src/runtime/query/tool-call-budget.ts +115 -0
  278. package/src/runtime/query/tooling.ts +6 -0
  279. package/src/scheduler/local.ts +1 -0
  280. package/src/session/handoff/capacity.ts +7 -3
  281. package/src/store/memory/disk.ts +52 -30
  282. package/src/store/memory/index.ts +75 -27
  283. package/src/store/memory/memory.ts +18 -6
  284. package/src/store/memory/operation-lock.ts +99 -0
  285. package/src/tools/builtins/computer-use.ts +61 -7
  286. package/src/tools/builtins/run-code.ts +24 -5
  287. package/src/tools/builtins/search-tools.ts +18 -3
  288. package/src/tools/defineTool.ts +5 -0
  289. package/src/tools/memory/delete.ts +29 -0
  290. package/src/tools/memory/index.ts +6 -0
  291. package/src/tools/memory/save.ts +4 -2
  292. package/src/tools/memory/search.ts +12 -5
  293. package/src/tools/memory/update.ts +50 -0
  294. package/src/types/agent/scheduler.ts +6 -0
  295. package/src/types/agent/task.ts +13 -0
  296. package/src/types/computer-use/index.ts +6 -0
  297. package/src/types/errors/catalog.ts +1 -1
  298. package/src/types/hitl/index.ts +11 -1
  299. package/src/types/memory/index.ts +16 -1
  300. package/src/types/project/entity.ts +1 -0
  301. package/src/types/provider/config.ts +2 -0
  302. package/src/types/provider/model.ts +4 -0
  303. package/src/types/run/answer-review.ts +2 -0
  304. package/src/types/run/events.ts +10 -0
  305. package/src/types/run/prepare-step.ts +19 -1
  306. package/src/types/structured-output/index.ts +15 -2
  307. package/src/types/tool/index.ts +16 -0
  308. package/src/utils/json-snapshot.ts +76 -0
@@ -1,4 +1,5 @@
1
1
  import { AGENT_MANAGER_DEFAULTS } from '../../constants/agent/index.js'
2
+ import { EMPTY_TOKEN_USAGE } from '../../constants/limits.js'
2
3
  import { GENAI } from '../../constants/telemetry/index.js'
3
4
  import type { AgentRegistry } from '../../registry/agent/definitions.js'
4
5
  import {
@@ -91,6 +92,18 @@ interface AgentManagerBaseDeps {
91
92
  */
92
93
  export type AgentManagerDeps = AgentManagerBaseDeps & TopicManagerDependency
93
94
 
95
+ /** Internal backpressure: the parent's unmeasured request owns its budget until its receipt. */
96
+ class ParentBudgetRequestPending extends Error {}
97
+
98
+ interface PendingSpawn {
99
+ ready: boolean
100
+ readonly task: AgentTask
101
+ readonly options: SendMessageOptions
102
+ readonly context: AgentTaskContext
103
+ readonly listener?: RunEventListener
104
+ readonly removeAbortListener: () => void
105
+ }
106
+
94
107
  interface ChildSpawnRecord {
95
108
  subSessionId: SubSessionId
96
109
  childSessionId: SessionId
@@ -141,6 +154,12 @@ export class AgentManager {
141
154
  private spawnLocks: Map<SessionId, Promise<void>> = new Map()
142
155
  private deps: AgentManagerDeps
143
156
  private topicManager: TopicManager
157
+ private readonly pendingSpawns = new Map<SessionId, PendingSpawn[]>()
158
+ private readonly drainingParents = new Set<SessionId>()
159
+ private readonly executingTasks = new Set<TaskId>()
160
+ private readonly cancelingTasks = new Set<TaskId>()
161
+ private admissionTimer: ReturnType<typeof setTimeout> | undefined
162
+ private disposed = false
144
163
 
145
164
  constructor(
146
165
  registry: AgentRegistry,
@@ -149,6 +168,9 @@ export class AgentManager {
149
168
  ) {
150
169
  this.registry = registry
151
170
  this.config = { ...AGENT_MANAGER_DEFAULTS, ...config }
171
+ const maxPending = this.config.maxPendingTasks ?? 128
172
+ if (!Number.isSafeInteger(maxPending) || maxPending < 1)
173
+ throw new Error('maxPendingTasks must be a positive safe integer')
152
174
  this.log = resolveLogger(deps.log).child({
153
175
  [SCOPE_ATTRIBUTE]: 'manager/agent/lifecycle',
154
176
  })
@@ -161,6 +183,182 @@ export class AgentManager {
161
183
  context: AgentTaskContext,
162
184
  listener?: RunEventListener,
163
185
  ): Promise<AgentTask> {
186
+ if (this.disposed) throw new Error('Agent manager is disposed')
187
+ if (this.config.capacityBehavior === 'queue')
188
+ return this.enqueueMessage(options, context, listener)
189
+ return this.startMessage(options, context, listener)
190
+ }
191
+
192
+ private async enqueueMessage(
193
+ options: SendMessageOptions,
194
+ context: AgentTaskContext,
195
+ listener?: RunEventListener,
196
+ ): Promise<AgentTask> {
197
+ context.parentAbortController.signal.throwIfAborted()
198
+ if (context.depth >= this.config.maxDepth)
199
+ throw new Error(`Max task depth ${this.config.maxDepth} exceeded`)
200
+ if (options.tenantId !== context.tenantId)
201
+ throw new Error('Tenant mismatch: cross-tenant spawn rejected')
202
+ const definition = this.registry.getOrThrow(options.agentId)
203
+ const count = [...this.pendingSpawns.values()].reduce((sum, queue) => sum + queue.length, 0)
204
+ if (count >= (this.config.maxPendingTasks ?? 128))
205
+ throw new Error(
206
+ `Delegation queue is full (${this.config.maxPendingTasks ?? 128} pending tasks). Wait for existing tasks before submitting more work.`,
207
+ )
208
+ const task: AgentTask = {
209
+ taskId: generateTaskId(),
210
+ agentId: options.agentId,
211
+ agent: definition.typedAgent,
212
+ childAbortController: createChildAbortController(context.parentAbortController),
213
+ context,
214
+ state: 'pending',
215
+ pendingMessages: [],
216
+ createdAt: Date.now(),
217
+ runEventListener: listener,
218
+ }
219
+ this.instances.set(task.taskId, task)
220
+ const onAbort = (): void => {
221
+ // Before admission this observer owns cancellation. Once child scope
222
+ // exists, startup rollback may abort its controller for a configuration
223
+ // error; that is a failure, not a user cancellation.
224
+ if (task.context === context || context.parentAbortController.signal.aborted)
225
+ this.cancel(task.taskId, 'parent')
226
+ }
227
+ task.childAbortController.signal.addEventListener('abort', onAbort, { once: true })
228
+ const entry: PendingSpawn = {
229
+ ready: false,
230
+ task,
231
+ options,
232
+ context,
233
+ listener,
234
+ removeAbortListener: () =>
235
+ task.childAbortController.signal.removeEventListener('abort', onAbort),
236
+ }
237
+ const queue = this.pendingSpawns.get(options.parentSessionId) ?? []
238
+ queue.push(entry)
239
+ this.pendingSpawns.set(options.parentSessionId, queue)
240
+ this.emit({
241
+ type: 'pending',
242
+ taskId: task.taskId,
243
+ agentId: options.agentId,
244
+ parentAgentId: context.parentAgentId,
245
+ depth: context.depth,
246
+ })
247
+ try {
248
+ await listener?.({
249
+ type: 'agent_pending',
250
+ runId: context.parentRunId,
251
+ taskId: task.taskId,
252
+ parentAgentId: context.parentAgentId,
253
+ childAgentId: options.agentId,
254
+ depth: context.depth,
255
+ })
256
+ entry.ready = true
257
+ } catch (error) {
258
+ this.failAdmission(entry, error)
259
+ }
260
+ this.pumpAdmissions(options.parentSessionId)
261
+ return task
262
+ }
263
+
264
+ private pumpAdmissions(parentSessionId: SessionId): void {
265
+ if (this.disposed || this.drainingParents.has(parentSessionId)) return
266
+ this.drainingParents.add(parentSessionId)
267
+ void this.drainAdmissions(parentSessionId)
268
+ .finally(() => {
269
+ this.drainingParents.delete(parentSessionId)
270
+ // External handoffs and metadata changes have no manager event. A
271
+ // single slow, unref'ed timer observes those without spinning or
272
+ // keeping a host alive. Actual completions wake admission directly.
273
+ if (!this.disposed && this.pendingSpawns.size > 0 && !this.admissionTimer) {
274
+ this.admissionTimer = setTimeout(() => {
275
+ this.admissionTimer = undefined
276
+ for (const parent of this.pendingSpawns.keys()) this.pumpAdmissions(parent)
277
+ }, 250)
278
+ this.admissionTimer.unref?.()
279
+ }
280
+ })
281
+ .catch((error) =>
282
+ this.log.error('Delegation admission failed', {
283
+ 'exception.message': toErrorMessage(error),
284
+ }),
285
+ )
286
+ }
287
+
288
+ private async drainAdmissions(parentSessionId: SessionId): Promise<void> {
289
+ const queue = this.pendingSpawns.get(parentSessionId)
290
+ if (!queue) return
291
+ while (!this.disposed && queue.length > 0) {
292
+ const entry = queue[0]
293
+ if (!entry) break
294
+ if (isTerminalAgentTaskState(entry.task.state)) {
295
+ entry.removeAbortListener()
296
+ queue.shift()
297
+ continue
298
+ }
299
+ // A concurrent enqueue can pump this same FIFO while the head's
300
+ // pending listener still owns its acknowledgement. Do not provision
301
+ // or spend until that acknowledgement succeeds.
302
+ if (!entry.ready) return
303
+ try {
304
+ await entry.options.beforeStart?.()
305
+ entry.task.childAbortController.signal.throwIfAborted()
306
+ await this.validateSpawn(entry.options, entry.context)
307
+ entry.task.childAbortController.signal.throwIfAborted()
308
+ await this.startMessage(entry.options, entry.context, entry.listener, entry.task)
309
+ entry.removeAbortListener()
310
+ } catch (error) {
311
+ if (
312
+ (error instanceof ParentBudgetRequestPending ||
313
+ (error instanceof DelegationCapacityExceeded && error.details.dimension === 'width')) &&
314
+ !isTerminalAgentTaskState(entry.task.state)
315
+ )
316
+ return
317
+ this.failAdmission(entry, error)
318
+ }
319
+ queue.shift()
320
+ }
321
+ if (queue.length === 0 && this.pendingSpawns.get(parentSessionId) === queue)
322
+ this.pendingSpawns.delete(parentSessionId)
323
+ }
324
+
325
+ private failAdmission(entry: PendingSpawn, reason: unknown): void {
326
+ entry.removeAbortListener()
327
+ const task = entry.task
328
+ if (isTerminalAgentTaskState(task.state)) return
329
+ task.childAbortController.abort(reason)
330
+ const error = toErrorMessage(reason)
331
+ task.result = {
332
+ runId: entry.context.parentRunId,
333
+ status: 'failed',
334
+ usage: { ...EMPTY_TOKEN_USAGE },
335
+ cost: { ...ZERO_COST },
336
+ iterations: 0,
337
+ durationMs: Date.now() - task.createdAt,
338
+ messages: [],
339
+ lastError: error,
340
+ }
341
+ task.state = 'failed'
342
+ task.completedAt = Date.now()
343
+ this.emit({ type: 'failed', taskId: task.taskId, error })
344
+ this.emitRunEvent(task, {
345
+ type: 'agent_failed',
346
+ runId: entry.context.parentRunId,
347
+ taskId: task.taskId,
348
+ error,
349
+ })
350
+ this.scheduleEviction(task.taskId)
351
+ this.resolveCompletionCallbacks(task.taskId)
352
+ }
353
+
354
+ private async startMessage(
355
+ options: SendMessageOptions,
356
+ context: AgentTaskContext,
357
+ listener?: RunEventListener,
358
+ queuedTask?: AgentTask,
359
+ ): Promise<AgentTask> {
360
+ await options.beforeStart?.()
361
+ queuedTask?.childAbortController.signal.throwIfAborted()
164
362
  if (context.depth >= this.config.maxDepth) {
165
363
  throw new Error(
166
364
  `Max task depth ${this.config.maxDepth} exceeded (current: ${context.depth}). Recursive agent delegation is limited to prevent resource exhaustion.`,
@@ -200,9 +398,32 @@ export class AgentManager {
200
398
  // Reserve synchronously before provisioning yields. The authority is shared
201
399
  // across managers and nested sessions, while the session lock below only
202
400
  // serializes filesystem capacity checks.
401
+ // Queued siblings share the available budget with the parent. The first
402
+ // of eight children receives at most one ninth; later siblings receive
403
+ // comparable grants instead of a geometric 1/2, 1/4, ... starvation tail.
404
+ let budgetShares = 1
405
+ if (queuedTask) {
406
+ const project = await requireOpenProject(
407
+ this.deps.sessionStore,
408
+ context.projectId,
409
+ context.tenantId,
410
+ 'spawn',
411
+ )
412
+ const children = await this.deps.sessionStore.getChildren(
413
+ options.parentSessionId,
414
+ context.tenantId,
415
+ )
416
+ const active = children.filter(
417
+ (child) =>
418
+ child.status !== 'idle' && child.status !== 'failed' && child.status !== 'archived',
419
+ ).length
420
+ budgetShares = Math.max(2, project.config.maxDelegationWidth - active + 1)
421
+ }
422
+ context.parentAbortController.signal.throwIfAborted()
423
+ queuedTask?.childAbortController.signal.throwIfAborted()
203
424
  const remaining = context.budget.remaining
204
425
  const maxAllocation = Number.isFinite(remaining)
205
- ? Math.floor(remaining * this.config.maxBudgetFraction)
426
+ ? Math.floor(Math.min(remaining * this.config.maxBudgetFraction, remaining / budgetShares))
206
427
  : (options.budgetAllocation?.tokenBudget ??
207
428
  (options.configOverrides?.tokenBudget === 0
208
429
  ? 200_000
@@ -217,6 +438,12 @@ export class AgentManager {
217
438
  message: `Cannot spawn "${options.agentId}": the parent has ${remaining} tokens remaining; a child allocation must be a finite positive integer.`,
218
439
  })
219
440
  }
441
+ // No await between this check and reserve: a parent's response may start
442
+ // during the scope reads above. Its own in-flight request is temporary
443
+ // backpressure; descendant requests are expected during a fan-out.
444
+ // Invalid/zero allocations above still fail rather than waiting forever.
445
+ if (queuedTask && context.budget.hasInFlightRequest)
446
+ throw new ParentBudgetRequestPending('The parent provider request is still in flight')
220
447
  const childBudget = context.budget.reserve(allocatedTokens)
221
448
  let spawnRecord: ChildSpawnRecord
222
449
  try {
@@ -230,9 +457,12 @@ export class AgentManager {
230
457
  let childAbortController: AbortController | undefined
231
458
  let agentTask: AgentTask | undefined
232
459
  try {
233
- childAbortController = createChildAbortController(context.parentAbortController)
460
+ childAbortController =
461
+ queuedTask?.childAbortController ??
462
+ createChildAbortController(context.parentAbortController)
234
463
 
235
- const taskId = generateTaskId()
464
+ childAbortController.signal.throwIfAborted()
465
+ const taskId = queuedTask?.taskId ?? generateTaskId()
236
466
 
237
467
  const childParentActor: ActorRef = {
238
468
  kind: 'agent',
@@ -279,40 +509,42 @@ export class AgentManager {
279
509
  ...(resolvedDenies.length > 0 ? { toolDenies: resolvedDenies } : {}),
280
510
  }
281
511
 
282
- agentTask = {
512
+ agentTask = Object.assign(queuedTask ?? {}, {
283
513
  taskId,
284
514
  agentId: options.agentId,
285
515
  agent,
286
516
  childAbortController,
287
517
  context: childContext,
288
518
  state: 'pending',
289
- pendingMessages: [],
290
- createdAt: Date.now(),
519
+ pendingMessages: queuedTask?.pendingMessages ?? [],
520
+ createdAt: queuedTask?.createdAt ?? Date.now(),
291
521
  runEventListener: listener,
292
- }
522
+ } satisfies AgentTask)
293
523
 
294
524
  childAbortController.signal.throwIfAborted()
295
525
  this.instances.set(taskId, agentTask)
296
526
  if (resolvedDenies.length > 0) spawnRecord.resolvedToolDenies = resolvedDenies
297
527
  this.spawnRecords.set(taskId, spawnRecord)
298
- this.emit({
299
- type: 'pending',
300
- taskId,
301
- agentId: options.agentId,
302
- parentAgentId: context.parentAgentId,
303
- depth: context.depth,
304
- })
305
-
306
- if (listener) {
307
- await listener({
308
- type: 'agent_pending',
309
- runId: context.parentRunId,
528
+ if (!queuedTask)
529
+ this.emit({
530
+ type: 'pending',
310
531
  taskId,
532
+ agentId: options.agentId,
311
533
  parentAgentId: context.parentAgentId,
312
- childAgentId: options.agentId,
313
534
  depth: context.depth,
314
535
  })
315
536
 
537
+ if (listener) {
538
+ if (!queuedTask)
539
+ await listener({
540
+ type: 'agent_pending',
541
+ runId: context.parentRunId,
542
+ taskId,
543
+ parentAgentId: context.parentAgentId,
544
+ childAgentId: options.agentId,
545
+ depth: context.depth,
546
+ })
547
+
316
548
  const lineage: Lineage = {
317
549
  parentSessionId: spawnRecord.parentSessionId,
318
550
  rootSessionId: spawnRecord.rootSessionId,
@@ -503,17 +735,35 @@ export class AgentManager {
503
735
 
504
736
  await childBudget.flush()
505
737
  childAbortController.signal.throwIfAborted()
506
- this.runChild(agentTask, options, childConfig, listener).catch(async (err) => {
507
- // A thrown invocation supplied no final usage receipt. Keep its
508
- // reservation, including when its task handle was canceled or evicted.
509
- let failure = err
510
- try {
511
- await childBudget.flush()
512
- } catch (writeError) {
513
- failure = writeError
514
- }
515
- this.markFailed(taskId, toErrorMessage(failure))
516
- })
738
+ this.executingTasks.add(taskId)
739
+ const runningTask = agentTask
740
+ this.runChild(runningTask, options, childConfig, listener)
741
+ .catch(async (err) => {
742
+ // A thrown invocation supplied no final usage receipt. Keep its
743
+ // reservation, including when its task handle was canceled or evicted.
744
+ let failure = err
745
+ try {
746
+ await childBudget.flush()
747
+ } catch (writeError) {
748
+ failure = writeError
749
+ }
750
+ // Cancellation may already have published a terminal handle. Its
751
+ // invocation has only NOW stopped; release the persisted edge here.
752
+ if (!this.instances.has(taskId) || isTerminalAgentTaskState(runningTask.state)) {
753
+ await this.failSubSession(spawnRecord)
754
+ } else this.markFailed(taskId, toErrorMessage(failure))
755
+ })
756
+ .finally(() => {
757
+ this.executingTasks.delete(taskId)
758
+ if (!this.instances.has(taskId)) this.spawnRecords.delete(taskId)
759
+ this.pumpAdmissions(options.parentSessionId)
760
+ })
761
+ .catch((error) =>
762
+ this.log.warn('Child cleanup failed', {
763
+ 'namzu.task.id': taskId,
764
+ 'exception.message': toErrorMessage(error),
765
+ }),
766
+ )
517
767
 
518
768
  return agentTask
519
769
  } catch (err) {
@@ -521,7 +771,7 @@ export class AgentManager {
521
771
  // provisioned resources are still ours to return. A builder/listener
522
772
  // failure must not strand a pending task the caller never received.
523
773
  if (agentTask) {
524
- await this.rollbackUnstartedSpawn(agentTask, spawnRecord, err)
774
+ await this.rollbackUnstartedSpawn(agentTask, spawnRecord, err, queuedTask !== undefined)
525
775
  } else {
526
776
  childAbortController?.abort()
527
777
  childBudget.settle(0)
@@ -536,6 +786,7 @@ export class AgentManager {
536
786
  agentTask: AgentTask,
537
787
  spawnRecord: ChildSpawnRecord,
538
788
  reason: unknown,
789
+ retainHandle = false,
539
790
  ): Promise<void> {
540
791
  agentTask.childAbortController.abort()
541
792
  agentTask.context.budget.settle(0)
@@ -559,7 +810,20 @@ export class AgentManager {
559
810
  }
560
811
  }
561
812
  this.clearEvictionTimer(agentTask.taskId)
562
- this.instances.delete(agentTask.taskId)
813
+ if (retainHandle) {
814
+ agentTask.result ??= {
815
+ runId: agentTask.context.parentRunId,
816
+ status: 'failed',
817
+ usage: { ...EMPTY_TOKEN_USAGE },
818
+ cost: { ...ZERO_COST },
819
+ iterations: 0,
820
+ durationMs: Date.now() - agentTask.createdAt,
821
+ messages: [],
822
+ lastError: toErrorMessage(reason),
823
+ }
824
+ agentTask.completedAt = Date.now()
825
+ this.scheduleEviction(agentTask.taskId)
826
+ } else this.instances.delete(agentTask.taskId)
563
827
  this.spawnRecords.delete(agentTask.taskId)
564
828
  this.resolveCompletionCallbacks(agentTask.taskId)
565
829
  await this.rollbackSpawnResources(spawnRecord)
@@ -581,14 +845,22 @@ export class AgentManager {
581
845
  }
582
846
 
583
847
  cancel(taskId: TaskId, cause?: CancelCause): void {
848
+ if (this.cancelingTasks.has(taskId)) return
584
849
  const agentTask = this.instances.get(taskId)
585
850
  if (!agentTask || isTerminalAgentTaskState(agentTask.state)) return
586
851
 
587
852
  // Was the bare string `'canceled'`, which `abortReasonText` suppresses
588
853
  // by name — its docblock cites this exact call site — so the child's
589
854
  // run saw a cancellation with no attributable origin at all.
590
- agentTask.childAbortController.abort(cause ? new RunCancelled(cause) : undefined)
591
- this.markCanceled(taskId, cause)
855
+ // Abort listeners run synchronously. A pending task's parent observer
856
+ // must not reenter this method and replace an explicit user's cause.
857
+ this.cancelingTasks.add(taskId)
858
+ try {
859
+ agentTask.childAbortController.abort(cause ? new RunCancelled(cause) : undefined)
860
+ this.markCanceled(taskId, cause)
861
+ } finally {
862
+ this.cancelingTasks.delete(taskId)
863
+ }
592
864
  }
593
865
 
594
866
  cancelAll(parentRunId: RunId, cause: CancelCause = 'parent'): void {
@@ -687,12 +959,18 @@ export class AgentManager {
687
959
  if (isTerminalAgentTaskState(agentTask.state)) {
688
960
  this.clearEvictionTimer(taskId)
689
961
  this.instances.delete(taskId)
690
- this.spawnRecords.delete(taskId)
962
+ if (!this.executingTasks.has(taskId)) this.spawnRecords.delete(taskId)
691
963
  }
692
964
  }
693
965
  }
694
966
 
695
967
  dispose(): void {
968
+ this.disposed = true
969
+ if (this.admissionTimer) clearTimeout(this.admissionTimer)
970
+ this.admissionTimer = undefined
971
+ for (const queue of this.pendingSpawns.values())
972
+ for (const entry of queue) entry.removeAbortListener()
973
+ this.pendingSpawns.clear()
696
974
  for (const taskId of this.instances.keys()) {
697
975
  this.clearEvictionTimer(taskId)
698
976
  }
@@ -704,7 +982,8 @@ export class AgentManager {
704
982
  this.cancel(taskId)
705
983
  }
706
984
  this.instances.clear()
707
- this.spawnRecords.clear()
985
+ for (const taskId of this.spawnRecords.keys())
986
+ if (!this.executingTasks.has(taskId)) this.spawnRecords.delete(taskId)
708
987
  this.listeners.length = 0
709
988
  }
710
989
 
@@ -748,10 +1027,10 @@ export class AgentManager {
748
1027
  }
749
1028
  }
750
1029
 
751
- private async provisionSpawnUnlocked(
1030
+ private async validateSpawn(
752
1031
  options: SendMessageOptions,
753
1032
  context: AgentTaskContext,
754
- ): Promise<ChildSpawnRecord> {
1033
+ ): Promise<void> {
755
1034
  // Phase 9: deps are unconditional required. Every spawn produces a
756
1035
  // SubSession + Session + WorkspaceRef triple (Convention #0: no
757
1036
  // partial/legacy path).
@@ -782,6 +1061,8 @@ export class AgentManager {
782
1061
  `Parent session ${options.parentSessionId} not found for tenant ${context.tenantId} — spawn rejected`,
783
1062
  )
784
1063
  }
1064
+ if (parentSession.status === 'archived')
1065
+ throw new Error('Delegation parent session is archived')
785
1066
  if (parentSession.topicId !== context.topicId) {
786
1067
  throw new Error(
787
1068
  `Topic mismatch on spawn: parent session ${parentSession.id} is on topic ${parentSession.topicId}, but context.topicId=${context.topicId}. Cross-topic spawn is forbidden (session-hierarchy.md §6.3).`,
@@ -812,6 +1093,15 @@ export class AgentManager {
812
1093
  project.config.maxDelegationWidth,
813
1094
  context.tenantId,
814
1095
  )
1096
+ }
1097
+
1098
+ private async provisionSpawnUnlocked(
1099
+ options: SendMessageOptions,
1100
+ context: AgentTaskContext,
1101
+ ): Promise<ChildSpawnRecord> {
1102
+ await this.validateSpawn(options, context)
1103
+ context.parentAbortController.signal.throwIfAborted()
1104
+ const store = this.deps.sessionStore
815
1105
 
816
1106
  // Ancestry walk gives both the child depth and the root session id
817
1107
  // attached to every sub-session event from here down.
@@ -1228,6 +1518,7 @@ export class AgentManager {
1228
1518
  }
1229
1519
 
1230
1520
  private scheduleEviction(taskId: TaskId): void {
1521
+ if (this.disposed) return
1231
1522
  const agentTask = this.instances.get(taskId)
1232
1523
  if (!agentTask) return
1233
1524
 
@@ -1235,7 +1526,7 @@ export class AgentManager {
1235
1526
 
1236
1527
  const timer = setTimeout(() => {
1237
1528
  this.instances.delete(taskId)
1238
- this.spawnRecords.delete(taskId)
1529
+ if (!this.executingTasks.has(taskId)) this.spawnRecords.delete(taskId)
1239
1530
  this.evictionTimers.delete(taskId)
1240
1531
  this.log.info('Agent task evicted', { 'namzu.agent.task_id': taskId })
1241
1532
  }, this.config.evictionMs)
@@ -1274,15 +1565,19 @@ export class AgentManager {
1274
1565
 
1275
1566
  private emitRunEvent(agentTask: AgentTask, event: RunEvent): void {
1276
1567
  if (!agentTask.runEventListener) return
1277
- try {
1278
- agentTask.runEventListener(event)
1279
- } catch (err) {
1568
+ const reportFailure = (error: unknown): void => {
1280
1569
  this.log.error('RunEvent emission error', {
1281
1570
  'namzu.event.type': event.type,
1282
- 'namzu.task.id': agentTask.taskId,
1283
- 'exception.message': toErrorMessage(err),
1571
+ 'exception.message': toErrorMessage(error),
1284
1572
  })
1285
1573
  }
1574
+ try {
1575
+ // Terminal observation must not delay completion or leak a rejected
1576
+ // listener promise into the host as an unhandled rejection.
1577
+ void Promise.resolve(agentTask.runEventListener(event)).catch(reportFailure)
1578
+ } catch (error) {
1579
+ reportFailure(error)
1580
+ }
1286
1581
  }
1287
1582
  }
1288
1583
 
@@ -306,6 +306,7 @@ export class RunPersistence {
306
306
  }
307
307
 
308
308
  markFailed(error: string, providerError?: ProviderErrorInfo): void {
309
+ this.clearStructuredOutput()
309
310
  this.run.status = 'failed'
310
311
  this.run.stopReason = 'error'
311
312
  this.run.lastError = error
@@ -314,6 +315,7 @@ export class RunPersistence {
314
315
  }
315
316
 
316
317
  markCancelled(): void {
318
+ this.clearStructuredOutput()
317
319
  this.run.status = 'cancelled'
318
320
  this.run.stopReason = 'cancelled'
319
321
  this.run.endedAt = Date.now()
@@ -459,6 +461,11 @@ export class RunPersistence {
459
461
  * and without the override flag it would walk the tail and put the stale
460
462
  * prose back.
461
463
  */
464
+ /** Invalidate a structured value without replacing the host's textual result. */
465
+ clearStructuredOutput(): void {
466
+ delete this.run.structuredOutput
467
+ }
468
+
462
469
  setStructuredOutput(value: unknown): void {
463
470
  this.run.structuredOutput = value
464
471
  this.setResult(typeof value === 'string' ? value : JSON.stringify(value))
@@ -1,4 +1,9 @@
1
- import type { LLMProvider, ProviderCapabilities } from '../types/provider/index.js'
1
+ import type {
2
+ ChatCompletionParams,
3
+ LLMProvider,
4
+ ProviderCapabilities,
5
+ } from '../types/provider/index.js'
6
+ import { ProviderRequestError } from './errors.js'
2
7
 
3
8
  /**
4
9
  * Fully-resolved capability set: every flag present, no optionals left.
@@ -59,3 +64,22 @@ export function resolveProviderCapabilities(
59
64
  maxOutputTokens: declared?.maxOutputTokens,
60
65
  }
61
66
  }
67
+
68
+ /** Require explicit wire support before dispatching a native JSON Schema request. */
69
+ export function assertNativeStructuredOutputSupported(
70
+ provider: Pick<LLMProvider, 'id' | 'capabilities'>,
71
+ params: Pick<ChatCompletionParams, 'responseFormat'>,
72
+ ): void {
73
+ if (
74
+ params.responseFormat?.type === 'json_schema' &&
75
+ provider.capabilities?.supportsNativeStructuredOutput !== true
76
+ ) {
77
+ throw new ProviderRequestError({
78
+ kind: 'bad_request',
79
+ providerId: provider.id,
80
+ providerCode: 'native_structured_output_unsupported',
81
+ detail:
82
+ 'Native JSON Schema output requires a provider that declares supportsNativeStructuredOutput: true.',
83
+ })
84
+ }
85
+ }
@@ -31,6 +31,7 @@ import type {
31
31
  ThinkingConfig,
32
32
  } from '../types/provider/index.js'
33
33
  import type { Logger } from '../utils/logger.js'
34
+ import { assertNativeStructuredOutputSupported } from './capabilities.js'
34
35
 
35
36
  /**
36
37
  * One member of the chain: a constructed provider, and the model to ask it for.
@@ -396,6 +397,7 @@ export function withProviderFallback(
396
397
  chainIndex: cursor,
397
398
  },
398
399
  }
400
+ assertNativeStructuredOutputSupported(member.provider, request)
399
401
  let produced = false
400
402
  try {
401
403
  for await (const chunk of member.provider.chatStream(request)) {
@@ -380,6 +380,8 @@ export type {
380
380
  // nothing.
381
381
  export { RUN_MEMORY_TAG, createMemoryPromoter } from './run/index.js'
382
382
  export type { MemoryPromoterOptions } from './run/index.js'
383
+ export { createMemoryRecallStep } from './run/memory-recall.js'
384
+ export type { MemoryRecallOptions } from './run/memory-recall.js'
383
385
 
384
386
  // ─── personas, skills, advisory ──────────────────────────────────────────
385
387
 
@@ -1111,6 +1113,8 @@ export { anyOf, hasToolCall, stepCountIs } from './types/run/step.js'
1111
1113
  // ─── evaluation harness ──────────────────────────────────────────────────
1112
1114
 
1113
1115
  export {
1116
+ compareHarnessTrials,
1117
+ reviewHarnessCandidate,
1114
1118
  completionScorer,
1115
1119
  containsScorer,
1116
1120
  customScorer,
@@ -97,7 +97,11 @@ export {
97
97
  buildTaskUpdateTool,
98
98
  } from './tools/task/index.js'
99
99
  export { buildAdvisoryTools } from './tools/advisory/index.js'
100
- export { buildMemoryTools } from './tools/memory/index.js'
100
+ export {
101
+ buildMemoryTools,
102
+ buildUpdateMemoryTool,
103
+ buildDeleteMemoryTool,
104
+ } from './tools/memory/index.js'
101
105
  export { buildCoordinatorTools } from './tools/coordinator/index.js'
102
106
  export {
103
107
  buildAskUserQuestionTool,
@@ -19,6 +19,7 @@ export type * from './types/common/index.js'
19
19
  export type { CoalesceOptions } from './streaming/coalesce.js'
20
20
  export type * from './types/bidi/index.js'
21
21
  export type * from './types/tool/index.js'
22
+ export type { WorkerCodeRuntimeOptions } from './execution/code-runtime/worker.js'
22
23
  export type {
23
24
  CodeRunOutcome,
24
25
  CodeRunResult,