@nhtio/adk 1.20260925.0 → 1.20260928.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 (332) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/artifact_methods-Cg0go7Q4.mjs +1 -0
  3. package/artifact_methods-CxeKTocm.cjs +1 -0
  4. package/batteries/artifacts/ecmascript.cjs +1 -1
  5. package/batteries/artifacts/ecmascript.mjs +1 -1
  6. package/batteries/artifacts/toon.cjs +1 -1
  7. package/batteries/artifacts/toon.mjs +1 -1
  8. package/batteries/artifacts/xml.cjs +1 -1
  9. package/batteries/artifacts/xml.mjs +1 -1
  10. package/batteries/artifacts/yaml.cjs +1 -1
  11. package/batteries/artifacts/yaml.mjs +1 -1
  12. package/batteries/artifacts.cjs +4 -4
  13. package/batteries/artifacts.mjs +4 -4
  14. package/batteries/dev-tools/forge.cjs +3 -3
  15. package/batteries/dev-tools/forge.mjs +3 -3
  16. package/batteries/dev-tools.cjs +3 -3
  17. package/batteries/dev-tools.mjs +3 -3
  18. package/batteries/encoding.cjs +7 -7
  19. package/batteries/encoding.mjs +7 -7
  20. package/batteries/generation/gemini/adapter.cjs +1 -1
  21. package/batteries/generation/gemini/adapter.mjs +1 -1
  22. package/batteries/generation/local_diffusion/adapter.cjs +1 -1
  23. package/batteries/generation/local_diffusion/adapter.mjs +1 -1
  24. package/batteries/generation/openai/adapter.cjs +1 -1
  25. package/batteries/generation/openai/adapter.mjs +1 -1
  26. package/batteries/isolation/child_process.cjs +1 -1
  27. package/batteries/isolation/child_process.mjs +1 -1
  28. package/batteries/isolation.cjs +1 -1
  29. package/batteries/isolation.mjs +1 -1
  30. package/batteries/llm/anthropic_messages/adapter.cjs +6 -6
  31. package/batteries/llm/anthropic_messages/adapter.mjs +6 -6
  32. package/batteries/llm/anthropic_messages/count_tokens.cjs +1 -1
  33. package/batteries/llm/anthropic_messages/count_tokens.mjs +1 -1
  34. package/batteries/llm/anthropic_messages/helpers.cjs +3 -3
  35. package/batteries/llm/anthropic_messages/helpers.mjs +3 -3
  36. package/batteries/llm/anthropic_messages/validation.cjs +2 -2
  37. package/batteries/llm/anthropic_messages/validation.mjs +2 -2
  38. package/batteries/llm/anthropic_messages.cjs +2 -2
  39. package/batteries/llm/anthropic_messages.mjs +2 -2
  40. package/batteries/llm/bedrock_converse/adapter.cjs +6 -6
  41. package/batteries/llm/bedrock_converse/adapter.mjs +6 -6
  42. package/batteries/llm/bedrock_converse/helpers.cjs +1 -1
  43. package/batteries/llm/bedrock_converse/helpers.mjs +1 -1
  44. package/batteries/llm/bedrock_converse/validation.cjs +2 -2
  45. package/batteries/llm/bedrock_converse/validation.mjs +2 -2
  46. package/batteries/llm/bedrock_converse.cjs +2 -2
  47. package/batteries/llm/bedrock_converse.mjs +2 -2
  48. package/batteries/llm/claude_code_cli/adapter.cjs +7 -7
  49. package/batteries/llm/claude_code_cli/adapter.mjs +7 -7
  50. package/batteries/llm/claude_code_cli/helpers.cjs +3 -3
  51. package/batteries/llm/claude_code_cli/helpers.mjs +3 -3
  52. package/batteries/llm/claude_code_cli/validation.cjs +2 -2
  53. package/batteries/llm/claude_code_cli/validation.mjs +2 -2
  54. package/batteries/llm/claude_code_cli.cjs +2 -2
  55. package/batteries/llm/claude_code_cli.mjs +2 -2
  56. package/batteries/llm/gemini_generate_content/adapter.cjs +6 -6
  57. package/batteries/llm/gemini_generate_content/adapter.mjs +6 -6
  58. package/batteries/llm/gemini_generate_content/helpers.cjs +1 -1
  59. package/batteries/llm/gemini_generate_content/helpers.mjs +1 -1
  60. package/batteries/llm/gemini_generate_content/validation.cjs +2 -2
  61. package/batteries/llm/gemini_generate_content/validation.mjs +2 -2
  62. package/batteries/llm/gemini_generate_content.cjs +1 -1
  63. package/batteries/llm/gemini_generate_content.mjs +1 -1
  64. package/batteries/llm/litert_lm/adapter.cjs +6 -6
  65. package/batteries/llm/litert_lm/adapter.mjs +6 -6
  66. package/batteries/llm/litert_lm/helpers.cjs +3 -3
  67. package/batteries/llm/litert_lm/helpers.mjs +3 -3
  68. package/batteries/llm/litert_lm/validation.cjs +2 -2
  69. package/batteries/llm/litert_lm/validation.mjs +2 -2
  70. package/batteries/llm/litert_lm.cjs +1 -1
  71. package/batteries/llm/litert_lm.mjs +1 -1
  72. package/batteries/llm/ollama/adapter.cjs +6 -6
  73. package/batteries/llm/ollama/adapter.mjs +6 -6
  74. package/batteries/llm/ollama/helpers.cjs +4 -4
  75. package/batteries/llm/ollama/helpers.mjs +4 -4
  76. package/batteries/llm/ollama/validation.cjs +2 -2
  77. package/batteries/llm/ollama/validation.mjs +2 -2
  78. package/batteries/llm/ollama.cjs +2 -2
  79. package/batteries/llm/ollama.mjs +2 -2
  80. package/batteries/llm/openai_chat_completions/adapter.cjs +6 -6
  81. package/batteries/llm/openai_chat_completions/adapter.mjs +6 -6
  82. package/batteries/llm/openai_chat_completions/helpers.cjs +4 -4
  83. package/batteries/llm/openai_chat_completions/helpers.mjs +4 -4
  84. package/batteries/llm/openai_chat_completions/validation.cjs +2 -2
  85. package/batteries/llm/openai_chat_completions/validation.mjs +2 -2
  86. package/batteries/llm/openai_chat_completions.cjs +2 -2
  87. package/batteries/llm/openai_chat_completions.mjs +2 -2
  88. package/batteries/llm/openai_responses/adapter.cjs +6 -6
  89. package/batteries/llm/openai_responses/adapter.mjs +6 -6
  90. package/batteries/llm/openai_responses/helpers.cjs +3 -3
  91. package/batteries/llm/openai_responses/helpers.mjs +3 -3
  92. package/batteries/llm/openai_responses/validation.cjs +2 -2
  93. package/batteries/llm/openai_responses/validation.mjs +2 -2
  94. package/batteries/llm/openai_responses.cjs +2 -2
  95. package/batteries/llm/openai_responses.mjs +2 -2
  96. package/batteries/llm/transformers_js/adapter.cjs +6 -6
  97. package/batteries/llm/transformers_js/adapter.mjs +6 -6
  98. package/batteries/llm/transformers_js/helpers.cjs +3 -3
  99. package/batteries/llm/transformers_js/helpers.mjs +3 -3
  100. package/batteries/llm/transformers_js/validation.cjs +2 -2
  101. package/batteries/llm/transformers_js/validation.mjs +2 -2
  102. package/batteries/llm/transformers_js.cjs +1 -1
  103. package/batteries/llm/transformers_js.mjs +1 -1
  104. package/batteries/llm/webllm_chat_completions/adapter.cjs +6 -6
  105. package/batteries/llm/webllm_chat_completions/adapter.mjs +6 -6
  106. package/batteries/llm/webllm_chat_completions/helpers.cjs +1 -1
  107. package/batteries/llm/webllm_chat_completions/helpers.mjs +1 -1
  108. package/batteries/llm/webllm_chat_completions/validation.cjs +2 -2
  109. package/batteries/llm/webllm_chat_completions/validation.mjs +2 -2
  110. package/batteries/llm/webllm_chat_completions.cjs +2 -2
  111. package/batteries/llm/webllm_chat_completions.mjs +2 -2
  112. package/batteries/llm.cjs +2 -2
  113. package/batteries/llm.mjs +2 -2
  114. package/batteries/media/forge.cjs +4 -4
  115. package/batteries/media/forge.mjs +4 -4
  116. package/batteries/media/lint.cjs +1 -1
  117. package/batteries/media/lint.mjs +1 -1
  118. package/batteries/orchestration/cells/jexl.cjs +1 -1
  119. package/batteries/orchestration/cells/jexl.mjs +1 -1
  120. package/batteries/orchestration/cells/lua.cjs +1 -1
  121. package/batteries/orchestration/cells/lua.mjs +1 -1
  122. package/batteries/orchestration/cells/structured.cjs +1 -1
  123. package/batteries/orchestration/cells/structured.mjs +1 -1
  124. package/batteries/orchestration/dispatch_reasoner.cjs +4 -4
  125. package/batteries/orchestration/dispatch_reasoner.mjs +4 -4
  126. package/batteries/orchestration/executor.cjs +2 -2
  127. package/batteries/orchestration/executor.mjs +2 -2
  128. package/batteries/orchestration/forge.cjs +3 -3
  129. package/batteries/orchestration/forge.mjs +3 -3
  130. package/batteries/orchestration/validation.cjs +2 -2
  131. package/batteries/orchestration/validation.mjs +2 -2
  132. package/batteries/orchestration.cjs +3 -3
  133. package/batteries/orchestration.mjs +3 -3
  134. package/batteries/sandbox/js.cjs +1 -1
  135. package/batteries/sandbox/js.mjs +1 -1
  136. package/batteries/sandbox/tools.cjs +1 -1
  137. package/batteries/sandbox/tools.mjs +1 -1
  138. package/batteries/sandbox.cjs +4 -4
  139. package/batteries/sandbox.mjs +4 -4
  140. package/batteries/skills/in_memory.cjs +1 -1
  141. package/batteries/skills/in_memory.mjs +1 -1
  142. package/batteries/skills.cjs +9 -9
  143. package/batteries/skills.mjs +9 -9
  144. package/batteries/specialists/stt/transformers_js.cjs +1 -1
  145. package/batteries/specialists/stt/transformers_js.mjs +1 -1
  146. package/batteries/specialists/stt.cjs +1 -1
  147. package/batteries/specialists/stt.mjs +1 -1
  148. package/batteries/specialists.cjs +1 -1
  149. package/batteries/specialists.mjs +1 -1
  150. package/batteries/tools/_shared.cjs +2 -2
  151. package/batteries/tools/_shared.mjs +2 -2
  152. package/batteries/tools/color.cjs +2 -2
  153. package/batteries/tools/color.mjs +2 -2
  154. package/batteries/tools/comparison.cjs +2 -2
  155. package/batteries/tools/comparison.mjs +2 -2
  156. package/batteries/tools/data_structure.cjs +2 -2
  157. package/batteries/tools/data_structure.mjs +2 -2
  158. package/batteries/tools/datetime_extended.cjs +2 -2
  159. package/batteries/tools/datetime_extended.mjs +2 -2
  160. package/batteries/tools/datetime_math.cjs +2 -2
  161. package/batteries/tools/datetime_math.mjs +2 -2
  162. package/batteries/tools/encoding.cjs +2 -2
  163. package/batteries/tools/encoding.mjs +2 -2
  164. package/batteries/tools/formatting.cjs +2 -2
  165. package/batteries/tools/formatting.mjs +2 -2
  166. package/batteries/tools/geo_basics.cjs +2 -2
  167. package/batteries/tools/geo_basics.mjs +2 -2
  168. package/batteries/tools/math.cjs +2 -2
  169. package/batteries/tools/math.mjs +2 -2
  170. package/batteries/tools/memory.cjs +4 -4
  171. package/batteries/tools/memory.mjs +4 -4
  172. package/batteries/tools/parsing.cjs +3 -3
  173. package/batteries/tools/parsing.mjs +3 -3
  174. package/batteries/tools/retrievables.cjs +4 -4
  175. package/batteries/tools/retrievables.mjs +4 -4
  176. package/batteries/tools/scrapper.cjs +1 -1
  177. package/batteries/tools/scrapper.mjs +1 -1
  178. package/batteries/tools/searxng.cjs +1 -1
  179. package/batteries/tools/searxng.mjs +1 -1
  180. package/batteries/tools/standing_instructions.cjs +3 -3
  181. package/batteries/tools/standing_instructions.mjs +3 -3
  182. package/batteries/tools/statistics.cjs +3 -3
  183. package/batteries/tools/statistics.mjs +3 -3
  184. package/batteries/tools/string_processing.cjs +2 -2
  185. package/batteries/tools/string_processing.mjs +2 -2
  186. package/batteries/tools/structured_data.cjs +2 -2
  187. package/batteries/tools/structured_data.mjs +2 -2
  188. package/batteries/tools/text_analysis.cjs +3 -3
  189. package/batteries/tools/text_analysis.mjs +3 -3
  190. package/batteries/tools/text_comparison.cjs +2 -2
  191. package/batteries/tools/text_comparison.mjs +2 -2
  192. package/batteries/tools/time.cjs +2 -2
  193. package/batteries/tools/time.mjs +2 -2
  194. package/batteries/tools/unit_conversion.cjs +2 -2
  195. package/batteries/tools/unit_conversion.mjs +2 -2
  196. package/batteries/tools.cjs +2 -2
  197. package/batteries/tools.mjs +2 -2
  198. package/batteries/validation.cjs +5 -5
  199. package/batteries/validation.mjs +5 -5
  200. package/batteries/vector/conformance.cjs +59 -0
  201. package/batteries/vector/conformance.cjs.map +1 -1
  202. package/batteries/vector/conformance.mjs +59 -0
  203. package/batteries/vector/conformance.mjs.map +1 -1
  204. package/batteries/vector/lancedb.cjs +1 -1
  205. package/batteries/vector/lancedb.cjs.map +1 -1
  206. package/batteries/vector/lancedb.mjs +1 -1
  207. package/batteries/vector/lancedb.mjs.map +1 -1
  208. package/batteries/vector/retrievable.cjs +1 -1
  209. package/batteries/vector/retrievable.mjs +1 -1
  210. package/batteries/vector/sqlite_vec/index.d.ts +1 -1
  211. package/batteries/vector/sqlite_vec.cjs +19 -30
  212. package/batteries/vector/sqlite_vec.cjs.map +1 -1
  213. package/batteries/vector/sqlite_vec.mjs +20 -31
  214. package/batteries/vector/sqlite_vec.mjs.map +1 -1
  215. package/batteries.cjs +6 -6
  216. package/batteries.mjs +6 -6
  217. package/{chat_common-4huaTp6d.cjs → chat_common-CNayzS1V.cjs} +2 -2
  218. package/{chat_common-4huaTp6d.cjs.map → chat_common-CNayzS1V.cjs.map} +1 -1
  219. package/{chat_common-D_XGNjcK.mjs → chat_common-DKw8FDol.mjs} +2 -2
  220. package/{chat_common-D_XGNjcK.mjs.map → chat_common-DKw8FDol.mjs.map} +1 -1
  221. package/{common-BiRzOsxe.cjs → common-CqetsItm.cjs} +7 -7
  222. package/{common-BiRzOsxe.cjs.map → common-CqetsItm.cjs.map} +1 -1
  223. package/{common-DsLvTGmm.mjs → common-oI1niK9Z.mjs} +7 -7
  224. package/{common-DsLvTGmm.mjs.map → common-oI1niK9Z.mjs.map} +1 -1
  225. package/common.cjs +7 -7
  226. package/common.mjs +7 -7
  227. package/{dispatch_runner-DDH_dGPU.mjs → dispatch_runner-BZDXUe0G.mjs} +4 -4
  228. package/{dispatch_runner-DDH_dGPU.mjs.map → dispatch_runner-BZDXUe0G.mjs.map} +1 -1
  229. package/{dispatch_runner-C5S3KCqH.cjs → dispatch_runner-DDUxXJC3.cjs} +4 -4
  230. package/{dispatch_runner-C5S3KCqH.cjs.map → dispatch_runner-DDUxXJC3.cjs.map} +1 -1
  231. package/dispatch_runner.cjs +1 -1
  232. package/dispatch_runner.mjs +1 -1
  233. package/{ecmascript-CWLZ7bCX.mjs → ecmascript-B9Z2C24U.mjs} +5 -5
  234. package/{ecmascript-CWLZ7bCX.mjs.map → ecmascript-B9Z2C24U.mjs.map} +1 -1
  235. package/{ecmascript-BGr_0Dwn.cjs → ecmascript-BYfmjg7y.cjs} +5 -5
  236. package/{ecmascript-BGr_0Dwn.cjs.map → ecmascript-BYfmjg7y.cjs.map} +1 -1
  237. package/eslint/rules.cjs +1 -1
  238. package/eslint/rules.mjs +1 -1
  239. package/eslint.cjs +3 -3
  240. package/eslint.mjs +3 -3
  241. package/exceptions.cjs +1 -1
  242. package/exceptions.mjs +1 -1
  243. package/forge.cjs +2 -2
  244. package/forge.mjs +2 -2
  245. package/guards.cjs +7 -7
  246. package/guards.mjs +7 -7
  247. package/{helpers-BPi_iwxv.cjs → helpers-DPlh_7Bn.cjs} +3 -3
  248. package/{helpers-BPi_iwxv.cjs.map → helpers-DPlh_7Bn.cjs.map} +1 -1
  249. package/{helpers-D47G8WQb.mjs → helpers-mbn_EsDV.mjs} +3 -3
  250. package/{helpers-D47G8WQb.mjs.map → helpers-mbn_EsDV.mjs.map} +1 -1
  251. package/index.cjs +11 -11
  252. package/index.mjs +11 -11
  253. package/{isolation-B2FgKbap.cjs → isolation-B01xCIoV.cjs} +2 -2
  254. package/{isolation-B2FgKbap.cjs.map → isolation-B01xCIoV.cjs.map} +1 -1
  255. package/{isolation-BRGpiU-K.mjs → isolation-CO0NiK8R.mjs} +2 -2
  256. package/{isolation-BRGpiU-K.mjs.map → isolation-CO0NiK8R.mjs.map} +1 -1
  257. package/{manifest-B5bWMHgj.mjs → manifest-D8UTRohY.mjs} +2 -2
  258. package/{manifest-B5bWMHgj.mjs.map → manifest-D8UTRohY.mjs.map} +1 -1
  259. package/{manifest-Chjh-3s1.cjs → manifest-IP1IOJcg.cjs} +2 -2
  260. package/{manifest-Chjh-3s1.cjs.map → manifest-IP1IOJcg.cjs.map} +1 -1
  261. package/mcp/adk-docs-corpus.json +2 -2
  262. package/package.json +538 -538
  263. package/{predicates-C9jl2QPZ.cjs → predicates-Bzaa7gNI.cjs} +2 -2
  264. package/{predicates-C9jl2QPZ.cjs.map → predicates-Bzaa7gNI.cjs.map} +1 -1
  265. package/{predicates-2dZQ82LY.mjs → predicates-CM27Z3TF.mjs} +2 -2
  266. package/{predicates-2dZQ82LY.mjs.map → predicates-CM27Z3TF.mjs.map} +1 -1
  267. package/{retrievable-ReauMJxJ.cjs → retrievable-Bq-O3k6r.cjs} +3 -3
  268. package/{retrievable-ReauMJxJ.cjs.map → retrievable-Bq-O3k6r.cjs.map} +1 -1
  269. package/{retrievable-mFgC1aty.mjs → retrievable-CXTAUuuv.mjs} +3 -3
  270. package/{retrievable-mFgC1aty.mjs.map → retrievable-CXTAUuuv.mjs.map} +1 -1
  271. package/{scrapper-BsEY0Wo6.cjs → scrapper-B8xG9lTD.cjs} +5 -5
  272. package/{scrapper-BsEY0Wo6.cjs.map → scrapper-B8xG9lTD.cjs.map} +1 -1
  273. package/{scrapper-bShwZxKP.mjs → scrapper-DiQ5FfDL.mjs} +5 -5
  274. package/{scrapper-bShwZxKP.mjs.map → scrapper-DiQ5FfDL.mjs.map} +1 -1
  275. package/{searxng-CAY-bOMl.mjs → searxng-BFTJ6rTE.mjs} +5 -5
  276. package/{searxng-CAY-bOMl.mjs.map → searxng-BFTJ6rTE.mjs.map} +1 -1
  277. package/{searxng-CLF0vBMT.cjs → searxng-EJhWRnIE.cjs} +5 -5
  278. package/{searxng-CLF0vBMT.cjs.map → searxng-EJhWRnIE.cjs.map} +1 -1
  279. package/server.json +2 -2
  280. package/skills/adk-assembly/SKILL.md +2 -2
  281. package/{spooled_artifact-CFjf6ULg.cjs → spooled_artifact---DmicFW.cjs} +384 -384
  282. package/spooled_artifact---DmicFW.cjs.map +1 -0
  283. package/{spooled_artifact-B710Rb0d.mjs → spooled_artifact-Bw_7swIp.mjs} +385 -385
  284. package/spooled_artifact-Bw_7swIp.mjs.map +1 -0
  285. package/spooled_artifact.cjs +2 -2
  286. package/spooled_artifact.mjs +2 -2
  287. package/{spooled_markdown_artifact-PWppwnPQ.cjs → spooled_markdown_artifact-Rjzj-kyh.cjs} +3 -3
  288. package/{spooled_markdown_artifact-PWppwnPQ.cjs.map → spooled_markdown_artifact-Rjzj-kyh.cjs.map} +1 -1
  289. package/{spooled_markdown_artifact-1C4mmi73.mjs → spooled_markdown_artifact-vd6eNtIP.mjs} +3 -3
  290. package/{spooled_markdown_artifact-1C4mmi73.mjs.map → spooled_markdown_artifact-vd6eNtIP.mjs.map} +1 -1
  291. package/{thought-BKXwUZoq.mjs → thought-CxSaF6Xf.mjs} +3 -3
  292. package/{thought-BKXwUZoq.mjs.map → thought-CxSaF6Xf.mjs.map} +1 -1
  293. package/{thought-D5fJsxBW.cjs → thought-Dp3sMWW6.cjs} +3 -3
  294. package/{thought-D5fJsxBW.cjs.map → thought-Dp3sMWW6.cjs.map} +1 -1
  295. package/{tokenizable-DDIdXbJN.cjs → tokenizable-BcodRtoW.cjs} +29 -29
  296. package/{tokenizable-DDIdXbJN.cjs.map → tokenizable-BcodRtoW.cjs.map} +1 -1
  297. package/{tokenizable-xPXj1AQX.mjs → tokenizable-VB4Av8GF.mjs} +30 -30
  298. package/{tokenizable-xPXj1AQX.mjs.map → tokenizable-VB4Av8GF.mjs.map} +1 -1
  299. package/{tool_call-CDV5pW13.cjs → tool_call-B9px4W9k.cjs} +3 -3
  300. package/{tool_call-CDV5pW13.cjs.map → tool_call-B9px4W9k.cjs.map} +1 -1
  301. package/{tool_call-D-LqMvpU.mjs → tool_call-Cfaj-6zK.mjs} +3 -3
  302. package/{tool_call-D-LqMvpU.mjs.map → tool_call-Cfaj-6zK.mjs.map} +1 -1
  303. package/{tools-CvCMdAd7.mjs → tools-D0MBDh2R.mjs} +6 -6
  304. package/{tools-CvCMdAd7.mjs.map → tools-D0MBDh2R.mjs.map} +1 -1
  305. package/{tools-CACuuMV4.cjs → tools-aNbi6JyA.cjs} +6 -6
  306. package/{tools-CACuuMV4.cjs.map → tools-aNbi6JyA.cjs.map} +1 -1
  307. package/{toon-CCjuuzd_.mjs → toon-BSTQnHed.mjs} +6 -6
  308. package/{toon-CCjuuzd_.mjs.map → toon-BSTQnHed.mjs.map} +1 -1
  309. package/{toon-B7Q9RWJF.cjs → toon-DmLwZ6H1.cjs} +6 -6
  310. package/{toon-B7Q9RWJF.cjs.map → toon-DmLwZ6H1.cjs.map} +1 -1
  311. package/{transformers_js-DM01eAzh.cjs → transformers_js-7OzeS_Tp.cjs} +2 -2
  312. package/{transformers_js-DM01eAzh.cjs.map → transformers_js-7OzeS_Tp.cjs.map} +1 -1
  313. package/{transformers_js-BR2Ov0Su.mjs → transformers_js-p3lAkHFH.mjs} +2 -2
  314. package/{transformers_js-BR2Ov0Su.mjs.map → transformers_js-p3lAkHFH.mjs.map} +1 -1
  315. package/{turn_runner-BgPw9uqb.mjs → turn_runner-BHHD6h77.mjs} +4 -4
  316. package/{turn_runner-BgPw9uqb.mjs.map → turn_runner-BHHD6h77.mjs.map} +1 -1
  317. package/{turn_runner-CP2zxSlu.cjs → turn_runner-Dj7JsUTQ.cjs} +4 -4
  318. package/{turn_runner-CP2zxSlu.cjs.map → turn_runner-Dj7JsUTQ.cjs.map} +1 -1
  319. package/turn_runner.cjs +1 -1
  320. package/turn_runner.mjs +1 -1
  321. package/{xml-BqTTIFhv.mjs → xml-CYseDztH.mjs} +6 -6
  322. package/{xml-BqTTIFhv.mjs.map → xml-CYseDztH.mjs.map} +1 -1
  323. package/{xml-viE54OTe.cjs → xml-zJul8jMQ.cjs} +6 -6
  324. package/{xml-viE54OTe.cjs.map → xml-zJul8jMQ.cjs.map} +1 -1
  325. package/{yaml-B1So-pUR.mjs → yaml-BPBoiOjx.mjs} +6 -6
  326. package/{yaml-B1So-pUR.mjs.map → yaml-BPBoiOjx.mjs.map} +1 -1
  327. package/{yaml-cGhhPyZq.cjs → yaml-D0PzoRAr.cjs} +6 -6
  328. package/{yaml-cGhhPyZq.cjs.map → yaml-D0PzoRAr.cjs.map} +1 -1
  329. package/artifact_methods-9BemAvd4.mjs +0 -1
  330. package/artifact_methods-FKgk4q_1.cjs +0 -1
  331. package/spooled_artifact-B710Rb0d.mjs.map +0 -1
  332. package/spooled_artifact-CFjf6ULg.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"chat_common-4huaTp6d.cjs","names":[],"sources":["../src/batteries/llm/chat_common/types.ts"],"sourcesContent":["/**\n * Wire-shape-agnostic TypeScript types shared across the Chat-family LLM batteries.\n *\n * @remarks\n * This module is INTERNAL to the bundled LLM batteries and is intentionally **not** tagged with\n * an `@module` JSDoc directive — `bin/utils/index.ts` `getEntries` only mints a public package\n * subpath for files that carry such a tag, so a tagless file stays private and is inlined into\n * each consumer by the bundler (the same way `src/lib/utils/retry.ts` is shared, minus the public\n * subpath). It holds the type aliases that the OpenAI Chat Completions battery and the native\n * Ollama battery both need: the validator-description envelope, the JSON Schema subset, the\n * trust-/memory-/retrievable-/thought-attribute envelopes, the system-prompt bucket ordering, the\n * function-tool wire shape, the unsupported-media policy, the retry config, and the\n * {@link ChatHelpersCommon} contract for the wire-shape-agnostic translation helpers.\n *\n * Battery-specific wire shapes (OpenAI Chat Completions message/chunk/response objects, the Ollama\n * native message/chunk objects) live in each battery's own `types.ts`, not here.\n */\n\nimport { v6 as uuidv6 } from 'uuid'\nimport type { ParsedToolCall } from './tool_parsers'\nimport type { DispatchContext } from '@nhtio/adk/types'\nimport type {\n Tokenizable,\n Memory,\n Thought,\n Retrievable,\n Tool,\n ArtifactTool,\n MediaKind,\n} from '@nhtio/adk/common'\n\n// ─── DescriptionLike (validator description envelope) ─────────────────────────\n\n/**\n * Structural shape of a validator/Joi `describe()` output, as consumed by the JSON-Schema\n * renderer. A loose superset — only the fields the renderer reads are typed; the index signature\n * carries everything else through untouched.\n */\nexport interface DescriptionLike {\n /** Validator type name (e.g. `'string'`, `'object'`, `'array'`). */\n type?: string\n /** Human-readable description of the field. */\n description?: string\n /** Presence flag (`'optional'`, `'required'`, or `'forbidden'`) at the top level. */\n presence?: string\n /** Default value supplied when the field is absent. */\n default?: unknown\n /** Permitted values declared via an enum/valid set. */\n enum?: unknown[]\n /** Permitted values declared via the validator's `valid()` rule. */\n valids?: unknown[]\n /** Example values for the field. */\n examples?: unknown[]\n /** Nested property descriptions, keyed by property name (for object types). */\n properties?: Record<string, DescriptionLike>\n /** Element description(s) for array types. */\n items?: DescriptionLike | DescriptionLike[]\n /** Names of required properties (for object types). */\n required?: string[]\n /** Validator flags bag carrying presence, description, and default. */\n flags?: { presence?: string; description?: string; default?: unknown }\n /** Pass-through for any other validator metadata the renderer does not read. */\n [key: string]: unknown\n}\n\n// ─── JSON Schema (Chat-Completions-compatible subset) ─────────────────────────\n\n/**\n * The subset of JSON Schema that Chat-family tool/function `parameters` accept, as emitted by\n * {@link ChatHelpersCommon.descriptionToChatCompletionsJsonSchema}. The index signature allows\n * extra keywords to pass through to the wire.\n */\nexport interface JsonSchema {\n /** JSON Schema primitive/compound type. */\n type?: 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null'\n /** Human-readable description of the schema node. */\n description?: string\n /** Permitted values for the node. */\n enum?: unknown[]\n /** Default value for the node. */\n default?: unknown\n /** Example values for the node. */\n examples?: unknown[]\n /** Property schemas keyed by property name (for `object` types). */\n properties?: Record<string, JsonSchema>\n /** Names of required properties (for `object` types). */\n required?: string[]\n /** Element schema(s) for `array` types. */\n items?: JsonSchema | JsonSchema[]\n /** Whether (or what schema) additional, undeclared properties are permitted. */\n additionalProperties?: boolean | JsonSchema\n /** Pass-through for any other JSON Schema keyword. */\n [key: string]: unknown\n}\n\n// ─── Helper-attribute envelopes ───────────────────────────────────────────────\n\n/**\n * Attribute bag rendered onto the trust envelope that wraps untrusted (third-party) content.\n */\nexport interface UntrustedContentAttrs {\n /**\n * Nonce binding the envelope's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the fence cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Content classifier rendered on the envelope. */\n kind: string\n /** Name of the tool that produced the content, when applicable. */\n tool?: string\n /**\n * When wrapping a {@link @nhtio/adk!Media}-derived text marker, the modality hazard axis derived from\n * `media.modalityHazard`: `'inert'`, `'extractable'` (from `'extractable-instructions'`), or\n * `'opaque'` (from `'opaque-perceptual'`). Omitted for non-media envelopes.\n */\n modality?: 'inert' | 'extractable' | 'opaque'\n}\n\n/**\n * Attribute bag rendered onto the trust envelope that wraps trusted (first-party) content.\n */\nexport interface TrustedContentAttrs {\n /**\n * Nonce binding the envelope's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the fence cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Content classifier rendered on the envelope. */\n kind: string\n /** Name of the tool that produced the content, when applicable. */\n tool?: string\n /**\n * Same semantics as {@link UntrustedContentAttrs.modality}.\n */\n modality?: 'inert' | 'extractable' | 'opaque'\n}\n\n/**\n * Attribute bag rendered onto a standing-instruction block.\n */\nexport interface StandingInstructionAttrs {\n /** Optional version label for the standing instruction. */\n version?: string\n}\n\n/**\n * Attribute bag rendered onto a memory block.\n */\nexport interface MemoryAttrs {\n /**\n * Nonce binding the block's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the block cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Origin of the memory (e.g. the producing subsystem). */\n source?: string\n /** ISO-8601 creation timestamp of the memory. */\n createdAt?: string\n /** Memory classifier. */\n kind?: string\n /** Relevance/recall score, when the memory was retrieved by similarity. */\n score?: number\n}\n\n/**\n * Attribute bag rendered onto a retrievable block.\n */\nexport interface RetrievableAttrs {\n /**\n * Nonce binding the block's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the block cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Origin of the retrievable (e.g. the source document or system). */\n source?: string\n /** ISO-8601 creation timestamp of the retrievable. */\n createdAt?: string\n /** Retrievable classifier. */\n kind?: string\n /** Relevance score from the retrieval query. */\n score?: number\n}\n\n/**\n * Attribute bag rendered onto a thought block.\n */\nexport interface ThoughtAttrs {\n /**\n * Nonce binding the block's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the block cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Whether the thought is the model's own, a peer's, or opaque vendor reasoning. */\n kind: 'self-reasoning' | 'peer-reasoning' | 'opaque-reasoning'\n /** Identity of the agent the thought originated from. */\n from: string\n /** ISO-8601 creation timestamp of the thought. */\n createdAt?: string\n /** Replay-compatibility label gating whether the thought is surfaced on replay. */\n replayCompatibility?: string\n}\n\n// ─── Bucket order ─────────────────────────────────────────────────────────────\n\n/**\n * Name of a system-prompt content bucket whose render order is configurable.\n */\nexport type ChatCompletionsBucketLabel =\n | 'standingInstructions'\n | 'memories'\n | 'retrievables'\n | 'timeline'\n\n/**\n * Ordered list of {@link ChatCompletionsBucketLabel}s controlling the sequence in which content\n * buckets are assembled into the prompt.\n */\nexport type ChatCompletionsBucketOrder = ReadonlyArray<ChatCompletionsBucketLabel>\n\n// ─── Function-tool wire shape (identical for OpenAI Chat Completions and Ollama) ──\n\n/**\n * Wire shape of a single function tool advertised to the model — identical for OpenAI Chat\n * Completions and Ollama.\n */\nexport interface ChatCompletionsTool {\n /** Tool kind; always `'function'` for the bundled batteries. */\n type: 'function'\n /** The function declaration: its name, description, and JSON-Schema parameters. */\n function: {\n name: string\n description?: string\n parameters?: JsonSchema\n }\n}\n\n// ─── Unsupported-media policy ─────────────────────────────────────────────────\n\n/**\n * Policy for how a Chat-family battery handles a {@link @nhtio/adk!Media} instance whose modality the\n * wire protocol cannot natively represent.\n *\n * @remarks\n * The option SHAPE is shared; each battery decides which modalities count as \"unsupported\"\n * (OpenAI Chat Completions: video; Ollama native `/api/chat`: everything except image). Three\n * modes:\n *\n * - `'throw'` — raise the battery's unsupported-media exception and fail the dispatch. Loud\n * failure; the default, so a misconfigured pipeline surfaces immediately.\n * - `'fallback-stash'` — look for a model-readable text entry in `media.stash`. If present, render\n * that text inside the appropriate trust envelope in lieu of a media block. If no entry is found,\n * fall through to `'synthetic-description'` behaviour. The shorthand string form uses the\n * battery's default key list (`['text:transcript', 'text:caption', 'text:description']`, walked\n * in order). The object form `{ mode: 'fallback-stash'; stashKeys }` overrides the key list.\n * - `'synthetic-description'` — always render a synthetic text description constructed from\n * `filename`, `byteLength`, and `mimeType` regardless of `stash` presence.\n */\nexport type UnsupportedMediaPolicy =\n | 'throw'\n | 'fallback-stash'\n | 'synthetic-description'\n | { mode: 'fallback-stash'; stashKeys: ReadonlyArray<string> }\n\n// ─── Media OUTPUT (generated media surfaced as assistant attachments) ─────────\n\n/**\n * One piece of media a model GENERATED as turn output — the descriptor a\n * {@link MediaOutputExtractorFn} returns for the adapter to persist + attach to the assistant\n * {@link @nhtio/adk!Message}.\n *\n * @remarks\n * The LLM batteries are multimodal-IN, text-OUT by default: the tested open-weight chat checkpoints\n * emit only text, so no media output is produced unless a consumer wraps a media-emitting model AND\n * supplies an extractor. The framework contract already supports the output direction —\n * `Message.attachments` is symmetric across roles and `ctx.storeMediaBytes` persists generated bytes —\n * so this descriptor is all the adapter needs: it calls `storeMediaBytes` with `bytes`, builds a\n * `Media.toolGenerated({ kind, mimeType, filename, reader })` from the returned reader, and attaches it.\n */\nexport interface GeneratedMediaOutput {\n /** Media modality (`'image'`/`'audio'`/`'video'`/`'document'`). */\n kind: MediaKind\n /** Concrete MIME type of the generated bytes (e.g. `'audio/wav'`, `'image/png'`). */\n mimeType: string\n /** The generated media bytes. */\n bytes: Uint8Array\n /** Optional filename for the attachment; the adapter supplies a default when omitted. */\n filename?: string\n}\n\n/**\n * Extracts generated media from a battery's raw generation result so the adapter can surface it as\n * assistant `Message.attachments`. Injectable + defaulted to absent (no media output) on every LLM\n * battery, mirroring the `toolCallParser` / `reasoningParser` / `decodeMedia` injection seams.\n *\n * @remarks\n * `result` is the battery-native generation object (transformers.js `model.generate` / pipeline output;\n * the LiteRT-LM final `Message` + raw content items) — deliberately typed `unknown` because its shape is\n * battery-specific and the extractor is supplied by whoever wraps a media-emitting model. Returning an\n * empty array (or not supplying the hook) yields today's text-only behavior, byte-for-byte unchanged.\n */\nexport type MediaOutputExtractorFn = (\n result: unknown\n) => GeneratedMediaOutput[] | Promise<GeneratedMediaOutput[]>\n\n// ─── Raw generation observability (the model's text BEFORE parsing) ───────────\n\n/**\n * One observation of a battery's raw model output for a single completed generation, fired the instant\n * the full text is in hand — AFTER envelope-token stripping + reasoning/tool-call parsing, but BEFORE\n * the parsed result is persisted. The whole point is to expose the gap between what the model literally\n * emitted (`rawText`) and what the battery managed to extract (`cleanedText` / `toolCalls` /\n * `reasoning`): when a small on-device model emits a tool call in a shape no parser matches, the call\n * silently leaks into `cleanedText` as prose, and this is the ONLY seam where that is visible.\n *\n * @remarks\n * This is a pure observability tap — it returns `void`, never mutates the result, and never throws into\n * the generation path (the adapter swallows callback errors). It fires once per terminal generation\n * (one per non-streamed turn; one per stream at stream end), for BOTH the transformers.js and LiteRT-LM\n * on-device batteries, at the identical point in each. Use it for parser bring-up against a new model,\n * live debugging (\"why did the agent abstain?\"), or capturing ground-truth fixtures — exactly the job\n * that previously required patching a temporary hook into the adapter.\n */\nexport interface RawGenerationObservation {\n /**\n * The model's complete decoded output for this generation, with non-semantic envelope/turn-boundary\n * special tokens already stripped (the same text handed to the parsers) — i.e. what the parsers\n * actually saw. This is the field to inspect when a tool call did not parse.\n */\n rawText: string\n /**\n * The residual prose after reasoning + tool-call extraction — what becomes the assistant message\n * `content`. If a tool call failed to parse, its source text is still here (the leak).\n */\n cleanedText: string\n /** The reasoning/thinking traces the reasoning parser extracted (empty when none / not applicable). */\n reasoning: ReadonlyArray<string>\n /** The tool calls the tool-call parser extracted (empty when the model emitted none, or none parsed). */\n toolCalls: ReadonlyArray<ParsedToolCall>\n /** Whether this generation streamed its prose to the consumer (vs. a single batch decode). */\n streamed: boolean\n /** The adapter's stream/message id for this generation, for correlating with other telemetry. */\n streamId: string\n}\n\n/**\n * Observe a battery's raw model output for one completed generation. Injectable + defaulted to absent\n * on the on-device LLM batteries (transformers.js, LiteRT-LM), mirroring the `toolCallParser` /\n * `reasoningParser` / `extractMediaOutputs` injection seams. Fired once per terminal generation, after\n * parsing and before persistence; purely observational (return value ignored, errors swallowed).\n */\nexport type RawGenerationObserverFn = (observation: RawGenerationObservation) => void\n\n// ─── Prompt observability (the exact request BEFORE it is dispatched) ──────────\n\n/**\n * One observation of the fully-assembled request a battery is about to send TO the model, fired the\n * instant assembly completes and BEFORE the engine/HTTP dispatch. It is the mirror of\n * {@link RawGenerationObservation}: that seam exposes the raw text coming back FROM the model; this one\n * exposes the raw request going TO it. Together they let you read ground truth at both ends of the wire —\n * e.g. to settle whether a \"smart quote\" in a rendered answer came from the model itself or from a\n * downstream markdown renderer, you inspect the bytes here, not the DOM.\n *\n * @remarks\n * This is a pure observability tap — it returns `void`, never mutates the request, and never throws into\n * the generation path (the adapter swallows callback errors). It fires once per terminal generation\n * (one per non-streamed turn; one per stream, at dispatch), across ALL five LLM batteries.\n *\n * **Handed back AS-IS — no redaction.** The observation carries the request exactly as assembled. The ADK\n * does not scrub credentials, headers, or any other field for you: what you put on the request is what you\n * see here, and if you route this to a persistent sink (a log, `localStorage`, a file) you may persist\n * secrets that rode the request (an `apiKey`, `Authorization` header, etc.). That is your responsibility to\n * handle, not the battery's — the ADK surfaces the truth and lets you decide what to do with it. (In\n * practice the API batteries strip ADK-control keys like `apiKey` out of the wire body before this fires,\n * but that is incidental to how the body is built, not a guarantee.)\n */\nexport interface PromptAssembledObservation {\n /** Which battery assembled this request (e.g. `'litert_lm'`, `'openai_chat_completions'`). */\n battery: string\n /**\n * The shape of the assembled request. `'rendered-prompt'` for the on-device batteries (transformers.js,\n * LiteRT-LM), which render a preface string + a messages array for the engine; `'request-body'` for the\n * API batteries (OpenAI-compatible, Ollama, WebLLM), which POST a JSON body.\n */\n kind: 'rendered-prompt' | 'request-body'\n /**\n * On-device leading/system content rendered ahead of the timeline (e.g. the LiteRT `preface` object,\n * which carries the assembled system message text and — for native tool delivery — the tool list), when\n * applicable. Its concrete shape is battery-specific; captured verbatim. Absent for the API batteries.\n */\n preface?: unknown\n /**\n * The per-turn messages exactly as handed to the engine (on-device) or placed on the wire (API): the\n * engine's message array, or the request body's `messages`.\n */\n messages: unknown\n /**\n * The tool declarations exactly as dispatched: the rendered `<tool_definitions>` prompt text (on-device\n * prompt-delivery) or the wire `tools` array (API / native tool delivery). Absent when no tools are sent.\n */\n tools?: unknown\n /**\n * API batteries only: the complete assembled request body, exactly as it will be sent (see the AS-IS /\n * no-redaction note above). Absent for the on-device batteries.\n */\n requestBody?: unknown\n /** Whether this generation streams its response (vs. a single batch call). */\n streamed: boolean\n /** The adapter's stream/message id for this generation, for correlating with other telemetry. */\n streamId: string\n}\n\n/**\n * Observe the fully-assembled request a battery is about to dispatch. Injectable + defaulted to absent on\n * every LLM battery, mirroring {@link RawGenerationObserverFn}. Fired once per terminal generation, after\n * assembly and before dispatch; purely observational (return value ignored, errors swallowed). The request\n * is handed back AS-IS — see {@link PromptAssembledObservation} for the no-redaction contract.\n */\nexport type PromptAssembledObserverFn = (observation: PromptAssembledObservation) => void\n\n// ─── Tool-call id ingress ─────────────────────────────────────────────────────\n\n/**\n * Shapes a provider-supplied tool-call id at adapter ingress, before the call is stored or used for\n * spool/result correlation. This hook exists to prevent the concrete failure seen with grok-4.3 on\n * Bedrock Mantle, which repeats `call_0` across tool-calling turns. Default absent = identity, so\n * adapters retain today's behaviour unless a consumer opts in.\n *\n * @remarks\n * `#doStoreToolCall` adds to `turnToolCalls` synchronously before its await, and adoption is a\n * sequential loop, so each call sees every prior call — including same-response siblings. A correctly\n * numbered parallel batch (`call_0`..`call_3`) is therefore safe because those ids are already\n * DISTINCT, not because the siblings are unstored. A genuine same-response duplicate IS de-collided,\n * which is intentional.\n */\nexport type ToolCallIdFilterFn = (id: string, ctx: DispatchContext) => string\n\n/**\n * De-collides a provider-supplied tool-call id against calls already adopted in this dispatch. It\n * prevents the concrete `call_0`-repeated-across-turns failure seen with grok-4.3 on Bedrock Mantle.\n * Default absent = identity; this implementation returns the original id when no collision exists.\n *\n * @remarks\n * `#doStoreToolCall` adds to `turnToolCalls` synchronously before its await, and adoption is a\n * sequential loop, so each call sees every prior call — including same-response siblings. A correctly\n * numbered parallel batch (`call_0`..`call_3`) passes through because those ids are already DISTINCT,\n * not because the siblings are unstored. A genuine same-response duplicate is de-collided, as intended.\n */\nexport const deCollideToolCallIds: ToolCallIdFilterFn = (id, ctx) =>\n [...ctx.turnToolCalls].some((tc) => tc.id === id) ? uuidv6() : id\n\n// ─── Retry config ─────────────────────────────────────────────────────────────\n\n/**\n * Retry/backoff configuration for a Chat-family battery's HTTP requests.\n */\nexport interface ChatCompletionsRetryConfig {\n /** Maximum number of attempts (including the first) before giving up. */\n maxAttempts?: number\n /** Base delay in milliseconds for the first retry; doubles each attempt. */\n baseDelayMs?: number\n /** Upper bound in milliseconds on any single backoff delay. */\n maxDelayMs?: number\n /** HTTP status codes that trigger a retry. */\n retriableStatuses?: number[]\n /** Whether to honour a server `Retry-After` header in place of computed backoff. */\n honorRetryAfter?: boolean\n}\n\n// ─── Shared helper contract (wire-shape-agnostic members) ─────────────────────\n\n/**\n * The wire-shape-agnostic subset of a Chat-family battery's translation helpers — every helper\n * that produces a plain `string` (or JSON Schema / tool-definition wire, which is identical across\n * the family) rather than a battery-specific message object.\n *\n * @remarks\n * Both `ChatCompletionsHelpers` (OpenAI battery) and `OllamaHelpers` (Ollama battery) extend this\n * contract and add their own wire-specific members (timeline-message rendering, tool-call-result\n * rendering, history assembly, and — for OpenAI — streaming tool-call delta accumulation). Helpers\n * that compose other helpers receive their dependents via explicit `deps` arguments typed against\n * THIS contract (never against a battery-specific bag), so the shared implementations carry no\n * import edge back to any individual battery.\n */\nexport interface ChatHelpersCommon {\n /** Converts a validator `describe()` envelope into the Chat-Completions JSON-Schema subset. */\n descriptionToChatCompletionsJsonSchema: (d: DescriptionLike) => JsonSchema\n /** Wraps untrusted (third-party) text in the untrusted-content trust envelope. */\n renderUntrustedContent: (content: string, attrs: UntrustedContentAttrs) => string\n /** Wraps trusted (first-party) text in the trusted-content trust envelope. */\n renderTrustedContent: (content: string, attrs: TrustedContentAttrs) => string\n /** Renders standing instructions into a single prompt block. */\n renderStandingInstructions: (\n items: Iterable<Tokenizable>,\n attrs?: StandingInstructionAttrs\n ) => string\n /** Renders memories (each with its attribute bag) into a single prompt block. */\n renderMemories: (items: Iterable<{ memory: Memory; attrs: MemoryAttrs }>) => string\n /** Renders the safety directive that precedes any retrievable content. */\n renderRetrievableSafetyDirective: () => string\n /** Renders first-party (trusted) retrievables into a single prompt block. */\n renderFirstPartyRetrievables: (\n items: Iterable<{ retrievable: Retrievable; attrs: RetrievableAttrs }>,\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n ) => Promise<string>\n /** Renders third-party public retrievables, wrapping each in the untrusted-content envelope. */\n renderThirdPartyPublicRetrievables: (\n items: Iterable<{ retrievable: Retrievable; attrs: RetrievableAttrs }>,\n deps: {\n renderUntrustedContent: ChatHelpersCommon['renderUntrustedContent']\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n }\n ) => Promise<string>\n /** Renders third-party private retrievables, wrapping each in the untrusted-content envelope. */\n renderThirdPartyPrivateRetrievables: (\n items: Iterable<{ retrievable: Retrievable; attrs: RetrievableAttrs }>,\n deps: {\n renderUntrustedContent: ChatHelpersCommon['renderUntrustedContent']\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n }\n ) => Promise<string>\n /** Assembles the full retrievables block: safety directive plus the trust-tiered sub-renderers. */\n renderRetrievables: (\n items: Iterable<{ retrievable: Retrievable; attrs: RetrievableAttrs }>,\n deps: {\n renderRetrievableSafetyDirective: ChatHelpersCommon['renderRetrievableSafetyDirective']\n renderFirstPartyRetrievables: ChatHelpersCommon['renderFirstPartyRetrievables']\n renderThirdPartyPublicRetrievables: ChatHelpersCommon['renderThirdPartyPublicRetrievables']\n renderThirdPartyPrivateRetrievables: ChatHelpersCommon['renderThirdPartyPrivateRetrievables']\n renderUntrustedContent: ChatHelpersCommon['renderUntrustedContent']\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n }\n ) => Promise<string>\n /**\n * Renders the directions-bearing \"handle\" body for a non-inlined {@link @nhtio/adk!SpooledArtifact}\n * tool result: metadata (callId/kind/byteLength/lineCount) plus the forged `artifact_*` tools the\n * model should call to read it incrementally.\n *\n * @remarks\n * Optional override seam. When omitted the battery uses the shared\n * {@link defaultRenderArtifactHandleBody}. A consumer overrides it to change WHICH reader the model\n * is steered toward first — e.g. promoting the JSON content-readers (`artifact_json_get` /\n * `artifact_json_keys`) ahead of the metadata-only `artifact_json_type` for a small model that grabs\n * the first listed tool. The tool list itself comes from the artifact's `constructor.toolMethods`;\n * an override typically reorders or re-annotates that list before delegating to the default renderer.\n */\n renderArtifactHandleBody?: (input: {\n callId: string\n artifact: unknown\n byteLength: number\n lineCount: number\n estimatedTokens?: number\n encoding?: string\n }) => string\n /**\n * Renders the directions-bearing \"handle\" body for a non-inlined {@link @nhtio/adk!Retrievable}\n * whose content is a {@link @nhtio/adk!SpooledArtifact}: metadata (callId/kind/byteLength/lineCount)\n * plus the forged `artifact_*` tools the model should call to read it incrementally.\n *\n * @remarks\n * Optional override seam, the retrievable-side counterpart to {@link renderArtifactHandleBody}.\n * When omitted the battery uses the shared {@link defaultRenderRetrievableHandleBody}.\n */\n renderRetrievableHandleBody?: (input: {\n callId: string\n artifact: unknown\n byteLength: number\n lineCount: number\n estimatedTokens?: number\n encoding?: string\n }) => string\n /** Renders a single thought into its prompt block, optionally carrying an opaque replay payload. */\n renderThought: (content: string, attrs: ThoughtAttrs, payload?: unknown) => string\n /** Selects which thoughts to surface, by surfacing mode, self identity, and replay compatibility. */\n filterThoughts: (\n thoughts: Iterable<Thought>,\n mode: 'all-self' | 'latest-self' | 'all',\n selfIdentity: string,\n replayCompatibility: ReadonlyArray<string>\n ) => Thought[]\n /** Translates the tool registry into the function-tool wire array advertised to the model. */\n toolsToChatCompletionsTools: (\n tools: ReadonlyArray<Tool | ArtifactTool>,\n deps: { descriptionToChatCompletionsJsonSchema: (d: DescriptionLike) => JsonSchema }\n ) => ChatCompletionsTool[]\n /** Assembles the system-prompt message from its constituent buckets in {@link ChatCompletionsBucketOrder}. */\n renderChatCompletionsSystemPrompt: (input: {\n systemPrompt: Tokenizable\n /**\n * Live dispatch context for resolving a DYNAMIC {@link Tokenizable} `systemPrompt` via\n * `.render(ctx)`. Optional; a static `systemPrompt` ignores it. The real implementation\n * (`chat_common/helpers.ts`) already accepts and forwards this — declared here so the type\n * matches what the function actually does.\n */\n renderCtx?: unknown\n standingInstructions: Iterable<Tokenizable>\n memories: Iterable<Memory>\n retrievables: Iterable<Retrievable>\n bucketOrder: ChatCompletionsBucketOrder\n renderStandingInstructions: ChatHelpersCommon['renderStandingInstructions']\n renderMemories: ChatHelpersCommon['renderMemories']\n renderRetrievables: ChatHelpersCommon['renderRetrievables']\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n renderRetrievableSafetyDirective: ChatHelpersCommon['renderRetrievableSafetyDirective']\n renderFirstPartyRetrievables: ChatHelpersCommon['renderFirstPartyRetrievables']\n renderThirdPartyPublicRetrievables: ChatHelpersCommon['renderThirdPartyPublicRetrievables']\n renderThirdPartyPrivateRetrievables: ChatHelpersCommon['renderThirdPartyPrivateRetrievables']\n renderUntrustedContent: ChatHelpersCommon['renderUntrustedContent']\n }) => Promise<string>\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwdA,IAAa,wBAA4C,IAAI,QAC3D,CAAC,GAAG,IAAI,aAAa,EAAE,MAAM,OAAO,GAAG,OAAO,EAAE,KAAA,GAAA,KAAA,IAAW,IAAI"}
1
+ {"version":3,"file":"chat_common-CNayzS1V.cjs","names":[],"sources":["../src/batteries/llm/chat_common/types.ts"],"sourcesContent":["/**\n * Wire-shape-agnostic TypeScript types shared across the Chat-family LLM batteries.\n *\n * @remarks\n * This module is INTERNAL to the bundled LLM batteries and is intentionally **not** tagged with\n * an `@module` JSDoc directive — `bin/utils/index.ts` `getEntries` only mints a public package\n * subpath for files that carry such a tag, so a tagless file stays private and is inlined into\n * each consumer by the bundler (the same way `src/lib/utils/retry.ts` is shared, minus the public\n * subpath). It holds the type aliases that the OpenAI Chat Completions battery and the native\n * Ollama battery both need: the validator-description envelope, the JSON Schema subset, the\n * trust-/memory-/retrievable-/thought-attribute envelopes, the system-prompt bucket ordering, the\n * function-tool wire shape, the unsupported-media policy, the retry config, and the\n * {@link ChatHelpersCommon} contract for the wire-shape-agnostic translation helpers.\n *\n * Battery-specific wire shapes (OpenAI Chat Completions message/chunk/response objects, the Ollama\n * native message/chunk objects) live in each battery's own `types.ts`, not here.\n */\n\nimport { v6 as uuidv6 } from 'uuid'\nimport type { ParsedToolCall } from './tool_parsers'\nimport type { DispatchContext } from '@nhtio/adk/types'\nimport type {\n Tokenizable,\n Memory,\n Thought,\n Retrievable,\n Tool,\n ArtifactTool,\n MediaKind,\n} from '@nhtio/adk/common'\n\n// ─── DescriptionLike (validator description envelope) ─────────────────────────\n\n/**\n * Structural shape of a validator/Joi `describe()` output, as consumed by the JSON-Schema\n * renderer. A loose superset — only the fields the renderer reads are typed; the index signature\n * carries everything else through untouched.\n */\nexport interface DescriptionLike {\n /** Validator type name (e.g. `'string'`, `'object'`, `'array'`). */\n type?: string\n /** Human-readable description of the field. */\n description?: string\n /** Presence flag (`'optional'`, `'required'`, or `'forbidden'`) at the top level. */\n presence?: string\n /** Default value supplied when the field is absent. */\n default?: unknown\n /** Permitted values declared via an enum/valid set. */\n enum?: unknown[]\n /** Permitted values declared via the validator's `valid()` rule. */\n valids?: unknown[]\n /** Example values for the field. */\n examples?: unknown[]\n /** Nested property descriptions, keyed by property name (for object types). */\n properties?: Record<string, DescriptionLike>\n /** Element description(s) for array types. */\n items?: DescriptionLike | DescriptionLike[]\n /** Names of required properties (for object types). */\n required?: string[]\n /** Validator flags bag carrying presence, description, and default. */\n flags?: { presence?: string; description?: string; default?: unknown }\n /** Pass-through for any other validator metadata the renderer does not read. */\n [key: string]: unknown\n}\n\n// ─── JSON Schema (Chat-Completions-compatible subset) ─────────────────────────\n\n/**\n * The subset of JSON Schema that Chat-family tool/function `parameters` accept, as emitted by\n * {@link ChatHelpersCommon.descriptionToChatCompletionsJsonSchema}. The index signature allows\n * extra keywords to pass through to the wire.\n */\nexport interface JsonSchema {\n /** JSON Schema primitive/compound type. */\n type?: 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null'\n /** Human-readable description of the schema node. */\n description?: string\n /** Permitted values for the node. */\n enum?: unknown[]\n /** Default value for the node. */\n default?: unknown\n /** Example values for the node. */\n examples?: unknown[]\n /** Property schemas keyed by property name (for `object` types). */\n properties?: Record<string, JsonSchema>\n /** Names of required properties (for `object` types). */\n required?: string[]\n /** Element schema(s) for `array` types. */\n items?: JsonSchema | JsonSchema[]\n /** Whether (or what schema) additional, undeclared properties are permitted. */\n additionalProperties?: boolean | JsonSchema\n /** Pass-through for any other JSON Schema keyword. */\n [key: string]: unknown\n}\n\n// ─── Helper-attribute envelopes ───────────────────────────────────────────────\n\n/**\n * Attribute bag rendered onto the trust envelope that wraps untrusted (third-party) content.\n */\nexport interface UntrustedContentAttrs {\n /**\n * Nonce binding the envelope's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the fence cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Content classifier rendered on the envelope. */\n kind: string\n /** Name of the tool that produced the content, when applicable. */\n tool?: string\n /**\n * When wrapping a {@link @nhtio/adk!Media}-derived text marker, the modality hazard axis derived from\n * `media.modalityHazard`: `'inert'`, `'extractable'` (from `'extractable-instructions'`), or\n * `'opaque'` (from `'opaque-perceptual'`). Omitted for non-media envelopes.\n */\n modality?: 'inert' | 'extractable' | 'opaque'\n}\n\n/**\n * Attribute bag rendered onto the trust envelope that wraps trusted (first-party) content.\n */\nexport interface TrustedContentAttrs {\n /**\n * Nonce binding the envelope's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the fence cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Content classifier rendered on the envelope. */\n kind: string\n /** Name of the tool that produced the content, when applicable. */\n tool?: string\n /**\n * Same semantics as {@link UntrustedContentAttrs.modality}.\n */\n modality?: 'inert' | 'extractable' | 'opaque'\n}\n\n/**\n * Attribute bag rendered onto a standing-instruction block.\n */\nexport interface StandingInstructionAttrs {\n /** Optional version label for the standing instruction. */\n version?: string\n}\n\n/**\n * Attribute bag rendered onto a memory block.\n */\nexport interface MemoryAttrs {\n /**\n * Nonce binding the block's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the block cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Origin of the memory (e.g. the producing subsystem). */\n source?: string\n /** ISO-8601 creation timestamp of the memory. */\n createdAt?: string\n /** Memory classifier. */\n kind?: string\n /** Relevance/recall score, when the memory was retrieved by similarity. */\n score?: number\n}\n\n/**\n * Attribute bag rendered onto a retrievable block.\n */\nexport interface RetrievableAttrs {\n /**\n * Nonce binding the block's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the block cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Origin of the retrievable (e.g. the source document or system). */\n source?: string\n /** ISO-8601 creation timestamp of the retrievable. */\n createdAt?: string\n /** Retrievable classifier. */\n kind?: string\n /** Relevance score from the retrieval query. */\n score?: number\n}\n\n/**\n * Attribute bag rendered onto a thought block.\n */\nexport interface ThoughtAttrs {\n /**\n * Nonce binding the block's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the block cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Whether the thought is the model's own, a peer's, or opaque vendor reasoning. */\n kind: 'self-reasoning' | 'peer-reasoning' | 'opaque-reasoning'\n /** Identity of the agent the thought originated from. */\n from: string\n /** ISO-8601 creation timestamp of the thought. */\n createdAt?: string\n /** Replay-compatibility label gating whether the thought is surfaced on replay. */\n replayCompatibility?: string\n}\n\n// ─── Bucket order ─────────────────────────────────────────────────────────────\n\n/**\n * Name of a system-prompt content bucket whose render order is configurable.\n */\nexport type ChatCompletionsBucketLabel =\n | 'standingInstructions'\n | 'memories'\n | 'retrievables'\n | 'timeline'\n\n/**\n * Ordered list of {@link ChatCompletionsBucketLabel}s controlling the sequence in which content\n * buckets are assembled into the prompt.\n */\nexport type ChatCompletionsBucketOrder = ReadonlyArray<ChatCompletionsBucketLabel>\n\n// ─── Function-tool wire shape (identical for OpenAI Chat Completions and Ollama) ──\n\n/**\n * Wire shape of a single function tool advertised to the model — identical for OpenAI Chat\n * Completions and Ollama.\n */\nexport interface ChatCompletionsTool {\n /** Tool kind; always `'function'` for the bundled batteries. */\n type: 'function'\n /** The function declaration: its name, description, and JSON-Schema parameters. */\n function: {\n name: string\n description?: string\n parameters?: JsonSchema\n }\n}\n\n// ─── Unsupported-media policy ─────────────────────────────────────────────────\n\n/**\n * Policy for how a Chat-family battery handles a {@link @nhtio/adk!Media} instance whose modality the\n * wire protocol cannot natively represent.\n *\n * @remarks\n * The option SHAPE is shared; each battery decides which modalities count as \"unsupported\"\n * (OpenAI Chat Completions: video; Ollama native `/api/chat`: everything except image). Three\n * modes:\n *\n * - `'throw'` — raise the battery's unsupported-media exception and fail the dispatch. Loud\n * failure; the default, so a misconfigured pipeline surfaces immediately.\n * - `'fallback-stash'` — look for a model-readable text entry in `media.stash`. If present, render\n * that text inside the appropriate trust envelope in lieu of a media block. If no entry is found,\n * fall through to `'synthetic-description'` behaviour. The shorthand string form uses the\n * battery's default key list (`['text:transcript', 'text:caption', 'text:description']`, walked\n * in order). The object form `{ mode: 'fallback-stash'; stashKeys }` overrides the key list.\n * - `'synthetic-description'` — always render a synthetic text description constructed from\n * `filename`, `byteLength`, and `mimeType` regardless of `stash` presence.\n */\nexport type UnsupportedMediaPolicy =\n | 'throw'\n | 'fallback-stash'\n | 'synthetic-description'\n | { mode: 'fallback-stash'; stashKeys: ReadonlyArray<string> }\n\n// ─── Media OUTPUT (generated media surfaced as assistant attachments) ─────────\n\n/**\n * One piece of media a model GENERATED as turn output — the descriptor a\n * {@link MediaOutputExtractorFn} returns for the adapter to persist + attach to the assistant\n * {@link @nhtio/adk!Message}.\n *\n * @remarks\n * The LLM batteries are multimodal-IN, text-OUT by default: the tested open-weight chat checkpoints\n * emit only text, so no media output is produced unless a consumer wraps a media-emitting model AND\n * supplies an extractor. The framework contract already supports the output direction —\n * `Message.attachments` is symmetric across roles and `ctx.storeMediaBytes` persists generated bytes —\n * so this descriptor is all the adapter needs: it calls `storeMediaBytes` with `bytes`, builds a\n * `Media.toolGenerated({ kind, mimeType, filename, reader })` from the returned reader, and attaches it.\n */\nexport interface GeneratedMediaOutput {\n /** Media modality (`'image'`/`'audio'`/`'video'`/`'document'`). */\n kind: MediaKind\n /** Concrete MIME type of the generated bytes (e.g. `'audio/wav'`, `'image/png'`). */\n mimeType: string\n /** The generated media bytes. */\n bytes: Uint8Array\n /** Optional filename for the attachment; the adapter supplies a default when omitted. */\n filename?: string\n}\n\n/**\n * Extracts generated media from a battery's raw generation result so the adapter can surface it as\n * assistant `Message.attachments`. Injectable + defaulted to absent (no media output) on every LLM\n * battery, mirroring the `toolCallParser` / `reasoningParser` / `decodeMedia` injection seams.\n *\n * @remarks\n * `result` is the battery-native generation object (transformers.js `model.generate` / pipeline output;\n * the LiteRT-LM final `Message` + raw content items) — deliberately typed `unknown` because its shape is\n * battery-specific and the extractor is supplied by whoever wraps a media-emitting model. Returning an\n * empty array (or not supplying the hook) yields today's text-only behavior, byte-for-byte unchanged.\n */\nexport type MediaOutputExtractorFn = (\n result: unknown\n) => GeneratedMediaOutput[] | Promise<GeneratedMediaOutput[]>\n\n// ─── Raw generation observability (the model's text BEFORE parsing) ───────────\n\n/**\n * One observation of a battery's raw model output for a single completed generation, fired the instant\n * the full text is in hand — AFTER envelope-token stripping + reasoning/tool-call parsing, but BEFORE\n * the parsed result is persisted. The whole point is to expose the gap between what the model literally\n * emitted (`rawText`) and what the battery managed to extract (`cleanedText` / `toolCalls` /\n * `reasoning`): when a small on-device model emits a tool call in a shape no parser matches, the call\n * silently leaks into `cleanedText` as prose, and this is the ONLY seam where that is visible.\n *\n * @remarks\n * This is a pure observability tap — it returns `void`, never mutates the result, and never throws into\n * the generation path (the adapter swallows callback errors). It fires once per terminal generation\n * (one per non-streamed turn; one per stream at stream end), for BOTH the transformers.js and LiteRT-LM\n * on-device batteries, at the identical point in each. Use it for parser bring-up against a new model,\n * live debugging (\"why did the agent abstain?\"), or capturing ground-truth fixtures — exactly the job\n * that previously required patching a temporary hook into the adapter.\n */\nexport interface RawGenerationObservation {\n /**\n * The model's complete decoded output for this generation, with non-semantic envelope/turn-boundary\n * special tokens already stripped (the same text handed to the parsers) — i.e. what the parsers\n * actually saw. This is the field to inspect when a tool call did not parse.\n */\n rawText: string\n /**\n * The residual prose after reasoning + tool-call extraction — what becomes the assistant message\n * `content`. If a tool call failed to parse, its source text is still here (the leak).\n */\n cleanedText: string\n /** The reasoning/thinking traces the reasoning parser extracted (empty when none / not applicable). */\n reasoning: ReadonlyArray<string>\n /** The tool calls the tool-call parser extracted (empty when the model emitted none, or none parsed). */\n toolCalls: ReadonlyArray<ParsedToolCall>\n /** Whether this generation streamed its prose to the consumer (vs. a single batch decode). */\n streamed: boolean\n /** The adapter's stream/message id for this generation, for correlating with other telemetry. */\n streamId: string\n}\n\n/**\n * Observe a battery's raw model output for one completed generation. Injectable + defaulted to absent\n * on the on-device LLM batteries (transformers.js, LiteRT-LM), mirroring the `toolCallParser` /\n * `reasoningParser` / `extractMediaOutputs` injection seams. Fired once per terminal generation, after\n * parsing and before persistence; purely observational (return value ignored, errors swallowed).\n */\nexport type RawGenerationObserverFn = (observation: RawGenerationObservation) => void\n\n// ─── Prompt observability (the exact request BEFORE it is dispatched) ──────────\n\n/**\n * One observation of the fully-assembled request a battery is about to send TO the model, fired the\n * instant assembly completes and BEFORE the engine/HTTP dispatch. It is the mirror of\n * {@link RawGenerationObservation}: that seam exposes the raw text coming back FROM the model; this one\n * exposes the raw request going TO it. Together they let you read ground truth at both ends of the wire —\n * e.g. to settle whether a \"smart quote\" in a rendered answer came from the model itself or from a\n * downstream markdown renderer, you inspect the bytes here, not the DOM.\n *\n * @remarks\n * This is a pure observability tap — it returns `void`, never mutates the request, and never throws into\n * the generation path (the adapter swallows callback errors). It fires once per terminal generation\n * (one per non-streamed turn; one per stream, at dispatch), across ALL five LLM batteries.\n *\n * **Handed back AS-IS — no redaction.** The observation carries the request exactly as assembled. The ADK\n * does not scrub credentials, headers, or any other field for you: what you put on the request is what you\n * see here, and if you route this to a persistent sink (a log, `localStorage`, a file) you may persist\n * secrets that rode the request (an `apiKey`, `Authorization` header, etc.). That is your responsibility to\n * handle, not the battery's — the ADK surfaces the truth and lets you decide what to do with it. (In\n * practice the API batteries strip ADK-control keys like `apiKey` out of the wire body before this fires,\n * but that is incidental to how the body is built, not a guarantee.)\n */\nexport interface PromptAssembledObservation {\n /** Which battery assembled this request (e.g. `'litert_lm'`, `'openai_chat_completions'`). */\n battery: string\n /**\n * The shape of the assembled request. `'rendered-prompt'` for the on-device batteries (transformers.js,\n * LiteRT-LM), which render a preface string + a messages array for the engine; `'request-body'` for the\n * API batteries (OpenAI-compatible, Ollama, WebLLM), which POST a JSON body.\n */\n kind: 'rendered-prompt' | 'request-body'\n /**\n * On-device leading/system content rendered ahead of the timeline (e.g. the LiteRT `preface` object,\n * which carries the assembled system message text and — for native tool delivery — the tool list), when\n * applicable. Its concrete shape is battery-specific; captured verbatim. Absent for the API batteries.\n */\n preface?: unknown\n /**\n * The per-turn messages exactly as handed to the engine (on-device) or placed on the wire (API): the\n * engine's message array, or the request body's `messages`.\n */\n messages: unknown\n /**\n * The tool declarations exactly as dispatched: the rendered `<tool_definitions>` prompt text (on-device\n * prompt-delivery) or the wire `tools` array (API / native tool delivery). Absent when no tools are sent.\n */\n tools?: unknown\n /**\n * API batteries only: the complete assembled request body, exactly as it will be sent (see the AS-IS /\n * no-redaction note above). Absent for the on-device batteries.\n */\n requestBody?: unknown\n /** Whether this generation streams its response (vs. a single batch call). */\n streamed: boolean\n /** The adapter's stream/message id for this generation, for correlating with other telemetry. */\n streamId: string\n}\n\n/**\n * Observe the fully-assembled request a battery is about to dispatch. Injectable + defaulted to absent on\n * every LLM battery, mirroring {@link RawGenerationObserverFn}. Fired once per terminal generation, after\n * assembly and before dispatch; purely observational (return value ignored, errors swallowed). The request\n * is handed back AS-IS — see {@link PromptAssembledObservation} for the no-redaction contract.\n */\nexport type PromptAssembledObserverFn = (observation: PromptAssembledObservation) => void\n\n// ─── Tool-call id ingress ─────────────────────────────────────────────────────\n\n/**\n * Shapes a provider-supplied tool-call id at adapter ingress, before the call is stored or used for\n * spool/result correlation. This hook exists to prevent the concrete failure seen with grok-4.3 on\n * Bedrock Mantle, which repeats `call_0` across tool-calling turns. Default absent = identity, so\n * adapters retain today's behaviour unless a consumer opts in.\n *\n * @remarks\n * `#doStoreToolCall` adds to `turnToolCalls` synchronously before its await, and adoption is a\n * sequential loop, so each call sees every prior call — including same-response siblings. A correctly\n * numbered parallel batch (`call_0`..`call_3`) is therefore safe because those ids are already\n * DISTINCT, not because the siblings are unstored. A genuine same-response duplicate IS de-collided,\n * which is intentional.\n */\nexport type ToolCallIdFilterFn = (id: string, ctx: DispatchContext) => string\n\n/**\n * De-collides a provider-supplied tool-call id against calls already adopted in this dispatch. It\n * prevents the concrete `call_0`-repeated-across-turns failure seen with grok-4.3 on Bedrock Mantle.\n * Default absent = identity; this implementation returns the original id when no collision exists.\n *\n * @remarks\n * `#doStoreToolCall` adds to `turnToolCalls` synchronously before its await, and adoption is a\n * sequential loop, so each call sees every prior call — including same-response siblings. A correctly\n * numbered parallel batch (`call_0`..`call_3`) passes through because those ids are already DISTINCT,\n * not because the siblings are unstored. A genuine same-response duplicate is de-collided, as intended.\n */\nexport const deCollideToolCallIds: ToolCallIdFilterFn = (id, ctx) =>\n [...ctx.turnToolCalls].some((tc) => tc.id === id) ? uuidv6() : id\n\n// ─── Retry config ─────────────────────────────────────────────────────────────\n\n/**\n * Retry/backoff configuration for a Chat-family battery's HTTP requests.\n */\nexport interface ChatCompletionsRetryConfig {\n /** Maximum number of attempts (including the first) before giving up. */\n maxAttempts?: number\n /** Base delay in milliseconds for the first retry; doubles each attempt. */\n baseDelayMs?: number\n /** Upper bound in milliseconds on any single backoff delay. */\n maxDelayMs?: number\n /** HTTP status codes that trigger a retry. */\n retriableStatuses?: number[]\n /** Whether to honour a server `Retry-After` header in place of computed backoff. */\n honorRetryAfter?: boolean\n}\n\n// ─── Shared helper contract (wire-shape-agnostic members) ─────────────────────\n\n/**\n * The wire-shape-agnostic subset of a Chat-family battery's translation helpers — every helper\n * that produces a plain `string` (or JSON Schema / tool-definition wire, which is identical across\n * the family) rather than a battery-specific message object.\n *\n * @remarks\n * Both `ChatCompletionsHelpers` (OpenAI battery) and `OllamaHelpers` (Ollama battery) extend this\n * contract and add their own wire-specific members (timeline-message rendering, tool-call-result\n * rendering, history assembly, and — for OpenAI — streaming tool-call delta accumulation). Helpers\n * that compose other helpers receive their dependents via explicit `deps` arguments typed against\n * THIS contract (never against a battery-specific bag), so the shared implementations carry no\n * import edge back to any individual battery.\n */\nexport interface ChatHelpersCommon {\n /** Converts a validator `describe()` envelope into the Chat-Completions JSON-Schema subset. */\n descriptionToChatCompletionsJsonSchema: (d: DescriptionLike) => JsonSchema\n /** Wraps untrusted (third-party) text in the untrusted-content trust envelope. */\n renderUntrustedContent: (content: string, attrs: UntrustedContentAttrs) => string\n /** Wraps trusted (first-party) text in the trusted-content trust envelope. */\n renderTrustedContent: (content: string, attrs: TrustedContentAttrs) => string\n /** Renders standing instructions into a single prompt block. */\n renderStandingInstructions: (\n items: Iterable<Tokenizable>,\n attrs?: StandingInstructionAttrs\n ) => string\n /** Renders memories (each with its attribute bag) into a single prompt block. */\n renderMemories: (items: Iterable<{ memory: Memory; attrs: MemoryAttrs }>) => string\n /** Renders the safety directive that precedes any retrievable content. */\n renderRetrievableSafetyDirective: () => string\n /** Renders first-party (trusted) retrievables into a single prompt block. */\n renderFirstPartyRetrievables: (\n items: Iterable<{ retrievable: Retrievable; attrs: RetrievableAttrs }>,\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n ) => Promise<string>\n /** Renders third-party public retrievables, wrapping each in the untrusted-content envelope. */\n renderThirdPartyPublicRetrievables: (\n items: Iterable<{ retrievable: Retrievable; attrs: RetrievableAttrs }>,\n deps: {\n renderUntrustedContent: ChatHelpersCommon['renderUntrustedContent']\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n }\n ) => Promise<string>\n /** Renders third-party private retrievables, wrapping each in the untrusted-content envelope. */\n renderThirdPartyPrivateRetrievables: (\n items: Iterable<{ retrievable: Retrievable; attrs: RetrievableAttrs }>,\n deps: {\n renderUntrustedContent: ChatHelpersCommon['renderUntrustedContent']\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n }\n ) => Promise<string>\n /** Assembles the full retrievables block: safety directive plus the trust-tiered sub-renderers. */\n renderRetrievables: (\n items: Iterable<{ retrievable: Retrievable; attrs: RetrievableAttrs }>,\n deps: {\n renderRetrievableSafetyDirective: ChatHelpersCommon['renderRetrievableSafetyDirective']\n renderFirstPartyRetrievables: ChatHelpersCommon['renderFirstPartyRetrievables']\n renderThirdPartyPublicRetrievables: ChatHelpersCommon['renderThirdPartyPublicRetrievables']\n renderThirdPartyPrivateRetrievables: ChatHelpersCommon['renderThirdPartyPrivateRetrievables']\n renderUntrustedContent: ChatHelpersCommon['renderUntrustedContent']\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n }\n ) => Promise<string>\n /**\n * Renders the directions-bearing \"handle\" body for a non-inlined {@link @nhtio/adk!SpooledArtifact}\n * tool result: metadata (callId/kind/byteLength/lineCount) plus the forged `artifact_*` tools the\n * model should call to read it incrementally.\n *\n * @remarks\n * Optional override seam. When omitted the battery uses the shared\n * {@link defaultRenderArtifactHandleBody}. A consumer overrides it to change WHICH reader the model\n * is steered toward first — e.g. promoting the JSON content-readers (`artifact_json_get` /\n * `artifact_json_keys`) ahead of the metadata-only `artifact_json_type` for a small model that grabs\n * the first listed tool. The tool list itself comes from the artifact's `constructor.toolMethods`;\n * an override typically reorders or re-annotates that list before delegating to the default renderer.\n */\n renderArtifactHandleBody?: (input: {\n callId: string\n artifact: unknown\n byteLength: number\n lineCount: number\n estimatedTokens?: number\n encoding?: string\n }) => string\n /**\n * Renders the directions-bearing \"handle\" body for a non-inlined {@link @nhtio/adk!Retrievable}\n * whose content is a {@link @nhtio/adk!SpooledArtifact}: metadata (callId/kind/byteLength/lineCount)\n * plus the forged `artifact_*` tools the model should call to read it incrementally.\n *\n * @remarks\n * Optional override seam, the retrievable-side counterpart to {@link renderArtifactHandleBody}.\n * When omitted the battery uses the shared {@link defaultRenderRetrievableHandleBody}.\n */\n renderRetrievableHandleBody?: (input: {\n callId: string\n artifact: unknown\n byteLength: number\n lineCount: number\n estimatedTokens?: number\n encoding?: string\n }) => string\n /** Renders a single thought into its prompt block, optionally carrying an opaque replay payload. */\n renderThought: (content: string, attrs: ThoughtAttrs, payload?: unknown) => string\n /** Selects which thoughts to surface, by surfacing mode, self identity, and replay compatibility. */\n filterThoughts: (\n thoughts: Iterable<Thought>,\n mode: 'all-self' | 'latest-self' | 'all',\n selfIdentity: string,\n replayCompatibility: ReadonlyArray<string>\n ) => Thought[]\n /** Translates the tool registry into the function-tool wire array advertised to the model. */\n toolsToChatCompletionsTools: (\n tools: ReadonlyArray<Tool | ArtifactTool>,\n deps: { descriptionToChatCompletionsJsonSchema: (d: DescriptionLike) => JsonSchema }\n ) => ChatCompletionsTool[]\n /** Assembles the system-prompt message from its constituent buckets in {@link ChatCompletionsBucketOrder}. */\n renderChatCompletionsSystemPrompt: (input: {\n systemPrompt: Tokenizable\n /**\n * Live dispatch context for resolving a DYNAMIC {@link Tokenizable} `systemPrompt` via\n * `.render(ctx)`. Optional; a static `systemPrompt` ignores it. The real implementation\n * (`chat_common/helpers.ts`) already accepts and forwards this — declared here so the type\n * matches what the function actually does.\n */\n renderCtx?: unknown\n standingInstructions: Iterable<Tokenizable>\n memories: Iterable<Memory>\n retrievables: Iterable<Retrievable>\n bucketOrder: ChatCompletionsBucketOrder\n renderStandingInstructions: ChatHelpersCommon['renderStandingInstructions']\n renderMemories: ChatHelpersCommon['renderMemories']\n renderRetrievables: ChatHelpersCommon['renderRetrievables']\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n renderRetrievableSafetyDirective: ChatHelpersCommon['renderRetrievableSafetyDirective']\n renderFirstPartyRetrievables: ChatHelpersCommon['renderFirstPartyRetrievables']\n renderThirdPartyPublicRetrievables: ChatHelpersCommon['renderThirdPartyPublicRetrievables']\n renderThirdPartyPrivateRetrievables: ChatHelpersCommon['renderThirdPartyPrivateRetrievables']\n renderUntrustedContent: ChatHelpersCommon['renderUntrustedContent']\n }) => Promise<string>\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwdA,IAAa,wBAA4C,IAAI,QAC3D,CAAC,GAAG,IAAI,aAAa,EAAE,MAAM,OAAO,GAAG,OAAO,EAAE,KAAA,GAAA,KAAA,IAAW,IAAI"}
@@ -1,5 +1,5 @@
1
1
  import "./tool_parsers-DgZhgxV8.mjs";
2
- import "./helpers-D47G8WQb.mjs";
2
+ import "./helpers-mbn_EsDV.mjs";
3
3
  import "./gpu_budget-Bi2nUUil.mjs";
4
4
  import "./lifecycle-C4kwYJ-N.mjs";
5
5
  import "./batteries/llm/chat_common/exceptions.mjs";
@@ -37,4 +37,4 @@ var deCollideToolCallIds = (id, ctx) => [...ctx.turnToolCalls].some((tc) => tc.i
37
37
  //#endregion
38
38
  export { deCollideToolCallIds as t };
39
39
 
40
- //# sourceMappingURL=chat_common-D_XGNjcK.mjs.map
40
+ //# sourceMappingURL=chat_common-DKw8FDol.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"chat_common-D_XGNjcK.mjs","names":[],"sources":["../src/batteries/llm/chat_common/types.ts"],"sourcesContent":["/**\n * Wire-shape-agnostic TypeScript types shared across the Chat-family LLM batteries.\n *\n * @remarks\n * This module is INTERNAL to the bundled LLM batteries and is intentionally **not** tagged with\n * an `@module` JSDoc directive — `bin/utils/index.ts` `getEntries` only mints a public package\n * subpath for files that carry such a tag, so a tagless file stays private and is inlined into\n * each consumer by the bundler (the same way `src/lib/utils/retry.ts` is shared, minus the public\n * subpath). It holds the type aliases that the OpenAI Chat Completions battery and the native\n * Ollama battery both need: the validator-description envelope, the JSON Schema subset, the\n * trust-/memory-/retrievable-/thought-attribute envelopes, the system-prompt bucket ordering, the\n * function-tool wire shape, the unsupported-media policy, the retry config, and the\n * {@link ChatHelpersCommon} contract for the wire-shape-agnostic translation helpers.\n *\n * Battery-specific wire shapes (OpenAI Chat Completions message/chunk/response objects, the Ollama\n * native message/chunk objects) live in each battery's own `types.ts`, not here.\n */\n\nimport { v6 as uuidv6 } from 'uuid'\nimport type { ParsedToolCall } from './tool_parsers'\nimport type { DispatchContext } from '@nhtio/adk/types'\nimport type {\n Tokenizable,\n Memory,\n Thought,\n Retrievable,\n Tool,\n ArtifactTool,\n MediaKind,\n} from '@nhtio/adk/common'\n\n// ─── DescriptionLike (validator description envelope) ─────────────────────────\n\n/**\n * Structural shape of a validator/Joi `describe()` output, as consumed by the JSON-Schema\n * renderer. A loose superset — only the fields the renderer reads are typed; the index signature\n * carries everything else through untouched.\n */\nexport interface DescriptionLike {\n /** Validator type name (e.g. `'string'`, `'object'`, `'array'`). */\n type?: string\n /** Human-readable description of the field. */\n description?: string\n /** Presence flag (`'optional'`, `'required'`, or `'forbidden'`) at the top level. */\n presence?: string\n /** Default value supplied when the field is absent. */\n default?: unknown\n /** Permitted values declared via an enum/valid set. */\n enum?: unknown[]\n /** Permitted values declared via the validator's `valid()` rule. */\n valids?: unknown[]\n /** Example values for the field. */\n examples?: unknown[]\n /** Nested property descriptions, keyed by property name (for object types). */\n properties?: Record<string, DescriptionLike>\n /** Element description(s) for array types. */\n items?: DescriptionLike | DescriptionLike[]\n /** Names of required properties (for object types). */\n required?: string[]\n /** Validator flags bag carrying presence, description, and default. */\n flags?: { presence?: string; description?: string; default?: unknown }\n /** Pass-through for any other validator metadata the renderer does not read. */\n [key: string]: unknown\n}\n\n// ─── JSON Schema (Chat-Completions-compatible subset) ─────────────────────────\n\n/**\n * The subset of JSON Schema that Chat-family tool/function `parameters` accept, as emitted by\n * {@link ChatHelpersCommon.descriptionToChatCompletionsJsonSchema}. The index signature allows\n * extra keywords to pass through to the wire.\n */\nexport interface JsonSchema {\n /** JSON Schema primitive/compound type. */\n type?: 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null'\n /** Human-readable description of the schema node. */\n description?: string\n /** Permitted values for the node. */\n enum?: unknown[]\n /** Default value for the node. */\n default?: unknown\n /** Example values for the node. */\n examples?: unknown[]\n /** Property schemas keyed by property name (for `object` types). */\n properties?: Record<string, JsonSchema>\n /** Names of required properties (for `object` types). */\n required?: string[]\n /** Element schema(s) for `array` types. */\n items?: JsonSchema | JsonSchema[]\n /** Whether (or what schema) additional, undeclared properties are permitted. */\n additionalProperties?: boolean | JsonSchema\n /** Pass-through for any other JSON Schema keyword. */\n [key: string]: unknown\n}\n\n// ─── Helper-attribute envelopes ───────────────────────────────────────────────\n\n/**\n * Attribute bag rendered onto the trust envelope that wraps untrusted (third-party) content.\n */\nexport interface UntrustedContentAttrs {\n /**\n * Nonce binding the envelope's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the fence cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Content classifier rendered on the envelope. */\n kind: string\n /** Name of the tool that produced the content, when applicable. */\n tool?: string\n /**\n * When wrapping a {@link @nhtio/adk!Media}-derived text marker, the modality hazard axis derived from\n * `media.modalityHazard`: `'inert'`, `'extractable'` (from `'extractable-instructions'`), or\n * `'opaque'` (from `'opaque-perceptual'`). Omitted for non-media envelopes.\n */\n modality?: 'inert' | 'extractable' | 'opaque'\n}\n\n/**\n * Attribute bag rendered onto the trust envelope that wraps trusted (first-party) content.\n */\nexport interface TrustedContentAttrs {\n /**\n * Nonce binding the envelope's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the fence cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Content classifier rendered on the envelope. */\n kind: string\n /** Name of the tool that produced the content, when applicable. */\n tool?: string\n /**\n * Same semantics as {@link UntrustedContentAttrs.modality}.\n */\n modality?: 'inert' | 'extractable' | 'opaque'\n}\n\n/**\n * Attribute bag rendered onto a standing-instruction block.\n */\nexport interface StandingInstructionAttrs {\n /** Optional version label for the standing instruction. */\n version?: string\n}\n\n/**\n * Attribute bag rendered onto a memory block.\n */\nexport interface MemoryAttrs {\n /**\n * Nonce binding the block's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the block cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Origin of the memory (e.g. the producing subsystem). */\n source?: string\n /** ISO-8601 creation timestamp of the memory. */\n createdAt?: string\n /** Memory classifier. */\n kind?: string\n /** Relevance/recall score, when the memory was retrieved by similarity. */\n score?: number\n}\n\n/**\n * Attribute bag rendered onto a retrievable block.\n */\nexport interface RetrievableAttrs {\n /**\n * Nonce binding the block's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the block cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Origin of the retrievable (e.g. the source document or system). */\n source?: string\n /** ISO-8601 creation timestamp of the retrievable. */\n createdAt?: string\n /** Retrievable classifier. */\n kind?: string\n /** Relevance score from the retrieval query. */\n score?: number\n}\n\n/**\n * Attribute bag rendered onto a thought block.\n */\nexport interface ThoughtAttrs {\n /**\n * Nonce binding the block's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the block cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Whether the thought is the model's own, a peer's, or opaque vendor reasoning. */\n kind: 'self-reasoning' | 'peer-reasoning' | 'opaque-reasoning'\n /** Identity of the agent the thought originated from. */\n from: string\n /** ISO-8601 creation timestamp of the thought. */\n createdAt?: string\n /** Replay-compatibility label gating whether the thought is surfaced on replay. */\n replayCompatibility?: string\n}\n\n// ─── Bucket order ─────────────────────────────────────────────────────────────\n\n/**\n * Name of a system-prompt content bucket whose render order is configurable.\n */\nexport type ChatCompletionsBucketLabel =\n | 'standingInstructions'\n | 'memories'\n | 'retrievables'\n | 'timeline'\n\n/**\n * Ordered list of {@link ChatCompletionsBucketLabel}s controlling the sequence in which content\n * buckets are assembled into the prompt.\n */\nexport type ChatCompletionsBucketOrder = ReadonlyArray<ChatCompletionsBucketLabel>\n\n// ─── Function-tool wire shape (identical for OpenAI Chat Completions and Ollama) ──\n\n/**\n * Wire shape of a single function tool advertised to the model — identical for OpenAI Chat\n * Completions and Ollama.\n */\nexport interface ChatCompletionsTool {\n /** Tool kind; always `'function'` for the bundled batteries. */\n type: 'function'\n /** The function declaration: its name, description, and JSON-Schema parameters. */\n function: {\n name: string\n description?: string\n parameters?: JsonSchema\n }\n}\n\n// ─── Unsupported-media policy ─────────────────────────────────────────────────\n\n/**\n * Policy for how a Chat-family battery handles a {@link @nhtio/adk!Media} instance whose modality the\n * wire protocol cannot natively represent.\n *\n * @remarks\n * The option SHAPE is shared; each battery decides which modalities count as \"unsupported\"\n * (OpenAI Chat Completions: video; Ollama native `/api/chat`: everything except image). Three\n * modes:\n *\n * - `'throw'` — raise the battery's unsupported-media exception and fail the dispatch. Loud\n * failure; the default, so a misconfigured pipeline surfaces immediately.\n * - `'fallback-stash'` — look for a model-readable text entry in `media.stash`. If present, render\n * that text inside the appropriate trust envelope in lieu of a media block. If no entry is found,\n * fall through to `'synthetic-description'` behaviour. The shorthand string form uses the\n * battery's default key list (`['text:transcript', 'text:caption', 'text:description']`, walked\n * in order). The object form `{ mode: 'fallback-stash'; stashKeys }` overrides the key list.\n * - `'synthetic-description'` — always render a synthetic text description constructed from\n * `filename`, `byteLength`, and `mimeType` regardless of `stash` presence.\n */\nexport type UnsupportedMediaPolicy =\n | 'throw'\n | 'fallback-stash'\n | 'synthetic-description'\n | { mode: 'fallback-stash'; stashKeys: ReadonlyArray<string> }\n\n// ─── Media OUTPUT (generated media surfaced as assistant attachments) ─────────\n\n/**\n * One piece of media a model GENERATED as turn output — the descriptor a\n * {@link MediaOutputExtractorFn} returns for the adapter to persist + attach to the assistant\n * {@link @nhtio/adk!Message}.\n *\n * @remarks\n * The LLM batteries are multimodal-IN, text-OUT by default: the tested open-weight chat checkpoints\n * emit only text, so no media output is produced unless a consumer wraps a media-emitting model AND\n * supplies an extractor. The framework contract already supports the output direction —\n * `Message.attachments` is symmetric across roles and `ctx.storeMediaBytes` persists generated bytes —\n * so this descriptor is all the adapter needs: it calls `storeMediaBytes` with `bytes`, builds a\n * `Media.toolGenerated({ kind, mimeType, filename, reader })` from the returned reader, and attaches it.\n */\nexport interface GeneratedMediaOutput {\n /** Media modality (`'image'`/`'audio'`/`'video'`/`'document'`). */\n kind: MediaKind\n /** Concrete MIME type of the generated bytes (e.g. `'audio/wav'`, `'image/png'`). */\n mimeType: string\n /** The generated media bytes. */\n bytes: Uint8Array\n /** Optional filename for the attachment; the adapter supplies a default when omitted. */\n filename?: string\n}\n\n/**\n * Extracts generated media from a battery's raw generation result so the adapter can surface it as\n * assistant `Message.attachments`. Injectable + defaulted to absent (no media output) on every LLM\n * battery, mirroring the `toolCallParser` / `reasoningParser` / `decodeMedia` injection seams.\n *\n * @remarks\n * `result` is the battery-native generation object (transformers.js `model.generate` / pipeline output;\n * the LiteRT-LM final `Message` + raw content items) — deliberately typed `unknown` because its shape is\n * battery-specific and the extractor is supplied by whoever wraps a media-emitting model. Returning an\n * empty array (or not supplying the hook) yields today's text-only behavior, byte-for-byte unchanged.\n */\nexport type MediaOutputExtractorFn = (\n result: unknown\n) => GeneratedMediaOutput[] | Promise<GeneratedMediaOutput[]>\n\n// ─── Raw generation observability (the model's text BEFORE parsing) ───────────\n\n/**\n * One observation of a battery's raw model output for a single completed generation, fired the instant\n * the full text is in hand — AFTER envelope-token stripping + reasoning/tool-call parsing, but BEFORE\n * the parsed result is persisted. The whole point is to expose the gap between what the model literally\n * emitted (`rawText`) and what the battery managed to extract (`cleanedText` / `toolCalls` /\n * `reasoning`): when a small on-device model emits a tool call in a shape no parser matches, the call\n * silently leaks into `cleanedText` as prose, and this is the ONLY seam where that is visible.\n *\n * @remarks\n * This is a pure observability tap — it returns `void`, never mutates the result, and never throws into\n * the generation path (the adapter swallows callback errors). It fires once per terminal generation\n * (one per non-streamed turn; one per stream at stream end), for BOTH the transformers.js and LiteRT-LM\n * on-device batteries, at the identical point in each. Use it for parser bring-up against a new model,\n * live debugging (\"why did the agent abstain?\"), or capturing ground-truth fixtures — exactly the job\n * that previously required patching a temporary hook into the adapter.\n */\nexport interface RawGenerationObservation {\n /**\n * The model's complete decoded output for this generation, with non-semantic envelope/turn-boundary\n * special tokens already stripped (the same text handed to the parsers) — i.e. what the parsers\n * actually saw. This is the field to inspect when a tool call did not parse.\n */\n rawText: string\n /**\n * The residual prose after reasoning + tool-call extraction — what becomes the assistant message\n * `content`. If a tool call failed to parse, its source text is still here (the leak).\n */\n cleanedText: string\n /** The reasoning/thinking traces the reasoning parser extracted (empty when none / not applicable). */\n reasoning: ReadonlyArray<string>\n /** The tool calls the tool-call parser extracted (empty when the model emitted none, or none parsed). */\n toolCalls: ReadonlyArray<ParsedToolCall>\n /** Whether this generation streamed its prose to the consumer (vs. a single batch decode). */\n streamed: boolean\n /** The adapter's stream/message id for this generation, for correlating with other telemetry. */\n streamId: string\n}\n\n/**\n * Observe a battery's raw model output for one completed generation. Injectable + defaulted to absent\n * on the on-device LLM batteries (transformers.js, LiteRT-LM), mirroring the `toolCallParser` /\n * `reasoningParser` / `extractMediaOutputs` injection seams. Fired once per terminal generation, after\n * parsing and before persistence; purely observational (return value ignored, errors swallowed).\n */\nexport type RawGenerationObserverFn = (observation: RawGenerationObservation) => void\n\n// ─── Prompt observability (the exact request BEFORE it is dispatched) ──────────\n\n/**\n * One observation of the fully-assembled request a battery is about to send TO the model, fired the\n * instant assembly completes and BEFORE the engine/HTTP dispatch. It is the mirror of\n * {@link RawGenerationObservation}: that seam exposes the raw text coming back FROM the model; this one\n * exposes the raw request going TO it. Together they let you read ground truth at both ends of the wire —\n * e.g. to settle whether a \"smart quote\" in a rendered answer came from the model itself or from a\n * downstream markdown renderer, you inspect the bytes here, not the DOM.\n *\n * @remarks\n * This is a pure observability tap — it returns `void`, never mutates the request, and never throws into\n * the generation path (the adapter swallows callback errors). It fires once per terminal generation\n * (one per non-streamed turn; one per stream, at dispatch), across ALL five LLM batteries.\n *\n * **Handed back AS-IS — no redaction.** The observation carries the request exactly as assembled. The ADK\n * does not scrub credentials, headers, or any other field for you: what you put on the request is what you\n * see here, and if you route this to a persistent sink (a log, `localStorage`, a file) you may persist\n * secrets that rode the request (an `apiKey`, `Authorization` header, etc.). That is your responsibility to\n * handle, not the battery's — the ADK surfaces the truth and lets you decide what to do with it. (In\n * practice the API batteries strip ADK-control keys like `apiKey` out of the wire body before this fires,\n * but that is incidental to how the body is built, not a guarantee.)\n */\nexport interface PromptAssembledObservation {\n /** Which battery assembled this request (e.g. `'litert_lm'`, `'openai_chat_completions'`). */\n battery: string\n /**\n * The shape of the assembled request. `'rendered-prompt'` for the on-device batteries (transformers.js,\n * LiteRT-LM), which render a preface string + a messages array for the engine; `'request-body'` for the\n * API batteries (OpenAI-compatible, Ollama, WebLLM), which POST a JSON body.\n */\n kind: 'rendered-prompt' | 'request-body'\n /**\n * On-device leading/system content rendered ahead of the timeline (e.g. the LiteRT `preface` object,\n * which carries the assembled system message text and — for native tool delivery — the tool list), when\n * applicable. Its concrete shape is battery-specific; captured verbatim. Absent for the API batteries.\n */\n preface?: unknown\n /**\n * The per-turn messages exactly as handed to the engine (on-device) or placed on the wire (API): the\n * engine's message array, or the request body's `messages`.\n */\n messages: unknown\n /**\n * The tool declarations exactly as dispatched: the rendered `<tool_definitions>` prompt text (on-device\n * prompt-delivery) or the wire `tools` array (API / native tool delivery). Absent when no tools are sent.\n */\n tools?: unknown\n /**\n * API batteries only: the complete assembled request body, exactly as it will be sent (see the AS-IS /\n * no-redaction note above). Absent for the on-device batteries.\n */\n requestBody?: unknown\n /** Whether this generation streams its response (vs. a single batch call). */\n streamed: boolean\n /** The adapter's stream/message id for this generation, for correlating with other telemetry. */\n streamId: string\n}\n\n/**\n * Observe the fully-assembled request a battery is about to dispatch. Injectable + defaulted to absent on\n * every LLM battery, mirroring {@link RawGenerationObserverFn}. Fired once per terminal generation, after\n * assembly and before dispatch; purely observational (return value ignored, errors swallowed). The request\n * is handed back AS-IS — see {@link PromptAssembledObservation} for the no-redaction contract.\n */\nexport type PromptAssembledObserverFn = (observation: PromptAssembledObservation) => void\n\n// ─── Tool-call id ingress ─────────────────────────────────────────────────────\n\n/**\n * Shapes a provider-supplied tool-call id at adapter ingress, before the call is stored or used for\n * spool/result correlation. This hook exists to prevent the concrete failure seen with grok-4.3 on\n * Bedrock Mantle, which repeats `call_0` across tool-calling turns. Default absent = identity, so\n * adapters retain today's behaviour unless a consumer opts in.\n *\n * @remarks\n * `#doStoreToolCall` adds to `turnToolCalls` synchronously before its await, and adoption is a\n * sequential loop, so each call sees every prior call — including same-response siblings. A correctly\n * numbered parallel batch (`call_0`..`call_3`) is therefore safe because those ids are already\n * DISTINCT, not because the siblings are unstored. A genuine same-response duplicate IS de-collided,\n * which is intentional.\n */\nexport type ToolCallIdFilterFn = (id: string, ctx: DispatchContext) => string\n\n/**\n * De-collides a provider-supplied tool-call id against calls already adopted in this dispatch. It\n * prevents the concrete `call_0`-repeated-across-turns failure seen with grok-4.3 on Bedrock Mantle.\n * Default absent = identity; this implementation returns the original id when no collision exists.\n *\n * @remarks\n * `#doStoreToolCall` adds to `turnToolCalls` synchronously before its await, and adoption is a\n * sequential loop, so each call sees every prior call — including same-response siblings. A correctly\n * numbered parallel batch (`call_0`..`call_3`) passes through because those ids are already DISTINCT,\n * not because the siblings are unstored. A genuine same-response duplicate is de-collided, as intended.\n */\nexport const deCollideToolCallIds: ToolCallIdFilterFn = (id, ctx) =>\n [...ctx.turnToolCalls].some((tc) => tc.id === id) ? uuidv6() : id\n\n// ─── Retry config ─────────────────────────────────────────────────────────────\n\n/**\n * Retry/backoff configuration for a Chat-family battery's HTTP requests.\n */\nexport interface ChatCompletionsRetryConfig {\n /** Maximum number of attempts (including the first) before giving up. */\n maxAttempts?: number\n /** Base delay in milliseconds for the first retry; doubles each attempt. */\n baseDelayMs?: number\n /** Upper bound in milliseconds on any single backoff delay. */\n maxDelayMs?: number\n /** HTTP status codes that trigger a retry. */\n retriableStatuses?: number[]\n /** Whether to honour a server `Retry-After` header in place of computed backoff. */\n honorRetryAfter?: boolean\n}\n\n// ─── Shared helper contract (wire-shape-agnostic members) ─────────────────────\n\n/**\n * The wire-shape-agnostic subset of a Chat-family battery's translation helpers — every helper\n * that produces a plain `string` (or JSON Schema / tool-definition wire, which is identical across\n * the family) rather than a battery-specific message object.\n *\n * @remarks\n * Both `ChatCompletionsHelpers` (OpenAI battery) and `OllamaHelpers` (Ollama battery) extend this\n * contract and add their own wire-specific members (timeline-message rendering, tool-call-result\n * rendering, history assembly, and — for OpenAI — streaming tool-call delta accumulation). Helpers\n * that compose other helpers receive their dependents via explicit `deps` arguments typed against\n * THIS contract (never against a battery-specific bag), so the shared implementations carry no\n * import edge back to any individual battery.\n */\nexport interface ChatHelpersCommon {\n /** Converts a validator `describe()` envelope into the Chat-Completions JSON-Schema subset. */\n descriptionToChatCompletionsJsonSchema: (d: DescriptionLike) => JsonSchema\n /** Wraps untrusted (third-party) text in the untrusted-content trust envelope. */\n renderUntrustedContent: (content: string, attrs: UntrustedContentAttrs) => string\n /** Wraps trusted (first-party) text in the trusted-content trust envelope. */\n renderTrustedContent: (content: string, attrs: TrustedContentAttrs) => string\n /** Renders standing instructions into a single prompt block. */\n renderStandingInstructions: (\n items: Iterable<Tokenizable>,\n attrs?: StandingInstructionAttrs\n ) => string\n /** Renders memories (each with its attribute bag) into a single prompt block. */\n renderMemories: (items: Iterable<{ memory: Memory; attrs: MemoryAttrs }>) => string\n /** Renders the safety directive that precedes any retrievable content. */\n renderRetrievableSafetyDirective: () => string\n /** Renders first-party (trusted) retrievables into a single prompt block. */\n renderFirstPartyRetrievables: (\n items: Iterable<{ retrievable: Retrievable; attrs: RetrievableAttrs }>,\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n ) => Promise<string>\n /** Renders third-party public retrievables, wrapping each in the untrusted-content envelope. */\n renderThirdPartyPublicRetrievables: (\n items: Iterable<{ retrievable: Retrievable; attrs: RetrievableAttrs }>,\n deps: {\n renderUntrustedContent: ChatHelpersCommon['renderUntrustedContent']\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n }\n ) => Promise<string>\n /** Renders third-party private retrievables, wrapping each in the untrusted-content envelope. */\n renderThirdPartyPrivateRetrievables: (\n items: Iterable<{ retrievable: Retrievable; attrs: RetrievableAttrs }>,\n deps: {\n renderUntrustedContent: ChatHelpersCommon['renderUntrustedContent']\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n }\n ) => Promise<string>\n /** Assembles the full retrievables block: safety directive plus the trust-tiered sub-renderers. */\n renderRetrievables: (\n items: Iterable<{ retrievable: Retrievable; attrs: RetrievableAttrs }>,\n deps: {\n renderRetrievableSafetyDirective: ChatHelpersCommon['renderRetrievableSafetyDirective']\n renderFirstPartyRetrievables: ChatHelpersCommon['renderFirstPartyRetrievables']\n renderThirdPartyPublicRetrievables: ChatHelpersCommon['renderThirdPartyPublicRetrievables']\n renderThirdPartyPrivateRetrievables: ChatHelpersCommon['renderThirdPartyPrivateRetrievables']\n renderUntrustedContent: ChatHelpersCommon['renderUntrustedContent']\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n }\n ) => Promise<string>\n /**\n * Renders the directions-bearing \"handle\" body for a non-inlined {@link @nhtio/adk!SpooledArtifact}\n * tool result: metadata (callId/kind/byteLength/lineCount) plus the forged `artifact_*` tools the\n * model should call to read it incrementally.\n *\n * @remarks\n * Optional override seam. When omitted the battery uses the shared\n * {@link defaultRenderArtifactHandleBody}. A consumer overrides it to change WHICH reader the model\n * is steered toward first — e.g. promoting the JSON content-readers (`artifact_json_get` /\n * `artifact_json_keys`) ahead of the metadata-only `artifact_json_type` for a small model that grabs\n * the first listed tool. The tool list itself comes from the artifact's `constructor.toolMethods`;\n * an override typically reorders or re-annotates that list before delegating to the default renderer.\n */\n renderArtifactHandleBody?: (input: {\n callId: string\n artifact: unknown\n byteLength: number\n lineCount: number\n estimatedTokens?: number\n encoding?: string\n }) => string\n /**\n * Renders the directions-bearing \"handle\" body for a non-inlined {@link @nhtio/adk!Retrievable}\n * whose content is a {@link @nhtio/adk!SpooledArtifact}: metadata (callId/kind/byteLength/lineCount)\n * plus the forged `artifact_*` tools the model should call to read it incrementally.\n *\n * @remarks\n * Optional override seam, the retrievable-side counterpart to {@link renderArtifactHandleBody}.\n * When omitted the battery uses the shared {@link defaultRenderRetrievableHandleBody}.\n */\n renderRetrievableHandleBody?: (input: {\n callId: string\n artifact: unknown\n byteLength: number\n lineCount: number\n estimatedTokens?: number\n encoding?: string\n }) => string\n /** Renders a single thought into its prompt block, optionally carrying an opaque replay payload. */\n renderThought: (content: string, attrs: ThoughtAttrs, payload?: unknown) => string\n /** Selects which thoughts to surface, by surfacing mode, self identity, and replay compatibility. */\n filterThoughts: (\n thoughts: Iterable<Thought>,\n mode: 'all-self' | 'latest-self' | 'all',\n selfIdentity: string,\n replayCompatibility: ReadonlyArray<string>\n ) => Thought[]\n /** Translates the tool registry into the function-tool wire array advertised to the model. */\n toolsToChatCompletionsTools: (\n tools: ReadonlyArray<Tool | ArtifactTool>,\n deps: { descriptionToChatCompletionsJsonSchema: (d: DescriptionLike) => JsonSchema }\n ) => ChatCompletionsTool[]\n /** Assembles the system-prompt message from its constituent buckets in {@link ChatCompletionsBucketOrder}. */\n renderChatCompletionsSystemPrompt: (input: {\n systemPrompt: Tokenizable\n /**\n * Live dispatch context for resolving a DYNAMIC {@link Tokenizable} `systemPrompt` via\n * `.render(ctx)`. Optional; a static `systemPrompt` ignores it. The real implementation\n * (`chat_common/helpers.ts`) already accepts and forwards this — declared here so the type\n * matches what the function actually does.\n */\n renderCtx?: unknown\n standingInstructions: Iterable<Tokenizable>\n memories: Iterable<Memory>\n retrievables: Iterable<Retrievable>\n bucketOrder: ChatCompletionsBucketOrder\n renderStandingInstructions: ChatHelpersCommon['renderStandingInstructions']\n renderMemories: ChatHelpersCommon['renderMemories']\n renderRetrievables: ChatHelpersCommon['renderRetrievables']\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n renderRetrievableSafetyDirective: ChatHelpersCommon['renderRetrievableSafetyDirective']\n renderFirstPartyRetrievables: ChatHelpersCommon['renderFirstPartyRetrievables']\n renderThirdPartyPublicRetrievables: ChatHelpersCommon['renderThirdPartyPublicRetrievables']\n renderThirdPartyPrivateRetrievables: ChatHelpersCommon['renderThirdPartyPrivateRetrievables']\n renderUntrustedContent: ChatHelpersCommon['renderUntrustedContent']\n }) => Promise<string>\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwdA,IAAa,wBAA4C,IAAI,QAC3D,CAAC,GAAG,IAAI,aAAa,EAAE,MAAM,OAAO,GAAG,OAAO,EAAE,IAAI,GAAO,IAAI"}
1
+ {"version":3,"file":"chat_common-DKw8FDol.mjs","names":[],"sources":["../src/batteries/llm/chat_common/types.ts"],"sourcesContent":["/**\n * Wire-shape-agnostic TypeScript types shared across the Chat-family LLM batteries.\n *\n * @remarks\n * This module is INTERNAL to the bundled LLM batteries and is intentionally **not** tagged with\n * an `@module` JSDoc directive — `bin/utils/index.ts` `getEntries` only mints a public package\n * subpath for files that carry such a tag, so a tagless file stays private and is inlined into\n * each consumer by the bundler (the same way `src/lib/utils/retry.ts` is shared, minus the public\n * subpath). It holds the type aliases that the OpenAI Chat Completions battery and the native\n * Ollama battery both need: the validator-description envelope, the JSON Schema subset, the\n * trust-/memory-/retrievable-/thought-attribute envelopes, the system-prompt bucket ordering, the\n * function-tool wire shape, the unsupported-media policy, the retry config, and the\n * {@link ChatHelpersCommon} contract for the wire-shape-agnostic translation helpers.\n *\n * Battery-specific wire shapes (OpenAI Chat Completions message/chunk/response objects, the Ollama\n * native message/chunk objects) live in each battery's own `types.ts`, not here.\n */\n\nimport { v6 as uuidv6 } from 'uuid'\nimport type { ParsedToolCall } from './tool_parsers'\nimport type { DispatchContext } from '@nhtio/adk/types'\nimport type {\n Tokenizable,\n Memory,\n Thought,\n Retrievable,\n Tool,\n ArtifactTool,\n MediaKind,\n} from '@nhtio/adk/common'\n\n// ─── DescriptionLike (validator description envelope) ─────────────────────────\n\n/**\n * Structural shape of a validator/Joi `describe()` output, as consumed by the JSON-Schema\n * renderer. A loose superset — only the fields the renderer reads are typed; the index signature\n * carries everything else through untouched.\n */\nexport interface DescriptionLike {\n /** Validator type name (e.g. `'string'`, `'object'`, `'array'`). */\n type?: string\n /** Human-readable description of the field. */\n description?: string\n /** Presence flag (`'optional'`, `'required'`, or `'forbidden'`) at the top level. */\n presence?: string\n /** Default value supplied when the field is absent. */\n default?: unknown\n /** Permitted values declared via an enum/valid set. */\n enum?: unknown[]\n /** Permitted values declared via the validator's `valid()` rule. */\n valids?: unknown[]\n /** Example values for the field. */\n examples?: unknown[]\n /** Nested property descriptions, keyed by property name (for object types). */\n properties?: Record<string, DescriptionLike>\n /** Element description(s) for array types. */\n items?: DescriptionLike | DescriptionLike[]\n /** Names of required properties (for object types). */\n required?: string[]\n /** Validator flags bag carrying presence, description, and default. */\n flags?: { presence?: string; description?: string; default?: unknown }\n /** Pass-through for any other validator metadata the renderer does not read. */\n [key: string]: unknown\n}\n\n// ─── JSON Schema (Chat-Completions-compatible subset) ─────────────────────────\n\n/**\n * The subset of JSON Schema that Chat-family tool/function `parameters` accept, as emitted by\n * {@link ChatHelpersCommon.descriptionToChatCompletionsJsonSchema}. The index signature allows\n * extra keywords to pass through to the wire.\n */\nexport interface JsonSchema {\n /** JSON Schema primitive/compound type. */\n type?: 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null'\n /** Human-readable description of the schema node. */\n description?: string\n /** Permitted values for the node. */\n enum?: unknown[]\n /** Default value for the node. */\n default?: unknown\n /** Example values for the node. */\n examples?: unknown[]\n /** Property schemas keyed by property name (for `object` types). */\n properties?: Record<string, JsonSchema>\n /** Names of required properties (for `object` types). */\n required?: string[]\n /** Element schema(s) for `array` types. */\n items?: JsonSchema | JsonSchema[]\n /** Whether (or what schema) additional, undeclared properties are permitted. */\n additionalProperties?: boolean | JsonSchema\n /** Pass-through for any other JSON Schema keyword. */\n [key: string]: unknown\n}\n\n// ─── Helper-attribute envelopes ───────────────────────────────────────────────\n\n/**\n * Attribute bag rendered onto the trust envelope that wraps untrusted (third-party) content.\n */\nexport interface UntrustedContentAttrs {\n /**\n * Nonce binding the envelope's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the fence cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Content classifier rendered on the envelope. */\n kind: string\n /** Name of the tool that produced the content, when applicable. */\n tool?: string\n /**\n * When wrapping a {@link @nhtio/adk!Media}-derived text marker, the modality hazard axis derived from\n * `media.modalityHazard`: `'inert'`, `'extractable'` (from `'extractable-instructions'`), or\n * `'opaque'` (from `'opaque-perceptual'`). Omitted for non-media envelopes.\n */\n modality?: 'inert' | 'extractable' | 'opaque'\n}\n\n/**\n * Attribute bag rendered onto the trust envelope that wraps trusted (first-party) content.\n */\nexport interface TrustedContentAttrs {\n /**\n * Nonce binding the envelope's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the fence cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Content classifier rendered on the envelope. */\n kind: string\n /** Name of the tool that produced the content, when applicable. */\n tool?: string\n /**\n * Same semantics as {@link UntrustedContentAttrs.modality}.\n */\n modality?: 'inert' | 'extractable' | 'opaque'\n}\n\n/**\n * Attribute bag rendered onto a standing-instruction block.\n */\nexport interface StandingInstructionAttrs {\n /** Optional version label for the standing instruction. */\n version?: string\n}\n\n/**\n * Attribute bag rendered onto a memory block.\n */\nexport interface MemoryAttrs {\n /**\n * Nonce binding the block's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the block cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Origin of the memory (e.g. the producing subsystem). */\n source?: string\n /** ISO-8601 creation timestamp of the memory. */\n createdAt?: string\n /** Memory classifier. */\n kind?: string\n /** Relevance/recall score, when the memory was retrieved by similarity. */\n score?: number\n}\n\n/**\n * Attribute bag rendered onto a retrievable block.\n */\nexport interface RetrievableAttrs {\n /**\n * Nonce binding the block's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the block cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Origin of the retrievable (e.g. the source document or system). */\n source?: string\n /** ISO-8601 creation timestamp of the retrievable. */\n createdAt?: string\n /** Retrievable classifier. */\n kind?: string\n /** Relevance score from the retrieval query. */\n score?: number\n}\n\n/**\n * Attribute bag rendered onto a thought block.\n */\nexport interface ThoughtAttrs {\n /**\n * Nonce binding the block's open and close markers together — it becomes part of the tag NAME\n * (`<..._<nonce>>`) so a model mirroring the block cannot forge a sibling's closer.\n *\n * FOOTGUN: this nonce MUST be unguessable AND non-path-shaped. It is typically the source record's id; a\n * path-shaped id (e.g. `chunk-assembly-events-9`) is copied by small models as a CITATION\n * (`/assembly/events-9`), which a doc-path validator then rejects → re-cite loop. Mint record ids with\n * `crypto.randomUUID()`; carry page/human provenance in `source=` (rendered before `nonce=`), never in the id.\n */\n nonce: string\n /** Whether the thought is the model's own, a peer's, or opaque vendor reasoning. */\n kind: 'self-reasoning' | 'peer-reasoning' | 'opaque-reasoning'\n /** Identity of the agent the thought originated from. */\n from: string\n /** ISO-8601 creation timestamp of the thought. */\n createdAt?: string\n /** Replay-compatibility label gating whether the thought is surfaced on replay. */\n replayCompatibility?: string\n}\n\n// ─── Bucket order ─────────────────────────────────────────────────────────────\n\n/**\n * Name of a system-prompt content bucket whose render order is configurable.\n */\nexport type ChatCompletionsBucketLabel =\n | 'standingInstructions'\n | 'memories'\n | 'retrievables'\n | 'timeline'\n\n/**\n * Ordered list of {@link ChatCompletionsBucketLabel}s controlling the sequence in which content\n * buckets are assembled into the prompt.\n */\nexport type ChatCompletionsBucketOrder = ReadonlyArray<ChatCompletionsBucketLabel>\n\n// ─── Function-tool wire shape (identical for OpenAI Chat Completions and Ollama) ──\n\n/**\n * Wire shape of a single function tool advertised to the model — identical for OpenAI Chat\n * Completions and Ollama.\n */\nexport interface ChatCompletionsTool {\n /** Tool kind; always `'function'` for the bundled batteries. */\n type: 'function'\n /** The function declaration: its name, description, and JSON-Schema parameters. */\n function: {\n name: string\n description?: string\n parameters?: JsonSchema\n }\n}\n\n// ─── Unsupported-media policy ─────────────────────────────────────────────────\n\n/**\n * Policy for how a Chat-family battery handles a {@link @nhtio/adk!Media} instance whose modality the\n * wire protocol cannot natively represent.\n *\n * @remarks\n * The option SHAPE is shared; each battery decides which modalities count as \"unsupported\"\n * (OpenAI Chat Completions: video; Ollama native `/api/chat`: everything except image). Three\n * modes:\n *\n * - `'throw'` — raise the battery's unsupported-media exception and fail the dispatch. Loud\n * failure; the default, so a misconfigured pipeline surfaces immediately.\n * - `'fallback-stash'` — look for a model-readable text entry in `media.stash`. If present, render\n * that text inside the appropriate trust envelope in lieu of a media block. If no entry is found,\n * fall through to `'synthetic-description'` behaviour. The shorthand string form uses the\n * battery's default key list (`['text:transcript', 'text:caption', 'text:description']`, walked\n * in order). The object form `{ mode: 'fallback-stash'; stashKeys }` overrides the key list.\n * - `'synthetic-description'` — always render a synthetic text description constructed from\n * `filename`, `byteLength`, and `mimeType` regardless of `stash` presence.\n */\nexport type UnsupportedMediaPolicy =\n | 'throw'\n | 'fallback-stash'\n | 'synthetic-description'\n | { mode: 'fallback-stash'; stashKeys: ReadonlyArray<string> }\n\n// ─── Media OUTPUT (generated media surfaced as assistant attachments) ─────────\n\n/**\n * One piece of media a model GENERATED as turn output — the descriptor a\n * {@link MediaOutputExtractorFn} returns for the adapter to persist + attach to the assistant\n * {@link @nhtio/adk!Message}.\n *\n * @remarks\n * The LLM batteries are multimodal-IN, text-OUT by default: the tested open-weight chat checkpoints\n * emit only text, so no media output is produced unless a consumer wraps a media-emitting model AND\n * supplies an extractor. The framework contract already supports the output direction —\n * `Message.attachments` is symmetric across roles and `ctx.storeMediaBytes` persists generated bytes —\n * so this descriptor is all the adapter needs: it calls `storeMediaBytes` with `bytes`, builds a\n * `Media.toolGenerated({ kind, mimeType, filename, reader })` from the returned reader, and attaches it.\n */\nexport interface GeneratedMediaOutput {\n /** Media modality (`'image'`/`'audio'`/`'video'`/`'document'`). */\n kind: MediaKind\n /** Concrete MIME type of the generated bytes (e.g. `'audio/wav'`, `'image/png'`). */\n mimeType: string\n /** The generated media bytes. */\n bytes: Uint8Array\n /** Optional filename for the attachment; the adapter supplies a default when omitted. */\n filename?: string\n}\n\n/**\n * Extracts generated media from a battery's raw generation result so the adapter can surface it as\n * assistant `Message.attachments`. Injectable + defaulted to absent (no media output) on every LLM\n * battery, mirroring the `toolCallParser` / `reasoningParser` / `decodeMedia` injection seams.\n *\n * @remarks\n * `result` is the battery-native generation object (transformers.js `model.generate` / pipeline output;\n * the LiteRT-LM final `Message` + raw content items) — deliberately typed `unknown` because its shape is\n * battery-specific and the extractor is supplied by whoever wraps a media-emitting model. Returning an\n * empty array (or not supplying the hook) yields today's text-only behavior, byte-for-byte unchanged.\n */\nexport type MediaOutputExtractorFn = (\n result: unknown\n) => GeneratedMediaOutput[] | Promise<GeneratedMediaOutput[]>\n\n// ─── Raw generation observability (the model's text BEFORE parsing) ───────────\n\n/**\n * One observation of a battery's raw model output for a single completed generation, fired the instant\n * the full text is in hand — AFTER envelope-token stripping + reasoning/tool-call parsing, but BEFORE\n * the parsed result is persisted. The whole point is to expose the gap between what the model literally\n * emitted (`rawText`) and what the battery managed to extract (`cleanedText` / `toolCalls` /\n * `reasoning`): when a small on-device model emits a tool call in a shape no parser matches, the call\n * silently leaks into `cleanedText` as prose, and this is the ONLY seam where that is visible.\n *\n * @remarks\n * This is a pure observability tap — it returns `void`, never mutates the result, and never throws into\n * the generation path (the adapter swallows callback errors). It fires once per terminal generation\n * (one per non-streamed turn; one per stream at stream end), for BOTH the transformers.js and LiteRT-LM\n * on-device batteries, at the identical point in each. Use it for parser bring-up against a new model,\n * live debugging (\"why did the agent abstain?\"), or capturing ground-truth fixtures — exactly the job\n * that previously required patching a temporary hook into the adapter.\n */\nexport interface RawGenerationObservation {\n /**\n * The model's complete decoded output for this generation, with non-semantic envelope/turn-boundary\n * special tokens already stripped (the same text handed to the parsers) — i.e. what the parsers\n * actually saw. This is the field to inspect when a tool call did not parse.\n */\n rawText: string\n /**\n * The residual prose after reasoning + tool-call extraction — what becomes the assistant message\n * `content`. If a tool call failed to parse, its source text is still here (the leak).\n */\n cleanedText: string\n /** The reasoning/thinking traces the reasoning parser extracted (empty when none / not applicable). */\n reasoning: ReadonlyArray<string>\n /** The tool calls the tool-call parser extracted (empty when the model emitted none, or none parsed). */\n toolCalls: ReadonlyArray<ParsedToolCall>\n /** Whether this generation streamed its prose to the consumer (vs. a single batch decode). */\n streamed: boolean\n /** The adapter's stream/message id for this generation, for correlating with other telemetry. */\n streamId: string\n}\n\n/**\n * Observe a battery's raw model output for one completed generation. Injectable + defaulted to absent\n * on the on-device LLM batteries (transformers.js, LiteRT-LM), mirroring the `toolCallParser` /\n * `reasoningParser` / `extractMediaOutputs` injection seams. Fired once per terminal generation, after\n * parsing and before persistence; purely observational (return value ignored, errors swallowed).\n */\nexport type RawGenerationObserverFn = (observation: RawGenerationObservation) => void\n\n// ─── Prompt observability (the exact request BEFORE it is dispatched) ──────────\n\n/**\n * One observation of the fully-assembled request a battery is about to send TO the model, fired the\n * instant assembly completes and BEFORE the engine/HTTP dispatch. It is the mirror of\n * {@link RawGenerationObservation}: that seam exposes the raw text coming back FROM the model; this one\n * exposes the raw request going TO it. Together they let you read ground truth at both ends of the wire —\n * e.g. to settle whether a \"smart quote\" in a rendered answer came from the model itself or from a\n * downstream markdown renderer, you inspect the bytes here, not the DOM.\n *\n * @remarks\n * This is a pure observability tap — it returns `void`, never mutates the request, and never throws into\n * the generation path (the adapter swallows callback errors). It fires once per terminal generation\n * (one per non-streamed turn; one per stream, at dispatch), across ALL five LLM batteries.\n *\n * **Handed back AS-IS — no redaction.** The observation carries the request exactly as assembled. The ADK\n * does not scrub credentials, headers, or any other field for you: what you put on the request is what you\n * see here, and if you route this to a persistent sink (a log, `localStorage`, a file) you may persist\n * secrets that rode the request (an `apiKey`, `Authorization` header, etc.). That is your responsibility to\n * handle, not the battery's — the ADK surfaces the truth and lets you decide what to do with it. (In\n * practice the API batteries strip ADK-control keys like `apiKey` out of the wire body before this fires,\n * but that is incidental to how the body is built, not a guarantee.)\n */\nexport interface PromptAssembledObservation {\n /** Which battery assembled this request (e.g. `'litert_lm'`, `'openai_chat_completions'`). */\n battery: string\n /**\n * The shape of the assembled request. `'rendered-prompt'` for the on-device batteries (transformers.js,\n * LiteRT-LM), which render a preface string + a messages array for the engine; `'request-body'` for the\n * API batteries (OpenAI-compatible, Ollama, WebLLM), which POST a JSON body.\n */\n kind: 'rendered-prompt' | 'request-body'\n /**\n * On-device leading/system content rendered ahead of the timeline (e.g. the LiteRT `preface` object,\n * which carries the assembled system message text and — for native tool delivery — the tool list), when\n * applicable. Its concrete shape is battery-specific; captured verbatim. Absent for the API batteries.\n */\n preface?: unknown\n /**\n * The per-turn messages exactly as handed to the engine (on-device) or placed on the wire (API): the\n * engine's message array, or the request body's `messages`.\n */\n messages: unknown\n /**\n * The tool declarations exactly as dispatched: the rendered `<tool_definitions>` prompt text (on-device\n * prompt-delivery) or the wire `tools` array (API / native tool delivery). Absent when no tools are sent.\n */\n tools?: unknown\n /**\n * API batteries only: the complete assembled request body, exactly as it will be sent (see the AS-IS /\n * no-redaction note above). Absent for the on-device batteries.\n */\n requestBody?: unknown\n /** Whether this generation streams its response (vs. a single batch call). */\n streamed: boolean\n /** The adapter's stream/message id for this generation, for correlating with other telemetry. */\n streamId: string\n}\n\n/**\n * Observe the fully-assembled request a battery is about to dispatch. Injectable + defaulted to absent on\n * every LLM battery, mirroring {@link RawGenerationObserverFn}. Fired once per terminal generation, after\n * assembly and before dispatch; purely observational (return value ignored, errors swallowed). The request\n * is handed back AS-IS — see {@link PromptAssembledObservation} for the no-redaction contract.\n */\nexport type PromptAssembledObserverFn = (observation: PromptAssembledObservation) => void\n\n// ─── Tool-call id ingress ─────────────────────────────────────────────────────\n\n/**\n * Shapes a provider-supplied tool-call id at adapter ingress, before the call is stored or used for\n * spool/result correlation. This hook exists to prevent the concrete failure seen with grok-4.3 on\n * Bedrock Mantle, which repeats `call_0` across tool-calling turns. Default absent = identity, so\n * adapters retain today's behaviour unless a consumer opts in.\n *\n * @remarks\n * `#doStoreToolCall` adds to `turnToolCalls` synchronously before its await, and adoption is a\n * sequential loop, so each call sees every prior call — including same-response siblings. A correctly\n * numbered parallel batch (`call_0`..`call_3`) is therefore safe because those ids are already\n * DISTINCT, not because the siblings are unstored. A genuine same-response duplicate IS de-collided,\n * which is intentional.\n */\nexport type ToolCallIdFilterFn = (id: string, ctx: DispatchContext) => string\n\n/**\n * De-collides a provider-supplied tool-call id against calls already adopted in this dispatch. It\n * prevents the concrete `call_0`-repeated-across-turns failure seen with grok-4.3 on Bedrock Mantle.\n * Default absent = identity; this implementation returns the original id when no collision exists.\n *\n * @remarks\n * `#doStoreToolCall` adds to `turnToolCalls` synchronously before its await, and adoption is a\n * sequential loop, so each call sees every prior call — including same-response siblings. A correctly\n * numbered parallel batch (`call_0`..`call_3`) passes through because those ids are already DISTINCT,\n * not because the siblings are unstored. A genuine same-response duplicate is de-collided, as intended.\n */\nexport const deCollideToolCallIds: ToolCallIdFilterFn = (id, ctx) =>\n [...ctx.turnToolCalls].some((tc) => tc.id === id) ? uuidv6() : id\n\n// ─── Retry config ─────────────────────────────────────────────────────────────\n\n/**\n * Retry/backoff configuration for a Chat-family battery's HTTP requests.\n */\nexport interface ChatCompletionsRetryConfig {\n /** Maximum number of attempts (including the first) before giving up. */\n maxAttempts?: number\n /** Base delay in milliseconds for the first retry; doubles each attempt. */\n baseDelayMs?: number\n /** Upper bound in milliseconds on any single backoff delay. */\n maxDelayMs?: number\n /** HTTP status codes that trigger a retry. */\n retriableStatuses?: number[]\n /** Whether to honour a server `Retry-After` header in place of computed backoff. */\n honorRetryAfter?: boolean\n}\n\n// ─── Shared helper contract (wire-shape-agnostic members) ─────────────────────\n\n/**\n * The wire-shape-agnostic subset of a Chat-family battery's translation helpers — every helper\n * that produces a plain `string` (or JSON Schema / tool-definition wire, which is identical across\n * the family) rather than a battery-specific message object.\n *\n * @remarks\n * Both `ChatCompletionsHelpers` (OpenAI battery) and `OllamaHelpers` (Ollama battery) extend this\n * contract and add their own wire-specific members (timeline-message rendering, tool-call-result\n * rendering, history assembly, and — for OpenAI — streaming tool-call delta accumulation). Helpers\n * that compose other helpers receive their dependents via explicit `deps` arguments typed against\n * THIS contract (never against a battery-specific bag), so the shared implementations carry no\n * import edge back to any individual battery.\n */\nexport interface ChatHelpersCommon {\n /** Converts a validator `describe()` envelope into the Chat-Completions JSON-Schema subset. */\n descriptionToChatCompletionsJsonSchema: (d: DescriptionLike) => JsonSchema\n /** Wraps untrusted (third-party) text in the untrusted-content trust envelope. */\n renderUntrustedContent: (content: string, attrs: UntrustedContentAttrs) => string\n /** Wraps trusted (first-party) text in the trusted-content trust envelope. */\n renderTrustedContent: (content: string, attrs: TrustedContentAttrs) => string\n /** Renders standing instructions into a single prompt block. */\n renderStandingInstructions: (\n items: Iterable<Tokenizable>,\n attrs?: StandingInstructionAttrs\n ) => string\n /** Renders memories (each with its attribute bag) into a single prompt block. */\n renderMemories: (items: Iterable<{ memory: Memory; attrs: MemoryAttrs }>) => string\n /** Renders the safety directive that precedes any retrievable content. */\n renderRetrievableSafetyDirective: () => string\n /** Renders first-party (trusted) retrievables into a single prompt block. */\n renderFirstPartyRetrievables: (\n items: Iterable<{ retrievable: Retrievable; attrs: RetrievableAttrs }>,\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n ) => Promise<string>\n /** Renders third-party public retrievables, wrapping each in the untrusted-content envelope. */\n renderThirdPartyPublicRetrievables: (\n items: Iterable<{ retrievable: Retrievable; attrs: RetrievableAttrs }>,\n deps: {\n renderUntrustedContent: ChatHelpersCommon['renderUntrustedContent']\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n }\n ) => Promise<string>\n /** Renders third-party private retrievables, wrapping each in the untrusted-content envelope. */\n renderThirdPartyPrivateRetrievables: (\n items: Iterable<{ retrievable: Retrievable; attrs: RetrievableAttrs }>,\n deps: {\n renderUntrustedContent: ChatHelpersCommon['renderUntrustedContent']\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n }\n ) => Promise<string>\n /** Assembles the full retrievables block: safety directive plus the trust-tiered sub-renderers. */\n renderRetrievables: (\n items: Iterable<{ retrievable: Retrievable; attrs: RetrievableAttrs }>,\n deps: {\n renderRetrievableSafetyDirective: ChatHelpersCommon['renderRetrievableSafetyDirective']\n renderFirstPartyRetrievables: ChatHelpersCommon['renderFirstPartyRetrievables']\n renderThirdPartyPublicRetrievables: ChatHelpersCommon['renderThirdPartyPublicRetrievables']\n renderThirdPartyPrivateRetrievables: ChatHelpersCommon['renderThirdPartyPrivateRetrievables']\n renderUntrustedContent: ChatHelpersCommon['renderUntrustedContent']\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n }\n ) => Promise<string>\n /**\n * Renders the directions-bearing \"handle\" body for a non-inlined {@link @nhtio/adk!SpooledArtifact}\n * tool result: metadata (callId/kind/byteLength/lineCount) plus the forged `artifact_*` tools the\n * model should call to read it incrementally.\n *\n * @remarks\n * Optional override seam. When omitted the battery uses the shared\n * {@link defaultRenderArtifactHandleBody}. A consumer overrides it to change WHICH reader the model\n * is steered toward first — e.g. promoting the JSON content-readers (`artifact_json_get` /\n * `artifact_json_keys`) ahead of the metadata-only `artifact_json_type` for a small model that grabs\n * the first listed tool. The tool list itself comes from the artifact's `constructor.toolMethods`;\n * an override typically reorders or re-annotates that list before delegating to the default renderer.\n */\n renderArtifactHandleBody?: (input: {\n callId: string\n artifact: unknown\n byteLength: number\n lineCount: number\n estimatedTokens?: number\n encoding?: string\n }) => string\n /**\n * Renders the directions-bearing \"handle\" body for a non-inlined {@link @nhtio/adk!Retrievable}\n * whose content is a {@link @nhtio/adk!SpooledArtifact}: metadata (callId/kind/byteLength/lineCount)\n * plus the forged `artifact_*` tools the model should call to read it incrementally.\n *\n * @remarks\n * Optional override seam, the retrievable-side counterpart to {@link renderArtifactHandleBody}.\n * When omitted the battery uses the shared {@link defaultRenderRetrievableHandleBody}.\n */\n renderRetrievableHandleBody?: (input: {\n callId: string\n artifact: unknown\n byteLength: number\n lineCount: number\n estimatedTokens?: number\n encoding?: string\n }) => string\n /** Renders a single thought into its prompt block, optionally carrying an opaque replay payload. */\n renderThought: (content: string, attrs: ThoughtAttrs, payload?: unknown) => string\n /** Selects which thoughts to surface, by surfacing mode, self identity, and replay compatibility. */\n filterThoughts: (\n thoughts: Iterable<Thought>,\n mode: 'all-self' | 'latest-self' | 'all',\n selfIdentity: string,\n replayCompatibility: ReadonlyArray<string>\n ) => Thought[]\n /** Translates the tool registry into the function-tool wire array advertised to the model. */\n toolsToChatCompletionsTools: (\n tools: ReadonlyArray<Tool | ArtifactTool>,\n deps: { descriptionToChatCompletionsJsonSchema: (d: DescriptionLike) => JsonSchema }\n ) => ChatCompletionsTool[]\n /** Assembles the system-prompt message from its constituent buckets in {@link ChatCompletionsBucketOrder}. */\n renderChatCompletionsSystemPrompt: (input: {\n systemPrompt: Tokenizable\n /**\n * Live dispatch context for resolving a DYNAMIC {@link Tokenizable} `systemPrompt` via\n * `.render(ctx)`. Optional; a static `systemPrompt` ignores it. The real implementation\n * (`chat_common/helpers.ts`) already accepts and forwards this — declared here so the type\n * matches what the function actually does.\n */\n renderCtx?: unknown\n standingInstructions: Iterable<Tokenizable>\n memories: Iterable<Memory>\n retrievables: Iterable<Retrievable>\n bucketOrder: ChatCompletionsBucketOrder\n renderStandingInstructions: ChatHelpersCommon['renderStandingInstructions']\n renderMemories: ChatHelpersCommon['renderMemories']\n renderRetrievables: ChatHelpersCommon['renderRetrievables']\n renderRetrievableHandleBody?: ChatHelpersCommon['renderRetrievableHandleBody']\n renderRetrievableSafetyDirective: ChatHelpersCommon['renderRetrievableSafetyDirective']\n renderFirstPartyRetrievables: ChatHelpersCommon['renderFirstPartyRetrievables']\n renderThirdPartyPublicRetrievables: ChatHelpersCommon['renderThirdPartyPublicRetrievables']\n renderThirdPartyPrivateRetrievables: ChatHelpersCommon['renderThirdPartyPrivateRetrievables']\n renderUntrustedContent: ChatHelpersCommon['renderUntrustedContent']\n }) => Promise<string>\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwdA,IAAa,wBAA4C,IAAI,QAC3D,CAAC,GAAG,IAAI,aAAa,EAAE,MAAM,OAAO,GAAG,OAAO,EAAE,IAAI,GAAO,IAAI"}
@@ -1,11 +1,11 @@
1
1
  const require_exceptions = require("./exceptions-DrHnAGQz.cjs");
2
2
  const require_guards = require("./guards-5-XmJgD2.cjs");
3
- require("./tokenizable-DDIdXbJN.cjs");
4
- require("./spooled_artifact-CFjf6ULg.cjs");
5
- require("./retrievable-ReauMJxJ.cjs");
6
- require("./thought-D5fJsxBW.cjs");
7
- const require_tool_call = require("./tool_call-CDV5pW13.cjs");
8
- require("./spooled_markdown_artifact-PWppwnPQ.cjs");
3
+ require("./tokenizable-BcodRtoW.cjs");
4
+ require("./spooled_artifact---DmicFW.cjs");
5
+ require("./thought-Dp3sMWW6.cjs");
6
+ require("./retrievable-Bq-O3k6r.cjs");
7
+ const require_tool_call = require("./tool_call-B9px4W9k.cjs");
8
+ require("./spooled_markdown_artifact-Rjzj-kyh.cjs");
9
9
  //#region src/lib/contracts/byte_store.ts
10
10
  /**
11
11
  * Validator schema used to validate a {@link ByteStore} value.
@@ -186,4 +186,4 @@ Object.defineProperty(exports, "inMemoryMediaReader", {
186
186
  }
187
187
  });
188
188
 
189
- //# sourceMappingURL=common-BiRzOsxe.cjs.map
189
+ //# sourceMappingURL=common-CqetsItm.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"common-BiRzOsxe.cjs","names":[],"sources":["../src/lib/contracts/byte_store.ts","../src/lib/helpers/media_readers.ts"],"sourcesContent":["import { validator } from '@nhtio/validation'\nimport { passesSchema } from '../utils/validation'\nimport type { SpoolReader } from './spool_reader'\nimport type { MediaReader } from './media_reader'\n\n/**\n * Unified \"give bytes, get a reader\" persistence contract.\n *\n * @remarks\n * For the purposes of storage there is no meaningful distinction between text and binary — bytes\n * are bytes. `ByteStore` is the single low-level shape every ADK storage layer implements: hand it\n * bytes under an `id`, get back a replayable reader `R`; read or delete by the same `id` later. The\n * generic `R` is the reader the store hands out — different reader contracts (line-indexed\n * {@link @nhtio/adk!SpoolReader} vs binary-streamed {@link @nhtio/adk!MediaReader}) are\n * distinguished by the `R` instantiation, not by separate store interfaces. See the {@link SpoolStore}\n * and {@link MediaStore} aliases for the two concrete semantics.\n *\n * `write` accepts a `string`, a `Uint8Array`, or a `ReadableStream<Uint8Array>`. The stream form is\n * the point of the contract: a durable store can persist an arbitrarily large payload straight to\n * disk/object storage without first materializing it in memory. **String input is encoded as\n * UTF-8.** The returned reader is only guaranteed readable once the `write` result has resolved.\n *\n * All three methods may be synchronous or asynchronous so that in-memory implementations are not\n * forced to pay promise overhead while I/O-backed implementations stay async. Note that any\n * implementation accepting a `ReadableStream` must return a `Promise` for that input — draining a\n * stream cannot be synchronous.\n */\nexport interface ByteStore<R> {\n /**\n * Persists `bytes` under `id` and returns a reader over them.\n *\n * @remarks\n * Re-writing the same `id` replaces the prior entry. `string` input is encoded as UTF-8;\n * `Uint8Array` and `ReadableStream<Uint8Array>` are stored byte-faithfully. Stream input\n * necessarily resolves asynchronously.\n *\n * @param id - Identifier used to retrieve or delete the bytes later.\n * @param bytes - The payload, as a `string`, `Uint8Array`, or `ReadableStream<Uint8Array>`.\n * @returns A reader over the stored bytes (or a `Promise` of one).\n */\n write(id: string, bytes: string | Uint8Array | ReadableStream<Uint8Array>): R | Promise<R>\n\n /**\n * Returns a reader over the bytes previously written under `id`, or `undefined` if no entry\n * exists.\n *\n * @param id - Identifier supplied to a prior {@link ByteStore.write} call.\n * @returns A reader over the stored bytes, `undefined`, or a `Promise` of either.\n */\n read(id: string): R | undefined | Promise<R | undefined>\n\n /**\n * Removes the entry under `id`.\n *\n * @param id - Identifier whose entry should be removed.\n * @returns `true` if an entry existed and was removed; `false` otherwise (or a `Promise` of one).\n */\n delete(id: string): boolean | Promise<boolean>\n}\n\n/**\n * A {@link ByteStore} that hands out line-indexed text readers ({@link @nhtio/adk!SpoolReader}).\n *\n * @remarks\n * The store backing tool-output artifacts. Stored bytes are decoded as UTF-8 text for line-oriented\n * reads; binary input is stored byte-faithfully but `SpoolReader.readAll()` interprets it as text,\n * so opaque binary belongs in a {@link MediaStore} / `Media`, not here.\n */\nexport type SpoolStore = ByteStore<SpoolReader>\n\n/**\n * A {@link ByteStore} that hands out binary-streamed readers ({@link @nhtio/adk!MediaReader}).\n *\n * @remarks\n * The store backing persisted media bytes. Stored bytes are opaque and replayable via\n * `MediaReader.stream()`; no text decoding is implied.\n */\nexport type MediaStore = ByteStore<MediaReader>\n\n/**\n * Validator schema used to validate a {@link ByteStore} value.\n *\n * @remarks\n * Because `ByteStore` is a structural interface with no associated constructor, validation is\n * duck-typed: the value must be non-null with `write`, `read`, and `delete` present as callable\n * properties. Arity is not enforced — implementations may add optional parameters beyond the\n * contract. The reader type `R` cannot be checked structurally here; conformance of the reader is\n * the caller's concern at the point of use.\n */\nexport const byteStoreSchema = validator\n .any()\n .required()\n .custom((value, helpers) => {\n if (\n value !== null &&\n value !== undefined &&\n typeof (value as any).write === 'function' &&\n typeof (value as any).read === 'function' &&\n typeof (value as any).delete === 'function'\n ) {\n return value\n }\n return helpers.error('any.invalid')\n })\n\n/**\n * Returns `true` if `value` implements the {@link ByteStore} interface.\n *\n * @remarks\n * Duck-typed: checks that `value` is non-null with `write`, `read`, and `delete` as callable\n * functions. Does not use `instanceof` — there is no `ByteStore` constructor.\n *\n * @param value - The value to test.\n * @returns `true` when `value` conforms to the {@link ByteStore} interface.\n */\nexport const implementsByteStore = <R = unknown>(value: unknown): value is ByteStore<R> => {\n return passesSchema(byteStoreSchema, value)\n}\n","import { encodeBase64 } from './base64'\nimport { isInstanceOf } from '../utils/guards'\nimport type { MediaReader } from '../contracts/media_reader'\n\n/**\n * Resolver tag for the in-memory media reader handle. The locator inlines the bytes as base64 because an\n * in-memory reader owns its buffer outright — there is no external store to point at.\n */\nexport const MEDIA_READER_TAG_IN_MEMORY = 'media:in-memory'\n\n/**\n * Resolver tag for the fetch-backed media reader handle. The locator captures the URL (and any fetch\n * init) so decode can re-issue the request — no live binding to re-inject.\n */\nexport const MEDIA_READER_TAG_FETCH = 'media:fetch'\n\n/**\n * Constructs a {@link @nhtio/adk!MediaReader} backed by an in-memory `Uint8Array`.\n *\n * @remarks\n * Each `stream()` call returns a fresh single-chunk `ReadableStream` over the same buffer. The\n * reader is re-openable by construction — call `stream()` as many times as needed.\n *\n * @param bytes - The buffer to serve.\n * @returns A {@link @nhtio/adk!MediaReader} that re-reads `bytes` on every call.\n */\nexport const inMemoryMediaReader = (bytes: Uint8Array): MediaReader => {\n return {\n stream(): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(bytes)\n controller.close()\n },\n })\n },\n byteLength(): number {\n return bytes.byteLength\n },\n describe() {\n // The buffer IS the backing store — inline it as base64, no external locator exists.\n return { tag: MEDIA_READER_TAG_IN_MEMORY, locator: { bytesBase64: encodeBase64(bytes) } }\n },\n }\n}\n\n/**\n * Constructs a {@link @nhtio/adk!MediaReader} backed by a fetch call.\n *\n * @remarks\n * Each `stream()` call re-issues the fetch. Tool authors whose underlying source is rate-limited\n * or expensive must cache locally before constructing the reader — the framework cannot make\n * that decision for them.\n *\n * `byteLength()` returns `undefined` because most remote sources do not promise it without an\n * extra HEAD request; consumers that need a byte size should resolve it out-of-band.\n *\n * @param url - The URL to fetch on each call.\n * @param init - Optional `fetch` init forwarded verbatim.\n * @returns A {@link @nhtio/adk!MediaReader} that re-issues `fetch(url, init)` on every call.\n */\nexport const fromFetch = (url: string | URL, init?: RequestInit): MediaReader => {\n return {\n async stream(): Promise<ReadableStream<Uint8Array>> {\n const response = await fetch(url, init)\n if (!response.ok) {\n throw new Error(`fromFetch: fetch failed with status ${response.status}`)\n }\n if (!response.body) {\n throw new Error('fromFetch: response has no body')\n }\n return response.body as ReadableStream<Uint8Array>\n },\n byteLength(): undefined {\n return undefined\n },\n describe() {\n // The URL is the re-openable locator; decode re-issues fetch(url, init). Only JSON-expressible\n // init is captured (method/headers) — a streaming/AbortSignal init cannot survive serialisation\n // and is dropped, which is correct: a re-issued fetch on decode starts fresh.\n const locator: { url: string; init?: { method?: string; headers?: Record<string, string> } } =\n {\n url: typeof url === 'string' ? url : url.toString(),\n }\n if (init) {\n const captured: { method?: string; headers?: Record<string, string> } = {}\n if (typeof init.method === 'string') captured.method = init.method\n if (\n init.headers &&\n !isInstanceOf(init.headers, 'Headers', Headers) &&\n !Array.isArray(init.headers)\n ) {\n captured.headers = { ...(init.headers as Record<string, string>) }\n }\n if (Object.keys(captured).length > 0) locator.init = captured\n }\n return { tag: MEDIA_READER_TAG_FETCH, locator }\n },\n }\n}\n\n/**\n * Constructs a {@link @nhtio/adk!MediaReader} backed by a browser `File` or `Blob`.\n *\n * @remarks\n * Each `stream()` call re-streams the underlying File via `File.stream()`. `byteLength()`\n * resolves from `file.size`.\n *\n * @remarks\n * **Not describable / not encodable.** A browser `Blob` is not re-openable across a serialisation\n * boundary (it has no stable locator), and draining its bytes requires `await` — which the encoder's\n * synchronous `[ENCODE_METHOD]()` cannot do. So this reader intentionally omits `describe()`, and\n * `encode()`-ing a {@link @nhtio/adk!Media} backed by it throws {@link @nhtio/adk!E_READER_NOT_DESCRIBABLE}.\n * To serialise such media, persist the bytes to a media/spool store and wrap them in a describable\n * reader first.\n *\n * @param file - The browser `File` or `Blob` to stream.\n * @returns A {@link @nhtio/adk!MediaReader} that re-streams `file` on every call.\n */\nexport const fromWebFile = (file: Blob): MediaReader => {\n return {\n stream(): ReadableStream<Uint8Array> {\n return file.stream() as ReadableStream<Uint8Array>\n },\n byteLength(): number {\n return file.size\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAyFA,IAAa,6CAAkB,EAAA,UAC5B,IAAI,EACJ,SAAS,EACT,QAAQ,OAAO,YAAY;CAC1B,IACE,UAAU,QACV,UAAU,KAAA,KACV,OAAQ,MAAc,UAAU,cAChC,OAAQ,MAAc,SAAS,cAC/B,OAAQ,MAAc,WAAW,YAEjC,OAAO;CAET,OAAO,QAAQ,MAAM,aAAa;AACpC,CAAC;;;;;;;;;;;AAYH,IAAa,uBAAoC,UAA0C;CACzF,OAAO,mBAAA,aAAa,iBAAiB,KAAK;AAC5C;;;;;;;AC7GA,IAAa,6BAA6B;;;;;AAM1C,IAAa,yBAAyB;;;;;;;;;;;AAYtC,IAAa,uBAAuB,UAAmC;CACrE,OAAO;EACL,SAAqC;GACnC,OAAO,IAAI,eAA2B,EACpC,MAAM,YAAY;IAChB,WAAW,QAAQ,KAAK;IACxB,WAAW,MAAM;GACnB,EACF,CAAC;EACH;EACA,aAAqB;GACnB,OAAO,MAAM;EACf;EACA,WAAW;GAET,OAAO;IAAE,KAAK;IAA4B,SAAS,EAAE,aAAa,kBAAA,aAAa,KAAK,EAAE;GAAE;EAC1F;CACF;AACF;;;;;;;;;;;;;;;;AAiBA,IAAa,aAAa,KAAmB,SAAoC;CAC/E,OAAO;EACL,MAAM,SAA8C;GAClD,MAAM,WAAW,MAAM,MAAM,KAAK,IAAI;GACtC,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,uCAAuC,SAAS,QAAQ;GAE1E,IAAI,CAAC,SAAS,MACZ,MAAM,IAAI,MAAM,iCAAiC;GAEnD,OAAO,SAAS;EAClB;EACA,aAAwB,CAExB;EACA,WAAW;GAIT,MAAM,UACJ,EACE,KAAK,OAAO,QAAQ,WAAW,MAAM,IAAI,SAAS,EACpD;GACF,IAAI,MAAM;IACR,MAAM,WAAkE,CAAC;IACzE,IAAI,OAAO,KAAK,WAAW,UAAU,SAAS,SAAS,KAAK;IAC5D,IACE,KAAK,WACL,CAAC,eAAA,aAAa,KAAK,SAAS,WAAW,OAAO,KAC9C,CAAC,MAAM,QAAQ,KAAK,OAAO,GAE3B,SAAS,UAAU,EAAE,GAAI,KAAK,QAAmC;IAEnE,IAAI,OAAO,KAAK,QAAQ,EAAE,SAAS,GAAG,QAAQ,OAAO;GACvD;GACA,OAAO;IAAE,KAAK;IAAwB;GAAQ;EAChD;CACF;AACF;;;;;;;;;;;;;;;;;;;AAoBA,IAAa,eAAe,SAA4B;CACtD,OAAO;EACL,SAAqC;GACnC,OAAO,KAAK,OAAO;EACrB;EACA,aAAqB;GACnB,OAAO,KAAK;EACd;CACF;AACF"}
1
+ {"version":3,"file":"common-CqetsItm.cjs","names":[],"sources":["../src/lib/contracts/byte_store.ts","../src/lib/helpers/media_readers.ts"],"sourcesContent":["import { validator } from '@nhtio/validation'\nimport { passesSchema } from '../utils/validation'\nimport type { SpoolReader } from './spool_reader'\nimport type { MediaReader } from './media_reader'\n\n/**\n * Unified \"give bytes, get a reader\" persistence contract.\n *\n * @remarks\n * For the purposes of storage there is no meaningful distinction between text and binary — bytes\n * are bytes. `ByteStore` is the single low-level shape every ADK storage layer implements: hand it\n * bytes under an `id`, get back a replayable reader `R`; read or delete by the same `id` later. The\n * generic `R` is the reader the store hands out — different reader contracts (line-indexed\n * {@link @nhtio/adk!SpoolReader} vs binary-streamed {@link @nhtio/adk!MediaReader}) are\n * distinguished by the `R` instantiation, not by separate store interfaces. See the {@link SpoolStore}\n * and {@link MediaStore} aliases for the two concrete semantics.\n *\n * `write` accepts a `string`, a `Uint8Array`, or a `ReadableStream<Uint8Array>`. The stream form is\n * the point of the contract: a durable store can persist an arbitrarily large payload straight to\n * disk/object storage without first materializing it in memory. **String input is encoded as\n * UTF-8.** The returned reader is only guaranteed readable once the `write` result has resolved.\n *\n * All three methods may be synchronous or asynchronous so that in-memory implementations are not\n * forced to pay promise overhead while I/O-backed implementations stay async. Note that any\n * implementation accepting a `ReadableStream` must return a `Promise` for that input — draining a\n * stream cannot be synchronous.\n */\nexport interface ByteStore<R> {\n /**\n * Persists `bytes` under `id` and returns a reader over them.\n *\n * @remarks\n * Re-writing the same `id` replaces the prior entry. `string` input is encoded as UTF-8;\n * `Uint8Array` and `ReadableStream<Uint8Array>` are stored byte-faithfully. Stream input\n * necessarily resolves asynchronously.\n *\n * @param id - Identifier used to retrieve or delete the bytes later.\n * @param bytes - The payload, as a `string`, `Uint8Array`, or `ReadableStream<Uint8Array>`.\n * @returns A reader over the stored bytes (or a `Promise` of one).\n */\n write(id: string, bytes: string | Uint8Array | ReadableStream<Uint8Array>): R | Promise<R>\n\n /**\n * Returns a reader over the bytes previously written under `id`, or `undefined` if no entry\n * exists.\n *\n * @param id - Identifier supplied to a prior {@link ByteStore.write} call.\n * @returns A reader over the stored bytes, `undefined`, or a `Promise` of either.\n */\n read(id: string): R | undefined | Promise<R | undefined>\n\n /**\n * Removes the entry under `id`.\n *\n * @param id - Identifier whose entry should be removed.\n * @returns `true` if an entry existed and was removed; `false` otherwise (or a `Promise` of one).\n */\n delete(id: string): boolean | Promise<boolean>\n}\n\n/**\n * A {@link ByteStore} that hands out line-indexed text readers ({@link @nhtio/adk!SpoolReader}).\n *\n * @remarks\n * The store backing tool-output artifacts. Stored bytes are decoded as UTF-8 text for line-oriented\n * reads; binary input is stored byte-faithfully but `SpoolReader.readAll()` interprets it as text,\n * so opaque binary belongs in a {@link MediaStore} / `Media`, not here.\n */\nexport type SpoolStore = ByteStore<SpoolReader>\n\n/**\n * A {@link ByteStore} that hands out binary-streamed readers ({@link @nhtio/adk!MediaReader}).\n *\n * @remarks\n * The store backing persisted media bytes. Stored bytes are opaque and replayable via\n * `MediaReader.stream()`; no text decoding is implied.\n */\nexport type MediaStore = ByteStore<MediaReader>\n\n/**\n * Validator schema used to validate a {@link ByteStore} value.\n *\n * @remarks\n * Because `ByteStore` is a structural interface with no associated constructor, validation is\n * duck-typed: the value must be non-null with `write`, `read`, and `delete` present as callable\n * properties. Arity is not enforced — implementations may add optional parameters beyond the\n * contract. The reader type `R` cannot be checked structurally here; conformance of the reader is\n * the caller's concern at the point of use.\n */\nexport const byteStoreSchema = validator\n .any()\n .required()\n .custom((value, helpers) => {\n if (\n value !== null &&\n value !== undefined &&\n typeof (value as any).write === 'function' &&\n typeof (value as any).read === 'function' &&\n typeof (value as any).delete === 'function'\n ) {\n return value\n }\n return helpers.error('any.invalid')\n })\n\n/**\n * Returns `true` if `value` implements the {@link ByteStore} interface.\n *\n * @remarks\n * Duck-typed: checks that `value` is non-null with `write`, `read`, and `delete` as callable\n * functions. Does not use `instanceof` — there is no `ByteStore` constructor.\n *\n * @param value - The value to test.\n * @returns `true` when `value` conforms to the {@link ByteStore} interface.\n */\nexport const implementsByteStore = <R = unknown>(value: unknown): value is ByteStore<R> => {\n return passesSchema(byteStoreSchema, value)\n}\n","import { encodeBase64 } from './base64'\nimport { isInstanceOf } from '../utils/guards'\nimport type { MediaReader } from '../contracts/media_reader'\n\n/**\n * Resolver tag for the in-memory media reader handle. The locator inlines the bytes as base64 because an\n * in-memory reader owns its buffer outright — there is no external store to point at.\n */\nexport const MEDIA_READER_TAG_IN_MEMORY = 'media:in-memory'\n\n/**\n * Resolver tag for the fetch-backed media reader handle. The locator captures the URL (and any fetch\n * init) so decode can re-issue the request — no live binding to re-inject.\n */\nexport const MEDIA_READER_TAG_FETCH = 'media:fetch'\n\n/**\n * Constructs a {@link @nhtio/adk!MediaReader} backed by an in-memory `Uint8Array`.\n *\n * @remarks\n * Each `stream()` call returns a fresh single-chunk `ReadableStream` over the same buffer. The\n * reader is re-openable by construction — call `stream()` as many times as needed.\n *\n * @param bytes - The buffer to serve.\n * @returns A {@link @nhtio/adk!MediaReader} that re-reads `bytes` on every call.\n */\nexport const inMemoryMediaReader = (bytes: Uint8Array): MediaReader => {\n return {\n stream(): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(bytes)\n controller.close()\n },\n })\n },\n byteLength(): number {\n return bytes.byteLength\n },\n describe() {\n // The buffer IS the backing store — inline it as base64, no external locator exists.\n return { tag: MEDIA_READER_TAG_IN_MEMORY, locator: { bytesBase64: encodeBase64(bytes) } }\n },\n }\n}\n\n/**\n * Constructs a {@link @nhtio/adk!MediaReader} backed by a fetch call.\n *\n * @remarks\n * Each `stream()` call re-issues the fetch. Tool authors whose underlying source is rate-limited\n * or expensive must cache locally before constructing the reader — the framework cannot make\n * that decision for them.\n *\n * `byteLength()` returns `undefined` because most remote sources do not promise it without an\n * extra HEAD request; consumers that need a byte size should resolve it out-of-band.\n *\n * @param url - The URL to fetch on each call.\n * @param init - Optional `fetch` init forwarded verbatim.\n * @returns A {@link @nhtio/adk!MediaReader} that re-issues `fetch(url, init)` on every call.\n */\nexport const fromFetch = (url: string | URL, init?: RequestInit): MediaReader => {\n return {\n async stream(): Promise<ReadableStream<Uint8Array>> {\n const response = await fetch(url, init)\n if (!response.ok) {\n throw new Error(`fromFetch: fetch failed with status ${response.status}`)\n }\n if (!response.body) {\n throw new Error('fromFetch: response has no body')\n }\n return response.body as ReadableStream<Uint8Array>\n },\n byteLength(): undefined {\n return undefined\n },\n describe() {\n // The URL is the re-openable locator; decode re-issues fetch(url, init). Only JSON-expressible\n // init is captured (method/headers) — a streaming/AbortSignal init cannot survive serialisation\n // and is dropped, which is correct: a re-issued fetch on decode starts fresh.\n const locator: { url: string; init?: { method?: string; headers?: Record<string, string> } } =\n {\n url: typeof url === 'string' ? url : url.toString(),\n }\n if (init) {\n const captured: { method?: string; headers?: Record<string, string> } = {}\n if (typeof init.method === 'string') captured.method = init.method\n if (\n init.headers &&\n !isInstanceOf(init.headers, 'Headers', Headers) &&\n !Array.isArray(init.headers)\n ) {\n captured.headers = { ...(init.headers as Record<string, string>) }\n }\n if (Object.keys(captured).length > 0) locator.init = captured\n }\n return { tag: MEDIA_READER_TAG_FETCH, locator }\n },\n }\n}\n\n/**\n * Constructs a {@link @nhtio/adk!MediaReader} backed by a browser `File` or `Blob`.\n *\n * @remarks\n * Each `stream()` call re-streams the underlying File via `File.stream()`. `byteLength()`\n * resolves from `file.size`.\n *\n * @remarks\n * **Not describable / not encodable.** A browser `Blob` is not re-openable across a serialisation\n * boundary (it has no stable locator), and draining its bytes requires `await` — which the encoder's\n * synchronous `[ENCODE_METHOD]()` cannot do. So this reader intentionally omits `describe()`, and\n * `encode()`-ing a {@link @nhtio/adk!Media} backed by it throws {@link @nhtio/adk!E_READER_NOT_DESCRIBABLE}.\n * To serialise such media, persist the bytes to a media/spool store and wrap them in a describable\n * reader first.\n *\n * @param file - The browser `File` or `Blob` to stream.\n * @returns A {@link @nhtio/adk!MediaReader} that re-streams `file` on every call.\n */\nexport const fromWebFile = (file: Blob): MediaReader => {\n return {\n stream(): ReadableStream<Uint8Array> {\n return file.stream() as ReadableStream<Uint8Array>\n },\n byteLength(): number {\n return file.size\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAyFA,IAAa,6CAAkB,EAAA,UAC5B,IAAI,EACJ,SAAS,EACT,QAAQ,OAAO,YAAY;CAC1B,IACE,UAAU,QACV,UAAU,KAAA,KACV,OAAQ,MAAc,UAAU,cAChC,OAAQ,MAAc,SAAS,cAC/B,OAAQ,MAAc,WAAW,YAEjC,OAAO;CAET,OAAO,QAAQ,MAAM,aAAa;AACpC,CAAC;;;;;;;;;;;AAYH,IAAa,uBAAoC,UAA0C;CACzF,OAAO,mBAAA,aAAa,iBAAiB,KAAK;AAC5C;;;;;;;AC7GA,IAAa,6BAA6B;;;;;AAM1C,IAAa,yBAAyB;;;;;;;;;;;AAYtC,IAAa,uBAAuB,UAAmC;CACrE,OAAO;EACL,SAAqC;GACnC,OAAO,IAAI,eAA2B,EACpC,MAAM,YAAY;IAChB,WAAW,QAAQ,KAAK;IACxB,WAAW,MAAM;GACnB,EACF,CAAC;EACH;EACA,aAAqB;GACnB,OAAO,MAAM;EACf;EACA,WAAW;GAET,OAAO;IAAE,KAAK;IAA4B,SAAS,EAAE,aAAa,kBAAA,aAAa,KAAK,EAAE;GAAE;EAC1F;CACF;AACF;;;;;;;;;;;;;;;;AAiBA,IAAa,aAAa,KAAmB,SAAoC;CAC/E,OAAO;EACL,MAAM,SAA8C;GAClD,MAAM,WAAW,MAAM,MAAM,KAAK,IAAI;GACtC,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,uCAAuC,SAAS,QAAQ;GAE1E,IAAI,CAAC,SAAS,MACZ,MAAM,IAAI,MAAM,iCAAiC;GAEnD,OAAO,SAAS;EAClB;EACA,aAAwB,CAExB;EACA,WAAW;GAIT,MAAM,UACJ,EACE,KAAK,OAAO,QAAQ,WAAW,MAAM,IAAI,SAAS,EACpD;GACF,IAAI,MAAM;IACR,MAAM,WAAkE,CAAC;IACzE,IAAI,OAAO,KAAK,WAAW,UAAU,SAAS,SAAS,KAAK;IAC5D,IACE,KAAK,WACL,CAAC,eAAA,aAAa,KAAK,SAAS,WAAW,OAAO,KAC9C,CAAC,MAAM,QAAQ,KAAK,OAAO,GAE3B,SAAS,UAAU,EAAE,GAAI,KAAK,QAAmC;IAEnE,IAAI,OAAO,KAAK,QAAQ,EAAE,SAAS,GAAG,QAAQ,OAAO;GACvD;GACA,OAAO;IAAE,KAAK;IAAwB;GAAQ;EAChD;CACF;AACF;;;;;;;;;;;;;;;;;;;AAoBA,IAAa,eAAe,SAA4B;CACtD,OAAO;EACL,SAAqC;GACnC,OAAO,KAAK,OAAO;EACrB;EACA,aAAqB;GACnB,OAAO,KAAK;EACd;CACF;AACF"}
@@ -1,11 +1,11 @@
1
1
  import { a as passesSchema } from "./exceptions-DRYLe-J4.mjs";
2
2
  import { n as isInstanceOf } from "./guards-BEpY7lBI.mjs";
3
- import "./tokenizable-xPXj1AQX.mjs";
4
- import "./spooled_artifact-B710Rb0d.mjs";
5
- import "./retrievable-mFgC1aty.mjs";
6
- import "./thought-BKXwUZoq.mjs";
7
- import { s as encodeBase64 } from "./tool_call-D-LqMvpU.mjs";
8
- import "./spooled_markdown_artifact-1C4mmi73.mjs";
3
+ import "./tokenizable-VB4Av8GF.mjs";
4
+ import "./spooled_artifact-Bw_7swIp.mjs";
5
+ import "./thought-CxSaF6Xf.mjs";
6
+ import "./retrievable-CXTAUuuv.mjs";
7
+ import { s as encodeBase64 } from "./tool_call-Cfaj-6zK.mjs";
8
+ import "./spooled_markdown_artifact-vd6eNtIP.mjs";
9
9
  import { validator } from "@nhtio/validation";
10
10
  //#region src/lib/contracts/byte_store.ts
11
11
  /**
@@ -146,4 +146,4 @@ var fromWebFile = (file) => {
146
146
  //#endregion
147
147
  export { inMemoryMediaReader as a, fromWebFile as i, MEDIA_READER_TAG_IN_MEMORY as n, byteStoreSchema as o, fromFetch as r, implementsByteStore as s, MEDIA_READER_TAG_FETCH as t };
148
148
 
149
- //# sourceMappingURL=common-DsLvTGmm.mjs.map
149
+ //# sourceMappingURL=common-oI1niK9Z.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"common-DsLvTGmm.mjs","names":[],"sources":["../src/lib/contracts/byte_store.ts","../src/lib/helpers/media_readers.ts"],"sourcesContent":["import { validator } from '@nhtio/validation'\nimport { passesSchema } from '../utils/validation'\nimport type { SpoolReader } from './spool_reader'\nimport type { MediaReader } from './media_reader'\n\n/**\n * Unified \"give bytes, get a reader\" persistence contract.\n *\n * @remarks\n * For the purposes of storage there is no meaningful distinction between text and binary — bytes\n * are bytes. `ByteStore` is the single low-level shape every ADK storage layer implements: hand it\n * bytes under an `id`, get back a replayable reader `R`; read or delete by the same `id` later. The\n * generic `R` is the reader the store hands out — different reader contracts (line-indexed\n * {@link @nhtio/adk!SpoolReader} vs binary-streamed {@link @nhtio/adk!MediaReader}) are\n * distinguished by the `R` instantiation, not by separate store interfaces. See the {@link SpoolStore}\n * and {@link MediaStore} aliases for the two concrete semantics.\n *\n * `write` accepts a `string`, a `Uint8Array`, or a `ReadableStream<Uint8Array>`. The stream form is\n * the point of the contract: a durable store can persist an arbitrarily large payload straight to\n * disk/object storage without first materializing it in memory. **String input is encoded as\n * UTF-8.** The returned reader is only guaranteed readable once the `write` result has resolved.\n *\n * All three methods may be synchronous or asynchronous so that in-memory implementations are not\n * forced to pay promise overhead while I/O-backed implementations stay async. Note that any\n * implementation accepting a `ReadableStream` must return a `Promise` for that input — draining a\n * stream cannot be synchronous.\n */\nexport interface ByteStore<R> {\n /**\n * Persists `bytes` under `id` and returns a reader over them.\n *\n * @remarks\n * Re-writing the same `id` replaces the prior entry. `string` input is encoded as UTF-8;\n * `Uint8Array` and `ReadableStream<Uint8Array>` are stored byte-faithfully. Stream input\n * necessarily resolves asynchronously.\n *\n * @param id - Identifier used to retrieve or delete the bytes later.\n * @param bytes - The payload, as a `string`, `Uint8Array`, or `ReadableStream<Uint8Array>`.\n * @returns A reader over the stored bytes (or a `Promise` of one).\n */\n write(id: string, bytes: string | Uint8Array | ReadableStream<Uint8Array>): R | Promise<R>\n\n /**\n * Returns a reader over the bytes previously written under `id`, or `undefined` if no entry\n * exists.\n *\n * @param id - Identifier supplied to a prior {@link ByteStore.write} call.\n * @returns A reader over the stored bytes, `undefined`, or a `Promise` of either.\n */\n read(id: string): R | undefined | Promise<R | undefined>\n\n /**\n * Removes the entry under `id`.\n *\n * @param id - Identifier whose entry should be removed.\n * @returns `true` if an entry existed and was removed; `false` otherwise (or a `Promise` of one).\n */\n delete(id: string): boolean | Promise<boolean>\n}\n\n/**\n * A {@link ByteStore} that hands out line-indexed text readers ({@link @nhtio/adk!SpoolReader}).\n *\n * @remarks\n * The store backing tool-output artifacts. Stored bytes are decoded as UTF-8 text for line-oriented\n * reads; binary input is stored byte-faithfully but `SpoolReader.readAll()` interprets it as text,\n * so opaque binary belongs in a {@link MediaStore} / `Media`, not here.\n */\nexport type SpoolStore = ByteStore<SpoolReader>\n\n/**\n * A {@link ByteStore} that hands out binary-streamed readers ({@link @nhtio/adk!MediaReader}).\n *\n * @remarks\n * The store backing persisted media bytes. Stored bytes are opaque and replayable via\n * `MediaReader.stream()`; no text decoding is implied.\n */\nexport type MediaStore = ByteStore<MediaReader>\n\n/**\n * Validator schema used to validate a {@link ByteStore} value.\n *\n * @remarks\n * Because `ByteStore` is a structural interface with no associated constructor, validation is\n * duck-typed: the value must be non-null with `write`, `read`, and `delete` present as callable\n * properties. Arity is not enforced — implementations may add optional parameters beyond the\n * contract. The reader type `R` cannot be checked structurally here; conformance of the reader is\n * the caller's concern at the point of use.\n */\nexport const byteStoreSchema = validator\n .any()\n .required()\n .custom((value, helpers) => {\n if (\n value !== null &&\n value !== undefined &&\n typeof (value as any).write === 'function' &&\n typeof (value as any).read === 'function' &&\n typeof (value as any).delete === 'function'\n ) {\n return value\n }\n return helpers.error('any.invalid')\n })\n\n/**\n * Returns `true` if `value` implements the {@link ByteStore} interface.\n *\n * @remarks\n * Duck-typed: checks that `value` is non-null with `write`, `read`, and `delete` as callable\n * functions. Does not use `instanceof` — there is no `ByteStore` constructor.\n *\n * @param value - The value to test.\n * @returns `true` when `value` conforms to the {@link ByteStore} interface.\n */\nexport const implementsByteStore = <R = unknown>(value: unknown): value is ByteStore<R> => {\n return passesSchema(byteStoreSchema, value)\n}\n","import { encodeBase64 } from './base64'\nimport { isInstanceOf } from '../utils/guards'\nimport type { MediaReader } from '../contracts/media_reader'\n\n/**\n * Resolver tag for the in-memory media reader handle. The locator inlines the bytes as base64 because an\n * in-memory reader owns its buffer outright — there is no external store to point at.\n */\nexport const MEDIA_READER_TAG_IN_MEMORY = 'media:in-memory'\n\n/**\n * Resolver tag for the fetch-backed media reader handle. The locator captures the URL (and any fetch\n * init) so decode can re-issue the request — no live binding to re-inject.\n */\nexport const MEDIA_READER_TAG_FETCH = 'media:fetch'\n\n/**\n * Constructs a {@link @nhtio/adk!MediaReader} backed by an in-memory `Uint8Array`.\n *\n * @remarks\n * Each `stream()` call returns a fresh single-chunk `ReadableStream` over the same buffer. The\n * reader is re-openable by construction — call `stream()` as many times as needed.\n *\n * @param bytes - The buffer to serve.\n * @returns A {@link @nhtio/adk!MediaReader} that re-reads `bytes` on every call.\n */\nexport const inMemoryMediaReader = (bytes: Uint8Array): MediaReader => {\n return {\n stream(): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(bytes)\n controller.close()\n },\n })\n },\n byteLength(): number {\n return bytes.byteLength\n },\n describe() {\n // The buffer IS the backing store — inline it as base64, no external locator exists.\n return { tag: MEDIA_READER_TAG_IN_MEMORY, locator: { bytesBase64: encodeBase64(bytes) } }\n },\n }\n}\n\n/**\n * Constructs a {@link @nhtio/adk!MediaReader} backed by a fetch call.\n *\n * @remarks\n * Each `stream()` call re-issues the fetch. Tool authors whose underlying source is rate-limited\n * or expensive must cache locally before constructing the reader — the framework cannot make\n * that decision for them.\n *\n * `byteLength()` returns `undefined` because most remote sources do not promise it without an\n * extra HEAD request; consumers that need a byte size should resolve it out-of-band.\n *\n * @param url - The URL to fetch on each call.\n * @param init - Optional `fetch` init forwarded verbatim.\n * @returns A {@link @nhtio/adk!MediaReader} that re-issues `fetch(url, init)` on every call.\n */\nexport const fromFetch = (url: string | URL, init?: RequestInit): MediaReader => {\n return {\n async stream(): Promise<ReadableStream<Uint8Array>> {\n const response = await fetch(url, init)\n if (!response.ok) {\n throw new Error(`fromFetch: fetch failed with status ${response.status}`)\n }\n if (!response.body) {\n throw new Error('fromFetch: response has no body')\n }\n return response.body as ReadableStream<Uint8Array>\n },\n byteLength(): undefined {\n return undefined\n },\n describe() {\n // The URL is the re-openable locator; decode re-issues fetch(url, init). Only JSON-expressible\n // init is captured (method/headers) — a streaming/AbortSignal init cannot survive serialisation\n // and is dropped, which is correct: a re-issued fetch on decode starts fresh.\n const locator: { url: string; init?: { method?: string; headers?: Record<string, string> } } =\n {\n url: typeof url === 'string' ? url : url.toString(),\n }\n if (init) {\n const captured: { method?: string; headers?: Record<string, string> } = {}\n if (typeof init.method === 'string') captured.method = init.method\n if (\n init.headers &&\n !isInstanceOf(init.headers, 'Headers', Headers) &&\n !Array.isArray(init.headers)\n ) {\n captured.headers = { ...(init.headers as Record<string, string>) }\n }\n if (Object.keys(captured).length > 0) locator.init = captured\n }\n return { tag: MEDIA_READER_TAG_FETCH, locator }\n },\n }\n}\n\n/**\n * Constructs a {@link @nhtio/adk!MediaReader} backed by a browser `File` or `Blob`.\n *\n * @remarks\n * Each `stream()` call re-streams the underlying File via `File.stream()`. `byteLength()`\n * resolves from `file.size`.\n *\n * @remarks\n * **Not describable / not encodable.** A browser `Blob` is not re-openable across a serialisation\n * boundary (it has no stable locator), and draining its bytes requires `await` — which the encoder's\n * synchronous `[ENCODE_METHOD]()` cannot do. So this reader intentionally omits `describe()`, and\n * `encode()`-ing a {@link @nhtio/adk!Media} backed by it throws {@link @nhtio/adk!E_READER_NOT_DESCRIBABLE}.\n * To serialise such media, persist the bytes to a media/spool store and wrap them in a describable\n * reader first.\n *\n * @param file - The browser `File` or `Blob` to stream.\n * @returns A {@link @nhtio/adk!MediaReader} that re-streams `file` on every call.\n */\nexport const fromWebFile = (file: Blob): MediaReader => {\n return {\n stream(): ReadableStream<Uint8Array> {\n return file.stream() as ReadableStream<Uint8Array>\n },\n byteLength(): number {\n return file.size\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAyFA,IAAa,kBAAkB,UAC5B,IAAI,EACJ,SAAS,EACT,QAAQ,OAAO,YAAY;CAC1B,IACE,UAAU,QACV,UAAU,KAAA,KACV,OAAQ,MAAc,UAAU,cAChC,OAAQ,MAAc,SAAS,cAC/B,OAAQ,MAAc,WAAW,YAEjC,OAAO;CAET,OAAO,QAAQ,MAAM,aAAa;AACpC,CAAC;;;;;;;;;;;AAYH,IAAa,uBAAoC,UAA0C;CACzF,OAAO,aAAa,iBAAiB,KAAK;AAC5C;;;;;;;AC7GA,IAAa,6BAA6B;;;;;AAM1C,IAAa,yBAAyB;;;;;;;;;;;AAYtC,IAAa,uBAAuB,UAAmC;CACrE,OAAO;EACL,SAAqC;GACnC,OAAO,IAAI,eAA2B,EACpC,MAAM,YAAY;IAChB,WAAW,QAAQ,KAAK;IACxB,WAAW,MAAM;GACnB,EACF,CAAC;EACH;EACA,aAAqB;GACnB,OAAO,MAAM;EACf;EACA,WAAW;GAET,OAAO;IAAE,KAAK;IAA4B,SAAS,EAAE,aAAa,aAAa,KAAK,EAAE;GAAE;EAC1F;CACF;AACF;;;;;;;;;;;;;;;;AAiBA,IAAa,aAAa,KAAmB,SAAoC;CAC/E,OAAO;EACL,MAAM,SAA8C;GAClD,MAAM,WAAW,MAAM,MAAM,KAAK,IAAI;GACtC,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,uCAAuC,SAAS,QAAQ;GAE1E,IAAI,CAAC,SAAS,MACZ,MAAM,IAAI,MAAM,iCAAiC;GAEnD,OAAO,SAAS;EAClB;EACA,aAAwB,CAExB;EACA,WAAW;GAIT,MAAM,UACJ,EACE,KAAK,OAAO,QAAQ,WAAW,MAAM,IAAI,SAAS,EACpD;GACF,IAAI,MAAM;IACR,MAAM,WAAkE,CAAC;IACzE,IAAI,OAAO,KAAK,WAAW,UAAU,SAAS,SAAS,KAAK;IAC5D,IACE,KAAK,WACL,CAAC,aAAa,KAAK,SAAS,WAAW,OAAO,KAC9C,CAAC,MAAM,QAAQ,KAAK,OAAO,GAE3B,SAAS,UAAU,EAAE,GAAI,KAAK,QAAmC;IAEnE,IAAI,OAAO,KAAK,QAAQ,EAAE,SAAS,GAAG,QAAQ,OAAO;GACvD;GACA,OAAO;IAAE,KAAK;IAAwB;GAAQ;EAChD;CACF;AACF;;;;;;;;;;;;;;;;;;;AAoBA,IAAa,eAAe,SAA4B;CACtD,OAAO;EACL,SAAqC;GACnC,OAAO,KAAK,OAAO;EACrB;EACA,aAAqB;GACnB,OAAO,KAAK;EACd;CACF;AACF"}
1
+ {"version":3,"file":"common-oI1niK9Z.mjs","names":[],"sources":["../src/lib/contracts/byte_store.ts","../src/lib/helpers/media_readers.ts"],"sourcesContent":["import { validator } from '@nhtio/validation'\nimport { passesSchema } from '../utils/validation'\nimport type { SpoolReader } from './spool_reader'\nimport type { MediaReader } from './media_reader'\n\n/**\n * Unified \"give bytes, get a reader\" persistence contract.\n *\n * @remarks\n * For the purposes of storage there is no meaningful distinction between text and binary — bytes\n * are bytes. `ByteStore` is the single low-level shape every ADK storage layer implements: hand it\n * bytes under an `id`, get back a replayable reader `R`; read or delete by the same `id` later. The\n * generic `R` is the reader the store hands out — different reader contracts (line-indexed\n * {@link @nhtio/adk!SpoolReader} vs binary-streamed {@link @nhtio/adk!MediaReader}) are\n * distinguished by the `R` instantiation, not by separate store interfaces. See the {@link SpoolStore}\n * and {@link MediaStore} aliases for the two concrete semantics.\n *\n * `write` accepts a `string`, a `Uint8Array`, or a `ReadableStream<Uint8Array>`. The stream form is\n * the point of the contract: a durable store can persist an arbitrarily large payload straight to\n * disk/object storage without first materializing it in memory. **String input is encoded as\n * UTF-8.** The returned reader is only guaranteed readable once the `write` result has resolved.\n *\n * All three methods may be synchronous or asynchronous so that in-memory implementations are not\n * forced to pay promise overhead while I/O-backed implementations stay async. Note that any\n * implementation accepting a `ReadableStream` must return a `Promise` for that input — draining a\n * stream cannot be synchronous.\n */\nexport interface ByteStore<R> {\n /**\n * Persists `bytes` under `id` and returns a reader over them.\n *\n * @remarks\n * Re-writing the same `id` replaces the prior entry. `string` input is encoded as UTF-8;\n * `Uint8Array` and `ReadableStream<Uint8Array>` are stored byte-faithfully. Stream input\n * necessarily resolves asynchronously.\n *\n * @param id - Identifier used to retrieve or delete the bytes later.\n * @param bytes - The payload, as a `string`, `Uint8Array`, or `ReadableStream<Uint8Array>`.\n * @returns A reader over the stored bytes (or a `Promise` of one).\n */\n write(id: string, bytes: string | Uint8Array | ReadableStream<Uint8Array>): R | Promise<R>\n\n /**\n * Returns a reader over the bytes previously written under `id`, or `undefined` if no entry\n * exists.\n *\n * @param id - Identifier supplied to a prior {@link ByteStore.write} call.\n * @returns A reader over the stored bytes, `undefined`, or a `Promise` of either.\n */\n read(id: string): R | undefined | Promise<R | undefined>\n\n /**\n * Removes the entry under `id`.\n *\n * @param id - Identifier whose entry should be removed.\n * @returns `true` if an entry existed and was removed; `false` otherwise (or a `Promise` of one).\n */\n delete(id: string): boolean | Promise<boolean>\n}\n\n/**\n * A {@link ByteStore} that hands out line-indexed text readers ({@link @nhtio/adk!SpoolReader}).\n *\n * @remarks\n * The store backing tool-output artifacts. Stored bytes are decoded as UTF-8 text for line-oriented\n * reads; binary input is stored byte-faithfully but `SpoolReader.readAll()` interprets it as text,\n * so opaque binary belongs in a {@link MediaStore} / `Media`, not here.\n */\nexport type SpoolStore = ByteStore<SpoolReader>\n\n/**\n * A {@link ByteStore} that hands out binary-streamed readers ({@link @nhtio/adk!MediaReader}).\n *\n * @remarks\n * The store backing persisted media bytes. Stored bytes are opaque and replayable via\n * `MediaReader.stream()`; no text decoding is implied.\n */\nexport type MediaStore = ByteStore<MediaReader>\n\n/**\n * Validator schema used to validate a {@link ByteStore} value.\n *\n * @remarks\n * Because `ByteStore` is a structural interface with no associated constructor, validation is\n * duck-typed: the value must be non-null with `write`, `read`, and `delete` present as callable\n * properties. Arity is not enforced — implementations may add optional parameters beyond the\n * contract. The reader type `R` cannot be checked structurally here; conformance of the reader is\n * the caller's concern at the point of use.\n */\nexport const byteStoreSchema = validator\n .any()\n .required()\n .custom((value, helpers) => {\n if (\n value !== null &&\n value !== undefined &&\n typeof (value as any).write === 'function' &&\n typeof (value as any).read === 'function' &&\n typeof (value as any).delete === 'function'\n ) {\n return value\n }\n return helpers.error('any.invalid')\n })\n\n/**\n * Returns `true` if `value` implements the {@link ByteStore} interface.\n *\n * @remarks\n * Duck-typed: checks that `value` is non-null with `write`, `read`, and `delete` as callable\n * functions. Does not use `instanceof` — there is no `ByteStore` constructor.\n *\n * @param value - The value to test.\n * @returns `true` when `value` conforms to the {@link ByteStore} interface.\n */\nexport const implementsByteStore = <R = unknown>(value: unknown): value is ByteStore<R> => {\n return passesSchema(byteStoreSchema, value)\n}\n","import { encodeBase64 } from './base64'\nimport { isInstanceOf } from '../utils/guards'\nimport type { MediaReader } from '../contracts/media_reader'\n\n/**\n * Resolver tag for the in-memory media reader handle. The locator inlines the bytes as base64 because an\n * in-memory reader owns its buffer outright — there is no external store to point at.\n */\nexport const MEDIA_READER_TAG_IN_MEMORY = 'media:in-memory'\n\n/**\n * Resolver tag for the fetch-backed media reader handle. The locator captures the URL (and any fetch\n * init) so decode can re-issue the request — no live binding to re-inject.\n */\nexport const MEDIA_READER_TAG_FETCH = 'media:fetch'\n\n/**\n * Constructs a {@link @nhtio/adk!MediaReader} backed by an in-memory `Uint8Array`.\n *\n * @remarks\n * Each `stream()` call returns a fresh single-chunk `ReadableStream` over the same buffer. The\n * reader is re-openable by construction — call `stream()` as many times as needed.\n *\n * @param bytes - The buffer to serve.\n * @returns A {@link @nhtio/adk!MediaReader} that re-reads `bytes` on every call.\n */\nexport const inMemoryMediaReader = (bytes: Uint8Array): MediaReader => {\n return {\n stream(): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(bytes)\n controller.close()\n },\n })\n },\n byteLength(): number {\n return bytes.byteLength\n },\n describe() {\n // The buffer IS the backing store — inline it as base64, no external locator exists.\n return { tag: MEDIA_READER_TAG_IN_MEMORY, locator: { bytesBase64: encodeBase64(bytes) } }\n },\n }\n}\n\n/**\n * Constructs a {@link @nhtio/adk!MediaReader} backed by a fetch call.\n *\n * @remarks\n * Each `stream()` call re-issues the fetch. Tool authors whose underlying source is rate-limited\n * or expensive must cache locally before constructing the reader — the framework cannot make\n * that decision for them.\n *\n * `byteLength()` returns `undefined` because most remote sources do not promise it without an\n * extra HEAD request; consumers that need a byte size should resolve it out-of-band.\n *\n * @param url - The URL to fetch on each call.\n * @param init - Optional `fetch` init forwarded verbatim.\n * @returns A {@link @nhtio/adk!MediaReader} that re-issues `fetch(url, init)` on every call.\n */\nexport const fromFetch = (url: string | URL, init?: RequestInit): MediaReader => {\n return {\n async stream(): Promise<ReadableStream<Uint8Array>> {\n const response = await fetch(url, init)\n if (!response.ok) {\n throw new Error(`fromFetch: fetch failed with status ${response.status}`)\n }\n if (!response.body) {\n throw new Error('fromFetch: response has no body')\n }\n return response.body as ReadableStream<Uint8Array>\n },\n byteLength(): undefined {\n return undefined\n },\n describe() {\n // The URL is the re-openable locator; decode re-issues fetch(url, init). Only JSON-expressible\n // init is captured (method/headers) — a streaming/AbortSignal init cannot survive serialisation\n // and is dropped, which is correct: a re-issued fetch on decode starts fresh.\n const locator: { url: string; init?: { method?: string; headers?: Record<string, string> } } =\n {\n url: typeof url === 'string' ? url : url.toString(),\n }\n if (init) {\n const captured: { method?: string; headers?: Record<string, string> } = {}\n if (typeof init.method === 'string') captured.method = init.method\n if (\n init.headers &&\n !isInstanceOf(init.headers, 'Headers', Headers) &&\n !Array.isArray(init.headers)\n ) {\n captured.headers = { ...(init.headers as Record<string, string>) }\n }\n if (Object.keys(captured).length > 0) locator.init = captured\n }\n return { tag: MEDIA_READER_TAG_FETCH, locator }\n },\n }\n}\n\n/**\n * Constructs a {@link @nhtio/adk!MediaReader} backed by a browser `File` or `Blob`.\n *\n * @remarks\n * Each `stream()` call re-streams the underlying File via `File.stream()`. `byteLength()`\n * resolves from `file.size`.\n *\n * @remarks\n * **Not describable / not encodable.** A browser `Blob` is not re-openable across a serialisation\n * boundary (it has no stable locator), and draining its bytes requires `await` — which the encoder's\n * synchronous `[ENCODE_METHOD]()` cannot do. So this reader intentionally omits `describe()`, and\n * `encode()`-ing a {@link @nhtio/adk!Media} backed by it throws {@link @nhtio/adk!E_READER_NOT_DESCRIBABLE}.\n * To serialise such media, persist the bytes to a media/spool store and wrap them in a describable\n * reader first.\n *\n * @param file - The browser `File` or `Blob` to stream.\n * @returns A {@link @nhtio/adk!MediaReader} that re-streams `file` on every call.\n */\nexport const fromWebFile = (file: Blob): MediaReader => {\n return {\n stream(): ReadableStream<Uint8Array> {\n return file.stream() as ReadableStream<Uint8Array>\n },\n byteLength(): number {\n return file.size\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAyFA,IAAa,kBAAkB,UAC5B,IAAI,EACJ,SAAS,EACT,QAAQ,OAAO,YAAY;CAC1B,IACE,UAAU,QACV,UAAU,KAAA,KACV,OAAQ,MAAc,UAAU,cAChC,OAAQ,MAAc,SAAS,cAC/B,OAAQ,MAAc,WAAW,YAEjC,OAAO;CAET,OAAO,QAAQ,MAAM,aAAa;AACpC,CAAC;;;;;;;;;;;AAYH,IAAa,uBAAoC,UAA0C;CACzF,OAAO,aAAa,iBAAiB,KAAK;AAC5C;;;;;;;AC7GA,IAAa,6BAA6B;;;;;AAM1C,IAAa,yBAAyB;;;;;;;;;;;AAYtC,IAAa,uBAAuB,UAAmC;CACrE,OAAO;EACL,SAAqC;GACnC,OAAO,IAAI,eAA2B,EACpC,MAAM,YAAY;IAChB,WAAW,QAAQ,KAAK;IACxB,WAAW,MAAM;GACnB,EACF,CAAC;EACH;EACA,aAAqB;GACnB,OAAO,MAAM;EACf;EACA,WAAW;GAET,OAAO;IAAE,KAAK;IAA4B,SAAS,EAAE,aAAa,aAAa,KAAK,EAAE;GAAE;EAC1F;CACF;AACF;;;;;;;;;;;;;;;;AAiBA,IAAa,aAAa,KAAmB,SAAoC;CAC/E,OAAO;EACL,MAAM,SAA8C;GAClD,MAAM,WAAW,MAAM,MAAM,KAAK,IAAI;GACtC,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,uCAAuC,SAAS,QAAQ;GAE1E,IAAI,CAAC,SAAS,MACZ,MAAM,IAAI,MAAM,iCAAiC;GAEnD,OAAO,SAAS;EAClB;EACA,aAAwB,CAExB;EACA,WAAW;GAIT,MAAM,UACJ,EACE,KAAK,OAAO,QAAQ,WAAW,MAAM,IAAI,SAAS,EACpD;GACF,IAAI,MAAM;IACR,MAAM,WAAkE,CAAC;IACzE,IAAI,OAAO,KAAK,WAAW,UAAU,SAAS,SAAS,KAAK;IAC5D,IACE,KAAK,WACL,CAAC,aAAa,KAAK,SAAS,WAAW,OAAO,KAC9C,CAAC,MAAM,QAAQ,KAAK,OAAO,GAE3B,SAAS,UAAU,EAAE,GAAI,KAAK,QAAmC;IAEnE,IAAI,OAAO,KAAK,QAAQ,EAAE,SAAS,GAAG,QAAQ,OAAO;GACvD;GACA,OAAO;IAAE,KAAK;IAAwB;GAAQ;EAChD;CACF;AACF;;;;;;;;;;;;;;;;;;;AAoBA,IAAa,eAAe,SAA4B;CACtD,OAAO;EACL,SAAqC;GACnC,OAAO,KAAK,OAAO;EACrB;EACA,aAAqB;GACnB,OAAO,KAAK;EACd;CACF;AACF"}
package/common.cjs CHANGED
@@ -1,12 +1,12 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("./chunk-Cek0wNdY.cjs");
3
- const require_tokenizable = require("./tokenizable-DDIdXbJN.cjs");
4
- const require_spooled_artifact = require("./spooled_artifact-CFjf6ULg.cjs");
5
- const require_retrievable = require("./retrievable-ReauMJxJ.cjs");
6
- const require_thought = require("./thought-D5fJsxBW.cjs");
7
- const require_tool_call = require("./tool_call-CDV5pW13.cjs");
8
- const require_common = require("./common-BiRzOsxe.cjs");
9
- const require_spooled_markdown_artifact = require("./spooled_markdown_artifact-PWppwnPQ.cjs");
3
+ const require_tokenizable = require("./tokenizable-BcodRtoW.cjs");
4
+ const require_spooled_artifact = require("./spooled_artifact---DmicFW.cjs");
5
+ const require_thought = require("./thought-Dp3sMWW6.cjs");
6
+ const require_retrievable = require("./retrievable-Bq-O3k6r.cjs");
7
+ const require_tool_call = require("./tool_call-B9px4W9k.cjs");
8
+ const require_common = require("./common-CqetsItm.cjs");
9
+ const require_spooled_markdown_artifact = require("./spooled_markdown_artifact-Rjzj-kyh.cjs");
10
10
  exports.ArtifactTool = require_spooled_artifact.ArtifactTool;
11
11
  exports.Identity = require_thought.Identity;
12
12
  exports.MEDIA_READER_TAG_FETCH = require_common.MEDIA_READER_TAG_FETCH;
package/common.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import { n as TokenEncoding, r as Tokenizable } from "./tokenizable-xPXj1AQX.mjs";
2
- import { c as resolveMediaReader, d as ArtifactTool, f as Tool, g as ToolRegistry, i as effectiveToolMethods, l as resolveSpoolReader, m as Registry, o as registerMediaReaderResolver, s as registerSpoolReaderResolver, t as SpooledArtifact, u as implementsSpoolReader } from "./spooled_artifact-B710Rb0d.mjs";
3
- import { t as Retrievable } from "./retrievable-mFgC1aty.mjs";
4
- import { i as Identity, n as Message, r as Memory, t as Thought } from "./thought-BKXwUZoq.mjs";
5
- import { a as mediaReaderSchema, i as implementsMediaReader, n as Media, o as decodeBase64, r as isMedia, s as encodeBase64, t as ToolCall } from "./tool_call-D-LqMvpU.mjs";
6
- import { a as inMemoryMediaReader, i as fromWebFile, n as MEDIA_READER_TAG_IN_MEMORY, o as byteStoreSchema, r as fromFetch, s as implementsByteStore, t as MEDIA_READER_TAG_FETCH } from "./common-DsLvTGmm.mjs";
7
- import { n as SpooledJsonArtifact, t as SpooledMarkdownArtifact } from "./spooled_markdown_artifact-1C4mmi73.mjs";
1
+ import { n as TokenEncoding, r as Tokenizable } from "./tokenizable-VB4Av8GF.mjs";
2
+ import { c as resolveMediaReader, d as ToolRegistry, f as ArtifactTool, g as Registry, i as effectiveToolMethods, l as resolveSpoolReader, o as registerMediaReaderResolver, p as Tool, s as registerSpoolReaderResolver, t as SpooledArtifact, u as implementsSpoolReader } from "./spooled_artifact-Bw_7swIp.mjs";
3
+ import { i as Identity, n as Message, r as Memory, t as Thought } from "./thought-CxSaF6Xf.mjs";
4
+ import { t as Retrievable } from "./retrievable-CXTAUuuv.mjs";
5
+ import { a as mediaReaderSchema, i as implementsMediaReader, n as Media, o as decodeBase64, r as isMedia, s as encodeBase64, t as ToolCall } from "./tool_call-Cfaj-6zK.mjs";
6
+ import { a as inMemoryMediaReader, i as fromWebFile, n as MEDIA_READER_TAG_IN_MEMORY, o as byteStoreSchema, r as fromFetch, s as implementsByteStore, t as MEDIA_READER_TAG_FETCH } from "./common-oI1niK9Z.mjs";
7
+ import { n as SpooledJsonArtifact, t as SpooledMarkdownArtifact } from "./spooled_markdown_artifact-vd6eNtIP.mjs";
8
8
  export { ArtifactTool, Identity, MEDIA_READER_TAG_FETCH, MEDIA_READER_TAG_IN_MEMORY, Media, Memory, Message, Registry, Retrievable, SpooledArtifact, SpooledJsonArtifact, SpooledMarkdownArtifact, Thought, TokenEncoding, Tokenizable, Tool, ToolCall, ToolRegistry, byteStoreSchema, decodeBase64, effectiveToolMethods, encodeBase64, fromFetch, fromWebFile, implementsByteStore, implementsMediaReader, implementsSpoolReader, inMemoryMediaReader, isMedia, mediaReaderSchema, registerMediaReaderResolver, registerSpoolReaderResolver, resolveMediaReader, resolveSpoolReader };
@@ -1,8 +1,8 @@
1
1
  import { o as validateOrThrow } from "./exceptions-DRYLe-J4.mjs";
2
2
  import { n as isInstanceOf, t as isError } from "./guards-BEpY7lBI.mjs";
3
- import { D as E_LLM_EXECUTION_ALREADY_SIGNALLED, O as E_LLM_EXECUTION_EXECUTOR_ERROR, P as E_PIPELINE_SHORT_CIRCUITED, S as E_INVALID_LLM_EXECUTION_CONTEXT, a as runWithEstimationWarnings, c as E_ARTIFACT_ID_COLLISION, k as E_LLM_EXECUTION_GATE_NOT_SUPPORTED, l as E_DISPATCH_PIPELINE_ERROR, r as Tokenizable, w as E_INVALID_TURN_CONTEXT, x as E_INVALID_LLM_DISPATCH_INPUT } from "./tokenizable-xPXj1AQX.mjs";
4
- import { g as ToolRegistry, h as canonicalStringify, m as Registry, t as SpooledArtifact } from "./spooled_artifact-B710Rb0d.mjs";
5
- import { t as Retrievable } from "./retrievable-mFgC1aty.mjs";
3
+ import { D as E_LLM_EXECUTION_GATE_NOT_SUPPORTED, E as E_LLM_EXECUTION_EXECUTOR_ERROR, M as E_PIPELINE_SHORT_CIRCUITED, S as E_INVALID_TURN_CONTEXT, T as E_LLM_EXECUTION_ALREADY_SIGNALLED, a as runWithEstimationWarnings, b as E_INVALID_LLM_EXECUTION_CONTEXT, o as E_ARTIFACT_ID_COLLISION, r as Tokenizable, s as E_DISPATCH_PIPELINE_ERROR, y as E_INVALID_LLM_DISPATCH_INPUT } from "./tokenizable-VB4Av8GF.mjs";
4
+ import { d as ToolRegistry, g as Registry, h as canonicalStringify, t as SpooledArtifact } from "./spooled_artifact-Bw_7swIp.mjs";
5
+ import { t as Retrievable } from "./retrievable-CXTAUuuv.mjs";
6
6
  import { validator } from "@nhtio/validation";
7
7
  import { DateTime } from "luxon";
8
8
  import { sha256 } from "js-sha256";
@@ -2052,4 +2052,4 @@ var DispatchRunner = class DispatchRunner {
2052
2052
  //#endregion
2053
2053
  export { autoSpoolRetrievable as i, DispatchContext as n, TurnContext as r, DispatchRunner as t };
2054
2054
 
2055
- //# sourceMappingURL=dispatch_runner-DDH_dGPU.mjs.map
2055
+ //# sourceMappingURL=dispatch_runner-BZDXUe0G.mjs.map