@theokit/sdk 5.13.0 → 5.15.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 (241) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/{agent-DSMuwADp.d.ts → agent-B6C9i_qu.d.ts} +31 -213
  3. package/dist/{agent-iW5kPpfT.d.cts → agent-B6FQad6P.d.cts} +31 -213
  4. package/dist/{agent-5DSDDH7K.js → agent-DRDGUU6T.js} +21 -20
  5. package/dist/{agent-5DSDDH7K.js.map → agent-DRDGUU6T.js.map} +1 -1
  6. package/dist/{agent-WOMRT3KX.cjs → agent-VI2HITPT.cjs} +22 -21
  7. package/dist/{agent-WOMRT3KX.cjs.map → agent-VI2HITPT.cjs.map} +1 -1
  8. package/dist/agent.d.ts +2 -3
  9. package/dist/auth/index.cjs +17 -16
  10. package/dist/auth/index.cjs.map +1 -1
  11. package/dist/auth/index.js +5 -4
  12. package/dist/auth/index.js.map +1 -1
  13. package/dist/{batch-EP3FCL6D.js → batch-N2XDYZED.js} +4 -4
  14. package/dist/{batch-EP3FCL6D.js.map → batch-N2XDYZED.js.map} +1 -1
  15. package/dist/{batch-IZ5EDKJ5.cjs → batch-VFR2MAUE.cjs} +7 -7
  16. package/dist/{batch-IZ5EDKJ5.cjs.map → batch-VFR2MAUE.cjs.map} +1 -1
  17. package/dist/{chunk-XOYNB3YN.js → chunk-23SS4ID4.js} +3 -3
  18. package/dist/{chunk-XOYNB3YN.js.map → chunk-23SS4ID4.js.map} +1 -1
  19. package/dist/{chunk-NHOEXFZT.js → chunk-2HXTNVLM.js} +5 -2
  20. package/dist/chunk-2HXTNVLM.js.map +1 -0
  21. package/dist/{chunk-2C24NSNV.js → chunk-3BBTHFGJ.js} +3 -3
  22. package/dist/{chunk-2C24NSNV.js.map → chunk-3BBTHFGJ.js.map} +1 -1
  23. package/dist/{chunk-NP362THY.cjs → chunk-3F53FLQ7.cjs} +5 -7
  24. package/dist/chunk-3F53FLQ7.cjs.map +1 -0
  25. package/dist/{chunk-3FSBE4PS.js → chunk-3GTN4HOO.js} +10 -6
  26. package/dist/chunk-3GTN4HOO.js.map +1 -0
  27. package/dist/{chunk-7WARNHWW.cjs → chunk-3UMPP553.cjs} +5 -2
  28. package/dist/chunk-3UMPP553.cjs.map +1 -0
  29. package/dist/{chunk-SXH37C7X.cjs → chunk-55LLQFHW.cjs} +6 -6
  30. package/dist/{chunk-SXH37C7X.cjs.map → chunk-55LLQFHW.cjs.map} +1 -1
  31. package/dist/{chunk-QISSETTG.cjs → chunk-5645PMVU.cjs} +6 -4
  32. package/dist/chunk-5645PMVU.cjs.map +1 -0
  33. package/dist/{chunk-JX4LB6XO.js → chunk-5M5GQYBM.js} +617 -250
  34. package/dist/chunk-5M5GQYBM.js.map +1 -0
  35. package/dist/{chunk-KL7ZUMK3.cjs → chunk-64ECM3XM.cjs} +704 -337
  36. package/dist/chunk-64ECM3XM.cjs.map +1 -0
  37. package/dist/{chunk-ZJAYFSVI.js → chunk-7ACS6P5Z.js} +5 -7
  38. package/dist/chunk-7ACS6P5Z.js.map +1 -0
  39. package/dist/{chunk-5A4UFBHW.cjs → chunk-A77UMVMD.cjs} +15 -11
  40. package/dist/chunk-A77UMVMD.cjs.map +1 -0
  41. package/dist/{chunk-ZTP6ZACR.js → chunk-ARC2V7NY.js} +3 -3
  42. package/dist/{chunk-ZTP6ZACR.js.map → chunk-ARC2V7NY.js.map} +1 -1
  43. package/dist/{chunk-WDVG5R2Q.cjs → chunk-AUH2EVWY.cjs} +4 -3
  44. package/dist/chunk-AUH2EVWY.cjs.map +1 -0
  45. package/dist/chunk-BNEUB52I.cjs +55 -0
  46. package/dist/chunk-BNEUB52I.cjs.map +1 -0
  47. package/dist/chunk-BPL5CVZ5.js +53 -0
  48. package/dist/chunk-BPL5CVZ5.js.map +1 -0
  49. package/dist/{chunk-2SFLLOMN.js → chunk-CBBT42VX.js} +3 -3
  50. package/dist/{chunk-2SFLLOMN.js.map → chunk-CBBT42VX.js.map} +1 -1
  51. package/dist/chunk-CHKV2L2Y.cjs +416 -0
  52. package/dist/chunk-CHKV2L2Y.cjs.map +1 -0
  53. package/dist/{chunk-4UYHP6NF.cjs → chunk-DJKGDLYZ.cjs} +93 -63
  54. package/dist/chunk-DJKGDLYZ.cjs.map +1 -0
  55. package/dist/{chunk-354F3OF5.js → chunk-FGGVSHDW.js} +3 -3
  56. package/dist/{chunk-354F3OF5.js.map → chunk-FGGVSHDW.js.map} +1 -1
  57. package/dist/{chunk-6OCJWGVD.cjs → chunk-FTXY4D44.cjs} +4 -4
  58. package/dist/{chunk-6OCJWGVD.cjs.map → chunk-FTXY4D44.cjs.map} +1 -1
  59. package/dist/chunk-INVEGVGO.js +405 -0
  60. package/dist/chunk-INVEGVGO.js.map +1 -0
  61. package/dist/{chunk-2PRGRYEQ.js → chunk-IOBHFP2E.js} +50 -20
  62. package/dist/chunk-IOBHFP2E.js.map +1 -0
  63. package/dist/{chunk-47EACDOC.cjs → chunk-KMFBNKCT.cjs} +4 -4
  64. package/dist/{chunk-47EACDOC.cjs.map → chunk-KMFBNKCT.cjs.map} +1 -1
  65. package/dist/{chunk-DF77RBF4.js → chunk-LCCT5ZXJ.js} +6 -6
  66. package/dist/{chunk-DF77RBF4.js.map → chunk-LCCT5ZXJ.js.map} +1 -1
  67. package/dist/{chunk-G7XBVM3T.cjs → chunk-MHUOVS5I.cjs} +5 -5
  68. package/dist/{chunk-G7XBVM3T.cjs.map → chunk-MHUOVS5I.cjs.map} +1 -1
  69. package/dist/{chunk-CWQPQTUZ.cjs → chunk-NEH3BPFD.cjs} +15 -15
  70. package/dist/{chunk-CWQPQTUZ.cjs.map → chunk-NEH3BPFD.cjs.map} +1 -1
  71. package/dist/{chunk-5AR6O7GW.js → chunk-NK5EOTDY.js} +3 -3
  72. package/dist/{chunk-5AR6O7GW.js.map → chunk-NK5EOTDY.js.map} +1 -1
  73. package/dist/{chunk-S46WJTDL.cjs → chunk-P7QYG4RZ.cjs} +27 -19
  74. package/dist/chunk-P7QYG4RZ.cjs.map +1 -0
  75. package/dist/chunk-PPU2D4FZ.js +19 -0
  76. package/dist/chunk-PPU2D4FZ.js.map +1 -0
  77. package/dist/{chunk-MS3TQSXU.js → chunk-QD6B6W6I.js} +6 -4
  78. package/dist/chunk-QD6B6W6I.js.map +1 -0
  79. package/dist/{chunk-AB4OPJLD.js → chunk-RGVMJU57.js} +3 -3
  80. package/dist/{chunk-AB4OPJLD.js.map → chunk-RGVMJU57.js.map} +1 -1
  81. package/dist/{chunk-NWWTYBD3.cjs → chunk-RTDVSHJR.cjs} +5 -5
  82. package/dist/{chunk-NWWTYBD3.cjs.map → chunk-RTDVSHJR.cjs.map} +1 -1
  83. package/dist/{chunk-5HSMH2ZZ.js → chunk-RZL2W4C3.js} +25 -17
  84. package/dist/chunk-RZL2W4C3.js.map +1 -0
  85. package/dist/chunk-SPEN7RJU.cjs +18 -0
  86. package/dist/{chunk-LO6LIUZ6.cjs.map → chunk-SPEN7RJU.cjs.map} +1 -1
  87. package/dist/{chunk-ZF2LDKQQ.cjs → chunk-U3DW3WDE.cjs} +9 -8
  88. package/dist/chunk-U3DW3WDE.cjs.map +1 -0
  89. package/dist/{chunk-DVP3YMDA.cjs → chunk-U7PRI3XM.cjs} +3 -3
  90. package/dist/{chunk-DVP3YMDA.cjs.map → chunk-U7PRI3XM.cjs.map} +1 -1
  91. package/dist/{chunk-H7G65PNI.js → chunk-VCQ37TC5.js} +3 -3
  92. package/dist/{chunk-H7G65PNI.js.map → chunk-VCQ37TC5.js.map} +1 -1
  93. package/dist/{chunk-SDZ4XDWS.cjs → chunk-VWYFGE27.cjs} +9 -9
  94. package/dist/{chunk-SDZ4XDWS.cjs.map → chunk-VWYFGE27.cjs.map} +1 -1
  95. package/dist/{chunk-RN3XDZGS.js → chunk-WM646HEN.js} +4 -3
  96. package/dist/chunk-WM646HEN.js.map +1 -0
  97. package/dist/chunk-X7CE7Y5W.js +305 -0
  98. package/dist/chunk-X7CE7Y5W.js.map +1 -0
  99. package/dist/{chunk-CGH4BCIY.cjs → chunk-XE3CAY6Z.cjs} +5 -5
  100. package/dist/{chunk-CGH4BCIY.cjs.map → chunk-XE3CAY6Z.cjs.map} +1 -1
  101. package/dist/chunk-XOU3CL7S.cjs +312 -0
  102. package/dist/chunk-XOU3CL7S.cjs.map +1 -0
  103. package/dist/{chunk-NKQVLWDF.js → chunk-YKNBTHMD.js} +3 -3
  104. package/dist/{chunk-NKQVLWDF.js.map → chunk-YKNBTHMD.js.map} +1 -1
  105. package/dist/{compact-session-B7P6EU3Z.cjs → compact-session-NX7HUNTB.cjs} +18 -18
  106. package/dist/{compact-session-B7P6EU3Z.cjs.map → compact-session-NX7HUNTB.cjs.map} +1 -1
  107. package/dist/{compact-session-5HMX6KYT.js → compact-session-Q5IGNFPW.js} +9 -9
  108. package/dist/{compact-session-5HMX6KYT.js.map → compact-session-Q5IGNFPW.js.map} +1 -1
  109. package/dist/{cron-BvxrLW5J.d.cts → cron-Bh3aWgQ2.d.cts} +2 -2
  110. package/dist/{cron-DdKzwJqK.d.ts → cron-CCDxeeFZ.d.ts} +2 -2
  111. package/dist/cron.cjs +21 -20
  112. package/dist/cron.d.cts +4 -3
  113. package/dist/cron.d.ts +4 -3
  114. package/dist/cron.js +20 -19
  115. package/dist/eval.cjs +20 -19
  116. package/dist/eval.cjs.map +1 -1
  117. package/dist/eval.js +19 -18
  118. package/dist/eval.js.map +1 -1
  119. package/dist/fs-session-store-CYNTEPJZ.cjs +20 -0
  120. package/dist/{fs-session-store-S2AXVJIX.cjs.map → fs-session-store-CYNTEPJZ.cjs.map} +1 -1
  121. package/dist/fs-session-store-MYQEVUFL.js +11 -0
  122. package/dist/{fs-session-store-6ZCCJX3K.js.map → fs-session-store-MYQEVUFL.js.map} +1 -1
  123. package/dist/{index-manager-HO456AVW.cjs → index-manager-2KH75BRW.cjs} +7 -7
  124. package/dist/{index-manager-HO456AVW.cjs.map → index-manager-2KH75BRW.cjs.map} +1 -1
  125. package/dist/{index-manager-QDH56FER.js → index-manager-NF2WRLOU.js} +6 -6
  126. package/dist/{index-manager-QDH56FER.js.map → index-manager-NF2WRLOU.js.map} +1 -1
  127. package/dist/index.cjs +93 -273
  128. package/dist/index.cjs.map +1 -1
  129. package/dist/index.d.cts +13 -46
  130. package/dist/index.d.ts +13 -46
  131. package/dist/index.js +52 -236
  132. package/dist/index.js.map +1 -1
  133. package/dist/{inject-session-75L3NCNL.js → inject-session-4ROYLZHY.js} +3 -3
  134. package/dist/{inject-session-75L3NCNL.js.map → inject-session-4ROYLZHY.js.map} +1 -1
  135. package/dist/{inject-session-WOH7TPDX.cjs → inject-session-AWKDCGHV.cjs} +4 -4
  136. package/dist/{inject-session-WOH7TPDX.cjs.map → inject-session-AWKDCGHV.cjs.map} +1 -1
  137. package/dist/internal/agent-loop/doom-loop-tracker.d.ts +3 -0
  138. package/dist/internal/agent-loop/prune-tool-results.d.ts +37 -0
  139. package/dist/internal/agent-loop/types.d.ts +6 -0
  140. package/dist/internal/auth/credential-store.d.ts +1 -1
  141. package/dist/internal/auth/types.d.ts +4 -0
  142. package/dist/internal/error-mappers/anthropic.d.ts +3 -0
  143. package/dist/internal/error-mappers/openai-compatible.d.ts +2 -3
  144. package/dist/internal/local-agent/local-agent-dispatch.d.ts +3 -1
  145. package/dist/internal/local-agent/send-queue.d.ts +31 -0
  146. package/dist/internal/mcp/client.d.ts +2 -0
  147. package/dist/internal/mcp/oauth-bearer.d.ts +2 -0
  148. package/dist/internal/memory/adapters/index.cjs +3 -3
  149. package/dist/internal/memory/adapters/index.js +2 -2
  150. package/dist/internal/memory/dreaming/phases.d.ts +15 -0
  151. package/dist/internal/memory/dreaming/run.d.ts +29 -0
  152. package/dist/internal/memory/sdk-memory-peer-loader.d.ts +2 -0
  153. package/dist/internal/memory/storage/index.cjs +51 -35
  154. package/dist/internal/memory/storage/index.d.cts +2 -0
  155. package/dist/internal/memory/storage/index.d.ts +2 -0
  156. package/dist/internal/memory/storage/index.js +4 -4
  157. package/dist/internal/persistence/cwd-mutex.d.cts +4 -2
  158. package/dist/internal/persistence/cwd-mutex.d.ts +4 -2
  159. package/dist/internal/persistence/index.cjs +4 -4
  160. package/dist/internal/persistence/index.js +2 -2
  161. package/dist/internal/persistence/sqlite-session-store.d.cts +25 -0
  162. package/dist/internal/persistence/sqlite-session-store.d.ts +25 -0
  163. package/dist/internal/providers/registry.d.ts +5 -1
  164. package/dist/internal/runtime/skills/binary-on-path.d.ts +1 -0
  165. package/dist/internal/runtime/skills/discover-skills.d.ts +2 -0
  166. package/dist/mcp-auth.cjs +25 -307
  167. package/dist/mcp-auth.cjs.map +1 -1
  168. package/dist/mcp-auth.js +5 -305
  169. package/dist/mcp-auth.js.map +1 -1
  170. package/dist/models.cjs +11 -11
  171. package/dist/models.js +4 -4
  172. package/dist/persistence.cjs +9 -4
  173. package/dist/persistence.cjs.map +1 -1
  174. package/dist/persistence.d.cts +744 -40
  175. package/dist/persistence.d.ts +744 -40
  176. package/dist/persistence.js +3 -2
  177. package/dist/persistence.js.map +1 -1
  178. package/dist/providers.cjs +6 -6
  179. package/dist/providers.js +4 -4
  180. package/dist/sandbox/docker-sandbox.d.cts +58 -0
  181. package/dist/sandbox/docker-sandbox.d.ts +58 -0
  182. package/dist/sandbox/index.cjs +129 -1
  183. package/dist/sandbox/index.cjs.map +1 -1
  184. package/dist/sandbox/index.d.cts +1 -0
  185. package/dist/sandbox/index.d.ts +1 -0
  186. package/dist/sandbox/index.js +132 -5
  187. package/dist/sandbox/index.js.map +1 -1
  188. package/dist/{sdk-agent-4-dXI2GS.d.cts → sdk-agent-BA_6_wtc.d.cts} +57 -4
  189. package/dist/{sdk-agent-CTOJlWA_.d.ts → sdk-agent-CnwPODYH.d.ts} +57 -4
  190. package/dist/session-store-Dh07jr9N.d.cts +209 -0
  191. package/dist/session-store-Dh07jr9N.d.ts +209 -0
  192. package/dist/skills.cjs +4 -4
  193. package/dist/skills.js +1 -1
  194. package/dist/sqlite-session-store-BbcpKY1L.d.ts +64 -0
  195. package/dist/sqlite-session-store-TKXtT4ON.d.cts +64 -0
  196. package/dist/subagents-loader-KLWF4QPD.cjs +16 -0
  197. package/dist/{subagents-loader-TXOA5EJJ.cjs.map → subagents-loader-KLWF4QPD.cjs.map} +1 -1
  198. package/dist/subagents-loader-SXETS2F2.js +7 -0
  199. package/dist/{subagents-loader-Z744TAKD.js.map → subagents-loader-SXETS2F2.js.map} +1 -1
  200. package/dist/subagents-loader.cjs +2 -2
  201. package/dist/subagents-loader.d.cts +3 -2
  202. package/dist/subagents-loader.d.ts +3 -2
  203. package/dist/subagents-loader.js +1 -1
  204. package/dist/types/agent.d.ts +20 -1
  205. package/dist/types/budget-tracker.d.ts +6 -2
  206. package/dist/types/mcp.d.ts +14 -0
  207. package/dist/types/run.d.ts +42 -3
  208. package/dist/workflow.d.cts +1 -1
  209. package/dist/workflow.d.ts +1 -1
  210. package/docs/adr/mutation-testing-scope.md +66 -0
  211. package/docs/error-codes.md +48 -45
  212. package/docs/harness-capability-map.md +60 -6
  213. package/package.json +1 -1
  214. package/dist/chunk-2PRGRYEQ.js.map +0 -1
  215. package/dist/chunk-3FSBE4PS.js.map +0 -1
  216. package/dist/chunk-4UYHP6NF.cjs.map +0 -1
  217. package/dist/chunk-5A4UFBHW.cjs.map +0 -1
  218. package/dist/chunk-5HSMH2ZZ.js.map +0 -1
  219. package/dist/chunk-6CXRYPG7.cjs +0 -211
  220. package/dist/chunk-6CXRYPG7.cjs.map +0 -1
  221. package/dist/chunk-7WARNHWW.cjs.map +0 -1
  222. package/dist/chunk-JX4LB6XO.js.map +0 -1
  223. package/dist/chunk-KL7ZUMK3.cjs.map +0 -1
  224. package/dist/chunk-LO6LIUZ6.cjs +0 -18
  225. package/dist/chunk-MS3TQSXU.js.map +0 -1
  226. package/dist/chunk-MSEL5E5P.js +0 -204
  227. package/dist/chunk-MSEL5E5P.js.map +0 -1
  228. package/dist/chunk-NHOEXFZT.js.map +0 -1
  229. package/dist/chunk-NP362THY.cjs.map +0 -1
  230. package/dist/chunk-Q5EWJPRY.js +0 -18
  231. package/dist/chunk-Q5EWJPRY.js.map +0 -1
  232. package/dist/chunk-QISSETTG.cjs.map +0 -1
  233. package/dist/chunk-RN3XDZGS.js.map +0 -1
  234. package/dist/chunk-S46WJTDL.cjs.map +0 -1
  235. package/dist/chunk-WDVG5R2Q.cjs.map +0 -1
  236. package/dist/chunk-ZF2LDKQQ.cjs.map +0 -1
  237. package/dist/chunk-ZJAYFSVI.js.map +0 -1
  238. package/dist/fs-session-store-6ZCCJX3K.js +0 -11
  239. package/dist/fs-session-store-S2AXVJIX.cjs +0 -20
  240. package/dist/subagents-loader-TXOA5EJJ.cjs +0 -16
  241. package/dist/subagents-loader-Z744TAKD.js +0 -7
@@ -1,46 +1,47 @@
1
1
  import { submit, emitRunEvent } from './chunk-HWMGR3HA.js';
2
- import { enqueueSessionWrite, hydrateSession, persistTurnToTranscript, flushSessionWrites, appendSessionMessage, getSessionMessages, discardSession, clearSession } from './chunk-XOYNB3YN.js';
3
- import { IndexManager } from './chunk-2C24NSNV.js';
2
+ import { enqueueSessionWrite, hydrateSession, persistTurnToTranscript, flushSessionWrites, appendSessionMessage, getSessionMessages, discardSession, clearSession } from './chunk-23SS4ID4.js';
3
+ import { IndexManager } from './chunk-3BBTHFGJ.js';
4
4
  import { currentPersonalityContext, warnPersonalitySwitchInsideFork } from './chunk-HJ2LV464.js';
5
5
  import { extractCodePlugins, isCodePlugin } from './chunk-2SFBB54R.js';
6
- import { createOpenAiCompatibleRuntime } from './chunk-H7G65PNI.js';
6
+ import { createOpenAiCompatibleRuntime } from './chunk-VCQ37TC5.js';
7
7
  import { persistActiveMemoryTranscript } from './chunk-QK2ERTO3.js';
8
- import { resolveMaxFacts, writeSessionSummary, resolveMemoryRoot, MEMORY_KINDS, appendFact, readFacts, legacyMemoryJsonPath, memoryMdPath, appendFactToMarkdown } from './chunk-DF77RBF4.js';
9
- import { FsSessionStore } from './chunk-AB4OPJLD.js';
10
- import { discoverProviderPlugins, validateApiKeyShape, getConfiguredBaseUrl, httpRequest, isFixtureApiKey, presentProviderCredentialEnvVars, readTrustArray, buildDefaultSummarizer, shouldUseRealLocalRuntime, parseSseStream, CircuitBreaker, trustFilePath, resolveRunProvider, mergeExplicitApiKey, resolveProviderChain, abortError, tryFirstEvent, relayStream, renderToolResultContentText } from './chunk-2PRGRYEQ.js';
8
+ import { resolveMaxFacts, writeSessionSummary, resolveMemoryRoot, MEMORY_KINDS, appendFact, readFacts, legacyMemoryJsonPath, memoryMdPath, appendFactToMarkdown } from './chunk-LCCT5ZXJ.js';
9
+ import { FsSessionStore } from './chunk-RGVMJU57.js';
10
+ import { discoverProviderPlugins, validateApiKeyShape, getConfiguredBaseUrl, httpRequest, isFixtureApiKey, presentProviderCredentialEnvVars, readTrustArray, buildDefaultSummarizer, shouldUseRealLocalRuntime, parseSseStream, CircuitBreaker, trustFilePath, resolveRunProvider, mergeExplicitApiKey, resolveProviderChain, abortError, tryFirstEvent, relayStream, renderToolResultContentText } from './chunk-IOBHFP2E.js';
11
11
  import { resolveChildEnv } from './chunk-HKCKOAIO.js';
12
12
  import { DEFAULT_MAX_BYTES_PER_FILE, runDiscovery, truncateWithMarker } from './chunk-KCM3RMKR.js';
13
13
  import { warnFailureOnce, loadHookConfig, warnOnce } from './chunk-XJ3WU5CZ.js';
14
+ import { getTokens, lockedRefresh, refreshAccessToken, runPkceFlow, setTokens } from './chunk-X7CE7Y5W.js';
14
15
  import { readVersionedJson, writeVersionedJson } from './chunk-OLJOI4LK.js';
15
16
  import { toJsonSchema } from './chunk-7I5Z3UBJ.js';
16
17
  import { sanitizeToolInput } from './chunk-FJWQP6EE.js';
17
18
  import { withInheritedSubAgentCredentials, subAgentToolsFromDefinitions } from './chunk-VZGE7NAI.js';
18
19
  import { setAgentFacade } from './chunk-6X6ID4MO.js';
19
- import { escapeBlockBody, buildSkillsBlock, discoverSkills, stripSkillFrontmatter } from './chunk-NHOEXFZT.js';
20
+ import { escapeBlockBody, buildSkillsBlock, discoverSkills, stripSkillFrontmatter } from './chunk-2HXTNVLM.js';
20
21
  import { withToolWhitelist, checkToolWhitelist } from './chunk-SAGRF4IB.js';
21
22
  import { validateArtifactPath, PathTraversalError, safePathJoin } from './chunk-PKRPV3R7.js';
22
23
  import { insideRoot, atOrInsideRoot } from './chunk-UKMBRMGT.js';
23
24
  import { mapWithConcurrency } from './chunk-ORLTGPOS.js';
24
25
  import { expandTilde, defaultBaseDir } from './chunk-XESYJ4JC.js';
25
- import { withFileLock } from './chunk-354F3OF5.js';
26
- import { withCwdMutex } from './chunk-Q5EWJPRY.js';
26
+ import { withFileLock } from './chunk-FGGVSHDW.js';
27
+ import { withCwdMutex } from './chunk-PPU2D4FZ.js';
27
28
  import { sweepStaleAtomicTemps, atomicWriteJson } from './chunk-M4U24U6G.js';
28
- import { loadSubagents, pluginBundleDirs } from './chunk-RN3XDZGS.js';
29
+ import { loadSubagents, pluginBundleDirs } from './chunk-WM646HEN.js';
29
30
  import { reportUndeclaredSources, theokitConfigRoot, undefinedVariablesIn, getTheokitHome, adapterForConfigPath, adaptersForSurface, projectConfigRoots, pluginBundleRoots } from './chunk-YMVTUV5K.js';
30
31
  import { readWorkspaceDir, parseSimpleYaml } from './chunk-Q7UG242V.js';
31
32
  import { resolveEffectiveContextWindow, CONTEXT_WINDOW_FLOOR, CONTEXT_WINDOW_MARGIN } from './chunk-SZQFCHU6.js';
32
- import { isAnthropicFamilyModel } from './chunk-2SFLLOMN.js';
33
+ import { isAnthropicFamilyModel } from './chunk-CBBT42VX.js';
33
34
  import { parseModelId } from './chunk-R7WIIPUR.js';
34
- import { getProviderProfile } from './chunk-NKQVLWDF.js';
35
- import { getCatalogModelInfo, isPatchedModelKey } from './chunk-5HSMH2ZZ.js';
35
+ import { getProviderProfile } from './chunk-YKNBTHMD.js';
36
+ import { getCatalogModelInfo, isPatchedModelKey } from './chunk-RZL2W4C3.js';
36
37
  import { globalSingleton } from './chunk-AGACYRJ2.js';
37
38
  import { boundFetch } from './chunk-Q7GYMXVC.js';
38
- import { AgentRunError, coerceToKnownAgentRunErrorCode, UnknownAgentError, ConfigurationError, AuthenticationError, AgentDisposedError, UnsupportedRunOperationError, NetworkError, TheokitAgentError } from './chunk-TNFOU6SB.js';
39
- import { diag, resolveApiKey, API_KEY_ENV_VAR, redactSecrets, diagFailure } from './chunk-3OY6H3I7.js';
39
+ import { AgentRunError, coerceToKnownAgentRunErrorCode, UnknownAgentError, ConfigurationError, AuthenticationError, AgentDisposedError, UnsupportedRunOperationError, TheokitAgentError, NetworkError } from './chunk-TNFOU6SB.js';
40
+ import { diag, resolveApiKey, diagFailure, API_KEY_ENV_VAR, redactSecrets } from './chunk-3OY6H3I7.js';
40
41
  import { stat, mkdir, readFile, readdir, access, unlink } from 'fs/promises';
41
42
  import { randomUUID, createHash } from 'crypto';
42
- import { join, dirname, isAbsolute, resolve, relative } from 'path';
43
- import { existsSync, readFileSync, realpathSync } from 'fs';
43
+ import { join, dirname, isAbsolute, delimiter, resolve, relative } from 'path';
44
+ import { existsSync, readFileSync, realpathSync, accessSync, constants } from 'fs';
44
45
  import { platform } from 'process';
45
46
  import { spawn } from 'child_process';
46
47
  import { pathToFileURL } from 'url';
@@ -1673,7 +1674,10 @@ var RealCloudRun = class extends FixtureRunBase {
1673
1674
  await this.consumeStream(response);
1674
1675
  } catch (cause) {
1675
1676
  if (this.terminated) return;
1676
- this.fail(cause instanceof Error ? cause.message : String(cause));
1677
+ this.fail(
1678
+ cause instanceof Error ? cause.message : String(cause),
1679
+ cause instanceof TheokitAgentError ? cause : void 0
1680
+ );
1677
1681
  }
1678
1682
  }
1679
1683
  async postRun(apiKey, baseUrl) {
@@ -1751,13 +1755,17 @@ var RealCloudRun = class extends FixtureRunBase {
1751
1755
  message: { role: "assistant", content: [{ type: "text", text }] }
1752
1756
  };
1753
1757
  }
1754
- fail(message, code) {
1758
+ fail(message, cause) {
1755
1759
  const event = this.buildAssistantEvent(message);
1756
1760
  this.script.events.push(event);
1757
1761
  this.notifyNewEvents();
1758
1762
  this.script.result = message;
1759
1763
  if (this.script.errorDetail === void 0) {
1760
- this.script.errorDetail = { message, ...code !== void 0 ? { code } : {} };
1764
+ this.script.errorDetail = {
1765
+ message,
1766
+ ...cause?.code !== void 0 ? { code: cause.code } : {},
1767
+ ...cause !== void 0 ? { cause } : {}
1768
+ };
1761
1769
  }
1762
1770
  this.transitionTo("error");
1763
1771
  }
@@ -3163,34 +3171,230 @@ async function importEntry(candidate) {
3163
3171
  function isGeneralPlugin(value) {
3164
3172
  return isCodePlugin(value) && value.kind === "general" && typeof value.name === "string";
3165
3173
  }
3174
+
3175
+ // src/internal/runtime/registry/live-agent-registry.ts
3176
+ var DEFAULT_MAX_AGENTS = 100;
3177
+ var DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1e3;
3178
+ var DEFAULT_SWEEP_INTERVAL_MS = 6e4;
3179
+ var LiveAgentRegistry = class {
3180
+ #agents = /* @__PURE__ */ new Map();
3181
+ #maxAgents = DEFAULT_MAX_AGENTS;
3182
+ #idleTimeoutMs = DEFAULT_IDLE_TIMEOUT_MS;
3183
+ #sweepIntervalMs = DEFAULT_SWEEP_INTERVAL_MS;
3184
+ #onEvict;
3185
+ #sweepTimer;
3186
+ /**
3187
+ * Reconfigure registry behavior. Process-wide singleton (D310) — last
3188
+ * configure call wins for all subsequent operations.
3189
+ */
3190
+ configure(opts) {
3191
+ if (opts.maxAgents !== void 0) this.#maxAgents = Math.max(0, opts.maxAgents);
3192
+ if (opts.idleTimeoutMs !== void 0) this.#idleTimeoutMs = Math.max(0, opts.idleTimeoutMs);
3193
+ if (opts.sweepIntervalMs !== void 0)
3194
+ this.#sweepIntervalMs = Math.max(1e3, opts.sweepIntervalMs);
3195
+ this.#onEvict = opts.onEvict;
3196
+ this.#stopSweep();
3197
+ if (this.#idleTimeoutMs > 0) this.#startSweep();
3198
+ }
3199
+ /**
3200
+ * Lookup a cached agent. `get` is a use — refreshes `lastUsedAt` so the
3201
+ * entry survives LRU eviction.
3202
+ */
3203
+ get(id) {
3204
+ const entry = this.#agents.get(id);
3205
+ if (entry === void 0) return void 0;
3206
+ entry.lastUsedAt = Date.now();
3207
+ return entry.agent;
3208
+ }
3209
+ /**
3210
+ * Insert or overwrite an agent in the cache. Triggers fire-and-forget LRU
3211
+ * eviction when `size > maxAgents`.
3212
+ *
3213
+ * EC-4: when `id` already maps to a DIFFERENT agent instance, dispose the
3214
+ * old one before overwriting (race protection against two `getOrCreate`
3215
+ * calls creating two agents but only the second being cached — the first
3216
+ * would leak file handles + lifecycle controllers).
3217
+ */
3218
+ set(id, agent) {
3219
+ if (this.#maxAgents === 0) return;
3220
+ const existing = this.#agents.get(id);
3221
+ if (existing !== void 0 && existing.agent !== agent) {
3222
+ void existing.agent.dispose().catch(() => {
3223
+ diag(`[theokit-sdk] dispose during overwrite failed (${id})
3224
+ `);
3225
+ });
3226
+ }
3227
+ this.#agents.set(id, { agent, lastUsedAt: Date.now() });
3228
+ if (this.#agents.size > this.#maxAgents) void this.#evictLRU();
3229
+ }
3230
+ /**
3231
+ * Remove the entry from the cache WITHOUT calling `dispose()` or
3232
+ * `onEvict`. Used by `LocalAgent.dispose()` itself so the disposed
3233
+ * instance can never be returned by a subsequent `get(id)` (dispose-cache
3234
+ * race fix). Idempotent — calling on an unknown id is a no-op.
3235
+ *
3236
+ * @internal
3237
+ */
3238
+ forget(id) {
3239
+ this.#agents.delete(id);
3240
+ }
3241
+ /**
3242
+ * Explicitly evict an agent by id. Returns `true` when the entry was
3243
+ * present (false = already gone). Calls `agent.dispose()` + `onEvict`
3244
+ * with reason `"explicit"`.
3245
+ */
3246
+ async evict(id) {
3247
+ const entry = this.#agents.get(id);
3248
+ if (entry === void 0) return false;
3249
+ this.#agents.delete(id);
3250
+ await this.#disposeAndNotify(id, entry.agent, "explicit");
3251
+ return true;
3252
+ }
3253
+ /**
3254
+ * Evict every cached agent. Used by graceful shutdown (`process.on('SIGTERM')`)
3255
+ * or end-of-test cleanup.
3256
+ */
3257
+ async evictAll() {
3258
+ const entries = Array.from(this.#agents.entries());
3259
+ this.#agents.clear();
3260
+ this.#stopSweep();
3261
+ for (const [id, entry] of entries) {
3262
+ await this.#disposeAndNotify(id, entry.agent, "explicit");
3263
+ }
3264
+ }
3265
+ /** Number of currently cached agents. */
3266
+ size() {
3267
+ return this.#agents.size;
3268
+ }
3269
+ /** Ids of cached agents, newest first (by lastUsedAt). */
3270
+ ids() {
3271
+ return Array.from(this.#agents.entries()).sort((a, b) => b[1].lastUsedAt - a[1].lastUsedAt).map(([id]) => id);
3272
+ }
3273
+ /**
3274
+ * LRU eviction: drop the entry with the smallest `lastUsedAt`. Runs only
3275
+ * when `size > maxAgents`. Asynchronous because `dispose()` is a Promise;
3276
+ * the hot-path caller (`set`) does not await.
3277
+ *
3278
+ * @internal
3279
+ */
3280
+ async #evictLRU() {
3281
+ if (this.#agents.size <= this.#maxAgents) return;
3282
+ let oldestId;
3283
+ let oldestAt = Infinity;
3284
+ for (const [id, entry2] of this.#agents) {
3285
+ if (entry2.lastUsedAt < oldestAt) {
3286
+ oldestAt = entry2.lastUsedAt;
3287
+ oldestId = id;
3288
+ }
3289
+ }
3290
+ if (oldestId === void 0) return;
3291
+ const entry = this.#agents.get(oldestId);
3292
+ if (entry === void 0) return;
3293
+ this.#agents.delete(oldestId);
3294
+ await this.#disposeAndNotify(oldestId, entry.agent, "lru");
3295
+ }
3296
+ /** Background sweep — drops entries whose `lastUsedAt < now - idleTimeoutMs`. */
3297
+ async #sweepIdle() {
3298
+ if (this.#idleTimeoutMs === 0) return;
3299
+ const threshold = Date.now() - this.#idleTimeoutMs;
3300
+ const toEvict = [];
3301
+ for (const [id, entry] of this.#agents) {
3302
+ if (entry.lastUsedAt < threshold) toEvict.push([id, entry]);
3303
+ }
3304
+ for (const [id, entry] of toEvict) {
3305
+ const current = this.#agents.get(id);
3306
+ if (current === void 0 || current.agent !== entry.agent) continue;
3307
+ this.#agents.delete(id);
3308
+ await this.#disposeAndNotify(id, entry.agent, "idle");
3309
+ }
3310
+ }
3311
+ #startSweep() {
3312
+ this.#sweepTimer = setInterval(() => void this.#sweepIdle(), this.#sweepIntervalMs);
3313
+ this.#sweepTimer.unref?.();
3314
+ }
3315
+ #stopSweep() {
3316
+ if (this.#sweepTimer !== void 0) {
3317
+ clearInterval(this.#sweepTimer);
3318
+ this.#sweepTimer = void 0;
3319
+ }
3320
+ }
3321
+ /** Dispose + notify with errors swallowed (D309). Single chokepoint. */
3322
+ async #disposeAndNotify(id, agent, reason) {
3323
+ try {
3324
+ await agent.dispose();
3325
+ } catch (cause) {
3326
+ const msg = cause instanceof Error ? cause.message : String(cause);
3327
+ diag(`[theokit-sdk] dispose during eviction failed (${id}): ${msg}
3328
+ `);
3329
+ }
3330
+ if (this.#onEvict !== void 0) {
3331
+ try {
3332
+ this.#onEvict(id, reason);
3333
+ } catch (cause) {
3334
+ const msg = cause instanceof Error ? cause.message : String(cause);
3335
+ diag(`[theokit-sdk] onEvict listener threw (${id}): ${msg}
3336
+ `);
3337
+ }
3338
+ }
3339
+ }
3340
+ };
3341
+ var liveAgentRegistry = globalSingleton(
3342
+ "theokit-sdk.runtime.live-agents",
3343
+ () => new LiveAgentRegistry()
3344
+ );
3345
+ function executableExtensions() {
3346
+ return process.platform === "win32" ? ["", ...(process.env.PATHEXT ?? ".EXE;.CMD").split(";")] : [""];
3347
+ }
3348
+ function isExecutable(file) {
3349
+ try {
3350
+ accessSync(file, constants.X_OK);
3351
+ return true;
3352
+ } catch {
3353
+ return false;
3354
+ }
3355
+ }
3356
+ function binaryOnPath(bin) {
3357
+ if (bin.length === 0 || /[\\/]/.test(bin)) return false;
3358
+ const dirs = (process.env.PATH ?? "").split(delimiter).filter((dir) => dir.length > 0);
3359
+ return dirs.some(
3360
+ (dir) => executableExtensions().some((ext) => isExecutable(join(dir, bin + ext)))
3361
+ );
3362
+ }
3166
3363
  var SkillsManager = class {
3167
- constructor(cwd, _enabled, settingSourcesIncludeProject, skillsDir, inline, compatSources = []) {
3364
+ constructor(cwd, enabled, settingSourcesIncludeProject, skillsDir, inline, compatSources = [], bundledDirs = []) {
3168
3365
  this.cwd = cwd;
3366
+ this.enabled = enabled;
3169
3367
  this.settingSourcesIncludeProject = settingSourcesIncludeProject;
3170
3368
  this.skillsDir = skillsDir;
3171
3369
  this.inline = inline;
3172
3370
  this.compatSources = compatSources;
3371
+ this.bundledDirs = bundledDirs;
3173
3372
  }
3174
3373
  cwd;
3374
+ enabled;
3175
3375
  settingSourcesIncludeProject;
3176
3376
  skillsDir;
3177
3377
  inline;
3178
3378
  compatSources;
3379
+ bundledDirs;
3179
3380
  skills = [];
3180
3381
  async initialize() {
3181
3382
  if (!this.settingSourcesIncludeProject) {
3182
- this.skills = this.mergeInline([]);
3383
+ this.skills = this.mergeInline(await this.discoverFrom(this.bundledDirs));
3183
3384
  return;
3184
3385
  }
3185
3386
  await this.refresh();
3186
3387
  }
3187
3388
  async refresh() {
3188
- const roots = this.skillsDir === void 0 ? [
3389
+ const ownRoots = this.skillsDir === void 0 ? [
3189
3390
  ...projectConfigRoots(this.cwd, this.compatSources, "skills").map(
3190
3391
  (root) => join(root, "skills")
3191
3392
  ),
3192
3393
  ...(await pluginBundleDirs(this.cwd, this.compatSources)).map((b) => join(b, "skills"))
3193
3394
  ] : [this.skillsDir];
3395
+ this.skills = this.mergeInline(await this.discoverFrom([...ownRoots, ...this.bundledDirs]));
3396
+ }
3397
+ async discoverFrom(roots) {
3194
3398
  const discovered = [];
3195
3399
  const seen = /* @__PURE__ */ new Set();
3196
3400
  for (const root of roots) {
@@ -3205,7 +3409,7 @@ var SkillsManager = class {
3205
3409
  discovered.push(skill);
3206
3410
  }
3207
3411
  }
3208
- this.skills = this.mergeInline(discovered);
3412
+ return discovered;
3209
3413
  }
3210
3414
  /** M22 — merge inline skills over discovered ones; inline wins on a name conflict. */
3211
3415
  mergeInline(discovered) {
@@ -3213,8 +3417,12 @@ var SkillsManager = class {
3213
3417
  const inlineNames = new Set(this.inline.map((s) => s.name));
3214
3418
  return [...discovered.filter((s) => !inlineNames.has(s.name)), ...this.inline];
3215
3419
  }
3420
+ visible() {
3421
+ const allowed = this.enabled;
3422
+ return allowed === void 0 ? this.skills : this.skills.filter((s) => allowed.includes(s.name));
3423
+ }
3216
3424
  list() {
3217
- return Promise.resolve(this.skills);
3425
+ return Promise.resolve(this.visible());
3218
3426
  }
3219
3427
  /**
3220
3428
  * SE20 — resolve a skill by name INCLUDING its body. Inline (`createSkill`)
@@ -3223,7 +3431,7 @@ var SkillsManager = class {
3223
3431
  * enabled skill matches (malformed skills were already excluded at discovery).
3224
3432
  */
3225
3433
  async get(name) {
3226
- const skill = this.skills.find((s) => s.name === name);
3434
+ const skill = this.visible().find((s) => s.name === name);
3227
3435
  if (skill === void 0) return void 0;
3228
3436
  const instructions = typeof skill.instructions === "string" ? skill.instructions : stripSkillFrontmatter(await readFile(skill.source, "utf8"));
3229
3437
  const references = skill.references;
@@ -3333,7 +3541,8 @@ async function resolveSendSkills(inputs, userText, memoryFacts) {
3333
3541
  inputs.settingSourcesIncludeProject,
3334
3542
  settings.skillsDir,
3335
3543
  settings.inline,
3336
- resolveCompatSources(inputs.options, inputs.workspaceCwd)
3544
+ resolveCompatSources(inputs.options, inputs.workspaceCwd),
3545
+ settings.bundledDirs
3337
3546
  );
3338
3547
  await manager.initialize();
3339
3548
  return { manager, autoInject: settings.autoInject ?? true };
@@ -3352,7 +3561,9 @@ async function buildSystemPromptContext(inputs, userText, memoryFacts, manager =
3352
3561
  // because a caller naming one has already made the decision this field keeps away from the
3353
3562
  // model. Widening it to execution would break the case the field is FOR — a side-effecting
3354
3563
  // skill a human may run and the model may not propose.
3355
- skills: skills.filter((skill) => skill.disableModelInvocation !== true).map((skill) => ({ name: skill.name, description: skill.description })),
3564
+ skills: skills.filter((skill) => skill.disableModelInvocation !== true).filter(
3565
+ (skill) => skill.requiresBins === void 0 || skill.requiresBins.every((bin) => binaryOnPath(bin))
3566
+ ).map((skill) => ({ name: skill.name, description: skill.description })),
3356
3567
  userMessage: userText,
3357
3568
  memory: memoryFacts.map((fact) => ({ text: fact.text }))
3358
3569
  };
@@ -3648,6 +3859,23 @@ function validateMcpServers(options) {
3648
3859
  { code: "cloud_stdio_cwd_rejected" }
3649
3860
  );
3650
3861
  }
3862
+ rejectUnhonourableAuth(name, config, options.cloud !== void 0);
3863
+ }
3864
+ }
3865
+ function rejectUnhonourableAuth(name, config, cloud) {
3866
+ const auth = config.auth;
3867
+ if (auth === void 0) return;
3868
+ if (auth.oauth === void 0) {
3869
+ throw new ConfigurationError(
3870
+ `MCP server "${name}" declares auth without auth.oauth, which the SDK cannot honour; use auth.oauth or set an Authorization header`,
3871
+ { code: "mcp_auth_unsupported" }
3872
+ );
3873
+ }
3874
+ if (cloud) {
3875
+ throw new ConfigurationError(
3876
+ `MCP server "${name}" declares auth.oauth, which the SDK cannot run for a cloud agent`,
3877
+ { code: "mcp_auth_unsupported" }
3878
+ );
3651
3879
  }
3652
3880
  }
3653
3881
  function isStdioWithCwd(config) {
@@ -4164,8 +4392,13 @@ function wrapSpan(span, openSpans) {
4164
4392
  setAttribute: (k, v) => safe(() => span.setAttribute(k, redactAttrValue(v)), void 0),
4165
4393
  setAttributes: (attrs) => safe(() => span.setAttributes(redactAttrs(attrs)), void 0),
4166
4394
  addEvent: (name, attrs) => safe(() => span.addEvent(name, attrs ? redactAttrs(attrs) : void 0), void 0),
4167
- setStatus: (status) => safe(() => span.setStatus(status), void 0),
4168
- recordException: (err) => safe(() => span.recordException(err), void 0),
4395
+ setStatus: (status) => safe(
4396
+ () => span.setStatus(
4397
+ status.message === void 0 ? status : { ...status, message: redactSecrets(status.message) }
4398
+ ),
4399
+ void 0
4400
+ ),
4401
+ recordException: (err) => safe(() => span.recordException(redactException(err)), void 0),
4169
4402
  end: (endTime) => {
4170
4403
  safe(() => span.end(endTime), void 0);
4171
4404
  openSpans.delete(span);
@@ -4174,6 +4407,18 @@ function wrapSpan(span, openSpans) {
4174
4407
  isRecording: () => safe(() => span.isRecording(), false)
4175
4408
  };
4176
4409
  }
4410
+ function redactException(err) {
4411
+ if (typeof err === "string") return redactSecrets(err);
4412
+ if (typeof err !== "object" || err === null) return err;
4413
+ const src = err;
4414
+ const out = {};
4415
+ for (const k of ["name", "code", "message", "stack"]) {
4416
+ const v = src[k];
4417
+ if (typeof v === "string") out[k] = redactSecrets(v);
4418
+ else if (typeof v === "number") out[k] = v;
4419
+ }
4420
+ return out;
4421
+ }
4177
4422
  function redactAttrValue(value) {
4178
4423
  if (typeof value !== "string") return value;
4179
4424
  return redactSecrets(value);
@@ -4897,7 +5142,8 @@ function buildSkills(args, out) {
4897
5142
  staticSkills?.inline,
4898
5143
  // #524 — the same declaration the per-send manager reads. Omitting it here would make
4899
5144
  // `agent.skills` disagree with the system prompt about which skills exist.
4900
- resolveCompatSources(args.options, args.workspaceCwd)
5145
+ resolveCompatSources(args.options, args.workspaceCwd),
5146
+ staticSkills?.bundledDirs
4901
5147
  );
4902
5148
  const localSkills = out.skillsManager;
4903
5149
  out.skills = {
@@ -5137,7 +5383,9 @@ function evaluateBudgetGate(tracker) {
5137
5383
  return {
5138
5384
  allowed: false,
5139
5385
  reason: "custom",
5140
- detail: `budget_tracker_check_threw: ${message}`
5386
+ detail: `budget_tracker_check_threw: ${message}`,
5387
+ // Keep the thrown value so the run's error can carry it as its cause.
5388
+ cause: error
5141
5389
  };
5142
5390
  }
5143
5391
  }
@@ -5147,11 +5395,12 @@ function createDoomLoopTracker(option) {
5147
5395
  if (option === false) return void 0;
5148
5396
  return new DoomLoopTracker(option);
5149
5397
  }
5150
- var DEFAULT_CONFIG = { softThreshold: 3, hardThreshold: 5 };
5151
- function assertValidThresholds(soft, hard) {
5398
+ var DEFAULT_CONFIG = { softThreshold: 3, hardThreshold: 5, churnThreshold: 6 };
5399
+ function assertValidThresholds(soft, hard, churn) {
5152
5400
  for (const [label, value] of [
5153
5401
  ["softThreshold", soft],
5154
- ["hardThreshold", hard]
5402
+ ["hardThreshold", hard],
5403
+ ["churnThreshold", churn]
5155
5404
  ]) {
5156
5405
  if (!Number.isInteger(value) || value < 1) {
5157
5406
  throw new ConfigurationError(
@@ -5188,17 +5437,40 @@ var DoomLoopTracker = class {
5188
5437
  #config;
5189
5438
  #lastSignature = "";
5190
5439
  #count = 0;
5440
+ #lastName = "";
5441
+ #lastResult;
5442
+ #churn = 0;
5191
5443
  constructor(config) {
5192
5444
  const softThreshold = config?.softThreshold ?? DEFAULT_CONFIG.softThreshold;
5193
5445
  const hardThreshold = config?.hardThreshold ?? DEFAULT_CONFIG.hardThreshold;
5194
- assertValidThresholds(softThreshold, hardThreshold);
5195
- this.#config = { softThreshold, hardThreshold };
5446
+ const churnThreshold = config?.churnThreshold ?? DEFAULT_CONFIG.churnThreshold;
5447
+ assertValidThresholds(softThreshold, hardThreshold, churnThreshold);
5448
+ this.#config = { softThreshold, hardThreshold, churnThreshold };
5196
5449
  }
5197
5450
  inspect(call) {
5198
5451
  const signature = signatureOf(call);
5199
- this.#count = signature === this.#lastSignature ? this.#count + 1 : 1;
5452
+ const identical = signature === this.#lastSignature;
5453
+ const churning = !identical && call.name === this.#lastName && call.result !== void 0 && call.result === this.#lastResult;
5454
+ this.#churn = churning ? this.#churn + 1 : 1;
5455
+ this.#lastName = call.name;
5456
+ this.#lastResult = call.result;
5457
+ this.#count = identical ? this.#count + 1 : 1;
5200
5458
  this.#lastSignature = signature;
5201
5459
  const count = this.#count;
5460
+ const churn = this.#churn;
5461
+ const churnHard = this.#config.churnThreshold;
5462
+ if (churn >= churnHard) {
5463
+ return {
5464
+ kind: "hard",
5465
+ message: `Detected argument churn: ${churn} consecutive calls to \`${call.name}\` with different arguments and no change in the result; stopping to avoid a loop.`
5466
+ };
5467
+ }
5468
+ if (churn > 1 && churn === Math.max(2, churnHard - 2)) {
5469
+ return {
5470
+ kind: "soft",
5471
+ message: `Detected argument churn: ${churn} consecutive calls to \`${call.name}\` with different arguments and no change in the result; try a different approach.`
5472
+ };
5473
+ }
5202
5474
  if (count >= this.#config.hardThreshold) {
5203
5475
  return {
5204
5476
  kind: "hard",
@@ -5216,6 +5488,9 @@ var DoomLoopTracker = class {
5216
5488
  reset() {
5217
5489
  this.#lastSignature = "";
5218
5490
  this.#count = 0;
5491
+ this.#lastName = "";
5492
+ this.#lastResult = void 0;
5493
+ this.#churn = 0;
5219
5494
  }
5220
5495
  };
5221
5496
  function firstDoomLoopVerdict(tracker, calls) {
@@ -5460,7 +5735,16 @@ async function initLoopContext(inputs) {
5460
5735
  ),
5461
5736
  buildUserEvent(inputs)
5462
5737
  ]);
5463
- if (inputs.onLoopEvent !== void 0) events.subscribe(inputs.onLoopEvent);
5738
+ if (inputs.onLoopEvent !== void 0) {
5739
+ const sink = inputs.onLoopEvent;
5740
+ for (const seeded of events) {
5741
+ try {
5742
+ sink(seeded);
5743
+ } catch {
5744
+ }
5745
+ }
5746
+ events.subscribe(sink);
5747
+ }
5464
5748
  const priorMessages = replayMessages(inputs.priorMessages ?? []);
5465
5749
  let memorySystemPromptAdditions;
5466
5750
  if (inputs.memoryProvider !== void 0 && memoryProviderHandle !== void 0) {
@@ -5549,7 +5833,8 @@ async function collectTools(mcp, withheld, sink) {
5549
5833
  inputSchema: tool.inputSchema,
5550
5834
  origin: "mcp",
5551
5835
  mcpServerName: serverName,
5552
- mcpToolName: tool.name
5836
+ mcpToolName: tool.name,
5837
+ ...client.sequential === true ? { mcpSequential: true } : {}
5553
5838
  });
5554
5839
  }
5555
5840
  }
@@ -5964,6 +6249,42 @@ function stripThinkBlocks(content) {
5964
6249
  return { visible, thinking };
5965
6250
  }
5966
6251
 
6252
+ // src/internal/agent-loop/prune-tool-results.ts
6253
+ function stubFor(olderThanRounds) {
6254
+ return `[tool result pruned: older than ${olderThanRounds} rounds]`;
6255
+ }
6256
+ function carriesToolResult(message) {
6257
+ return message.content.some((part) => part.type === "tool_result");
6258
+ }
6259
+ function stubbed(message, stub) {
6260
+ const content = message.content.map(
6261
+ (part) => part.type === "tool_result" ? { ...part, content: stub } : part
6262
+ );
6263
+ return { ...message, content };
6264
+ }
6265
+ function pruneToolResultsForRequest(messages, options) {
6266
+ if (options === void 0) return messages;
6267
+ const stub = stubFor(options.olderThanRounds);
6268
+ const out = [...messages];
6269
+ let rounds = 0;
6270
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
6271
+ const message = messages[index];
6272
+ if (!carriesToolResult(message)) continue;
6273
+ rounds += 1;
6274
+ if (rounds > options.olderThanRounds) out[index] = stubbed(message, stub);
6275
+ }
6276
+ return out;
6277
+ }
6278
+ function validatePruneToolResults(options) {
6279
+ if (options === void 0) return;
6280
+ const value = options.olderThanRounds;
6281
+ if (typeof value === "number" && Number.isInteger(value) && value >= 1) return;
6282
+ throw new ConfigurationError(
6283
+ `SendOptions.pruneToolResults.olderThanRounds must be an integer of at least 1, got ${String(value)}`,
6284
+ { code: "invalid_prune_tool_results" }
6285
+ );
6286
+ }
6287
+
5967
6288
  // src/internal/agent-loop/loop-llm-stream.ts
5968
6289
  function resolveSystemPromptWithMemoryAdditions(systemPrompt, additions) {
5969
6290
  if (additions === void 0 || additions.length === 0) return systemPrompt;
@@ -6052,7 +6373,8 @@ async function streamLlmTurn(inputs, ctx) {
6052
6373
  const key = derivePromptCacheKey(inputs.agentId);
6053
6374
  return key !== void 0 ? { promptCacheKey: key } : {};
6054
6375
  })(),
6055
- messages: ctx.messages,
6376
+ // B-564: the request gets a pruned copy; ctx.messages stays whole (the transcript is resent from it).
6377
+ messages: pruneToolResultsForRequest(ctx.messages, inputs.pruneToolResults),
6056
6378
  tools: ctx.tools.map(toLlmTool)
6057
6379
  },
6058
6380
  signal
@@ -6499,11 +6821,35 @@ function raceToolExecution(exec, opts) {
6499
6821
  // src/internal/agent-loop/tool-dispatch.ts
6500
6822
  async function dispatchTools(inputs, tools, toolCalls, events, parentSpan) {
6501
6823
  const maxConcurrent = inputs.maxConcurrentTools ?? 4;
6502
- return mapWithConcurrency(
6503
- toolCalls,
6504
- maxConcurrent,
6505
- (call) => dispatchSingleCall(inputs, tools, call, events, parentSpan)
6506
- );
6824
+ const units = [];
6825
+ const bySequentialServer = /* @__PURE__ */ new Map();
6826
+ toolCalls.forEach((call, index) => {
6827
+ const tool = tools.find((t) => t.name === call.name);
6828
+ if (tool?.mcpSequential === true && tool.mcpServerName !== void 0) {
6829
+ let unit = bySequentialServer.get(tool.mcpServerName);
6830
+ if (unit === void 0) {
6831
+ unit = { indexes: [] };
6832
+ bySequentialServer.set(tool.mcpServerName, unit);
6833
+ units.push(unit);
6834
+ }
6835
+ unit.indexes.push(index);
6836
+ } else {
6837
+ units.push({ indexes: [index] });
6838
+ }
6839
+ });
6840
+ const results = new Array(toolCalls.length);
6841
+ await mapWithConcurrency(units, maxConcurrent, async (unit) => {
6842
+ for (const index of unit.indexes) {
6843
+ results[index] = await dispatchSingleCall(
6844
+ inputs,
6845
+ tools,
6846
+ toolCalls[index],
6847
+ events,
6848
+ parentSpan
6849
+ );
6850
+ }
6851
+ });
6852
+ return results;
6507
6853
  }
6508
6854
  async function dispatchSingleCall(inputs, tools, call, events, parentSpan) {
6509
6855
  const { call: workingCall, repairs } = applyRepairAndExtractCall(tools, call);
@@ -6880,12 +7226,17 @@ async function runAgentLoop(inputs) {
6880
7226
  const budget = inputs.budget ?? new IterationBudget({ maxIterations: inputs.maxIterations ?? 8 });
6881
7227
  let lastTurnDecision;
6882
7228
  while (budget.shouldContinue()) {
7229
+ injectSteered(ctx, inputs.steerQueue?.drain());
6883
7230
  if (inputs.budgetTracker !== void 0) {
6884
7231
  const decision2 = evaluateBudgetGate(inputs.budgetTracker);
6885
7232
  if (decision2.allowed === false) {
6886
7233
  ctx.finalStatus = "error";
6887
7234
  if (decision2.detail !== void 0) {
6888
- ctx.error = { message: decision2.detail, code: decision2.reason ?? "budget" };
7235
+ ctx.error = {
7236
+ message: decision2.detail,
7237
+ code: decision2.reason ?? "budget",
7238
+ ...decision2.cause !== void 0 ? { cause: decision2.cause } : {}
7239
+ };
6889
7240
  }
6890
7241
  if (decision2.reason === "iteration_limit") {
6891
7242
  ctx.stoppedAtIterationLimit = true;
@@ -6897,7 +7248,13 @@ async function runAgentLoop(inputs) {
6897
7248
  if (usingGrace) budget.useGraceCall();
6898
7249
  const decision = await runIteration(inputs, ctx);
6899
7250
  lastTurnDecision = decision;
6900
- if (decision === "done") break;
7251
+ if (decision === "done") {
7252
+ const late = inputs.steerQueue?.drainOrClose() ?? [];
7253
+ if (late.length === 0) break;
7254
+ injectSteered(ctx, late);
7255
+ budget.consume();
7256
+ continue;
7257
+ }
6901
7258
  if (decision === "error") {
6902
7259
  ctx.finalStatus = "error";
6903
7260
  break;
@@ -7025,6 +7382,10 @@ async function finishOrReflect(inputs, ctx, llmOutput) {
7025
7382
  ctx.finalStatus = "finished";
7026
7383
  return "done";
7027
7384
  }
7385
+ function injectSteered(ctx, texts) {
7386
+ if (texts === void 0) return;
7387
+ for (const text of texts) ctx.messages.push({ role: "user", content: [{ type: "text", text }] });
7388
+ }
7028
7389
  async function runIteration(inputs, ctx) {
7029
7390
  const hookCtx = { agentId: inputs.agentId, runId: inputs.runId };
7030
7391
  await inputs.pluginManager?.runPreLlmCallHooks(hookCtx);
@@ -7038,12 +7399,11 @@ function trackTurnUsage(inputs, llmOutput) {
7038
7399
  const tracker = inputs.budgetTracker;
7039
7400
  if (tracker === void 0) return;
7040
7401
  const model = inputs.model.id ?? "auto";
7041
- trackEvent(tracker, { tokens: promptTokens(llmOutput), model, type: "input" });
7402
+ trackEvent(tracker, { tokens: llmOutput.inputTokens ?? 0, model, type: "input" });
7403
+ trackEvent(tracker, { tokens: llmOutput.cacheReadTokens ?? 0, model, type: "cache_read" });
7404
+ trackEvent(tracker, { tokens: llmOutput.cacheWriteTokens ?? 0, model, type: "cache_write" });
7042
7405
  trackEvent(tracker, { tokens: llmOutput.outputTokens ?? 0, model, type: "output" });
7043
7406
  }
7044
- function promptTokens(llmOutput) {
7045
- return (llmOutput.inputTokens ?? 0) + (llmOutput.cacheReadTokens ?? 0) + (llmOutput.cacheWriteTokens ?? 0);
7046
- }
7047
7407
  function trackEvent(tracker, event) {
7048
7408
  if (event.tokens <= 0) return;
7049
7409
  try {
@@ -7102,12 +7462,22 @@ async function continueOrTerminate(inputs, ctx, llmOutput) {
7102
7462
  }
7103
7463
  }
7104
7464
  pushToolConversationSteps(ctx, llmOutput.toolCalls, toolResults);
7105
- if (await inspectDoomLoop(inputs, ctx, llmOutput.toolCalls) === "stop") return "done";
7465
+ if (await inspectDoomLoop(inputs, ctx, llmOutput.toolCalls, toolResults) === "stop")
7466
+ return "done";
7106
7467
  return handleToolErrorContinuation(inputs, ctx, toolResults);
7107
7468
  }
7108
- async function inspectDoomLoop(inputs, ctx, toolCalls) {
7469
+ async function inspectDoomLoop(inputs, ctx, toolCalls, toolResults) {
7109
7470
  if (ctx.doomLoop === void 0) return "continue";
7110
- const verdict = firstDoomLoopVerdict(ctx.doomLoop, toolCalls);
7471
+ const resultById = /* @__PURE__ */ new Map();
7472
+ for (const part of toolResults) {
7473
+ if (part.type === "tool_result") {
7474
+ resultById.set(part.toolUseId, JSON.stringify([part.content, part.isError === true]));
7475
+ }
7476
+ }
7477
+ const verdict = firstDoomLoopVerdict(
7478
+ ctx.doomLoop,
7479
+ toolCalls.map((c) => ({ name: c.name, input: c.input, result: resultById.get(c.id) }))
7480
+ );
7111
7481
  if (verdict.kind === "hard") {
7112
7482
  ctx.stoppedByDoomLoop = true;
7113
7483
  await emitAssistantTextStep(
@@ -7184,6 +7554,34 @@ function handshakeAwareTimeout(input) {
7184
7554
  return isReconnectHandshake ? Math.max(input.requestTimeoutMs, HANDSHAKE_FLOOR_MS) : input.requestTimeoutMs;
7185
7555
  }
7186
7556
 
7557
+ // src/internal/mcp/oauth-bearer.ts
7558
+ var EXPIRY_SKEW_MS = 3e4;
7559
+ async function obtain(serverName, clientId, scopes, oauth) {
7560
+ const stored = await getTokens(serverName);
7561
+ if (stored?.accessToken !== void 0 && stored.expiresAt - EXPIRY_SKEW_MS > Date.now()) {
7562
+ return stored;
7563
+ }
7564
+ const refreshToken = stored?.refreshToken;
7565
+ if (refreshToken !== void 0) {
7566
+ try {
7567
+ return await lockedRefresh(
7568
+ serverName,
7569
+ () => refreshAccessToken(serverName, clientId, refreshToken, oauth)
7570
+ );
7571
+ } catch {
7572
+ }
7573
+ }
7574
+ const fresh = await runPkceFlow(serverName, clientId, scopes, oauth);
7575
+ await setTokens(serverName, fresh);
7576
+ return fresh;
7577
+ }
7578
+ async function resolveBearer(serverName, auth) {
7579
+ if (auth.oauth === void 0)
7580
+ throw new Error(`MCP server "${serverName}" declares no auth.oauth`);
7581
+ const tokens = await obtain(serverName, auth.CLIENT_ID, auth.scopes, auth.oauth);
7582
+ return `Bearer ${tokens.accessToken}`;
7583
+ }
7584
+
7187
7585
  // src/internal/mcp/client.ts
7188
7586
  function createMcpClient(name, config, fetchImpl = fetch) {
7189
7587
  if (isStdio(config)) return new StdioMcpClient(name, config);
@@ -7264,6 +7662,9 @@ var StdioMcpClient = class extends BaseMcpClient {
7264
7662
  reconnectPromise;
7265
7663
  /** True only while `reconnect()`'s handshake is in flight — see `timeoutFor`. */
7266
7664
  reconnecting = false;
7665
+ get sequential() {
7666
+ return this.config.sequential === true;
7667
+ }
7267
7668
  get timeoutMs() {
7268
7669
  return this.config.requestTimeoutMs ?? DEFAULT_MCP_TIMEOUT_MS;
7269
7670
  }
@@ -7470,6 +7871,9 @@ var HttpMcpClient = class extends BaseMcpClient {
7470
7871
  */
7471
7872
  sessionId;
7472
7873
  fetchImpl;
7874
+ get sequential() {
7875
+ return this.config.sequential === true;
7876
+ }
7473
7877
  close() {
7474
7878
  return Promise.resolve();
7475
7879
  }
@@ -7482,7 +7886,9 @@ var HttpMcpClient = class extends BaseMcpClient {
7482
7886
  * override contract predates this change and is the only escape a user has while a server
7483
7887
  * misbehaves.
7484
7888
  */
7485
- buildHeaders() {
7889
+ async buildHeaders() {
7890
+ const auth = this.config.auth;
7891
+ const bearer = auth?.oauth !== void 0 ? await resolveBearer(this.name, auth) : void 0;
7486
7892
  return {
7487
7893
  "content-type": "application/json",
7488
7894
  // Streamable HTTP asks for BOTH media types. Declaring only `application/json` makes a
@@ -7491,6 +7897,7 @@ var HttpMcpClient = class extends BaseMcpClient {
7491
7897
  // Present only for a STATEFUL server. For a stateless one nothing is sent — inventing a
7492
7898
  // header would trade one broken transport for another.
7493
7899
  ...this.sessionId !== void 0 ? { "mcp-session-id": this.sessionId } : {},
7900
+ ...bearer !== void 0 ? { authorization: bearer } : {},
7494
7901
  ...this.config.headers ?? {}
7495
7902
  };
7496
7903
  }
@@ -7533,7 +7940,7 @@ var HttpMcpClient = class extends BaseMcpClient {
7533
7940
  async request(method, params) {
7534
7941
  const id = this.nextId++;
7535
7942
  const payload = { jsonrpc: "2.0", id, method, params };
7536
- const headers = this.buildHeaders();
7943
+ const headers = await this.buildHeaders();
7537
7944
  const timeoutMs = this.config.requestTimeoutMs ?? DEFAULT_MCP_TIMEOUT_MS;
7538
7945
  let response;
7539
7946
  try {
@@ -7795,6 +8202,13 @@ function createRealLocalRun(options) {
7795
8202
  registerRun(handle);
7796
8203
  return handle;
7797
8204
  }
8205
+ function toolResultPolicyInputs(sendOptions) {
8206
+ return {
8207
+ ...sendOptions.perToolTimeoutMs !== void 0 ? { perToolTimeoutMs: sendOptions.perToolTimeoutMs } : {},
8208
+ ...sendOptions.toolResultGuard !== void 0 ? { toolResultGuard: sendOptions.toolResultGuard } : {},
8209
+ ...sendOptions.pruneToolResults !== void 0 ? { pruneToolResults: sendOptions.pruneToolResults } : {}
8210
+ };
8211
+ }
7798
8212
  function buildLoopInputs(options, runId, userText, userImages) {
7799
8213
  const maxIterations = options.sendOptions.maxIterations;
7800
8214
  if (maxIterations !== void 0 && (!Number.isInteger(maxIterations) || maxIterations < 1)) {
@@ -7803,6 +8217,7 @@ function buildLoopInputs(options, runId, userText, userImages) {
7803
8217
  { code: "invalid_max_iterations" }
7804
8218
  );
7805
8219
  }
8220
+ validatePruneToolResults(options.sendOptions.pruneToolResults);
7806
8221
  const { primary, effectiveModelId } = resolveRunProvider(options);
7807
8222
  const fallback = options.agentOptions.providers?.fallback;
7808
8223
  const apiKeys = mergeExplicitApiKey(
@@ -7872,10 +8287,8 @@ function buildLoopInputs(options, runId, userText, userImages) {
7872
8287
  ...options.sendOptions.context !== void 0 ? { context: options.sendOptions.context } : {},
7873
8288
  // SE2 — forward the opt-in typed runtime-event sink to the loop.
7874
8289
  ...options.sendOptions.onRunEvent !== void 0 ? { runEventSink: options.sendOptions.onRunEvent } : {},
7875
- // #58 / #57 — forward the per-tool timeout + tool-result guard so a consumer
7876
- // can enable them via SendOptions (not only internal AgentLoopInputs).
7877
- ...options.sendOptions.perToolTimeoutMs !== void 0 ? { perToolTimeoutMs: options.sendOptions.perToolTimeoutMs } : {},
7878
- ...options.sendOptions.toolResultGuard !== void 0 ? { toolResultGuard: options.sendOptions.toolResultGuard } : {},
8290
+ ...options.steerQueue !== void 0 ? { steerQueue: options.steerQueue } : {},
8291
+ ...toolResultPolicyInputs(options.sendOptions),
7879
8292
  // M1-2: per-send iteration ceiling (validated above). The loop reads
7880
8293
  // inputs.maxIterations (default 8 when unset).
7881
8294
  ...maxIterations !== void 0 ? { maxIterations } : {},
@@ -8096,7 +8509,8 @@ function buildRealRunOptions(args) {
8096
8509
  ...args.priorMessages.length > 0 ? { priorMessages: args.priorMessages } : {},
8097
8510
  ...args.memoryTools !== void 0 && args.memoryTools.length > 0 ? { memoryTools: args.memoryTools } : {},
8098
8511
  ...args.personalityToolWhitelist !== void 0 ? { personalityToolWhitelist: args.personalityToolWhitelist } : {},
8099
- ...args.personalityName !== void 0 ? { personalityName: args.personalityName } : {}
8512
+ ...args.personalityName !== void 0 ? { personalityName: args.personalityName } : {},
8513
+ ...args.steerQueue !== void 0 ? { steerQueue: args.steerQueue } : {}
8100
8514
  };
8101
8515
  }
8102
8516
  async function createFixtureRunHelper(args) {
@@ -8128,6 +8542,7 @@ async function dispatchLocalRun(args) {
8128
8542
  systemPrompt: args.systemPrompt,
8129
8543
  priorMessages: args.priorMessages,
8130
8544
  memoryTools: args.memoryTools,
8545
+ ...args.steerQueue !== void 0 ? { steerQueue: args.steerQueue } : {},
8131
8546
  ...args.activePreset?.tools !== void 0 ? { personalityToolWhitelist: args.activePreset.tools } : {},
8132
8547
  ...args.activePreset !== void 0 ? { personalityName: args.activePreset.name } : {}
8133
8548
  })
@@ -8180,177 +8595,6 @@ async function consumePending(agentId, pending, clear, refresh) {
8180
8595
  await applyDeferredInvalidation(agentId, pending, refresh);
8181
8596
  }
8182
8597
 
8183
- // src/internal/runtime/registry/live-agent-registry.ts
8184
- var DEFAULT_MAX_AGENTS = 100;
8185
- var DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1e3;
8186
- var DEFAULT_SWEEP_INTERVAL_MS = 6e4;
8187
- var LiveAgentRegistry = class {
8188
- #agents = /* @__PURE__ */ new Map();
8189
- #maxAgents = DEFAULT_MAX_AGENTS;
8190
- #idleTimeoutMs = DEFAULT_IDLE_TIMEOUT_MS;
8191
- #sweepIntervalMs = DEFAULT_SWEEP_INTERVAL_MS;
8192
- #onEvict;
8193
- #sweepTimer;
8194
- /**
8195
- * Reconfigure registry behavior. Process-wide singleton (D310) — last
8196
- * configure call wins for all subsequent operations.
8197
- */
8198
- configure(opts) {
8199
- if (opts.maxAgents !== void 0) this.#maxAgents = Math.max(0, opts.maxAgents);
8200
- if (opts.idleTimeoutMs !== void 0) this.#idleTimeoutMs = Math.max(0, opts.idleTimeoutMs);
8201
- if (opts.sweepIntervalMs !== void 0)
8202
- this.#sweepIntervalMs = Math.max(1e3, opts.sweepIntervalMs);
8203
- this.#onEvict = opts.onEvict;
8204
- this.#stopSweep();
8205
- if (this.#idleTimeoutMs > 0) this.#startSweep();
8206
- }
8207
- /**
8208
- * Lookup a cached agent. `get` is a use — refreshes `lastUsedAt` so the
8209
- * entry survives LRU eviction.
8210
- */
8211
- get(id) {
8212
- const entry = this.#agents.get(id);
8213
- if (entry === void 0) return void 0;
8214
- entry.lastUsedAt = Date.now();
8215
- return entry.agent;
8216
- }
8217
- /**
8218
- * Insert or overwrite an agent in the cache. Triggers fire-and-forget LRU
8219
- * eviction when `size > maxAgents`.
8220
- *
8221
- * EC-4: when `id` already maps to a DIFFERENT agent instance, dispose the
8222
- * old one before overwriting (race protection against two `getOrCreate`
8223
- * calls creating two agents but only the second being cached — the first
8224
- * would leak file handles + lifecycle controllers).
8225
- */
8226
- set(id, agent) {
8227
- if (this.#maxAgents === 0) return;
8228
- const existing = this.#agents.get(id);
8229
- if (existing !== void 0 && existing.agent !== agent) {
8230
- void existing.agent.dispose().catch(() => {
8231
- diag(`[theokit-sdk] dispose during overwrite failed (${id})
8232
- `);
8233
- });
8234
- }
8235
- this.#agents.set(id, { agent, lastUsedAt: Date.now() });
8236
- if (this.#agents.size > this.#maxAgents) void this.#evictLRU();
8237
- }
8238
- /**
8239
- * Remove the entry from the cache WITHOUT calling `dispose()` or
8240
- * `onEvict`. Used by `LocalAgent.dispose()` itself so the disposed
8241
- * instance can never be returned by a subsequent `get(id)` (dispose-cache
8242
- * race fix). Idempotent — calling on an unknown id is a no-op.
8243
- *
8244
- * @internal
8245
- */
8246
- forget(id) {
8247
- this.#agents.delete(id);
8248
- }
8249
- /**
8250
- * Explicitly evict an agent by id. Returns `true` when the entry was
8251
- * present (false = already gone). Calls `agent.dispose()` + `onEvict`
8252
- * with reason `"explicit"`.
8253
- */
8254
- async evict(id) {
8255
- const entry = this.#agents.get(id);
8256
- if (entry === void 0) return false;
8257
- this.#agents.delete(id);
8258
- await this.#disposeAndNotify(id, entry.agent, "explicit");
8259
- return true;
8260
- }
8261
- /**
8262
- * Evict every cached agent. Used by graceful shutdown (`process.on('SIGTERM')`)
8263
- * or end-of-test cleanup.
8264
- */
8265
- async evictAll() {
8266
- const entries = Array.from(this.#agents.entries());
8267
- this.#agents.clear();
8268
- this.#stopSweep();
8269
- for (const [id, entry] of entries) {
8270
- await this.#disposeAndNotify(id, entry.agent, "explicit");
8271
- }
8272
- }
8273
- /** Number of currently cached agents. */
8274
- size() {
8275
- return this.#agents.size;
8276
- }
8277
- /** Ids of cached agents, newest first (by lastUsedAt). */
8278
- ids() {
8279
- return Array.from(this.#agents.entries()).sort((a, b) => b[1].lastUsedAt - a[1].lastUsedAt).map(([id]) => id);
8280
- }
8281
- /**
8282
- * LRU eviction: drop the entry with the smallest `lastUsedAt`. Runs only
8283
- * when `size > maxAgents`. Asynchronous because `dispose()` is a Promise;
8284
- * the hot-path caller (`set`) does not await.
8285
- *
8286
- * @internal
8287
- */
8288
- async #evictLRU() {
8289
- if (this.#agents.size <= this.#maxAgents) return;
8290
- let oldestId;
8291
- let oldestAt = Infinity;
8292
- for (const [id, entry2] of this.#agents) {
8293
- if (entry2.lastUsedAt < oldestAt) {
8294
- oldestAt = entry2.lastUsedAt;
8295
- oldestId = id;
8296
- }
8297
- }
8298
- if (oldestId === void 0) return;
8299
- const entry = this.#agents.get(oldestId);
8300
- if (entry === void 0) return;
8301
- this.#agents.delete(oldestId);
8302
- await this.#disposeAndNotify(oldestId, entry.agent, "lru");
8303
- }
8304
- /** Background sweep — drops entries whose `lastUsedAt < now - idleTimeoutMs`. */
8305
- async #sweepIdle() {
8306
- if (this.#idleTimeoutMs === 0) return;
8307
- const threshold = Date.now() - this.#idleTimeoutMs;
8308
- const toEvict = [];
8309
- for (const [id, entry] of this.#agents) {
8310
- if (entry.lastUsedAt < threshold) toEvict.push([id, entry]);
8311
- }
8312
- for (const [id, entry] of toEvict) {
8313
- const current = this.#agents.get(id);
8314
- if (current === void 0 || current.agent !== entry.agent) continue;
8315
- this.#agents.delete(id);
8316
- await this.#disposeAndNotify(id, entry.agent, "idle");
8317
- }
8318
- }
8319
- #startSweep() {
8320
- this.#sweepTimer = setInterval(() => void this.#sweepIdle(), this.#sweepIntervalMs);
8321
- this.#sweepTimer.unref?.();
8322
- }
8323
- #stopSweep() {
8324
- if (this.#sweepTimer !== void 0) {
8325
- clearInterval(this.#sweepTimer);
8326
- this.#sweepTimer = void 0;
8327
- }
8328
- }
8329
- /** Dispose + notify with errors swallowed (D309). Single chokepoint. */
8330
- async #disposeAndNotify(id, agent, reason) {
8331
- try {
8332
- await agent.dispose();
8333
- } catch (cause) {
8334
- const msg = cause instanceof Error ? cause.message : String(cause);
8335
- diag(`[theokit-sdk] dispose during eviction failed (${id}): ${msg}
8336
- `);
8337
- }
8338
- if (this.#onEvict !== void 0) {
8339
- try {
8340
- this.#onEvict(id, reason);
8341
- } catch (cause) {
8342
- const msg = cause instanceof Error ? cause.message : String(cause);
8343
- diag(`[theokit-sdk] onEvict listener threw (${id}): ${msg}
8344
- `);
8345
- }
8346
- }
8347
- }
8348
- };
8349
- var liveAgentRegistry = globalSingleton(
8350
- "theokit-sdk.runtime.live-agents",
8351
- () => new LiveAgentRegistry()
8352
- );
8353
-
8354
8598
  // src/internal/local-agent/local-agent-lifecycle.ts
8355
8599
  async function acquireLeaseIfPossible(store, agentId) {
8356
8600
  if (typeof store.acquire !== "function") return;
@@ -10069,6 +10313,14 @@ async function applyInputProcessors(inputs, message, rawUserText, options, sendM
10069
10313
  const effectiveMessage = typeof message === "string" ? res.value : { ...message, text: res.value };
10070
10314
  return { userText: res.value, effectiveMessage };
10071
10315
  }
10316
+ var lastSendAt = /* @__PURE__ */ new Map();
10317
+ function applyIdleReset(agentId, minutes) {
10318
+ const now = Date.now();
10319
+ const previous = lastSendAt.get(agentId);
10320
+ lastSendAt.set(agentId, now);
10321
+ if (minutes === void 0 || !Number.isFinite(minutes) || minutes <= 0) return;
10322
+ if (previous !== void 0 && now - previous > minutes * 6e4) clearSession(agentId);
10323
+ }
10072
10324
  async function executeSendLocked(inputs, message, options) {
10073
10325
  if (inputs.disposed) throw new AgentDisposedError(inputs.agentId);
10074
10326
  await consumePending(
@@ -10083,6 +10335,7 @@ async function executeSendLocked(inputs, message, options) {
10083
10335
  const gated = await applyInputProcessors(inputs, message, rawUserText, options, sendModel);
10084
10336
  if ("tripwireRun" in gated) return gated.tripwireRun;
10085
10337
  const { userText, effectiveMessage } = gated;
10338
+ applyIdleReset(inputs.agentId, inputs.options.sessionIdleResetMinutes);
10086
10339
  if (inputs.options.onBeforeSend !== void 0) {
10087
10340
  await inputs.options.onBeforeSend({
10088
10341
  conversationId: inputs.agentId,
@@ -10268,6 +10521,43 @@ function reportUnknownLocalOptions(local) {
10268
10521
  }
10269
10522
  }
10270
10523
 
10524
+ // src/internal/local-agent/send-queue.ts
10525
+ var TurnSteerQueue = class {
10526
+ pending = [];
10527
+ closed = false;
10528
+ /** @returns false when the turn can no longer pick the message up. */
10529
+ push(text) {
10530
+ if (this.closed) return false;
10531
+ this.pending.push(text);
10532
+ return true;
10533
+ }
10534
+ drain() {
10535
+ const taken = this.pending;
10536
+ this.pending = [];
10537
+ return taken;
10538
+ }
10539
+ drainOrClose() {
10540
+ const taken = this.drain();
10541
+ if (taken.length === 0) this.closed = true;
10542
+ return taken;
10543
+ }
10544
+ /** Stop accepting and hand back what no loop iteration picked up. */
10545
+ closeAndTake() {
10546
+ this.closed = true;
10547
+ return this.drain();
10548
+ }
10549
+ };
10550
+ function joinCollected(messages) {
10551
+ if (messages.length === 1) return messages[0];
10552
+ const texts = messages.map((m) => typeof m === "string" ? m : m.text);
10553
+ const images = messages.flatMap((m) => typeof m === "string" ? [] : m.images ?? []);
10554
+ const text = texts.join("\n\n");
10555
+ return images.length > 0 ? { text, images } : text;
10556
+ }
10557
+ function hasImages(message) {
10558
+ return typeof message !== "string" && (message.images?.length ?? 0) > 0;
10559
+ }
10560
+
10271
10561
  // src/internal/local-agent/local-agent.ts
10272
10562
  var LocalAgent = class {
10273
10563
  /**
@@ -10316,6 +10606,9 @@ var LocalAgent = class {
10316
10606
  settingSourcesIncludePlugins;
10317
10607
  resolvedSubagents = {};
10318
10608
  disposed = false;
10609
+ activeTurn;
10610
+ inflight = 0;
10611
+ collectBatch;
10319
10612
  invalidationPending;
10320
10613
  skillsManager;
10321
10614
  pluginsManager;
@@ -10440,10 +10733,48 @@ var LocalAgent = class {
10440
10733
  agentId: this.agentId,
10441
10734
  ...this.model?.id !== void 0 ? { model: this.model.id } : {}
10442
10735
  });
10736
+ return this.enqueueSend(message, options, sendSpan);
10737
+ }
10738
+ /** Queue one send behind the lock, or fold it into the running turn / pending batch. */
10739
+ enqueueSend(message, options, sendSpan) {
10740
+ const mode = options.queueMode ?? "followup";
10741
+ const text = typeof message === "string" ? message : message.text;
10742
+ const active = this.activeTurn;
10743
+ if (mode === "steer" && active !== void 0 && !hasImages(message) && active.steer.push(text)) {
10744
+ sendSpan.end();
10745
+ return active.run;
10746
+ }
10747
+ if (mode === "collect" && this.collectBatch !== void 0) {
10748
+ this.collectBatch.messages.push(message);
10749
+ sendSpan.end();
10750
+ return this.collectBatch.run;
10751
+ }
10752
+ const key = `agent-send:${this.agentId}`;
10753
+ this.inflight += 1;
10754
+ const release = () => {
10755
+ this.inflight -= 1;
10756
+ };
10757
+ if (mode === "collect" && this.inflight > 1) {
10758
+ const messages = [message];
10759
+ const run = new Promise((resolve, reject) => {
10760
+ void withCwdMutex(key, () => {
10761
+ this.collectBatch = void 0;
10762
+ return this.runLockedSendCycle(
10763
+ joinCollected(messages),
10764
+ options,
10765
+ sendSpan,
10766
+ resolve,
10767
+ reject
10768
+ ).finally(release);
10769
+ });
10770
+ });
10771
+ this.collectBatch = { messages, run };
10772
+ return run;
10773
+ }
10443
10774
  return new Promise((resolve, reject) => {
10444
10775
  void withCwdMutex(
10445
- `agent-send:${this.agentId}`,
10446
- () => this.runLockedSendCycle(message, options, sendSpan, resolve, reject)
10776
+ key,
10777
+ () => this.runLockedSendCycle(message, options, sendSpan, resolve, reject).finally(release)
10447
10778
  );
10448
10779
  });
10449
10780
  }
@@ -10459,20 +10790,40 @@ var LocalAgent = class {
10459
10790
  const declared = this.model?.contextWindow;
10460
10791
  return declared !== void 0 ? { contextWindow: declared } : {};
10461
10792
  }
10793
+ /** A steered message the loop never picked up (run errored, was cancelled) still gets answered. */
10794
+ followUpUnsteered(leftover) {
10795
+ if (leftover.length === 0) return;
10796
+ this.send(leftover.join("\n\n")).catch(
10797
+ (err) => diagFailure(`[theokit-sdk] steered message followup failed: ${String(err)}`)
10798
+ );
10799
+ }
10462
10800
  async runLockedSendCycle(message, options, sendSpan, resolve, reject) {
10463
10801
  const userText = typeof message === "string" ? message : message.text;
10464
10802
  let run;
10803
+ const steer = new TurnSteerQueue();
10804
+ let res = () => void 0;
10805
+ let rej = () => void 0;
10806
+ const turnRun = new Promise((a, b) => {
10807
+ res = a;
10808
+ rej = b;
10809
+ });
10810
+ turnRun.catch(() => void 0);
10811
+ this.activeTurn = { steer, run: turnRun };
10465
10812
  try {
10466
10813
  run = await this.sendLocked(message, options);
10467
10814
  } catch (err) {
10468
10815
  sendSpan.recordException(err);
10469
10816
  sendSpan.setStatus({ code: 2, message: err instanceof Error ? err.message : String(err) });
10470
10817
  sendSpan.end();
10818
+ this.activeTurn = void 0;
10819
+ rej(err);
10471
10820
  reject(err);
10472
10821
  return;
10473
10822
  }
10474
10823
  if (options.task !== void 0) registerRunAsTask(run, this.agentId, options.task, userText);
10475
- resolve(callerView(run, this.options.throwOnError));
10824
+ const view = callerView(run, this.options.throwOnError);
10825
+ res(view);
10826
+ resolve(view);
10476
10827
  try {
10477
10828
  await runPostRunLifecycle({
10478
10829
  run,
@@ -10496,6 +10847,8 @@ var LocalAgent = class {
10496
10847
  });
10497
10848
  } finally {
10498
10849
  sendSpan.end();
10850
+ this.activeTurn = void 0;
10851
+ this.followUpUnsteered(steer.closeAndTake());
10499
10852
  }
10500
10853
  }
10501
10854
  async sendLocked(message, options) {
@@ -10603,11 +10956,13 @@ var LocalAgent = class {
10603
10956
  memoryFacts,
10604
10957
  priorMessages,
10605
10958
  memoryTools,
10606
- activePreset: this.activePreset()
10959
+ activePreset: this.activePreset(),
10960
+ ...this.activeTurn !== void 0 ? { steerQueue: this.activeTurn.steer } : {}
10607
10961
  });
10608
10962
  }
10609
10963
  close() {
10610
10964
  this.disposed = true;
10965
+ liveAgentRegistry.forget(this.agentId);
10611
10966
  }
10612
10967
  async reload() {
10613
10968
  this.resolvedSubagents = await reloadLocalAgent(this);
@@ -10958,6 +11313,7 @@ function paginateByKey(all, keyOf, limit, cursor, sortByKey) {
10958
11313
 
10959
11314
  // src/agent.ts
10960
11315
  var streamObjectImport;
11316
+ var getOrCreateInFlight = /* @__PURE__ */ new Map();
10961
11317
  var Agent = class _Agent {
10962
11318
  constructor() {
10963
11319
  }
@@ -11142,7 +11498,7 @@ var Agent = class _Agent {
11142
11498
  * @public
11143
11499
  */
11144
11500
  static async batch(prompts, options) {
11145
- const { batchImpl } = await import('./batch-EP3FCL6D.js');
11501
+ const { batchImpl } = await import('./batch-N2XDYZED.js');
11146
11502
  return batchImpl(prompts, options, { create: (opts) => _Agent.create(opts) });
11147
11503
  }
11148
11504
  /**
@@ -11172,18 +11528,27 @@ var Agent = class _Agent {
11172
11528
  * The agent-builder's M85 interrupt rotates the session id to work around a
11173
11529
  * constraint that does not exist.
11174
11530
  *
11175
- * - `close()` marks the handle disposed WITHOUT evicting the cache entry. It is
11176
- * internal and unused today; if it becomes reachable, this bullet stops being true
11177
- * for that path.
11531
+ * - `close()` marks the handle disposed AND drops its cache entry, so the next call
11532
+ * builds a fresh handle.
11178
11533
  *
11179
11534
  * @public
11180
11535
  */
11181
11536
  static async getOrCreate(agentId, options) {
11182
11537
  const cached = _Agent.registry.get(agentId);
11183
11538
  if (cached !== void 0) return cached;
11184
- const fresh = await getOrCreateUncached(agentId, options);
11185
- _Agent.registry.set(agentId, fresh);
11186
- return fresh;
11539
+ const inFlight = getOrCreateInFlight.get(agentId);
11540
+ if (inFlight !== void 0) return inFlight;
11541
+ const build = (async () => {
11542
+ const fresh = await getOrCreateUncached(agentId, options);
11543
+ _Agent.registry.set(agentId, fresh);
11544
+ return fresh;
11545
+ })();
11546
+ getOrCreateInFlight.set(agentId, build);
11547
+ try {
11548
+ return await build;
11549
+ } finally {
11550
+ if (getOrCreateInFlight.get(agentId) === build) getOrCreateInFlight.delete(agentId);
11551
+ }
11187
11552
  }
11188
11553
  /**
11189
11554
  * List agents (local or cloud). M107 — `cwd` is READ, not ignored. B-115 (2026-08-19) —
@@ -11294,7 +11659,7 @@ var Agent = class _Agent {
11294
11659
  */
11295
11660
  static async compact(agentId, options = {}) {
11296
11661
  const reg = await requireLocalAgent(agentId, "compact");
11297
- const { compactSessionTranscript, buildDefaultSummarizer: buildDefaultSummarizer2 } = await import('./compact-session-5HMX6KYT.js');
11662
+ const { compactSessionTranscript, buildDefaultSummarizer: buildDefaultSummarizer2 } = await import('./compact-session-Q5IGNFPW.js');
11298
11663
  const { cwd, model, store } = await openLocalStore(reg);
11299
11664
  return enqueueSessionWrite(
11300
11665
  cwd,
@@ -11324,7 +11689,7 @@ var Agent = class _Agent {
11324
11689
  */
11325
11690
  static async injectSessionTurn(agentId, turn) {
11326
11691
  const reg = await requireLocalAgent(agentId, "injectSessionTurn");
11327
- const { injectSessionTurn } = await import('./inject-session-75L3NCNL.js');
11692
+ const { injectSessionTurn } = await import('./inject-session-4ROYLZHY.js');
11328
11693
  const { cwd, model, store } = await openLocalStore(reg);
11329
11694
  await injectSessionTurn({
11330
11695
  store,
@@ -11375,7 +11740,7 @@ var Agent = class _Agent {
11375
11740
  */
11376
11741
  static async describe(agentId) {
11377
11742
  const agent = await getRegisteredAgentOrThrow(agentId);
11378
- const { loadSubagents: loadSubagents2 } = await import('./subagents-loader-Z744TAKD.js');
11743
+ const { loadSubagents: loadSubagents2 } = await import('./subagents-loader-SXETS2F2.js');
11379
11744
  const settingSources = agent.options.local?.settingSources;
11380
11745
  const subagents = await loadSubagents2(
11381
11746
  agent.cwd ?? process.cwd(),
@@ -11474,7 +11839,9 @@ async function openLocalStore(reg) {
11474
11839
  const cwd = reg.cwd ?? process.cwd();
11475
11840
  const optModel = reg.options.model;
11476
11841
  const model = reg.model?.id ?? (typeof optModel === "string" ? optModel : optModel?.id) ?? "unknown";
11477
- const { FsSessionStore: FsSessionStore2 } = await import('./fs-session-store-6ZCCJX3K.js');
11842
+ const injected = reg.options.local?.sessionStore;
11843
+ if (injected !== void 0) return { cwd, model, store: injected };
11844
+ const { FsSessionStore: FsSessionStore2 } = await import('./fs-session-store-MYQEVUFL.js');
11478
11845
  const { defaultBaseDir: defaultBaseDir2, expandTilde: expandTilde2 } = await import('./session-transcript-BSHZYYY6.js');
11479
11846
  const configuredSessionDir = reg.options.local?.sessionDir ?? reg.options.local?.baseDir;
11480
11847
  const baseDir = configuredSessionDir !== void 0 ? expandTilde2(configuredSessionDir) : defaultBaseDir2();
@@ -11482,5 +11849,5 @@ async function openLocalStore(reg) {
11482
11849
  }
11483
11850
 
11484
11851
  export { Agent, AgentBuilder, DEFAULT_AGENTIC_MODEL_ID, MEMORY_EMBEDDING_ADAPTERS, Tool, ToolError, UsageAccumulator, computeCost, generateCronId, getPricingEntry, managedSettingsPathFor, openRouterMemoryEmbeddingProviderAdapter, readManagedSettings, resolveSessionDir };
11485
- //# sourceMappingURL=chunk-JX4LB6XO.js.map
11486
- //# sourceMappingURL=chunk-JX4LB6XO.js.map
11852
+ //# sourceMappingURL=chunk-5M5GQYBM.js.map
11853
+ //# sourceMappingURL=chunk-5M5GQYBM.js.map