@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.
- package/CHANGELOG.md +39 -0
- package/artifact_methods-Cg0go7Q4.mjs +1 -0
- package/artifact_methods-CxeKTocm.cjs +1 -0
- package/batteries/artifacts/ecmascript.cjs +1 -1
- package/batteries/artifacts/ecmascript.mjs +1 -1
- package/batteries/artifacts/toon.cjs +1 -1
- package/batteries/artifacts/toon.mjs +1 -1
- package/batteries/artifacts/xml.cjs +1 -1
- package/batteries/artifacts/xml.mjs +1 -1
- package/batteries/artifacts/yaml.cjs +1 -1
- package/batteries/artifacts/yaml.mjs +1 -1
- package/batteries/artifacts.cjs +4 -4
- package/batteries/artifacts.mjs +4 -4
- package/batteries/dev-tools/forge.cjs +3 -3
- package/batteries/dev-tools/forge.mjs +3 -3
- package/batteries/dev-tools.cjs +3 -3
- package/batteries/dev-tools.mjs +3 -3
- package/batteries/encoding.cjs +7 -7
- package/batteries/encoding.mjs +7 -7
- package/batteries/generation/gemini/adapter.cjs +1 -1
- package/batteries/generation/gemini/adapter.mjs +1 -1
- package/batteries/generation/local_diffusion/adapter.cjs +1 -1
- package/batteries/generation/local_diffusion/adapter.mjs +1 -1
- package/batteries/generation/openai/adapter.cjs +1 -1
- package/batteries/generation/openai/adapter.mjs +1 -1
- package/batteries/isolation/child_process.cjs +1 -1
- package/batteries/isolation/child_process.mjs +1 -1
- package/batteries/isolation.cjs +1 -1
- package/batteries/isolation.mjs +1 -1
- package/batteries/llm/anthropic_messages/adapter.cjs +6 -6
- package/batteries/llm/anthropic_messages/adapter.mjs +6 -6
- package/batteries/llm/anthropic_messages/count_tokens.cjs +1 -1
- package/batteries/llm/anthropic_messages/count_tokens.mjs +1 -1
- package/batteries/llm/anthropic_messages/helpers.cjs +3 -3
- package/batteries/llm/anthropic_messages/helpers.mjs +3 -3
- package/batteries/llm/anthropic_messages/validation.cjs +2 -2
- package/batteries/llm/anthropic_messages/validation.mjs +2 -2
- package/batteries/llm/anthropic_messages.cjs +2 -2
- package/batteries/llm/anthropic_messages.mjs +2 -2
- package/batteries/llm/bedrock_converse/adapter.cjs +6 -6
- package/batteries/llm/bedrock_converse/adapter.mjs +6 -6
- package/batteries/llm/bedrock_converse/helpers.cjs +1 -1
- package/batteries/llm/bedrock_converse/helpers.mjs +1 -1
- package/batteries/llm/bedrock_converse/validation.cjs +2 -2
- package/batteries/llm/bedrock_converse/validation.mjs +2 -2
- package/batteries/llm/bedrock_converse.cjs +2 -2
- package/batteries/llm/bedrock_converse.mjs +2 -2
- package/batteries/llm/claude_code_cli/adapter.cjs +7 -7
- package/batteries/llm/claude_code_cli/adapter.mjs +7 -7
- package/batteries/llm/claude_code_cli/helpers.cjs +3 -3
- package/batteries/llm/claude_code_cli/helpers.mjs +3 -3
- package/batteries/llm/claude_code_cli/validation.cjs +2 -2
- package/batteries/llm/claude_code_cli/validation.mjs +2 -2
- package/batteries/llm/claude_code_cli.cjs +2 -2
- package/batteries/llm/claude_code_cli.mjs +2 -2
- package/batteries/llm/gemini_generate_content/adapter.cjs +6 -6
- package/batteries/llm/gemini_generate_content/adapter.mjs +6 -6
- package/batteries/llm/gemini_generate_content/helpers.cjs +1 -1
- package/batteries/llm/gemini_generate_content/helpers.mjs +1 -1
- package/batteries/llm/gemini_generate_content/validation.cjs +2 -2
- package/batteries/llm/gemini_generate_content/validation.mjs +2 -2
- package/batteries/llm/gemini_generate_content.cjs +1 -1
- package/batteries/llm/gemini_generate_content.mjs +1 -1
- package/batteries/llm/litert_lm/adapter.cjs +6 -6
- package/batteries/llm/litert_lm/adapter.mjs +6 -6
- package/batteries/llm/litert_lm/helpers.cjs +3 -3
- package/batteries/llm/litert_lm/helpers.mjs +3 -3
- package/batteries/llm/litert_lm/validation.cjs +2 -2
- package/batteries/llm/litert_lm/validation.mjs +2 -2
- package/batteries/llm/litert_lm.cjs +1 -1
- package/batteries/llm/litert_lm.mjs +1 -1
- package/batteries/llm/ollama/adapter.cjs +6 -6
- package/batteries/llm/ollama/adapter.mjs +6 -6
- package/batteries/llm/ollama/helpers.cjs +4 -4
- package/batteries/llm/ollama/helpers.mjs +4 -4
- package/batteries/llm/ollama/validation.cjs +2 -2
- package/batteries/llm/ollama/validation.mjs +2 -2
- package/batteries/llm/ollama.cjs +2 -2
- package/batteries/llm/ollama.mjs +2 -2
- package/batteries/llm/openai_chat_completions/adapter.cjs +6 -6
- package/batteries/llm/openai_chat_completions/adapter.mjs +6 -6
- package/batteries/llm/openai_chat_completions/helpers.cjs +4 -4
- package/batteries/llm/openai_chat_completions/helpers.mjs +4 -4
- package/batteries/llm/openai_chat_completions/validation.cjs +2 -2
- package/batteries/llm/openai_chat_completions/validation.mjs +2 -2
- package/batteries/llm/openai_chat_completions.cjs +2 -2
- package/batteries/llm/openai_chat_completions.mjs +2 -2
- package/batteries/llm/openai_responses/adapter.cjs +6 -6
- package/batteries/llm/openai_responses/adapter.mjs +6 -6
- package/batteries/llm/openai_responses/helpers.cjs +3 -3
- package/batteries/llm/openai_responses/helpers.mjs +3 -3
- package/batteries/llm/openai_responses/validation.cjs +2 -2
- package/batteries/llm/openai_responses/validation.mjs +2 -2
- package/batteries/llm/openai_responses.cjs +2 -2
- package/batteries/llm/openai_responses.mjs +2 -2
- package/batteries/llm/transformers_js/adapter.cjs +6 -6
- package/batteries/llm/transformers_js/adapter.mjs +6 -6
- package/batteries/llm/transformers_js/helpers.cjs +3 -3
- package/batteries/llm/transformers_js/helpers.mjs +3 -3
- package/batteries/llm/transformers_js/validation.cjs +2 -2
- package/batteries/llm/transformers_js/validation.mjs +2 -2
- package/batteries/llm/transformers_js.cjs +1 -1
- package/batteries/llm/transformers_js.mjs +1 -1
- package/batteries/llm/webllm_chat_completions/adapter.cjs +6 -6
- package/batteries/llm/webllm_chat_completions/adapter.mjs +6 -6
- package/batteries/llm/webllm_chat_completions/helpers.cjs +1 -1
- package/batteries/llm/webllm_chat_completions/helpers.mjs +1 -1
- package/batteries/llm/webllm_chat_completions/validation.cjs +2 -2
- package/batteries/llm/webllm_chat_completions/validation.mjs +2 -2
- package/batteries/llm/webllm_chat_completions.cjs +2 -2
- package/batteries/llm/webllm_chat_completions.mjs +2 -2
- package/batteries/llm.cjs +2 -2
- package/batteries/llm.mjs +2 -2
- package/batteries/media/forge.cjs +4 -4
- package/batteries/media/forge.mjs +4 -4
- package/batteries/media/lint.cjs +1 -1
- package/batteries/media/lint.mjs +1 -1
- package/batteries/orchestration/cells/jexl.cjs +1 -1
- package/batteries/orchestration/cells/jexl.mjs +1 -1
- package/batteries/orchestration/cells/lua.cjs +1 -1
- package/batteries/orchestration/cells/lua.mjs +1 -1
- package/batteries/orchestration/cells/structured.cjs +1 -1
- package/batteries/orchestration/cells/structured.mjs +1 -1
- package/batteries/orchestration/dispatch_reasoner.cjs +4 -4
- package/batteries/orchestration/dispatch_reasoner.mjs +4 -4
- package/batteries/orchestration/executor.cjs +2 -2
- package/batteries/orchestration/executor.mjs +2 -2
- package/batteries/orchestration/forge.cjs +3 -3
- package/batteries/orchestration/forge.mjs +3 -3
- package/batteries/orchestration/validation.cjs +2 -2
- package/batteries/orchestration/validation.mjs +2 -2
- package/batteries/orchestration.cjs +3 -3
- package/batteries/orchestration.mjs +3 -3
- package/batteries/sandbox/js.cjs +1 -1
- package/batteries/sandbox/js.mjs +1 -1
- package/batteries/sandbox/tools.cjs +1 -1
- package/batteries/sandbox/tools.mjs +1 -1
- package/batteries/sandbox.cjs +4 -4
- package/batteries/sandbox.mjs +4 -4
- package/batteries/skills/in_memory.cjs +1 -1
- package/batteries/skills/in_memory.mjs +1 -1
- package/batteries/skills.cjs +9 -9
- package/batteries/skills.mjs +9 -9
- package/batteries/specialists/stt/transformers_js.cjs +1 -1
- package/batteries/specialists/stt/transformers_js.mjs +1 -1
- package/batteries/specialists/stt.cjs +1 -1
- package/batteries/specialists/stt.mjs +1 -1
- package/batteries/specialists.cjs +1 -1
- package/batteries/specialists.mjs +1 -1
- package/batteries/tools/_shared.cjs +2 -2
- package/batteries/tools/_shared.mjs +2 -2
- package/batteries/tools/color.cjs +2 -2
- package/batteries/tools/color.mjs +2 -2
- package/batteries/tools/comparison.cjs +2 -2
- package/batteries/tools/comparison.mjs +2 -2
- package/batteries/tools/data_structure.cjs +2 -2
- package/batteries/tools/data_structure.mjs +2 -2
- package/batteries/tools/datetime_extended.cjs +2 -2
- package/batteries/tools/datetime_extended.mjs +2 -2
- package/batteries/tools/datetime_math.cjs +2 -2
- package/batteries/tools/datetime_math.mjs +2 -2
- package/batteries/tools/encoding.cjs +2 -2
- package/batteries/tools/encoding.mjs +2 -2
- package/batteries/tools/formatting.cjs +2 -2
- package/batteries/tools/formatting.mjs +2 -2
- package/batteries/tools/geo_basics.cjs +2 -2
- package/batteries/tools/geo_basics.mjs +2 -2
- package/batteries/tools/math.cjs +2 -2
- package/batteries/tools/math.mjs +2 -2
- package/batteries/tools/memory.cjs +4 -4
- package/batteries/tools/memory.mjs +4 -4
- package/batteries/tools/parsing.cjs +3 -3
- package/batteries/tools/parsing.mjs +3 -3
- package/batteries/tools/retrievables.cjs +4 -4
- package/batteries/tools/retrievables.mjs +4 -4
- package/batteries/tools/scrapper.cjs +1 -1
- package/batteries/tools/scrapper.mjs +1 -1
- package/batteries/tools/searxng.cjs +1 -1
- package/batteries/tools/searxng.mjs +1 -1
- package/batteries/tools/standing_instructions.cjs +3 -3
- package/batteries/tools/standing_instructions.mjs +3 -3
- package/batteries/tools/statistics.cjs +3 -3
- package/batteries/tools/statistics.mjs +3 -3
- package/batteries/tools/string_processing.cjs +2 -2
- package/batteries/tools/string_processing.mjs +2 -2
- package/batteries/tools/structured_data.cjs +2 -2
- package/batteries/tools/structured_data.mjs +2 -2
- package/batteries/tools/text_analysis.cjs +3 -3
- package/batteries/tools/text_analysis.mjs +3 -3
- package/batteries/tools/text_comparison.cjs +2 -2
- package/batteries/tools/text_comparison.mjs +2 -2
- package/batteries/tools/time.cjs +2 -2
- package/batteries/tools/time.mjs +2 -2
- package/batteries/tools/unit_conversion.cjs +2 -2
- package/batteries/tools/unit_conversion.mjs +2 -2
- package/batteries/tools.cjs +2 -2
- package/batteries/tools.mjs +2 -2
- package/batteries/validation.cjs +5 -5
- package/batteries/validation.mjs +5 -5
- package/batteries/vector/conformance.cjs +59 -0
- package/batteries/vector/conformance.cjs.map +1 -1
- package/batteries/vector/conformance.mjs +59 -0
- package/batteries/vector/conformance.mjs.map +1 -1
- package/batteries/vector/lancedb.cjs +1 -1
- package/batteries/vector/lancedb.cjs.map +1 -1
- package/batteries/vector/lancedb.mjs +1 -1
- package/batteries/vector/lancedb.mjs.map +1 -1
- package/batteries/vector/retrievable.cjs +1 -1
- package/batteries/vector/retrievable.mjs +1 -1
- package/batteries/vector/sqlite_vec/index.d.ts +1 -1
- package/batteries/vector/sqlite_vec.cjs +19 -30
- package/batteries/vector/sqlite_vec.cjs.map +1 -1
- package/batteries/vector/sqlite_vec.mjs +20 -31
- package/batteries/vector/sqlite_vec.mjs.map +1 -1
- package/batteries.cjs +6 -6
- package/batteries.mjs +6 -6
- package/{chat_common-4huaTp6d.cjs → chat_common-CNayzS1V.cjs} +2 -2
- package/{chat_common-4huaTp6d.cjs.map → chat_common-CNayzS1V.cjs.map} +1 -1
- package/{chat_common-D_XGNjcK.mjs → chat_common-DKw8FDol.mjs} +2 -2
- package/{chat_common-D_XGNjcK.mjs.map → chat_common-DKw8FDol.mjs.map} +1 -1
- package/{common-BiRzOsxe.cjs → common-CqetsItm.cjs} +7 -7
- package/{common-BiRzOsxe.cjs.map → common-CqetsItm.cjs.map} +1 -1
- package/{common-DsLvTGmm.mjs → common-oI1niK9Z.mjs} +7 -7
- package/{common-DsLvTGmm.mjs.map → common-oI1niK9Z.mjs.map} +1 -1
- package/common.cjs +7 -7
- package/common.mjs +7 -7
- package/{dispatch_runner-DDH_dGPU.mjs → dispatch_runner-BZDXUe0G.mjs} +4 -4
- package/{dispatch_runner-DDH_dGPU.mjs.map → dispatch_runner-BZDXUe0G.mjs.map} +1 -1
- package/{dispatch_runner-C5S3KCqH.cjs → dispatch_runner-DDUxXJC3.cjs} +4 -4
- package/{dispatch_runner-C5S3KCqH.cjs.map → dispatch_runner-DDUxXJC3.cjs.map} +1 -1
- package/dispatch_runner.cjs +1 -1
- package/dispatch_runner.mjs +1 -1
- package/{ecmascript-CWLZ7bCX.mjs → ecmascript-B9Z2C24U.mjs} +5 -5
- package/{ecmascript-CWLZ7bCX.mjs.map → ecmascript-B9Z2C24U.mjs.map} +1 -1
- package/{ecmascript-BGr_0Dwn.cjs → ecmascript-BYfmjg7y.cjs} +5 -5
- package/{ecmascript-BGr_0Dwn.cjs.map → ecmascript-BYfmjg7y.cjs.map} +1 -1
- package/eslint/rules.cjs +1 -1
- package/eslint/rules.mjs +1 -1
- package/eslint.cjs +3 -3
- package/eslint.mjs +3 -3
- package/exceptions.cjs +1 -1
- package/exceptions.mjs +1 -1
- package/forge.cjs +2 -2
- package/forge.mjs +2 -2
- package/guards.cjs +7 -7
- package/guards.mjs +7 -7
- package/{helpers-BPi_iwxv.cjs → helpers-DPlh_7Bn.cjs} +3 -3
- package/{helpers-BPi_iwxv.cjs.map → helpers-DPlh_7Bn.cjs.map} +1 -1
- package/{helpers-D47G8WQb.mjs → helpers-mbn_EsDV.mjs} +3 -3
- package/{helpers-D47G8WQb.mjs.map → helpers-mbn_EsDV.mjs.map} +1 -1
- package/index.cjs +11 -11
- package/index.mjs +11 -11
- package/{isolation-B2FgKbap.cjs → isolation-B01xCIoV.cjs} +2 -2
- package/{isolation-B2FgKbap.cjs.map → isolation-B01xCIoV.cjs.map} +1 -1
- package/{isolation-BRGpiU-K.mjs → isolation-CO0NiK8R.mjs} +2 -2
- package/{isolation-BRGpiU-K.mjs.map → isolation-CO0NiK8R.mjs.map} +1 -1
- package/{manifest-B5bWMHgj.mjs → manifest-D8UTRohY.mjs} +2 -2
- package/{manifest-B5bWMHgj.mjs.map → manifest-D8UTRohY.mjs.map} +1 -1
- package/{manifest-Chjh-3s1.cjs → manifest-IP1IOJcg.cjs} +2 -2
- package/{manifest-Chjh-3s1.cjs.map → manifest-IP1IOJcg.cjs.map} +1 -1
- package/mcp/adk-docs-corpus.json +2 -2
- package/package.json +538 -538
- package/{predicates-C9jl2QPZ.cjs → predicates-Bzaa7gNI.cjs} +2 -2
- package/{predicates-C9jl2QPZ.cjs.map → predicates-Bzaa7gNI.cjs.map} +1 -1
- package/{predicates-2dZQ82LY.mjs → predicates-CM27Z3TF.mjs} +2 -2
- package/{predicates-2dZQ82LY.mjs.map → predicates-CM27Z3TF.mjs.map} +1 -1
- package/{retrievable-ReauMJxJ.cjs → retrievable-Bq-O3k6r.cjs} +3 -3
- package/{retrievable-ReauMJxJ.cjs.map → retrievable-Bq-O3k6r.cjs.map} +1 -1
- package/{retrievable-mFgC1aty.mjs → retrievable-CXTAUuuv.mjs} +3 -3
- package/{retrievable-mFgC1aty.mjs.map → retrievable-CXTAUuuv.mjs.map} +1 -1
- package/{scrapper-BsEY0Wo6.cjs → scrapper-B8xG9lTD.cjs} +5 -5
- package/{scrapper-BsEY0Wo6.cjs.map → scrapper-B8xG9lTD.cjs.map} +1 -1
- package/{scrapper-bShwZxKP.mjs → scrapper-DiQ5FfDL.mjs} +5 -5
- package/{scrapper-bShwZxKP.mjs.map → scrapper-DiQ5FfDL.mjs.map} +1 -1
- package/{searxng-CAY-bOMl.mjs → searxng-BFTJ6rTE.mjs} +5 -5
- package/{searxng-CAY-bOMl.mjs.map → searxng-BFTJ6rTE.mjs.map} +1 -1
- package/{searxng-CLF0vBMT.cjs → searxng-EJhWRnIE.cjs} +5 -5
- package/{searxng-CLF0vBMT.cjs.map → searxng-EJhWRnIE.cjs.map} +1 -1
- package/server.json +2 -2
- package/skills/adk-assembly/SKILL.md +2 -2
- package/{spooled_artifact-CFjf6ULg.cjs → spooled_artifact---DmicFW.cjs} +384 -384
- package/spooled_artifact---DmicFW.cjs.map +1 -0
- package/{spooled_artifact-B710Rb0d.mjs → spooled_artifact-Bw_7swIp.mjs} +385 -385
- package/spooled_artifact-Bw_7swIp.mjs.map +1 -0
- package/spooled_artifact.cjs +2 -2
- package/spooled_artifact.mjs +2 -2
- package/{spooled_markdown_artifact-PWppwnPQ.cjs → spooled_markdown_artifact-Rjzj-kyh.cjs} +3 -3
- package/{spooled_markdown_artifact-PWppwnPQ.cjs.map → spooled_markdown_artifact-Rjzj-kyh.cjs.map} +1 -1
- package/{spooled_markdown_artifact-1C4mmi73.mjs → spooled_markdown_artifact-vd6eNtIP.mjs} +3 -3
- package/{spooled_markdown_artifact-1C4mmi73.mjs.map → spooled_markdown_artifact-vd6eNtIP.mjs.map} +1 -1
- package/{thought-BKXwUZoq.mjs → thought-CxSaF6Xf.mjs} +3 -3
- package/{thought-BKXwUZoq.mjs.map → thought-CxSaF6Xf.mjs.map} +1 -1
- package/{thought-D5fJsxBW.cjs → thought-Dp3sMWW6.cjs} +3 -3
- package/{thought-D5fJsxBW.cjs.map → thought-Dp3sMWW6.cjs.map} +1 -1
- package/{tokenizable-DDIdXbJN.cjs → tokenizable-BcodRtoW.cjs} +29 -29
- package/{tokenizable-DDIdXbJN.cjs.map → tokenizable-BcodRtoW.cjs.map} +1 -1
- package/{tokenizable-xPXj1AQX.mjs → tokenizable-VB4Av8GF.mjs} +30 -30
- package/{tokenizable-xPXj1AQX.mjs.map → tokenizable-VB4Av8GF.mjs.map} +1 -1
- package/{tool_call-CDV5pW13.cjs → tool_call-B9px4W9k.cjs} +3 -3
- package/{tool_call-CDV5pW13.cjs.map → tool_call-B9px4W9k.cjs.map} +1 -1
- package/{tool_call-D-LqMvpU.mjs → tool_call-Cfaj-6zK.mjs} +3 -3
- package/{tool_call-D-LqMvpU.mjs.map → tool_call-Cfaj-6zK.mjs.map} +1 -1
- package/{tools-CvCMdAd7.mjs → tools-D0MBDh2R.mjs} +6 -6
- package/{tools-CvCMdAd7.mjs.map → tools-D0MBDh2R.mjs.map} +1 -1
- package/{tools-CACuuMV4.cjs → tools-aNbi6JyA.cjs} +6 -6
- package/{tools-CACuuMV4.cjs.map → tools-aNbi6JyA.cjs.map} +1 -1
- package/{toon-CCjuuzd_.mjs → toon-BSTQnHed.mjs} +6 -6
- package/{toon-CCjuuzd_.mjs.map → toon-BSTQnHed.mjs.map} +1 -1
- package/{toon-B7Q9RWJF.cjs → toon-DmLwZ6H1.cjs} +6 -6
- package/{toon-B7Q9RWJF.cjs.map → toon-DmLwZ6H1.cjs.map} +1 -1
- package/{transformers_js-DM01eAzh.cjs → transformers_js-7OzeS_Tp.cjs} +2 -2
- package/{transformers_js-DM01eAzh.cjs.map → transformers_js-7OzeS_Tp.cjs.map} +1 -1
- package/{transformers_js-BR2Ov0Su.mjs → transformers_js-p3lAkHFH.mjs} +2 -2
- package/{transformers_js-BR2Ov0Su.mjs.map → transformers_js-p3lAkHFH.mjs.map} +1 -1
- package/{turn_runner-BgPw9uqb.mjs → turn_runner-BHHD6h77.mjs} +4 -4
- package/{turn_runner-BgPw9uqb.mjs.map → turn_runner-BHHD6h77.mjs.map} +1 -1
- package/{turn_runner-CP2zxSlu.cjs → turn_runner-Dj7JsUTQ.cjs} +4 -4
- package/{turn_runner-CP2zxSlu.cjs.map → turn_runner-Dj7JsUTQ.cjs.map} +1 -1
- package/turn_runner.cjs +1 -1
- package/turn_runner.mjs +1 -1
- package/{xml-BqTTIFhv.mjs → xml-CYseDztH.mjs} +6 -6
- package/{xml-BqTTIFhv.mjs.map → xml-CYseDztH.mjs.map} +1 -1
- package/{xml-viE54OTe.cjs → xml-zJul8jMQ.cjs} +6 -6
- package/{xml-viE54OTe.cjs.map → xml-zJul8jMQ.cjs.map} +1 -1
- package/{yaml-B1So-pUR.mjs → yaml-BPBoiOjx.mjs} +6 -6
- package/{yaml-B1So-pUR.mjs.map → yaml-BPBoiOjx.mjs.map} +1 -1
- package/{yaml-cGhhPyZq.cjs → yaml-D0PzoRAr.cjs} +6 -6
- package/{yaml-cGhhPyZq.cjs.map → yaml-D0PzoRAr.cjs.map} +1 -1
- package/artifact_methods-9BemAvd4.mjs +0 -1
- package/artifact_methods-FKgk4q_1.cjs +0 -1
- package/spooled_artifact-B710Rb0d.mjs.map +0 -1
- package/spooled_artifact-CFjf6ULg.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xml-BqTTIFhv.mjs","names":["#attributeNamePrefix","#ignoreAttributes","#resolveParsed","#parsed"],"sources":["../src/batteries/artifacts/xml/exceptions.ts","../src/batteries/artifacts/xml/index.ts"],"sourcesContent":["/**\n * Battery-scoped exceptions for the XML artifact battery.\n *\n * @remarks\n * Internal sibling of the `@nhtio/adk/batteries/artifacts/xml` entry — re-exported from the battery's\n * own barrel per the battery-scoped-exceptions rule. These are the typed errors the\n * implementor-facing API throws; the agent-facing forge catches them and renders readable\n * failure strings the model can act on.\n */\n\nimport { createException } from '@nhtio/adk/factories'\n\n/**\n * Thrown when the fast-xml-parser optional peer is not installed or fails to load.\n *\n * @remarks\n * The message template includes the package name, a description of its purpose, the underlying\n * error, and the exact install command, so the consumer sees a complete, actionable message\n * regardless of call site.\n */\nexport const E_XML_PARSER_PEER_MISSING = createException<[string]>(\n 'E_XML_PARSER_PEER_MISSING',\n 'the XML battery could not load its peer dependency \"fast-xml-parser\" (needed for XML format artifact queries): %s — install it (pnpm add fast-xml-parser)',\n 'E_XML_PARSER_PEER_MISSING',\n 500,\n true\n)\n\n/**\n * Thrown when XML parsing fails due to malformed markup.\n *\n * @remarks\n * Printf args: `[errorDetail]` — includes the parser's own reason for the failure.\n */\nexport const E_XML_PARSE_FAILED = createException<[string]>(\n 'E_XML_PARSE_FAILED',\n 'XML parse failed: %s',\n 'E_XML_PARSE_FAILED',\n 422,\n false\n)\n","/**\n * A structured artifact battery for XML documents.\n *\n * @module @nhtio/adk/batteries/artifacts/xml\n *\n * @remarks\n * Provides {@link SpooledXmlArtifact} — a `SpooledArtifact` specialisation that parses XML\n * into a JSON projection and offers path-based query tools over that projection. The XML-to-JSON\n * mapping defaults to `ignoreAttributes: false` and `attributeNamePrefix: '_'`, both settable\n * per instance through the constructor; `preserveOrder: false` is fixed. Under the default\n * mapping:\n *\n * - Element attributes become keys prefixed with `_` (e.g., `root-element` with `href=\"x\"`\n * becomes `{ a: { _href: 'x', ... } }`).\n * - Element text content becomes a `#text` key when the element also has attributes or siblings.\n * - Repeated sibling elements collapse into an array.\n * - The full projection is queryable via JSONPath expressions (e.g., `$..name` finds all name\n * elements anywhere in the tree). Attributes are accessed via underscore-prefixed keys,\n * e.g. `$..[\"_href\"]` for the href attribute (recursive descent).\n *\n * The battery also exports two converter `Tool` constants: `xmlToJsonTool` and `jsonToXmlTool`.\n * These accept either inline XML/JSON text or a reference to an artifact produced earlier in\n * the turn, and return the converted result as a new `SpooledJsonArtifact` or\n * `SpooledXmlArtifact`.\n *\n * Battery exceptions are defined in this module's `exceptions.ts` file — `createException`\n * re-exported from `@nhtio/adk/factories`. Decoding a {@link SpooledXmlArtifact} instance via\n * `decode()` throws until `registerArtifactEncodables()` has run (see\n * {@link @nhtio/adk/batteries/artifacts!registerArtifactEncodables}).\n */\n\nimport { v6 as uuidv6 } from 'uuid'\nimport { JSONPath } from 'jsonpath-plus'\nimport { validator } from '@nhtio/validation'\nimport { resolveSpoolReader } from '@nhtio/adk/common'\nimport { SpooledJsonArtifact } from '@nhtio/adk/common'\nimport { isInstanceOf, isError, isObject } from '@nhtio/adk/guards'\nimport { E_XML_PARSER_PEER_MISSING, E_XML_PARSE_FAILED } from './exceptions'\nimport { ArtifactTool, Tool, ToolRegistry, ReaderDescriptor } from '@nhtio/adk/common'\n\n// Well-known @nhtio/encoder contract keys, resolved through the global symbol registry.\n// These are identical to the symbols core uses, with no import edge on the optional peer.\nconst ENCODE_METHOD: unique symbol = Symbol.for('@nhtio/encoder:toEncoded')\nconst DECODE_METHOD: unique symbol = Symbol.for('@nhtio/encoder:fromEncoded')\nimport {\n SpooledArtifact,\n collectArtifactCompatibleIds,\n resolveArtifactById,\n defaultSerialise,\n} from '@nhtio/adk/spooled_artifact'\nimport type { SpoolReader } from '@nhtio/adk/types'\nimport type { XMLParser, XMLBuilder } from 'fast-xml-parser'\nimport type { ToolMethodDescriptor, DispatchContext } from '@nhtio/adk/types'\n\n/** Snapshot payload for the encoder contract; the encoder treats it as opaque. */\ntype AdkEncodableSnapshot = unknown\n\n/**\n * Lazy-loaded promise for the `fast-xml-parser` module, cached at module scope.\n */\nlet xmlParserPromise:\n | Promise<{ XMLParser: typeof XMLParser; XMLBuilder: typeof XMLBuilder }>\n | undefined\n\n/**\n * Lazily import and cache the `fast-xml-parser` module with battery-scoped error handling.\n *\n * @returns The imported module.\n * @throws {@link E_XML_PARSER_PEER_MISSING} when the module is unavailable.\n */\nasync function getXmlParser(): Promise<{\n XMLParser: typeof XMLParser\n XMLBuilder: typeof XMLBuilder\n}> {\n xmlParserPromise ??= import('fast-xml-parser').catch((err) => {\n const detail = isError(err) ? err.message : String(err)\n throw new E_XML_PARSER_PEER_MISSING([detail])\n })\n return xmlParserPromise\n}\n\n/**\n * A {@link @nhtio/adk!SpooledArtifact} specialisation that adds XML-aware read operations.\n *\n * @remarks\n * The artifact parses XML into a JSON projection on first access and caches it for the\n * lifetime of the instance. The projection uses `ignoreAttributes` and `attributeNamePrefix` as\n * supplied to the constructor — defaulting to `false` and `'_'` — with `preserveOrder: false`.\n *\n * Under this mapping, an XML element like:\n *\n * `root-element` with an `href` attribute and text content becomes a JSON object like:\n * `{ root: { element: { _href: 'value', '#text': 'content' } } }`\n *\n * Attributes are prefixed with `_` by default rather than the conventional `@_`, because\n * `jsonpath-plus` reads a leading `@` in a path segment as its type-selector sigil before\n * honouring quotes: `$..[\"@_href\"]` throws `Unknown value type _hr`, while `$..[\"_href\"]`\n * matches. Text nodes use the `#text` key.\n *\n * All XML methods are async, consistent with {@link @nhtio/adk!SpooledArtifact}.\n *\n * Path-based methods (`xml_get`, `xml_filter`, `xml_pluck`) use\n * [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath) expressions over the projection.\n * Full JSONPath syntax is supported, including recursive descent (`..`), filter expressions,\n * and union selectors.\n */\nexport class SpooledXmlArtifact extends SpooledArtifact {\n #parsed: Record<string, unknown> | undefined\n #attributeNamePrefix: string\n #ignoreAttributes: boolean\n\n /**\n * @param reader - The backing store to read from.\n * @param options - Optional parser configuration.\n * @param options.attributeNamePrefix - Prefix for attribute keys (default: '_'). Set to '@_'\n * if you need the conventional XML-to-JSON mapping, but be aware that naming such a key in a\n * JSONPath segment fails — `$..[\"@_attr\"]` throws `Unknown value type _at`, and quoting does\n * not escape it. A filter expression still reaches it (`$..[?(@['@_attr'])]`); a wildcard\n * does too, but only when placed exactly one level above the key, so the working path\n * depends on whether repeated elements collapsed into an array.\n * @param options.ignoreAttributes - When true, ignore element attributes (default: false).\n */\n constructor(\n reader: SpoolReader,\n options?: {\n attributeNamePrefix?: string\n ignoreAttributes?: boolean\n }\n ) {\n super(reader)\n this.#attributeNamePrefix = options?.attributeNamePrefix ?? '_'\n this.#ignoreAttributes = options?.ignoreAttributes ?? false\n }\n\n /**\n * Returns `true` if `value` is a {@link SpooledXmlArtifact} instance.\n *\n * @remarks\n * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard. Safe against the\n * dual-module-copy case where two distinct `SpooledXmlArtifact` classes coexist in the same\n * realm.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link SpooledXmlArtifact} instance.\n */\n public static isSpooledXmlArtifact(value: unknown): value is SpooledXmlArtifact {\n return isInstanceOf(value, 'SpooledXmlArtifact', SpooledXmlArtifact)\n }\n\n /**\n * Returns the effective XML-to-JSON parser configuration for this artifact.\n *\n * @remarks\n * When converting an XML artifact to JSON by call_id, the converter inherits the source\n * artifact's attribute prefix and ignoreAttributes setting. This accessor exposes those\n * options so the converter can apply them consistently.\n *\n * @returns An object with `attributeNamePrefix` and `ignoreAttributes` keys.\n */\n public getParserOptions(): {\n attributeNamePrefix: string\n ignoreAttributes: boolean\n } {\n return {\n attributeNamePrefix: this.#attributeNamePrefix,\n ignoreAttributes: this.#ignoreAttributes,\n }\n }\n\n /**\n * The XML-specific artifact-query descriptors this class adds on top of the base set.\n *\n * @remarks\n * Lists `artifact_xml_root`, `artifact_xml_keys`, `artifact_xml_tags`, `artifact_xml_length`,\n * `artifact_xml_get`, `artifact_xml_filter`, `artifact_xml_pluck`. The base seven descriptors\n * (`artifact_head`, etc.) are NOT included here — they are forged separately by\n * {@link SpooledXmlArtifact.forgeTools}.\n */\n public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n {\n name: 'artifact_xml_root',\n method: 'xml_root',\n description: 'The root element name of the XML document produced earlier in this turn.',\n },\n {\n name: 'artifact_xml_keys',\n method: 'xml_keys',\n description:\n 'Keys directly under the root element of the XML document produced earlier in this turn.',\n },\n {\n name: 'artifact_xml_tags',\n method: 'xml_tags',\n description:\n 'Every distinct element name in the XML document produced earlier in this turn, deduplicated. ' +\n 'Call this before writing a path to an unfamiliar document — it tells you what elements are present.',\n },\n {\n name: 'artifact_xml_length',\n method: 'xml_length',\n description:\n 'Element count when the root element contains an array of children; otherwise 1. ' +\n 'The XML document was produced earlier in this turn.',\n },\n {\n name: 'artifact_xml_get',\n method: 'xml_get',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description(\n 'JSONPath expression to query the document. Attributes appear with a leading underscore (e.g., _href). Use bracket notation for recursive descent: $..[\"_href\"].'\n ),\n }),\n description:\n 'Query the XML document via JSONPath. The document was produced earlier in this turn. ' +\n 'Attributes appear as underscore-prefixed keys (e.g., _href for an href attribute). Use bracket notation in recursive-descent queries: $..[\"_href\"].',\n },\n {\n name: 'artifact_xml_filter',\n method: 'xml_filter',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description(\n 'JSONPath expression to filter the document. Attributes appear with a leading underscore (e.g., _href).'\n ),\n }),\n description:\n 'Return XML elements whose content matches a JSONPath filter. Differs from artifact_xml_get: get returns matched values; filter returns the element objects containing them. The document was produced earlier in this turn. Attributes appear as underscore-prefixed keys (e.g., _href).',\n },\n {\n name: 'artifact_xml_pluck',\n method: 'xml_pluck',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description(\n 'JSONPath expression to pluck values. Attributes appear with a leading underscore (e.g., _href).'\n ),\n }),\n description:\n 'Alias for artifact_xml_get — extract values matching a JSONPath. The document was produced earlier in this turn. ' +\n 'Attributes appear as underscore-prefixed keys (e.g., _href).',\n },\n ])\n\n /**\n * The root element name of the XML document.\n *\n * @returns The name of the root element.\n * @throws Error when the document is malformed or empty.\n */\n async xml_root(): Promise<string> {\n const parsed = await this.#resolveParsed()\n const keys = Object.keys(parsed)\n if (keys.length === 0) {\n throw new Error('XML document is empty')\n }\n return keys[0]\n }\n\n /**\n * Keys directly under the root element.\n *\n * @returns Array of key names at the root level.\n */\n async xml_keys(): Promise<string[]> {\n const parsed = await this.#resolveParsed()\n const rootKey = Object.keys(parsed)[0]\n if (!rootKey) return []\n const rootContent = parsed[rootKey]\n if (!isObject(rootContent)) return []\n return Object.keys(rootContent)\n }\n\n /**\n * Every distinct element name in the document, deduplicated.\n *\n * @remarks\n * Walks the entire projection recursively, excluding attribute keys (prefixed with the\n * configured `attributeNamePrefix`, default `_`) and `#text` keys. This is what a model\n * calls before it can write a path into an unfamiliar document.\n *\n * @returns Sorted array of unique element names.\n */\n async xml_tags(): Promise<string[]> {\n const parsed = await this.#resolveParsed()\n const tags = new Set<string>()\n const attributePrefix = this.#attributeNamePrefix\n\n function walk(obj: unknown): void {\n if (!isObject(obj)) return\n for (const [key, value] of Object.entries(obj)) {\n // Skip attribute keys and text nodes\n if (key.startsWith(attributePrefix) || key === '#text') {\n continue\n }\n tags.add(key)\n if (Array.isArray(value)) {\n for (const item of value) {\n walk(item)\n }\n } else {\n walk(value)\n }\n }\n }\n\n walk(parsed)\n return Array.from(tags).sort()\n }\n\n /**\n * Element count when the root contains an array of children; otherwise 1.\n *\n * @returns Number of elements.\n */\n async xml_length(): Promise<number> {\n const parsed = await this.#resolveParsed()\n const rootKey = Object.keys(parsed)[0]\n if (!rootKey) return 0\n const rootContent = parsed[rootKey]\n if (Array.isArray(rootContent)) {\n return rootContent.length\n }\n return 1\n }\n\n /**\n * Query the document via JSONPath expression.\n *\n * @param path - A JSONPath expression (e.g., `'$..name'`).\n * @returns Array of matched values.\n */\n async xml_get(path: string): Promise<unknown[]> {\n const parsed = await this.#resolveParsed()\n const results = JSONPath({ path, json: parsed })\n return results\n }\n\n /**\n * Returns the elements (subtrees) that match a JSONPath expression.\n *\n * @remarks\n * Evaluates the path against the XML projection and returns the elements that\n * contain matching values. Unlike xml_get (which returns matched values), xml_filter\n * returns the element objects containing those matches.\n *\n * Candidate set definition for XML's single-rooted projection:\n * - If the root element contains an array of repeated siblings (e.g., root.item\n * where item is an array property), filters across those siblings and returns\n * elements that have matching content.\n * - If the root element contains a single object, evaluates the path against it\n * and returns it when matched.\n *\n * The path is evaluated using JSONPath-Plus with resultType 'all' to extract\n * parent elements of matched values. The immediate parent object of any matched\n * value is included in the result, deduplicating elements.\n *\n * Example: for XML with root containing multiple 'item' elements each with an\n * 'id' attribute, xml_filter('$.root.item[*]._id') returns the item elements\n * that have an id attribute, whereas xml_get would return the id values themselves.\n *\n * @param path - A JSONPath expression (e.g. '$.root.item[*]._id' or '$[?(@.status)]').\n * @returns Array of matching element subtrees. Empty array when no matches found.\n */\n async xml_filter(path: string): Promise<unknown[]> {\n const parsed = await this.#resolveParsed()\n const rootKey = Object.keys(parsed)[0]\n if (!rootKey) return []\n\n const rootContent = parsed[rootKey]\n\n // If the root content is an array of siblings, filter the array elements\n if (Array.isArray(rootContent)) {\n // Evaluate the path against each sibling element to see if it matches\n return rootContent.filter((element) => {\n const matches = JSONPath({ path, json: element as object })\n return Array.isArray(matches) && matches.length > 0\n })\n }\n\n // If the root content is a single object, use 'all' resultType to get parent objects\n if (isObject(rootContent)) {\n // Evaluate the path against the full parsed document to get match information\n const allMatches = JSONPath({\n path,\n json: parsed,\n resultType: 'all',\n }) as unknown\n\n if (!Array.isArray(allMatches) || allMatches.length === 0) {\n return []\n }\n\n // Extract parent objects, deduplicating by reference\n const parentSet = new Set<object>()\n for (const match of allMatches) {\n const m = match as Record<string, unknown>\n if (isObject(m.parent)) {\n parentSet.add(m.parent as object)\n }\n }\n\n return Array.from(parentSet)\n }\n\n // For scalar or other types, return empty\n return []\n }\n\n /**\n * Alias for xml_get — extract values matching a JSONPath.\n *\n * @param path - A JSONPath expression (e.g., `'$..name'`).\n * @returns Array of matched values.\n */\n async xml_pluck(path: string): Promise<unknown[]> {\n return this.xml_get(path)\n }\n\n /**\n * Standard subclass extension pattern: call `SpooledArtifact.forgeTools(ctx)` to produce\n * the base seven `artifact_*` tools narrowed to any `SpooledArtifact` in the turn, then\n * register one `ArtifactTool` per XML-specific descriptor narrowed to XML artifacts.\n */\n public static override forgeTools(ctx: DispatchContext): ToolRegistry {\n const registry = SpooledArtifact.forgeTools(ctx)\n const requires = SpooledXmlArtifact\n const compatibleIds = collectArtifactCompatibleIds(ctx, requires)\n if (compatibleIds.length === 0) return registry\n\n for (const descriptor of this.toolMethods) {\n const callIdSchema = validator\n .string()\n .valid(...compatibleIds)\n .required()\n .description('ToolCall id of the artifact to query.')\n\n const argsSchema = (\n descriptor.argsSchema ?? validator.object<Record<string, never>>({})\n ).append({\n callId: callIdSchema,\n })\n\n const tool = new ArtifactTool({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: argsSchema,\n ephemeral: true,\n onCollision: 'replace',\n handler: async (rawArgs, ctxInner) => {\n const args = rawArgs as Record<string, unknown> & { callId: string }\n const resolved = resolveArtifactById(ctxInner, args.callId, requires)\n if (!resolved) return `Error: no artifact with id ${args.callId} in this turn`\n const artifact = resolved.artifact\n const methodArgs: unknown[] = []\n if (\n descriptor.method === 'xml_get' ||\n descriptor.method === 'xml_filter' ||\n descriptor.method === 'xml_pluck'\n ) {\n methodArgs.push(args.path as string)\n }\n const fn = (artifact as unknown as Record<string, (...a: unknown[]) => unknown>)[\n descriptor.method\n ]\n if (typeof fn !== 'function') {\n return `Error: artifact has no method ${descriptor.method}`\n }\n const result = await Promise.resolve(fn.apply(artifact, methodArgs))\n const serialise = descriptor.serialise ?? defaultSerialise\n return serialise(result)\n },\n })\n registry.register(tool)\n }\n return registry\n }\n\n /**\n * Parses and caches the XML projection.\n *\n * @returns The parsed projection as a JSON object.\n * @throws {@link E_XML_PARSE_FAILED} when XML parsing fails.\n */\n async #resolveParsed(): Promise<Record<string, unknown>> {\n if (this.#parsed !== undefined) {\n return this.#parsed\n }\n\n const parser = await getXmlParser()\n const xmlParser = new parser.XMLParser({\n ignoreAttributes: this.#ignoreAttributes,\n attributeNamePrefix: this.#attributeNamePrefix,\n preserveOrder: false,\n })\n\n const content = await this.asString()\n try {\n this.#parsed = xmlParser.parse(content) as Record<string, unknown>\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n throw new E_XML_PARSE_FAILED([detail])\n }\n return this.#parsed\n }\n\n /**\n * Serialise this SpooledXmlArtifact into an `@nhtio/encoder` snapshot — the reader **handle**\n * plus the constructor options for `attributeNamePrefix` and `ignoreAttributes`.\n *\n * @remarks\n * Overrides {@link SpooledArtifact.[ENCODE_METHOD]} to carry the constructor's options\n * (the parsed projection cache is derived and not encoded). Round-trips via\n * {@link SpooledXmlArtifact.[DECODE_METHOD]}.\n *\n * @returns A snapshot consumed by {@link SpooledXmlArtifact.[DECODE_METHOD]}.\n */\n [ENCODE_METHOD](): AdkEncodableSnapshot {\n return {\n reader: this.readerDescriptor(),\n attributeNamePrefix: this.#attributeNamePrefix,\n ignoreAttributes: this.#ignoreAttributes,\n }\n }\n\n /**\n * Reconstruct a {@link SpooledXmlArtifact} from a {@link SpooledXmlArtifact.[ENCODE_METHOD]}\n * snapshot.\n *\n * @param data - The snapshot produced by {@link SpooledXmlArtifact.[ENCODE_METHOD]}.\n * @returns A fresh {@link SpooledXmlArtifact} backed by a freshly-resolved reader.\n */\n static [DECODE_METHOD](data: AdkEncodableSnapshot): SpooledXmlArtifact {\n const snapshot = data as {\n reader: ReaderDescriptor\n attributeNamePrefix?: string\n ignoreAttributes?: boolean\n }\n return new SpooledXmlArtifact(resolveSpoolReader(snapshot.reader), {\n attributeNamePrefix: snapshot.attributeNamePrefix,\n ignoreAttributes: snapshot.ignoreAttributes,\n })\n }\n}\n\n/**\n * A tool that converts XML (inline or from an artifact) to JSON.\n *\n * @remarks\n * Input is either `text` (inline XML) or `call_id` (an XML artifact from earlier in this turn).\n * Provide exactly one. Returns a new {@link SpooledJsonArtifact}.\n */\nexport const xmlToJsonTool = new Tool({\n name: 'xml_to_json',\n description:\n 'Convert XML (inline or from an artifact produced earlier in this turn) to JSON. ' +\n 'Returns a queryable JSON artifact.',\n inputSchema: validator.object({\n text: validator\n .string()\n .optional()\n .allow('')\n .description('Inline XML text. Provide this or call_id, not both.'),\n call_id: validator\n .string()\n .optional()\n .allow('')\n .description('ToolCall id of an XML artifact produced earlier in this turn.'),\n }),\n artifactConstructor: () => SpooledJsonArtifact,\n handler: async (rawArgs, ctx) => {\n const args = rawArgs as { text?: string; call_id?: string }\n const text = (args.text ?? '').trim()\n const callId = (args.call_id ?? '').trim()\n\n // Validate input\n if (!text && !callId) {\n return 'Error: provide either text or call_id, not both or neither'\n }\n if (text && callId) {\n return 'Error: provide either text or call_id, not both'\n }\n\n let xmlContent: string\n let sourceId: string\n let attributeNamePrefix: string\n let ignoreAttributes: boolean\n\n if (callId) {\n const resolved = resolveArtifactById(ctx, callId, SpooledXmlArtifact)\n if (!resolved) {\n return `Error: no artifact with id ${callId} in this turn`\n }\n const xmlArtifact = resolved.artifact as SpooledXmlArtifact\n xmlContent = await xmlArtifact.asString()\n sourceId = callId\n // Inherit the source artifact's parser configuration\n const sourceOptions = xmlArtifact.getParserOptions()\n attributeNamePrefix = sourceOptions.attributeNamePrefix\n ignoreAttributes = sourceOptions.ignoreAttributes\n } else {\n xmlContent = text\n sourceId = uuidv6()\n // Use defaults for inline conversions\n attributeNamePrefix = '_'\n ignoreAttributes = false\n }\n\n // Parse XML to JSON projection\n const parser = await getXmlParser()\n const xmlParser = new parser.XMLParser({\n ignoreAttributes,\n attributeNamePrefix,\n preserveOrder: false,\n })\n\n let parsed: unknown\n try {\n parsed = xmlParser.parse(xmlContent)\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n return `Error: XML parse failed: ${detail}`\n }\n\n // Convert to JSON string\n const jsonString = JSON.stringify(parsed)\n\n // Spool and return\n const reader = await ctx.storeRetrievableBytes(`${ctx.id}:xml_to_json:${sourceId}`, jsonString)\n return new SpooledJsonArtifact(reader)\n },\n})\n\n/**\n * A tool that converts JSON (inline or from an artifact) to XML.\n *\n * @remarks\n * Input is either `text` (inline JSON) or `call_id` (a JSON artifact from earlier in this turn).\n * Provide exactly one. Returns a new {@link SpooledXmlArtifact}.\n *\n * Note: XML has no faithful JSON inverse. A JSON document that never came from XML may not\n * rebuild into sensible markup. This tool converts on a best-effort basis; the result may not\n * round-trip perfectly back to the original JSON.\n */\nexport const jsonToXmlTool = new Tool({\n name: 'json_to_xml',\n description:\n 'Convert JSON (inline or from an artifact produced earlier in this turn) to XML. ' +\n 'Returns a queryable XML artifact. ' +\n 'Note: XML has no faithful JSON inverse — a JSON document that never came from XML may not rebuild into sensible markup.',\n inputSchema: validator.object({\n text: validator\n .string()\n .optional()\n .allow('')\n .description('Inline JSON text. Provide this or call_id, not both.'),\n call_id: validator\n .string()\n .optional()\n .allow('')\n .description('ToolCall id of a JSON artifact produced earlier in this turn.'),\n }),\n artifactConstructor: () => SpooledXmlArtifact,\n handler: async (rawArgs, ctx) => {\n const args = rawArgs as { text?: string; call_id?: string }\n const text = (args.text ?? '').trim()\n const callId = (args.call_id ?? '').trim()\n\n // Validate input\n if (!text && !callId) {\n return 'Error: provide either text or call_id, not both or neither'\n }\n if (text && callId) {\n return 'Error: provide either text or call_id, not both'\n }\n\n let jsonContent: unknown\n let sourceId: string\n\n if (callId) {\n const resolved = resolveArtifactById(ctx, callId, SpooledJsonArtifact)\n if (!resolved) {\n return `Error: no artifact with id ${callId} in this turn`\n }\n const jsonString = await resolved.artifact.asString()\n try {\n jsonContent = JSON.parse(jsonString)\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n return `Error: JSON parse failed: ${detail}`\n }\n sourceId = callId\n } else {\n try {\n jsonContent = JSON.parse(text)\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n return `Error: JSON parse failed: ${detail}`\n }\n sourceId = uuidv6()\n }\n\n // Convert JSON to XML via builder\n const parser = await getXmlParser()\n const xmlBuilder = new parser.XMLBuilder({\n ignoreAttributes: false,\n attributeNamePrefix: '_',\n format: false,\n })\n\n let xmlString: string\n try {\n xmlString = xmlBuilder.build(jsonContent) as string\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n return `Error: XML build failed: ${detail}`\n }\n\n // Spool and return\n const reader = await ctx.storeRetrievableBytes(`${ctx.id}:json_to_xml:${sourceId}`, xmlString)\n return new SpooledXmlArtifact(reader)\n },\n})\n\n/**\n * Re-export the exceptions for battery-scoped error handling.\n *\n * @remarks\n * Battery exceptions are defined in `exceptions.ts` and re-exported here per the\n * battery-scoped-exceptions pattern — consumers of `@nhtio/adk/batteries/artifacts/xml`\n * can import these exception classes directly.\n */\nexport { E_XML_PARSER_PEER_MISSING, E_XML_PARSE_FAILED } from './exceptions'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"xml-CYseDztH.mjs","names":["#attributeNamePrefix","#ignoreAttributes","#resolveParsed","#parsed"],"sources":["../src/batteries/artifacts/xml/exceptions.ts","../src/batteries/artifacts/xml/index.ts"],"sourcesContent":["/**\n * Battery-scoped exceptions for the XML artifact battery.\n *\n * @remarks\n * Internal sibling of the `@nhtio/adk/batteries/artifacts/xml` entry — re-exported from the battery's\n * own barrel per the battery-scoped-exceptions rule. These are the typed errors the\n * implementor-facing API throws; the agent-facing forge catches them and renders readable\n * failure strings the model can act on.\n */\n\nimport { createException } from '@nhtio/adk/factories'\n\n/**\n * Thrown when the fast-xml-parser optional peer is not installed or fails to load.\n *\n * @remarks\n * The message template includes the package name, a description of its purpose, the underlying\n * error, and the exact install command, so the consumer sees a complete, actionable message\n * regardless of call site.\n */\nexport const E_XML_PARSER_PEER_MISSING = createException<[string]>(\n 'E_XML_PARSER_PEER_MISSING',\n 'the XML battery could not load its peer dependency \"fast-xml-parser\" (needed for XML format artifact queries): %s — install it (pnpm add fast-xml-parser)',\n 'E_XML_PARSER_PEER_MISSING',\n 500,\n true\n)\n\n/**\n * Thrown when XML parsing fails due to malformed markup.\n *\n * @remarks\n * Printf args: `[errorDetail]` — includes the parser's own reason for the failure.\n */\nexport const E_XML_PARSE_FAILED = createException<[string]>(\n 'E_XML_PARSE_FAILED',\n 'XML parse failed: %s',\n 'E_XML_PARSE_FAILED',\n 422,\n false\n)\n","/**\n * A structured artifact battery for XML documents.\n *\n * @module @nhtio/adk/batteries/artifacts/xml\n *\n * @remarks\n * Provides {@link SpooledXmlArtifact} — a `SpooledArtifact` specialisation that parses XML\n * into a JSON projection and offers path-based query tools over that projection. The XML-to-JSON\n * mapping defaults to `ignoreAttributes: false` and `attributeNamePrefix: '_'`, both settable\n * per instance through the constructor; `preserveOrder: false` is fixed. Under the default\n * mapping:\n *\n * - Element attributes become keys prefixed with `_` (e.g., `root-element` with `href=\"x\"`\n * becomes `{ a: { _href: 'x', ... } }`).\n * - Element text content becomes a `#text` key when the element also has attributes or siblings.\n * - Repeated sibling elements collapse into an array.\n * - The full projection is queryable via JSONPath expressions (e.g., `$..name` finds all name\n * elements anywhere in the tree). Attributes are accessed via underscore-prefixed keys,\n * e.g. `$..[\"_href\"]` for the href attribute (recursive descent).\n *\n * The battery also exports two converter `Tool` constants: `xmlToJsonTool` and `jsonToXmlTool`.\n * These accept either inline XML/JSON text or a reference to an artifact produced earlier in\n * the turn, and return the converted result as a new `SpooledJsonArtifact` or\n * `SpooledXmlArtifact`.\n *\n * Battery exceptions are defined in this module's `exceptions.ts` file — `createException`\n * re-exported from `@nhtio/adk/factories`. Decoding a {@link SpooledXmlArtifact} instance via\n * `decode()` throws until `registerArtifactEncodables()` has run (see\n * {@link @nhtio/adk/batteries/artifacts!registerArtifactEncodables}).\n */\n\nimport { v6 as uuidv6 } from 'uuid'\nimport { JSONPath } from 'jsonpath-plus'\nimport { validator } from '@nhtio/validation'\nimport { resolveSpoolReader } from '@nhtio/adk/common'\nimport { SpooledJsonArtifact } from '@nhtio/adk/common'\nimport { isInstanceOf, isError, isObject } from '@nhtio/adk/guards'\nimport { E_XML_PARSER_PEER_MISSING, E_XML_PARSE_FAILED } from './exceptions'\nimport { ArtifactTool, Tool, ToolRegistry, ReaderDescriptor } from '@nhtio/adk/common'\n\n// Well-known @nhtio/encoder contract keys, resolved through the global symbol registry.\n// These are identical to the symbols core uses, with no import edge on the optional peer.\nconst ENCODE_METHOD: unique symbol = Symbol.for('@nhtio/encoder:toEncoded')\nconst DECODE_METHOD: unique symbol = Symbol.for('@nhtio/encoder:fromEncoded')\nimport {\n SpooledArtifact,\n collectArtifactCompatibleIds,\n resolveArtifactById,\n defaultSerialise,\n} from '@nhtio/adk/spooled_artifact'\nimport type { SpoolReader } from '@nhtio/adk/types'\nimport type { XMLParser, XMLBuilder } from 'fast-xml-parser'\nimport type { ToolMethodDescriptor, DispatchContext } from '@nhtio/adk/types'\n\n/** Snapshot payload for the encoder contract; the encoder treats it as opaque. */\ntype AdkEncodableSnapshot = unknown\n\n/**\n * Lazy-loaded promise for the `fast-xml-parser` module, cached at module scope.\n */\nlet xmlParserPromise:\n | Promise<{ XMLParser: typeof XMLParser; XMLBuilder: typeof XMLBuilder }>\n | undefined\n\n/**\n * Lazily import and cache the `fast-xml-parser` module with battery-scoped error handling.\n *\n * @returns The imported module.\n * @throws {@link E_XML_PARSER_PEER_MISSING} when the module is unavailable.\n */\nasync function getXmlParser(): Promise<{\n XMLParser: typeof XMLParser\n XMLBuilder: typeof XMLBuilder\n}> {\n xmlParserPromise ??= import('fast-xml-parser').catch((err) => {\n const detail = isError(err) ? err.message : String(err)\n throw new E_XML_PARSER_PEER_MISSING([detail])\n })\n return xmlParserPromise\n}\n\n/**\n * A {@link @nhtio/adk!SpooledArtifact} specialisation that adds XML-aware read operations.\n *\n * @remarks\n * The artifact parses XML into a JSON projection on first access and caches it for the\n * lifetime of the instance. The projection uses `ignoreAttributes` and `attributeNamePrefix` as\n * supplied to the constructor — defaulting to `false` and `'_'` — with `preserveOrder: false`.\n *\n * Under this mapping, an XML element like:\n *\n * `root-element` with an `href` attribute and text content becomes a JSON object like:\n * `{ root: { element: { _href: 'value', '#text': 'content' } } }`\n *\n * Attributes are prefixed with `_` by default rather than the conventional `@_`, because\n * `jsonpath-plus` reads a leading `@` in a path segment as its type-selector sigil before\n * honouring quotes: `$..[\"@_href\"]` throws `Unknown value type _hr`, while `$..[\"_href\"]`\n * matches. Text nodes use the `#text` key.\n *\n * All XML methods are async, consistent with {@link @nhtio/adk!SpooledArtifact}.\n *\n * Path-based methods (`xml_get`, `xml_filter`, `xml_pluck`) use\n * [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath) expressions over the projection.\n * Full JSONPath syntax is supported, including recursive descent (`..`), filter expressions,\n * and union selectors.\n */\nexport class SpooledXmlArtifact extends SpooledArtifact {\n #parsed: Record<string, unknown> | undefined\n #attributeNamePrefix: string\n #ignoreAttributes: boolean\n\n /**\n * @param reader - The backing store to read from.\n * @param options - Optional parser configuration.\n * @param options.attributeNamePrefix - Prefix for attribute keys (default: '_'). Set to '@_'\n * if you need the conventional XML-to-JSON mapping, but be aware that naming such a key in a\n * JSONPath segment fails — `$..[\"@_attr\"]` throws `Unknown value type _at`, and quoting does\n * not escape it. A filter expression still reaches it (`$..[?(@['@_attr'])]`); a wildcard\n * does too, but only when placed exactly one level above the key, so the working path\n * depends on whether repeated elements collapsed into an array.\n * @param options.ignoreAttributes - When true, ignore element attributes (default: false).\n */\n constructor(\n reader: SpoolReader,\n options?: {\n attributeNamePrefix?: string\n ignoreAttributes?: boolean\n }\n ) {\n super(reader)\n this.#attributeNamePrefix = options?.attributeNamePrefix ?? '_'\n this.#ignoreAttributes = options?.ignoreAttributes ?? false\n }\n\n /**\n * Returns `true` if `value` is a {@link SpooledXmlArtifact} instance.\n *\n * @remarks\n * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard. Safe against the\n * dual-module-copy case where two distinct `SpooledXmlArtifact` classes coexist in the same\n * realm.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link SpooledXmlArtifact} instance.\n */\n public static isSpooledXmlArtifact(value: unknown): value is SpooledXmlArtifact {\n return isInstanceOf(value, 'SpooledXmlArtifact', SpooledXmlArtifact)\n }\n\n /**\n * Returns the effective XML-to-JSON parser configuration for this artifact.\n *\n * @remarks\n * When converting an XML artifact to JSON by call_id, the converter inherits the source\n * artifact's attribute prefix and ignoreAttributes setting. This accessor exposes those\n * options so the converter can apply them consistently.\n *\n * @returns An object with `attributeNamePrefix` and `ignoreAttributes` keys.\n */\n public getParserOptions(): {\n attributeNamePrefix: string\n ignoreAttributes: boolean\n } {\n return {\n attributeNamePrefix: this.#attributeNamePrefix,\n ignoreAttributes: this.#ignoreAttributes,\n }\n }\n\n /**\n * The XML-specific artifact-query descriptors this class adds on top of the base set.\n *\n * @remarks\n * Lists `artifact_xml_root`, `artifact_xml_keys`, `artifact_xml_tags`, `artifact_xml_length`,\n * `artifact_xml_get`, `artifact_xml_filter`, `artifact_xml_pluck`. The base seven descriptors\n * (`artifact_head`, etc.) are NOT included here — they are forged separately by\n * {@link SpooledXmlArtifact.forgeTools}.\n */\n public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n {\n name: 'artifact_xml_root',\n method: 'xml_root',\n description: 'The root element name of the XML document produced earlier in this turn.',\n },\n {\n name: 'artifact_xml_keys',\n method: 'xml_keys',\n description:\n 'Keys directly under the root element of the XML document produced earlier in this turn.',\n },\n {\n name: 'artifact_xml_tags',\n method: 'xml_tags',\n description:\n 'Every distinct element name in the XML document produced earlier in this turn, deduplicated. ' +\n 'Call this before writing a path to an unfamiliar document — it tells you what elements are present.',\n },\n {\n name: 'artifact_xml_length',\n method: 'xml_length',\n description:\n 'Element count when the root element contains an array of children; otherwise 1. ' +\n 'The XML document was produced earlier in this turn.',\n },\n {\n name: 'artifact_xml_get',\n method: 'xml_get',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description(\n 'JSONPath expression to query the document. Attributes appear with a leading underscore (e.g., _href). Use bracket notation for recursive descent: $..[\"_href\"].'\n ),\n }),\n description:\n 'Query the XML document via JSONPath. The document was produced earlier in this turn. ' +\n 'Attributes appear as underscore-prefixed keys (e.g., _href for an href attribute). Use bracket notation in recursive-descent queries: $..[\"_href\"].',\n },\n {\n name: 'artifact_xml_filter',\n method: 'xml_filter',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description(\n 'JSONPath expression to filter the document. Attributes appear with a leading underscore (e.g., _href).'\n ),\n }),\n description:\n 'Return XML elements whose content matches a JSONPath filter. Differs from artifact_xml_get: get returns matched values; filter returns the element objects containing them. The document was produced earlier in this turn. Attributes appear as underscore-prefixed keys (e.g., _href).',\n },\n {\n name: 'artifact_xml_pluck',\n method: 'xml_pluck',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description(\n 'JSONPath expression to pluck values. Attributes appear with a leading underscore (e.g., _href).'\n ),\n }),\n description:\n 'Alias for artifact_xml_get — extract values matching a JSONPath. The document was produced earlier in this turn. ' +\n 'Attributes appear as underscore-prefixed keys (e.g., _href).',\n },\n ])\n\n /**\n * The root element name of the XML document.\n *\n * @returns The name of the root element.\n * @throws Error when the document is malformed or empty.\n */\n async xml_root(): Promise<string> {\n const parsed = await this.#resolveParsed()\n const keys = Object.keys(parsed)\n if (keys.length === 0) {\n throw new Error('XML document is empty')\n }\n return keys[0]\n }\n\n /**\n * Keys directly under the root element.\n *\n * @returns Array of key names at the root level.\n */\n async xml_keys(): Promise<string[]> {\n const parsed = await this.#resolveParsed()\n const rootKey = Object.keys(parsed)[0]\n if (!rootKey) return []\n const rootContent = parsed[rootKey]\n if (!isObject(rootContent)) return []\n return Object.keys(rootContent)\n }\n\n /**\n * Every distinct element name in the document, deduplicated.\n *\n * @remarks\n * Walks the entire projection recursively, excluding attribute keys (prefixed with the\n * configured `attributeNamePrefix`, default `_`) and `#text` keys. This is what a model\n * calls before it can write a path into an unfamiliar document.\n *\n * @returns Sorted array of unique element names.\n */\n async xml_tags(): Promise<string[]> {\n const parsed = await this.#resolveParsed()\n const tags = new Set<string>()\n const attributePrefix = this.#attributeNamePrefix\n\n function walk(obj: unknown): void {\n if (!isObject(obj)) return\n for (const [key, value] of Object.entries(obj)) {\n // Skip attribute keys and text nodes\n if (key.startsWith(attributePrefix) || key === '#text') {\n continue\n }\n tags.add(key)\n if (Array.isArray(value)) {\n for (const item of value) {\n walk(item)\n }\n } else {\n walk(value)\n }\n }\n }\n\n walk(parsed)\n return Array.from(tags).sort()\n }\n\n /**\n * Element count when the root contains an array of children; otherwise 1.\n *\n * @returns Number of elements.\n */\n async xml_length(): Promise<number> {\n const parsed = await this.#resolveParsed()\n const rootKey = Object.keys(parsed)[0]\n if (!rootKey) return 0\n const rootContent = parsed[rootKey]\n if (Array.isArray(rootContent)) {\n return rootContent.length\n }\n return 1\n }\n\n /**\n * Query the document via JSONPath expression.\n *\n * @param path - A JSONPath expression (e.g., `'$..name'`).\n * @returns Array of matched values.\n */\n async xml_get(path: string): Promise<unknown[]> {\n const parsed = await this.#resolveParsed()\n const results = JSONPath({ path, json: parsed })\n return results\n }\n\n /**\n * Returns the elements (subtrees) that match a JSONPath expression.\n *\n * @remarks\n * Evaluates the path against the XML projection and returns the elements that\n * contain matching values. Unlike xml_get (which returns matched values), xml_filter\n * returns the element objects containing those matches.\n *\n * Candidate set definition for XML's single-rooted projection:\n * - If the root element contains an array of repeated siblings (e.g., root.item\n * where item is an array property), filters across those siblings and returns\n * elements that have matching content.\n * - If the root element contains a single object, evaluates the path against it\n * and returns it when matched.\n *\n * The path is evaluated using JSONPath-Plus with resultType 'all' to extract\n * parent elements of matched values. The immediate parent object of any matched\n * value is included in the result, deduplicating elements.\n *\n * Example: for XML with root containing multiple 'item' elements each with an\n * 'id' attribute, xml_filter('$.root.item[*]._id') returns the item elements\n * that have an id attribute, whereas xml_get would return the id values themselves.\n *\n * @param path - A JSONPath expression (e.g. '$.root.item[*]._id' or '$[?(@.status)]').\n * @returns Array of matching element subtrees. Empty array when no matches found.\n */\n async xml_filter(path: string): Promise<unknown[]> {\n const parsed = await this.#resolveParsed()\n const rootKey = Object.keys(parsed)[0]\n if (!rootKey) return []\n\n const rootContent = parsed[rootKey]\n\n // If the root content is an array of siblings, filter the array elements\n if (Array.isArray(rootContent)) {\n // Evaluate the path against each sibling element to see if it matches\n return rootContent.filter((element) => {\n const matches = JSONPath({ path, json: element as object })\n return Array.isArray(matches) && matches.length > 0\n })\n }\n\n // If the root content is a single object, use 'all' resultType to get parent objects\n if (isObject(rootContent)) {\n // Evaluate the path against the full parsed document to get match information\n const allMatches = JSONPath({\n path,\n json: parsed,\n resultType: 'all',\n }) as unknown\n\n if (!Array.isArray(allMatches) || allMatches.length === 0) {\n return []\n }\n\n // Extract parent objects, deduplicating by reference\n const parentSet = new Set<object>()\n for (const match of allMatches) {\n const m = match as Record<string, unknown>\n if (isObject(m.parent)) {\n parentSet.add(m.parent as object)\n }\n }\n\n return Array.from(parentSet)\n }\n\n // For scalar or other types, return empty\n return []\n }\n\n /**\n * Alias for xml_get — extract values matching a JSONPath.\n *\n * @param path - A JSONPath expression (e.g., `'$..name'`).\n * @returns Array of matched values.\n */\n async xml_pluck(path: string): Promise<unknown[]> {\n return this.xml_get(path)\n }\n\n /**\n * Standard subclass extension pattern: call `SpooledArtifact.forgeTools(ctx)` to produce\n * the base seven `artifact_*` tools narrowed to any `SpooledArtifact` in the turn, then\n * register one `ArtifactTool` per XML-specific descriptor narrowed to XML artifacts.\n */\n public static override forgeTools(ctx: DispatchContext): ToolRegistry {\n const registry = SpooledArtifact.forgeTools(ctx)\n const requires = SpooledXmlArtifact\n const compatibleIds = collectArtifactCompatibleIds(ctx, requires)\n if (compatibleIds.length === 0) return registry\n\n for (const descriptor of this.toolMethods) {\n const callIdSchema = validator\n .string()\n .valid(...compatibleIds)\n .required()\n .description('ToolCall id of the artifact to query.')\n\n const argsSchema = (\n descriptor.argsSchema ?? validator.object<Record<string, never>>({})\n ).append({\n callId: callIdSchema,\n })\n\n const tool = new ArtifactTool({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: argsSchema,\n ephemeral: true,\n onCollision: 'replace',\n handler: async (rawArgs, ctxInner) => {\n const args = rawArgs as Record<string, unknown> & { callId: string }\n const resolved = resolveArtifactById(ctxInner, args.callId, requires)\n if (!resolved) return `Error: no artifact with id ${args.callId} in this turn`\n const artifact = resolved.artifact\n const methodArgs: unknown[] = []\n if (\n descriptor.method === 'xml_get' ||\n descriptor.method === 'xml_filter' ||\n descriptor.method === 'xml_pluck'\n ) {\n methodArgs.push(args.path as string)\n }\n const fn = (artifact as unknown as Record<string, (...a: unknown[]) => unknown>)[\n descriptor.method\n ]\n if (typeof fn !== 'function') {\n return `Error: artifact has no method ${descriptor.method}`\n }\n const result = await Promise.resolve(fn.apply(artifact, methodArgs))\n const serialise = descriptor.serialise ?? defaultSerialise\n return serialise(result)\n },\n })\n registry.register(tool)\n }\n return registry\n }\n\n /**\n * Parses and caches the XML projection.\n *\n * @returns The parsed projection as a JSON object.\n * @throws {@link E_XML_PARSE_FAILED} when XML parsing fails.\n */\n async #resolveParsed(): Promise<Record<string, unknown>> {\n if (this.#parsed !== undefined) {\n return this.#parsed\n }\n\n const parser = await getXmlParser()\n const xmlParser = new parser.XMLParser({\n ignoreAttributes: this.#ignoreAttributes,\n attributeNamePrefix: this.#attributeNamePrefix,\n preserveOrder: false,\n })\n\n const content = await this.asString()\n try {\n this.#parsed = xmlParser.parse(content) as Record<string, unknown>\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n throw new E_XML_PARSE_FAILED([detail])\n }\n return this.#parsed\n }\n\n /**\n * Serialise this SpooledXmlArtifact into an `@nhtio/encoder` snapshot — the reader **handle**\n * plus the constructor options for `attributeNamePrefix` and `ignoreAttributes`.\n *\n * @remarks\n * Overrides {@link SpooledArtifact.[ENCODE_METHOD]} to carry the constructor's options\n * (the parsed projection cache is derived and not encoded). Round-trips via\n * {@link SpooledXmlArtifact.[DECODE_METHOD]}.\n *\n * @returns A snapshot consumed by {@link SpooledXmlArtifact.[DECODE_METHOD]}.\n */\n [ENCODE_METHOD](): AdkEncodableSnapshot {\n return {\n reader: this.readerDescriptor(),\n attributeNamePrefix: this.#attributeNamePrefix,\n ignoreAttributes: this.#ignoreAttributes,\n }\n }\n\n /**\n * Reconstruct a {@link SpooledXmlArtifact} from a {@link SpooledXmlArtifact.[ENCODE_METHOD]}\n * snapshot.\n *\n * @param data - The snapshot produced by {@link SpooledXmlArtifact.[ENCODE_METHOD]}.\n * @returns A fresh {@link SpooledXmlArtifact} backed by a freshly-resolved reader.\n */\n static [DECODE_METHOD](data: AdkEncodableSnapshot): SpooledXmlArtifact {\n const snapshot = data as {\n reader: ReaderDescriptor\n attributeNamePrefix?: string\n ignoreAttributes?: boolean\n }\n return new SpooledXmlArtifact(resolveSpoolReader(snapshot.reader), {\n attributeNamePrefix: snapshot.attributeNamePrefix,\n ignoreAttributes: snapshot.ignoreAttributes,\n })\n }\n}\n\n/**\n * A tool that converts XML (inline or from an artifact) to JSON.\n *\n * @remarks\n * Input is either `text` (inline XML) or `call_id` (an XML artifact from earlier in this turn).\n * Provide exactly one. Returns a new {@link SpooledJsonArtifact}.\n */\nexport const xmlToJsonTool = new Tool({\n name: 'xml_to_json',\n description:\n 'Convert XML (inline or from an artifact produced earlier in this turn) to JSON. ' +\n 'Returns a queryable JSON artifact.',\n inputSchema: validator.object({\n text: validator\n .string()\n .optional()\n .allow('')\n .description('Inline XML text. Provide this or call_id, not both.'),\n call_id: validator\n .string()\n .optional()\n .allow('')\n .description('ToolCall id of an XML artifact produced earlier in this turn.'),\n }),\n artifactConstructor: () => SpooledJsonArtifact,\n handler: async (rawArgs, ctx) => {\n const args = rawArgs as { text?: string; call_id?: string }\n const text = (args.text ?? '').trim()\n const callId = (args.call_id ?? '').trim()\n\n // Validate input\n if (!text && !callId) {\n return 'Error: provide either text or call_id, not both or neither'\n }\n if (text && callId) {\n return 'Error: provide either text or call_id, not both'\n }\n\n let xmlContent: string\n let sourceId: string\n let attributeNamePrefix: string\n let ignoreAttributes: boolean\n\n if (callId) {\n const resolved = resolveArtifactById(ctx, callId, SpooledXmlArtifact)\n if (!resolved) {\n return `Error: no artifact with id ${callId} in this turn`\n }\n const xmlArtifact = resolved.artifact as SpooledXmlArtifact\n xmlContent = await xmlArtifact.asString()\n sourceId = callId\n // Inherit the source artifact's parser configuration\n const sourceOptions = xmlArtifact.getParserOptions()\n attributeNamePrefix = sourceOptions.attributeNamePrefix\n ignoreAttributes = sourceOptions.ignoreAttributes\n } else {\n xmlContent = text\n sourceId = uuidv6()\n // Use defaults for inline conversions\n attributeNamePrefix = '_'\n ignoreAttributes = false\n }\n\n // Parse XML to JSON projection\n const parser = await getXmlParser()\n const xmlParser = new parser.XMLParser({\n ignoreAttributes,\n attributeNamePrefix,\n preserveOrder: false,\n })\n\n let parsed: unknown\n try {\n parsed = xmlParser.parse(xmlContent)\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n return `Error: XML parse failed: ${detail}`\n }\n\n // Convert to JSON string\n const jsonString = JSON.stringify(parsed)\n\n // Spool and return\n const reader = await ctx.storeRetrievableBytes(`${ctx.id}:xml_to_json:${sourceId}`, jsonString)\n return new SpooledJsonArtifact(reader)\n },\n})\n\n/**\n * A tool that converts JSON (inline or from an artifact) to XML.\n *\n * @remarks\n * Input is either `text` (inline JSON) or `call_id` (a JSON artifact from earlier in this turn).\n * Provide exactly one. Returns a new {@link SpooledXmlArtifact}.\n *\n * Note: XML has no faithful JSON inverse. A JSON document that never came from XML may not\n * rebuild into sensible markup. This tool converts on a best-effort basis; the result may not\n * round-trip perfectly back to the original JSON.\n */\nexport const jsonToXmlTool = new Tool({\n name: 'json_to_xml',\n description:\n 'Convert JSON (inline or from an artifact produced earlier in this turn) to XML. ' +\n 'Returns a queryable XML artifact. ' +\n 'Note: XML has no faithful JSON inverse — a JSON document that never came from XML may not rebuild into sensible markup.',\n inputSchema: validator.object({\n text: validator\n .string()\n .optional()\n .allow('')\n .description('Inline JSON text. Provide this or call_id, not both.'),\n call_id: validator\n .string()\n .optional()\n .allow('')\n .description('ToolCall id of a JSON artifact produced earlier in this turn.'),\n }),\n artifactConstructor: () => SpooledXmlArtifact,\n handler: async (rawArgs, ctx) => {\n const args = rawArgs as { text?: string; call_id?: string }\n const text = (args.text ?? '').trim()\n const callId = (args.call_id ?? '').trim()\n\n // Validate input\n if (!text && !callId) {\n return 'Error: provide either text or call_id, not both or neither'\n }\n if (text && callId) {\n return 'Error: provide either text or call_id, not both'\n }\n\n let jsonContent: unknown\n let sourceId: string\n\n if (callId) {\n const resolved = resolveArtifactById(ctx, callId, SpooledJsonArtifact)\n if (!resolved) {\n return `Error: no artifact with id ${callId} in this turn`\n }\n const jsonString = await resolved.artifact.asString()\n try {\n jsonContent = JSON.parse(jsonString)\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n return `Error: JSON parse failed: ${detail}`\n }\n sourceId = callId\n } else {\n try {\n jsonContent = JSON.parse(text)\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n return `Error: JSON parse failed: ${detail}`\n }\n sourceId = uuidv6()\n }\n\n // Convert JSON to XML via builder\n const parser = await getXmlParser()\n const xmlBuilder = new parser.XMLBuilder({\n ignoreAttributes: false,\n attributeNamePrefix: '_',\n format: false,\n })\n\n let xmlString: string\n try {\n xmlString = xmlBuilder.build(jsonContent) as string\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n return `Error: XML build failed: ${detail}`\n }\n\n // Spool and return\n const reader = await ctx.storeRetrievableBytes(`${ctx.id}:json_to_xml:${sourceId}`, xmlString)\n return new SpooledXmlArtifact(reader)\n },\n})\n\n/**\n * Re-export the exceptions for battery-scoped error handling.\n *\n * @remarks\n * Battery exceptions are defined in `exceptions.ts` and re-exported here per the\n * battery-scoped-exceptions pattern — consumers of `@nhtio/adk/batteries/artifacts/xml`\n * can import these exception classes directly.\n */\nexport { E_XML_PARSER_PEER_MISSING, E_XML_PARSE_FAILED } from './exceptions'\n"],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
const require_exceptions = require("./exceptions-DrHnAGQz.cjs");
|
|
2
|
-
require("./factories.cjs");
|
|
3
2
|
const require_guards = require("./guards-5-XmJgD2.cjs");
|
|
4
|
-
const require_spooled_artifact = require("./spooled_artifact
|
|
5
|
-
require("./common-
|
|
6
|
-
const require_spooled_markdown_artifact = require("./spooled_markdown_artifact-
|
|
7
|
-
require("./
|
|
3
|
+
const require_spooled_artifact = require("./spooled_artifact---DmicFW.cjs");
|
|
4
|
+
require("./common-CqetsItm.cjs");
|
|
5
|
+
const require_spooled_markdown_artifact = require("./spooled_markdown_artifact-Rjzj-kyh.cjs");
|
|
6
|
+
require("./factories.cjs");
|
|
8
7
|
require("./guards.cjs");
|
|
8
|
+
require("./spooled_artifact.cjs");
|
|
9
9
|
let _nhtio_validation = require("@nhtio/validation");
|
|
10
10
|
let uuid = require("uuid");
|
|
11
11
|
let jsonpath_plus = require("jsonpath-plus");
|
|
@@ -584,4 +584,4 @@ Object.defineProperty(exports, "xmlToJsonTool", {
|
|
|
584
584
|
}
|
|
585
585
|
});
|
|
586
586
|
|
|
587
|
-
//# sourceMappingURL=xml-
|
|
587
|
+
//# sourceMappingURL=xml-zJul8jMQ.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xml-viE54OTe.cjs","names":["#attributeNamePrefix","#ignoreAttributes","#resolveParsed","#parsed"],"sources":["../src/batteries/artifacts/xml/exceptions.ts","../src/batteries/artifacts/xml/index.ts"],"sourcesContent":["/**\n * Battery-scoped exceptions for the XML artifact battery.\n *\n * @remarks\n * Internal sibling of the `@nhtio/adk/batteries/artifacts/xml` entry — re-exported from the battery's\n * own barrel per the battery-scoped-exceptions rule. These are the typed errors the\n * implementor-facing API throws; the agent-facing forge catches them and renders readable\n * failure strings the model can act on.\n */\n\nimport { createException } from '@nhtio/adk/factories'\n\n/**\n * Thrown when the fast-xml-parser optional peer is not installed or fails to load.\n *\n * @remarks\n * The message template includes the package name, a description of its purpose, the underlying\n * error, and the exact install command, so the consumer sees a complete, actionable message\n * regardless of call site.\n */\nexport const E_XML_PARSER_PEER_MISSING = createException<[string]>(\n 'E_XML_PARSER_PEER_MISSING',\n 'the XML battery could not load its peer dependency \"fast-xml-parser\" (needed for XML format artifact queries): %s — install it (pnpm add fast-xml-parser)',\n 'E_XML_PARSER_PEER_MISSING',\n 500,\n true\n)\n\n/**\n * Thrown when XML parsing fails due to malformed markup.\n *\n * @remarks\n * Printf args: `[errorDetail]` — includes the parser's own reason for the failure.\n */\nexport const E_XML_PARSE_FAILED = createException<[string]>(\n 'E_XML_PARSE_FAILED',\n 'XML parse failed: %s',\n 'E_XML_PARSE_FAILED',\n 422,\n false\n)\n","/**\n * A structured artifact battery for XML documents.\n *\n * @module @nhtio/adk/batteries/artifacts/xml\n *\n * @remarks\n * Provides {@link SpooledXmlArtifact} — a `SpooledArtifact` specialisation that parses XML\n * into a JSON projection and offers path-based query tools over that projection. The XML-to-JSON\n * mapping defaults to `ignoreAttributes: false` and `attributeNamePrefix: '_'`, both settable\n * per instance through the constructor; `preserveOrder: false` is fixed. Under the default\n * mapping:\n *\n * - Element attributes become keys prefixed with `_` (e.g., `root-element` with `href=\"x\"`\n * becomes `{ a: { _href: 'x', ... } }`).\n * - Element text content becomes a `#text` key when the element also has attributes or siblings.\n * - Repeated sibling elements collapse into an array.\n * - The full projection is queryable via JSONPath expressions (e.g., `$..name` finds all name\n * elements anywhere in the tree). Attributes are accessed via underscore-prefixed keys,\n * e.g. `$..[\"_href\"]` for the href attribute (recursive descent).\n *\n * The battery also exports two converter `Tool` constants: `xmlToJsonTool` and `jsonToXmlTool`.\n * These accept either inline XML/JSON text or a reference to an artifact produced earlier in\n * the turn, and return the converted result as a new `SpooledJsonArtifact` or\n * `SpooledXmlArtifact`.\n *\n * Battery exceptions are defined in this module's `exceptions.ts` file — `createException`\n * re-exported from `@nhtio/adk/factories`. Decoding a {@link SpooledXmlArtifact} instance via\n * `decode()` throws until `registerArtifactEncodables()` has run (see\n * {@link @nhtio/adk/batteries/artifacts!registerArtifactEncodables}).\n */\n\nimport { v6 as uuidv6 } from 'uuid'\nimport { JSONPath } from 'jsonpath-plus'\nimport { validator } from '@nhtio/validation'\nimport { resolveSpoolReader } from '@nhtio/adk/common'\nimport { SpooledJsonArtifact } from '@nhtio/adk/common'\nimport { isInstanceOf, isError, isObject } from '@nhtio/adk/guards'\nimport { E_XML_PARSER_PEER_MISSING, E_XML_PARSE_FAILED } from './exceptions'\nimport { ArtifactTool, Tool, ToolRegistry, ReaderDescriptor } from '@nhtio/adk/common'\n\n// Well-known @nhtio/encoder contract keys, resolved through the global symbol registry.\n// These are identical to the symbols core uses, with no import edge on the optional peer.\nconst ENCODE_METHOD: unique symbol = Symbol.for('@nhtio/encoder:toEncoded')\nconst DECODE_METHOD: unique symbol = Symbol.for('@nhtio/encoder:fromEncoded')\nimport {\n SpooledArtifact,\n collectArtifactCompatibleIds,\n resolveArtifactById,\n defaultSerialise,\n} from '@nhtio/adk/spooled_artifact'\nimport type { SpoolReader } from '@nhtio/adk/types'\nimport type { XMLParser, XMLBuilder } from 'fast-xml-parser'\nimport type { ToolMethodDescriptor, DispatchContext } from '@nhtio/adk/types'\n\n/** Snapshot payload for the encoder contract; the encoder treats it as opaque. */\ntype AdkEncodableSnapshot = unknown\n\n/**\n * Lazy-loaded promise for the `fast-xml-parser` module, cached at module scope.\n */\nlet xmlParserPromise:\n | Promise<{ XMLParser: typeof XMLParser; XMLBuilder: typeof XMLBuilder }>\n | undefined\n\n/**\n * Lazily import and cache the `fast-xml-parser` module with battery-scoped error handling.\n *\n * @returns The imported module.\n * @throws {@link E_XML_PARSER_PEER_MISSING} when the module is unavailable.\n */\nasync function getXmlParser(): Promise<{\n XMLParser: typeof XMLParser\n XMLBuilder: typeof XMLBuilder\n}> {\n xmlParserPromise ??= import('fast-xml-parser').catch((err) => {\n const detail = isError(err) ? err.message : String(err)\n throw new E_XML_PARSER_PEER_MISSING([detail])\n })\n return xmlParserPromise\n}\n\n/**\n * A {@link @nhtio/adk!SpooledArtifact} specialisation that adds XML-aware read operations.\n *\n * @remarks\n * The artifact parses XML into a JSON projection on first access and caches it for the\n * lifetime of the instance. The projection uses `ignoreAttributes` and `attributeNamePrefix` as\n * supplied to the constructor — defaulting to `false` and `'_'` — with `preserveOrder: false`.\n *\n * Under this mapping, an XML element like:\n *\n * `root-element` with an `href` attribute and text content becomes a JSON object like:\n * `{ root: { element: { _href: 'value', '#text': 'content' } } }`\n *\n * Attributes are prefixed with `_` by default rather than the conventional `@_`, because\n * `jsonpath-plus` reads a leading `@` in a path segment as its type-selector sigil before\n * honouring quotes: `$..[\"@_href\"]` throws `Unknown value type _hr`, while `$..[\"_href\"]`\n * matches. Text nodes use the `#text` key.\n *\n * All XML methods are async, consistent with {@link @nhtio/adk!SpooledArtifact}.\n *\n * Path-based methods (`xml_get`, `xml_filter`, `xml_pluck`) use\n * [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath) expressions over the projection.\n * Full JSONPath syntax is supported, including recursive descent (`..`), filter expressions,\n * and union selectors.\n */\nexport class SpooledXmlArtifact extends SpooledArtifact {\n #parsed: Record<string, unknown> | undefined\n #attributeNamePrefix: string\n #ignoreAttributes: boolean\n\n /**\n * @param reader - The backing store to read from.\n * @param options - Optional parser configuration.\n * @param options.attributeNamePrefix - Prefix for attribute keys (default: '_'). Set to '@_'\n * if you need the conventional XML-to-JSON mapping, but be aware that naming such a key in a\n * JSONPath segment fails — `$..[\"@_attr\"]` throws `Unknown value type _at`, and quoting does\n * not escape it. A filter expression still reaches it (`$..[?(@['@_attr'])]`); a wildcard\n * does too, but only when placed exactly one level above the key, so the working path\n * depends on whether repeated elements collapsed into an array.\n * @param options.ignoreAttributes - When true, ignore element attributes (default: false).\n */\n constructor(\n reader: SpoolReader,\n options?: {\n attributeNamePrefix?: string\n ignoreAttributes?: boolean\n }\n ) {\n super(reader)\n this.#attributeNamePrefix = options?.attributeNamePrefix ?? '_'\n this.#ignoreAttributes = options?.ignoreAttributes ?? false\n }\n\n /**\n * Returns `true` if `value` is a {@link SpooledXmlArtifact} instance.\n *\n * @remarks\n * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard. Safe against the\n * dual-module-copy case where two distinct `SpooledXmlArtifact` classes coexist in the same\n * realm.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link SpooledXmlArtifact} instance.\n */\n public static isSpooledXmlArtifact(value: unknown): value is SpooledXmlArtifact {\n return isInstanceOf(value, 'SpooledXmlArtifact', SpooledXmlArtifact)\n }\n\n /**\n * Returns the effective XML-to-JSON parser configuration for this artifact.\n *\n * @remarks\n * When converting an XML artifact to JSON by call_id, the converter inherits the source\n * artifact's attribute prefix and ignoreAttributes setting. This accessor exposes those\n * options so the converter can apply them consistently.\n *\n * @returns An object with `attributeNamePrefix` and `ignoreAttributes` keys.\n */\n public getParserOptions(): {\n attributeNamePrefix: string\n ignoreAttributes: boolean\n } {\n return {\n attributeNamePrefix: this.#attributeNamePrefix,\n ignoreAttributes: this.#ignoreAttributes,\n }\n }\n\n /**\n * The XML-specific artifact-query descriptors this class adds on top of the base set.\n *\n * @remarks\n * Lists `artifact_xml_root`, `artifact_xml_keys`, `artifact_xml_tags`, `artifact_xml_length`,\n * `artifact_xml_get`, `artifact_xml_filter`, `artifact_xml_pluck`. The base seven descriptors\n * (`artifact_head`, etc.) are NOT included here — they are forged separately by\n * {@link SpooledXmlArtifact.forgeTools}.\n */\n public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n {\n name: 'artifact_xml_root',\n method: 'xml_root',\n description: 'The root element name of the XML document produced earlier in this turn.',\n },\n {\n name: 'artifact_xml_keys',\n method: 'xml_keys',\n description:\n 'Keys directly under the root element of the XML document produced earlier in this turn.',\n },\n {\n name: 'artifact_xml_tags',\n method: 'xml_tags',\n description:\n 'Every distinct element name in the XML document produced earlier in this turn, deduplicated. ' +\n 'Call this before writing a path to an unfamiliar document — it tells you what elements are present.',\n },\n {\n name: 'artifact_xml_length',\n method: 'xml_length',\n description:\n 'Element count when the root element contains an array of children; otherwise 1. ' +\n 'The XML document was produced earlier in this turn.',\n },\n {\n name: 'artifact_xml_get',\n method: 'xml_get',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description(\n 'JSONPath expression to query the document. Attributes appear with a leading underscore (e.g., _href). Use bracket notation for recursive descent: $..[\"_href\"].'\n ),\n }),\n description:\n 'Query the XML document via JSONPath. The document was produced earlier in this turn. ' +\n 'Attributes appear as underscore-prefixed keys (e.g., _href for an href attribute). Use bracket notation in recursive-descent queries: $..[\"_href\"].',\n },\n {\n name: 'artifact_xml_filter',\n method: 'xml_filter',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description(\n 'JSONPath expression to filter the document. Attributes appear with a leading underscore (e.g., _href).'\n ),\n }),\n description:\n 'Return XML elements whose content matches a JSONPath filter. Differs from artifact_xml_get: get returns matched values; filter returns the element objects containing them. The document was produced earlier in this turn. Attributes appear as underscore-prefixed keys (e.g., _href).',\n },\n {\n name: 'artifact_xml_pluck',\n method: 'xml_pluck',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description(\n 'JSONPath expression to pluck values. Attributes appear with a leading underscore (e.g., _href).'\n ),\n }),\n description:\n 'Alias for artifact_xml_get — extract values matching a JSONPath. The document was produced earlier in this turn. ' +\n 'Attributes appear as underscore-prefixed keys (e.g., _href).',\n },\n ])\n\n /**\n * The root element name of the XML document.\n *\n * @returns The name of the root element.\n * @throws Error when the document is malformed or empty.\n */\n async xml_root(): Promise<string> {\n const parsed = await this.#resolveParsed()\n const keys = Object.keys(parsed)\n if (keys.length === 0) {\n throw new Error('XML document is empty')\n }\n return keys[0]\n }\n\n /**\n * Keys directly under the root element.\n *\n * @returns Array of key names at the root level.\n */\n async xml_keys(): Promise<string[]> {\n const parsed = await this.#resolveParsed()\n const rootKey = Object.keys(parsed)[0]\n if (!rootKey) return []\n const rootContent = parsed[rootKey]\n if (!isObject(rootContent)) return []\n return Object.keys(rootContent)\n }\n\n /**\n * Every distinct element name in the document, deduplicated.\n *\n * @remarks\n * Walks the entire projection recursively, excluding attribute keys (prefixed with the\n * configured `attributeNamePrefix`, default `_`) and `#text` keys. This is what a model\n * calls before it can write a path into an unfamiliar document.\n *\n * @returns Sorted array of unique element names.\n */\n async xml_tags(): Promise<string[]> {\n const parsed = await this.#resolveParsed()\n const tags = new Set<string>()\n const attributePrefix = this.#attributeNamePrefix\n\n function walk(obj: unknown): void {\n if (!isObject(obj)) return\n for (const [key, value] of Object.entries(obj)) {\n // Skip attribute keys and text nodes\n if (key.startsWith(attributePrefix) || key === '#text') {\n continue\n }\n tags.add(key)\n if (Array.isArray(value)) {\n for (const item of value) {\n walk(item)\n }\n } else {\n walk(value)\n }\n }\n }\n\n walk(parsed)\n return Array.from(tags).sort()\n }\n\n /**\n * Element count when the root contains an array of children; otherwise 1.\n *\n * @returns Number of elements.\n */\n async xml_length(): Promise<number> {\n const parsed = await this.#resolveParsed()\n const rootKey = Object.keys(parsed)[0]\n if (!rootKey) return 0\n const rootContent = parsed[rootKey]\n if (Array.isArray(rootContent)) {\n return rootContent.length\n }\n return 1\n }\n\n /**\n * Query the document via JSONPath expression.\n *\n * @param path - A JSONPath expression (e.g., `'$..name'`).\n * @returns Array of matched values.\n */\n async xml_get(path: string): Promise<unknown[]> {\n const parsed = await this.#resolveParsed()\n const results = JSONPath({ path, json: parsed })\n return results\n }\n\n /**\n * Returns the elements (subtrees) that match a JSONPath expression.\n *\n * @remarks\n * Evaluates the path against the XML projection and returns the elements that\n * contain matching values. Unlike xml_get (which returns matched values), xml_filter\n * returns the element objects containing those matches.\n *\n * Candidate set definition for XML's single-rooted projection:\n * - If the root element contains an array of repeated siblings (e.g., root.item\n * where item is an array property), filters across those siblings and returns\n * elements that have matching content.\n * - If the root element contains a single object, evaluates the path against it\n * and returns it when matched.\n *\n * The path is evaluated using JSONPath-Plus with resultType 'all' to extract\n * parent elements of matched values. The immediate parent object of any matched\n * value is included in the result, deduplicating elements.\n *\n * Example: for XML with root containing multiple 'item' elements each with an\n * 'id' attribute, xml_filter('$.root.item[*]._id') returns the item elements\n * that have an id attribute, whereas xml_get would return the id values themselves.\n *\n * @param path - A JSONPath expression (e.g. '$.root.item[*]._id' or '$[?(@.status)]').\n * @returns Array of matching element subtrees. Empty array when no matches found.\n */\n async xml_filter(path: string): Promise<unknown[]> {\n const parsed = await this.#resolveParsed()\n const rootKey = Object.keys(parsed)[0]\n if (!rootKey) return []\n\n const rootContent = parsed[rootKey]\n\n // If the root content is an array of siblings, filter the array elements\n if (Array.isArray(rootContent)) {\n // Evaluate the path against each sibling element to see if it matches\n return rootContent.filter((element) => {\n const matches = JSONPath({ path, json: element as object })\n return Array.isArray(matches) && matches.length > 0\n })\n }\n\n // If the root content is a single object, use 'all' resultType to get parent objects\n if (isObject(rootContent)) {\n // Evaluate the path against the full parsed document to get match information\n const allMatches = JSONPath({\n path,\n json: parsed,\n resultType: 'all',\n }) as unknown\n\n if (!Array.isArray(allMatches) || allMatches.length === 0) {\n return []\n }\n\n // Extract parent objects, deduplicating by reference\n const parentSet = new Set<object>()\n for (const match of allMatches) {\n const m = match as Record<string, unknown>\n if (isObject(m.parent)) {\n parentSet.add(m.parent as object)\n }\n }\n\n return Array.from(parentSet)\n }\n\n // For scalar or other types, return empty\n return []\n }\n\n /**\n * Alias for xml_get — extract values matching a JSONPath.\n *\n * @param path - A JSONPath expression (e.g., `'$..name'`).\n * @returns Array of matched values.\n */\n async xml_pluck(path: string): Promise<unknown[]> {\n return this.xml_get(path)\n }\n\n /**\n * Standard subclass extension pattern: call `SpooledArtifact.forgeTools(ctx)` to produce\n * the base seven `artifact_*` tools narrowed to any `SpooledArtifact` in the turn, then\n * register one `ArtifactTool` per XML-specific descriptor narrowed to XML artifacts.\n */\n public static override forgeTools(ctx: DispatchContext): ToolRegistry {\n const registry = SpooledArtifact.forgeTools(ctx)\n const requires = SpooledXmlArtifact\n const compatibleIds = collectArtifactCompatibleIds(ctx, requires)\n if (compatibleIds.length === 0) return registry\n\n for (const descriptor of this.toolMethods) {\n const callIdSchema = validator\n .string()\n .valid(...compatibleIds)\n .required()\n .description('ToolCall id of the artifact to query.')\n\n const argsSchema = (\n descriptor.argsSchema ?? validator.object<Record<string, never>>({})\n ).append({\n callId: callIdSchema,\n })\n\n const tool = new ArtifactTool({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: argsSchema,\n ephemeral: true,\n onCollision: 'replace',\n handler: async (rawArgs, ctxInner) => {\n const args = rawArgs as Record<string, unknown> & { callId: string }\n const resolved = resolveArtifactById(ctxInner, args.callId, requires)\n if (!resolved) return `Error: no artifact with id ${args.callId} in this turn`\n const artifact = resolved.artifact\n const methodArgs: unknown[] = []\n if (\n descriptor.method === 'xml_get' ||\n descriptor.method === 'xml_filter' ||\n descriptor.method === 'xml_pluck'\n ) {\n methodArgs.push(args.path as string)\n }\n const fn = (artifact as unknown as Record<string, (...a: unknown[]) => unknown>)[\n descriptor.method\n ]\n if (typeof fn !== 'function') {\n return `Error: artifact has no method ${descriptor.method}`\n }\n const result = await Promise.resolve(fn.apply(artifact, methodArgs))\n const serialise = descriptor.serialise ?? defaultSerialise\n return serialise(result)\n },\n })\n registry.register(tool)\n }\n return registry\n }\n\n /**\n * Parses and caches the XML projection.\n *\n * @returns The parsed projection as a JSON object.\n * @throws {@link E_XML_PARSE_FAILED} when XML parsing fails.\n */\n async #resolveParsed(): Promise<Record<string, unknown>> {\n if (this.#parsed !== undefined) {\n return this.#parsed\n }\n\n const parser = await getXmlParser()\n const xmlParser = new parser.XMLParser({\n ignoreAttributes: this.#ignoreAttributes,\n attributeNamePrefix: this.#attributeNamePrefix,\n preserveOrder: false,\n })\n\n const content = await this.asString()\n try {\n this.#parsed = xmlParser.parse(content) as Record<string, unknown>\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n throw new E_XML_PARSE_FAILED([detail])\n }\n return this.#parsed\n }\n\n /**\n * Serialise this SpooledXmlArtifact into an `@nhtio/encoder` snapshot — the reader **handle**\n * plus the constructor options for `attributeNamePrefix` and `ignoreAttributes`.\n *\n * @remarks\n * Overrides {@link SpooledArtifact.[ENCODE_METHOD]} to carry the constructor's options\n * (the parsed projection cache is derived and not encoded). Round-trips via\n * {@link SpooledXmlArtifact.[DECODE_METHOD]}.\n *\n * @returns A snapshot consumed by {@link SpooledXmlArtifact.[DECODE_METHOD]}.\n */\n [ENCODE_METHOD](): AdkEncodableSnapshot {\n return {\n reader: this.readerDescriptor(),\n attributeNamePrefix: this.#attributeNamePrefix,\n ignoreAttributes: this.#ignoreAttributes,\n }\n }\n\n /**\n * Reconstruct a {@link SpooledXmlArtifact} from a {@link SpooledXmlArtifact.[ENCODE_METHOD]}\n * snapshot.\n *\n * @param data - The snapshot produced by {@link SpooledXmlArtifact.[ENCODE_METHOD]}.\n * @returns A fresh {@link SpooledXmlArtifact} backed by a freshly-resolved reader.\n */\n static [DECODE_METHOD](data: AdkEncodableSnapshot): SpooledXmlArtifact {\n const snapshot = data as {\n reader: ReaderDescriptor\n attributeNamePrefix?: string\n ignoreAttributes?: boolean\n }\n return new SpooledXmlArtifact(resolveSpoolReader(snapshot.reader), {\n attributeNamePrefix: snapshot.attributeNamePrefix,\n ignoreAttributes: snapshot.ignoreAttributes,\n })\n }\n}\n\n/**\n * A tool that converts XML (inline or from an artifact) to JSON.\n *\n * @remarks\n * Input is either `text` (inline XML) or `call_id` (an XML artifact from earlier in this turn).\n * Provide exactly one. Returns a new {@link SpooledJsonArtifact}.\n */\nexport const xmlToJsonTool = new Tool({\n name: 'xml_to_json',\n description:\n 'Convert XML (inline or from an artifact produced earlier in this turn) to JSON. ' +\n 'Returns a queryable JSON artifact.',\n inputSchema: validator.object({\n text: validator\n .string()\n .optional()\n .allow('')\n .description('Inline XML text. Provide this or call_id, not both.'),\n call_id: validator\n .string()\n .optional()\n .allow('')\n .description('ToolCall id of an XML artifact produced earlier in this turn.'),\n }),\n artifactConstructor: () => SpooledJsonArtifact,\n handler: async (rawArgs, ctx) => {\n const args = rawArgs as { text?: string; call_id?: string }\n const text = (args.text ?? '').trim()\n const callId = (args.call_id ?? '').trim()\n\n // Validate input\n if (!text && !callId) {\n return 'Error: provide either text or call_id, not both or neither'\n }\n if (text && callId) {\n return 'Error: provide either text or call_id, not both'\n }\n\n let xmlContent: string\n let sourceId: string\n let attributeNamePrefix: string\n let ignoreAttributes: boolean\n\n if (callId) {\n const resolved = resolveArtifactById(ctx, callId, SpooledXmlArtifact)\n if (!resolved) {\n return `Error: no artifact with id ${callId} in this turn`\n }\n const xmlArtifact = resolved.artifact as SpooledXmlArtifact\n xmlContent = await xmlArtifact.asString()\n sourceId = callId\n // Inherit the source artifact's parser configuration\n const sourceOptions = xmlArtifact.getParserOptions()\n attributeNamePrefix = sourceOptions.attributeNamePrefix\n ignoreAttributes = sourceOptions.ignoreAttributes\n } else {\n xmlContent = text\n sourceId = uuidv6()\n // Use defaults for inline conversions\n attributeNamePrefix = '_'\n ignoreAttributes = false\n }\n\n // Parse XML to JSON projection\n const parser = await getXmlParser()\n const xmlParser = new parser.XMLParser({\n ignoreAttributes,\n attributeNamePrefix,\n preserveOrder: false,\n })\n\n let parsed: unknown\n try {\n parsed = xmlParser.parse(xmlContent)\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n return `Error: XML parse failed: ${detail}`\n }\n\n // Convert to JSON string\n const jsonString = JSON.stringify(parsed)\n\n // Spool and return\n const reader = await ctx.storeRetrievableBytes(`${ctx.id}:xml_to_json:${sourceId}`, jsonString)\n return new SpooledJsonArtifact(reader)\n },\n})\n\n/**\n * A tool that converts JSON (inline or from an artifact) to XML.\n *\n * @remarks\n * Input is either `text` (inline JSON) or `call_id` (a JSON artifact from earlier in this turn).\n * Provide exactly one. Returns a new {@link SpooledXmlArtifact}.\n *\n * Note: XML has no faithful JSON inverse. A JSON document that never came from XML may not\n * rebuild into sensible markup. This tool converts on a best-effort basis; the result may not\n * round-trip perfectly back to the original JSON.\n */\nexport const jsonToXmlTool = new Tool({\n name: 'json_to_xml',\n description:\n 'Convert JSON (inline or from an artifact produced earlier in this turn) to XML. ' +\n 'Returns a queryable XML artifact. ' +\n 'Note: XML has no faithful JSON inverse — a JSON document that never came from XML may not rebuild into sensible markup.',\n inputSchema: validator.object({\n text: validator\n .string()\n .optional()\n .allow('')\n .description('Inline JSON text. Provide this or call_id, not both.'),\n call_id: validator\n .string()\n .optional()\n .allow('')\n .description('ToolCall id of a JSON artifact produced earlier in this turn.'),\n }),\n artifactConstructor: () => SpooledXmlArtifact,\n handler: async (rawArgs, ctx) => {\n const args = rawArgs as { text?: string; call_id?: string }\n const text = (args.text ?? '').trim()\n const callId = (args.call_id ?? '').trim()\n\n // Validate input\n if (!text && !callId) {\n return 'Error: provide either text or call_id, not both or neither'\n }\n if (text && callId) {\n return 'Error: provide either text or call_id, not both'\n }\n\n let jsonContent: unknown\n let sourceId: string\n\n if (callId) {\n const resolved = resolveArtifactById(ctx, callId, SpooledJsonArtifact)\n if (!resolved) {\n return `Error: no artifact with id ${callId} in this turn`\n }\n const jsonString = await resolved.artifact.asString()\n try {\n jsonContent = JSON.parse(jsonString)\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n return `Error: JSON parse failed: ${detail}`\n }\n sourceId = callId\n } else {\n try {\n jsonContent = JSON.parse(text)\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n return `Error: JSON parse failed: ${detail}`\n }\n sourceId = uuidv6()\n }\n\n // Convert JSON to XML via builder\n const parser = await getXmlParser()\n const xmlBuilder = new parser.XMLBuilder({\n ignoreAttributes: false,\n attributeNamePrefix: '_',\n format: false,\n })\n\n let xmlString: string\n try {\n xmlString = xmlBuilder.build(jsonContent) as string\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n return `Error: XML build failed: ${detail}`\n }\n\n // Spool and return\n const reader = await ctx.storeRetrievableBytes(`${ctx.id}:json_to_xml:${sourceId}`, xmlString)\n return new SpooledXmlArtifact(reader)\n },\n})\n\n/**\n * Re-export the exceptions for battery-scoped error handling.\n *\n * @remarks\n * Battery exceptions are defined in `exceptions.ts` and re-exported here per the\n * battery-scoped-exceptions pattern — consumers of `@nhtio/adk/batteries/artifacts/xml`\n * can import these exception classes directly.\n */\nexport { E_XML_PARSER_PEER_MISSING, E_XML_PARSE_FAILED } from './exceptions'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"xml-zJul8jMQ.cjs","names":["#attributeNamePrefix","#ignoreAttributes","#resolveParsed","#parsed"],"sources":["../src/batteries/artifacts/xml/exceptions.ts","../src/batteries/artifacts/xml/index.ts"],"sourcesContent":["/**\n * Battery-scoped exceptions for the XML artifact battery.\n *\n * @remarks\n * Internal sibling of the `@nhtio/adk/batteries/artifacts/xml` entry — re-exported from the battery's\n * own barrel per the battery-scoped-exceptions rule. These are the typed errors the\n * implementor-facing API throws; the agent-facing forge catches them and renders readable\n * failure strings the model can act on.\n */\n\nimport { createException } from '@nhtio/adk/factories'\n\n/**\n * Thrown when the fast-xml-parser optional peer is not installed or fails to load.\n *\n * @remarks\n * The message template includes the package name, a description of its purpose, the underlying\n * error, and the exact install command, so the consumer sees a complete, actionable message\n * regardless of call site.\n */\nexport const E_XML_PARSER_PEER_MISSING = createException<[string]>(\n 'E_XML_PARSER_PEER_MISSING',\n 'the XML battery could not load its peer dependency \"fast-xml-parser\" (needed for XML format artifact queries): %s — install it (pnpm add fast-xml-parser)',\n 'E_XML_PARSER_PEER_MISSING',\n 500,\n true\n)\n\n/**\n * Thrown when XML parsing fails due to malformed markup.\n *\n * @remarks\n * Printf args: `[errorDetail]` — includes the parser's own reason for the failure.\n */\nexport const E_XML_PARSE_FAILED = createException<[string]>(\n 'E_XML_PARSE_FAILED',\n 'XML parse failed: %s',\n 'E_XML_PARSE_FAILED',\n 422,\n false\n)\n","/**\n * A structured artifact battery for XML documents.\n *\n * @module @nhtio/adk/batteries/artifacts/xml\n *\n * @remarks\n * Provides {@link SpooledXmlArtifact} — a `SpooledArtifact` specialisation that parses XML\n * into a JSON projection and offers path-based query tools over that projection. The XML-to-JSON\n * mapping defaults to `ignoreAttributes: false` and `attributeNamePrefix: '_'`, both settable\n * per instance through the constructor; `preserveOrder: false` is fixed. Under the default\n * mapping:\n *\n * - Element attributes become keys prefixed with `_` (e.g., `root-element` with `href=\"x\"`\n * becomes `{ a: { _href: 'x', ... } }`).\n * - Element text content becomes a `#text` key when the element also has attributes or siblings.\n * - Repeated sibling elements collapse into an array.\n * - The full projection is queryable via JSONPath expressions (e.g., `$..name` finds all name\n * elements anywhere in the tree). Attributes are accessed via underscore-prefixed keys,\n * e.g. `$..[\"_href\"]` for the href attribute (recursive descent).\n *\n * The battery also exports two converter `Tool` constants: `xmlToJsonTool` and `jsonToXmlTool`.\n * These accept either inline XML/JSON text or a reference to an artifact produced earlier in\n * the turn, and return the converted result as a new `SpooledJsonArtifact` or\n * `SpooledXmlArtifact`.\n *\n * Battery exceptions are defined in this module's `exceptions.ts` file — `createException`\n * re-exported from `@nhtio/adk/factories`. Decoding a {@link SpooledXmlArtifact} instance via\n * `decode()` throws until `registerArtifactEncodables()` has run (see\n * {@link @nhtio/adk/batteries/artifacts!registerArtifactEncodables}).\n */\n\nimport { v6 as uuidv6 } from 'uuid'\nimport { JSONPath } from 'jsonpath-plus'\nimport { validator } from '@nhtio/validation'\nimport { resolveSpoolReader } from '@nhtio/adk/common'\nimport { SpooledJsonArtifact } from '@nhtio/adk/common'\nimport { isInstanceOf, isError, isObject } from '@nhtio/adk/guards'\nimport { E_XML_PARSER_PEER_MISSING, E_XML_PARSE_FAILED } from './exceptions'\nimport { ArtifactTool, Tool, ToolRegistry, ReaderDescriptor } from '@nhtio/adk/common'\n\n// Well-known @nhtio/encoder contract keys, resolved through the global symbol registry.\n// These are identical to the symbols core uses, with no import edge on the optional peer.\nconst ENCODE_METHOD: unique symbol = Symbol.for('@nhtio/encoder:toEncoded')\nconst DECODE_METHOD: unique symbol = Symbol.for('@nhtio/encoder:fromEncoded')\nimport {\n SpooledArtifact,\n collectArtifactCompatibleIds,\n resolveArtifactById,\n defaultSerialise,\n} from '@nhtio/adk/spooled_artifact'\nimport type { SpoolReader } from '@nhtio/adk/types'\nimport type { XMLParser, XMLBuilder } from 'fast-xml-parser'\nimport type { ToolMethodDescriptor, DispatchContext } from '@nhtio/adk/types'\n\n/** Snapshot payload for the encoder contract; the encoder treats it as opaque. */\ntype AdkEncodableSnapshot = unknown\n\n/**\n * Lazy-loaded promise for the `fast-xml-parser` module, cached at module scope.\n */\nlet xmlParserPromise:\n | Promise<{ XMLParser: typeof XMLParser; XMLBuilder: typeof XMLBuilder }>\n | undefined\n\n/**\n * Lazily import and cache the `fast-xml-parser` module with battery-scoped error handling.\n *\n * @returns The imported module.\n * @throws {@link E_XML_PARSER_PEER_MISSING} when the module is unavailable.\n */\nasync function getXmlParser(): Promise<{\n XMLParser: typeof XMLParser\n XMLBuilder: typeof XMLBuilder\n}> {\n xmlParserPromise ??= import('fast-xml-parser').catch((err) => {\n const detail = isError(err) ? err.message : String(err)\n throw new E_XML_PARSER_PEER_MISSING([detail])\n })\n return xmlParserPromise\n}\n\n/**\n * A {@link @nhtio/adk!SpooledArtifact} specialisation that adds XML-aware read operations.\n *\n * @remarks\n * The artifact parses XML into a JSON projection on first access and caches it for the\n * lifetime of the instance. The projection uses `ignoreAttributes` and `attributeNamePrefix` as\n * supplied to the constructor — defaulting to `false` and `'_'` — with `preserveOrder: false`.\n *\n * Under this mapping, an XML element like:\n *\n * `root-element` with an `href` attribute and text content becomes a JSON object like:\n * `{ root: { element: { _href: 'value', '#text': 'content' } } }`\n *\n * Attributes are prefixed with `_` by default rather than the conventional `@_`, because\n * `jsonpath-plus` reads a leading `@` in a path segment as its type-selector sigil before\n * honouring quotes: `$..[\"@_href\"]` throws `Unknown value type _hr`, while `$..[\"_href\"]`\n * matches. Text nodes use the `#text` key.\n *\n * All XML methods are async, consistent with {@link @nhtio/adk!SpooledArtifact}.\n *\n * Path-based methods (`xml_get`, `xml_filter`, `xml_pluck`) use\n * [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath) expressions over the projection.\n * Full JSONPath syntax is supported, including recursive descent (`..`), filter expressions,\n * and union selectors.\n */\nexport class SpooledXmlArtifact extends SpooledArtifact {\n #parsed: Record<string, unknown> | undefined\n #attributeNamePrefix: string\n #ignoreAttributes: boolean\n\n /**\n * @param reader - The backing store to read from.\n * @param options - Optional parser configuration.\n * @param options.attributeNamePrefix - Prefix for attribute keys (default: '_'). Set to '@_'\n * if you need the conventional XML-to-JSON mapping, but be aware that naming such a key in a\n * JSONPath segment fails — `$..[\"@_attr\"]` throws `Unknown value type _at`, and quoting does\n * not escape it. A filter expression still reaches it (`$..[?(@['@_attr'])]`); a wildcard\n * does too, but only when placed exactly one level above the key, so the working path\n * depends on whether repeated elements collapsed into an array.\n * @param options.ignoreAttributes - When true, ignore element attributes (default: false).\n */\n constructor(\n reader: SpoolReader,\n options?: {\n attributeNamePrefix?: string\n ignoreAttributes?: boolean\n }\n ) {\n super(reader)\n this.#attributeNamePrefix = options?.attributeNamePrefix ?? '_'\n this.#ignoreAttributes = options?.ignoreAttributes ?? false\n }\n\n /**\n * Returns `true` if `value` is a {@link SpooledXmlArtifact} instance.\n *\n * @remarks\n * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard. Safe against the\n * dual-module-copy case where two distinct `SpooledXmlArtifact` classes coexist in the same\n * realm.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link SpooledXmlArtifact} instance.\n */\n public static isSpooledXmlArtifact(value: unknown): value is SpooledXmlArtifact {\n return isInstanceOf(value, 'SpooledXmlArtifact', SpooledXmlArtifact)\n }\n\n /**\n * Returns the effective XML-to-JSON parser configuration for this artifact.\n *\n * @remarks\n * When converting an XML artifact to JSON by call_id, the converter inherits the source\n * artifact's attribute prefix and ignoreAttributes setting. This accessor exposes those\n * options so the converter can apply them consistently.\n *\n * @returns An object with `attributeNamePrefix` and `ignoreAttributes` keys.\n */\n public getParserOptions(): {\n attributeNamePrefix: string\n ignoreAttributes: boolean\n } {\n return {\n attributeNamePrefix: this.#attributeNamePrefix,\n ignoreAttributes: this.#ignoreAttributes,\n }\n }\n\n /**\n * The XML-specific artifact-query descriptors this class adds on top of the base set.\n *\n * @remarks\n * Lists `artifact_xml_root`, `artifact_xml_keys`, `artifact_xml_tags`, `artifact_xml_length`,\n * `artifact_xml_get`, `artifact_xml_filter`, `artifact_xml_pluck`. The base seven descriptors\n * (`artifact_head`, etc.) are NOT included here — they are forged separately by\n * {@link SpooledXmlArtifact.forgeTools}.\n */\n public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n {\n name: 'artifact_xml_root',\n method: 'xml_root',\n description: 'The root element name of the XML document produced earlier in this turn.',\n },\n {\n name: 'artifact_xml_keys',\n method: 'xml_keys',\n description:\n 'Keys directly under the root element of the XML document produced earlier in this turn.',\n },\n {\n name: 'artifact_xml_tags',\n method: 'xml_tags',\n description:\n 'Every distinct element name in the XML document produced earlier in this turn, deduplicated. ' +\n 'Call this before writing a path to an unfamiliar document — it tells you what elements are present.',\n },\n {\n name: 'artifact_xml_length',\n method: 'xml_length',\n description:\n 'Element count when the root element contains an array of children; otherwise 1. ' +\n 'The XML document was produced earlier in this turn.',\n },\n {\n name: 'artifact_xml_get',\n method: 'xml_get',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description(\n 'JSONPath expression to query the document. Attributes appear with a leading underscore (e.g., _href). Use bracket notation for recursive descent: $..[\"_href\"].'\n ),\n }),\n description:\n 'Query the XML document via JSONPath. The document was produced earlier in this turn. ' +\n 'Attributes appear as underscore-prefixed keys (e.g., _href for an href attribute). Use bracket notation in recursive-descent queries: $..[\"_href\"].',\n },\n {\n name: 'artifact_xml_filter',\n method: 'xml_filter',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description(\n 'JSONPath expression to filter the document. Attributes appear with a leading underscore (e.g., _href).'\n ),\n }),\n description:\n 'Return XML elements whose content matches a JSONPath filter. Differs from artifact_xml_get: get returns matched values; filter returns the element objects containing them. The document was produced earlier in this turn. Attributes appear as underscore-prefixed keys (e.g., _href).',\n },\n {\n name: 'artifact_xml_pluck',\n method: 'xml_pluck',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description(\n 'JSONPath expression to pluck values. Attributes appear with a leading underscore (e.g., _href).'\n ),\n }),\n description:\n 'Alias for artifact_xml_get — extract values matching a JSONPath. The document was produced earlier in this turn. ' +\n 'Attributes appear as underscore-prefixed keys (e.g., _href).',\n },\n ])\n\n /**\n * The root element name of the XML document.\n *\n * @returns The name of the root element.\n * @throws Error when the document is malformed or empty.\n */\n async xml_root(): Promise<string> {\n const parsed = await this.#resolveParsed()\n const keys = Object.keys(parsed)\n if (keys.length === 0) {\n throw new Error('XML document is empty')\n }\n return keys[0]\n }\n\n /**\n * Keys directly under the root element.\n *\n * @returns Array of key names at the root level.\n */\n async xml_keys(): Promise<string[]> {\n const parsed = await this.#resolveParsed()\n const rootKey = Object.keys(parsed)[0]\n if (!rootKey) return []\n const rootContent = parsed[rootKey]\n if (!isObject(rootContent)) return []\n return Object.keys(rootContent)\n }\n\n /**\n * Every distinct element name in the document, deduplicated.\n *\n * @remarks\n * Walks the entire projection recursively, excluding attribute keys (prefixed with the\n * configured `attributeNamePrefix`, default `_`) and `#text` keys. This is what a model\n * calls before it can write a path into an unfamiliar document.\n *\n * @returns Sorted array of unique element names.\n */\n async xml_tags(): Promise<string[]> {\n const parsed = await this.#resolveParsed()\n const tags = new Set<string>()\n const attributePrefix = this.#attributeNamePrefix\n\n function walk(obj: unknown): void {\n if (!isObject(obj)) return\n for (const [key, value] of Object.entries(obj)) {\n // Skip attribute keys and text nodes\n if (key.startsWith(attributePrefix) || key === '#text') {\n continue\n }\n tags.add(key)\n if (Array.isArray(value)) {\n for (const item of value) {\n walk(item)\n }\n } else {\n walk(value)\n }\n }\n }\n\n walk(parsed)\n return Array.from(tags).sort()\n }\n\n /**\n * Element count when the root contains an array of children; otherwise 1.\n *\n * @returns Number of elements.\n */\n async xml_length(): Promise<number> {\n const parsed = await this.#resolveParsed()\n const rootKey = Object.keys(parsed)[0]\n if (!rootKey) return 0\n const rootContent = parsed[rootKey]\n if (Array.isArray(rootContent)) {\n return rootContent.length\n }\n return 1\n }\n\n /**\n * Query the document via JSONPath expression.\n *\n * @param path - A JSONPath expression (e.g., `'$..name'`).\n * @returns Array of matched values.\n */\n async xml_get(path: string): Promise<unknown[]> {\n const parsed = await this.#resolveParsed()\n const results = JSONPath({ path, json: parsed })\n return results\n }\n\n /**\n * Returns the elements (subtrees) that match a JSONPath expression.\n *\n * @remarks\n * Evaluates the path against the XML projection and returns the elements that\n * contain matching values. Unlike xml_get (which returns matched values), xml_filter\n * returns the element objects containing those matches.\n *\n * Candidate set definition for XML's single-rooted projection:\n * - If the root element contains an array of repeated siblings (e.g., root.item\n * where item is an array property), filters across those siblings and returns\n * elements that have matching content.\n * - If the root element contains a single object, evaluates the path against it\n * and returns it when matched.\n *\n * The path is evaluated using JSONPath-Plus with resultType 'all' to extract\n * parent elements of matched values. The immediate parent object of any matched\n * value is included in the result, deduplicating elements.\n *\n * Example: for XML with root containing multiple 'item' elements each with an\n * 'id' attribute, xml_filter('$.root.item[*]._id') returns the item elements\n * that have an id attribute, whereas xml_get would return the id values themselves.\n *\n * @param path - A JSONPath expression (e.g. '$.root.item[*]._id' or '$[?(@.status)]').\n * @returns Array of matching element subtrees. Empty array when no matches found.\n */\n async xml_filter(path: string): Promise<unknown[]> {\n const parsed = await this.#resolveParsed()\n const rootKey = Object.keys(parsed)[0]\n if (!rootKey) return []\n\n const rootContent = parsed[rootKey]\n\n // If the root content is an array of siblings, filter the array elements\n if (Array.isArray(rootContent)) {\n // Evaluate the path against each sibling element to see if it matches\n return rootContent.filter((element) => {\n const matches = JSONPath({ path, json: element as object })\n return Array.isArray(matches) && matches.length > 0\n })\n }\n\n // If the root content is a single object, use 'all' resultType to get parent objects\n if (isObject(rootContent)) {\n // Evaluate the path against the full parsed document to get match information\n const allMatches = JSONPath({\n path,\n json: parsed,\n resultType: 'all',\n }) as unknown\n\n if (!Array.isArray(allMatches) || allMatches.length === 0) {\n return []\n }\n\n // Extract parent objects, deduplicating by reference\n const parentSet = new Set<object>()\n for (const match of allMatches) {\n const m = match as Record<string, unknown>\n if (isObject(m.parent)) {\n parentSet.add(m.parent as object)\n }\n }\n\n return Array.from(parentSet)\n }\n\n // For scalar or other types, return empty\n return []\n }\n\n /**\n * Alias for xml_get — extract values matching a JSONPath.\n *\n * @param path - A JSONPath expression (e.g., `'$..name'`).\n * @returns Array of matched values.\n */\n async xml_pluck(path: string): Promise<unknown[]> {\n return this.xml_get(path)\n }\n\n /**\n * Standard subclass extension pattern: call `SpooledArtifact.forgeTools(ctx)` to produce\n * the base seven `artifact_*` tools narrowed to any `SpooledArtifact` in the turn, then\n * register one `ArtifactTool` per XML-specific descriptor narrowed to XML artifacts.\n */\n public static override forgeTools(ctx: DispatchContext): ToolRegistry {\n const registry = SpooledArtifact.forgeTools(ctx)\n const requires = SpooledXmlArtifact\n const compatibleIds = collectArtifactCompatibleIds(ctx, requires)\n if (compatibleIds.length === 0) return registry\n\n for (const descriptor of this.toolMethods) {\n const callIdSchema = validator\n .string()\n .valid(...compatibleIds)\n .required()\n .description('ToolCall id of the artifact to query.')\n\n const argsSchema = (\n descriptor.argsSchema ?? validator.object<Record<string, never>>({})\n ).append({\n callId: callIdSchema,\n })\n\n const tool = new ArtifactTool({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: argsSchema,\n ephemeral: true,\n onCollision: 'replace',\n handler: async (rawArgs, ctxInner) => {\n const args = rawArgs as Record<string, unknown> & { callId: string }\n const resolved = resolveArtifactById(ctxInner, args.callId, requires)\n if (!resolved) return `Error: no artifact with id ${args.callId} in this turn`\n const artifact = resolved.artifact\n const methodArgs: unknown[] = []\n if (\n descriptor.method === 'xml_get' ||\n descriptor.method === 'xml_filter' ||\n descriptor.method === 'xml_pluck'\n ) {\n methodArgs.push(args.path as string)\n }\n const fn = (artifact as unknown as Record<string, (...a: unknown[]) => unknown>)[\n descriptor.method\n ]\n if (typeof fn !== 'function') {\n return `Error: artifact has no method ${descriptor.method}`\n }\n const result = await Promise.resolve(fn.apply(artifact, methodArgs))\n const serialise = descriptor.serialise ?? defaultSerialise\n return serialise(result)\n },\n })\n registry.register(tool)\n }\n return registry\n }\n\n /**\n * Parses and caches the XML projection.\n *\n * @returns The parsed projection as a JSON object.\n * @throws {@link E_XML_PARSE_FAILED} when XML parsing fails.\n */\n async #resolveParsed(): Promise<Record<string, unknown>> {\n if (this.#parsed !== undefined) {\n return this.#parsed\n }\n\n const parser = await getXmlParser()\n const xmlParser = new parser.XMLParser({\n ignoreAttributes: this.#ignoreAttributes,\n attributeNamePrefix: this.#attributeNamePrefix,\n preserveOrder: false,\n })\n\n const content = await this.asString()\n try {\n this.#parsed = xmlParser.parse(content) as Record<string, unknown>\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n throw new E_XML_PARSE_FAILED([detail])\n }\n return this.#parsed\n }\n\n /**\n * Serialise this SpooledXmlArtifact into an `@nhtio/encoder` snapshot — the reader **handle**\n * plus the constructor options for `attributeNamePrefix` and `ignoreAttributes`.\n *\n * @remarks\n * Overrides {@link SpooledArtifact.[ENCODE_METHOD]} to carry the constructor's options\n * (the parsed projection cache is derived and not encoded). Round-trips via\n * {@link SpooledXmlArtifact.[DECODE_METHOD]}.\n *\n * @returns A snapshot consumed by {@link SpooledXmlArtifact.[DECODE_METHOD]}.\n */\n [ENCODE_METHOD](): AdkEncodableSnapshot {\n return {\n reader: this.readerDescriptor(),\n attributeNamePrefix: this.#attributeNamePrefix,\n ignoreAttributes: this.#ignoreAttributes,\n }\n }\n\n /**\n * Reconstruct a {@link SpooledXmlArtifact} from a {@link SpooledXmlArtifact.[ENCODE_METHOD]}\n * snapshot.\n *\n * @param data - The snapshot produced by {@link SpooledXmlArtifact.[ENCODE_METHOD]}.\n * @returns A fresh {@link SpooledXmlArtifact} backed by a freshly-resolved reader.\n */\n static [DECODE_METHOD](data: AdkEncodableSnapshot): SpooledXmlArtifact {\n const snapshot = data as {\n reader: ReaderDescriptor\n attributeNamePrefix?: string\n ignoreAttributes?: boolean\n }\n return new SpooledXmlArtifact(resolveSpoolReader(snapshot.reader), {\n attributeNamePrefix: snapshot.attributeNamePrefix,\n ignoreAttributes: snapshot.ignoreAttributes,\n })\n }\n}\n\n/**\n * A tool that converts XML (inline or from an artifact) to JSON.\n *\n * @remarks\n * Input is either `text` (inline XML) or `call_id` (an XML artifact from earlier in this turn).\n * Provide exactly one. Returns a new {@link SpooledJsonArtifact}.\n */\nexport const xmlToJsonTool = new Tool({\n name: 'xml_to_json',\n description:\n 'Convert XML (inline or from an artifact produced earlier in this turn) to JSON. ' +\n 'Returns a queryable JSON artifact.',\n inputSchema: validator.object({\n text: validator\n .string()\n .optional()\n .allow('')\n .description('Inline XML text. Provide this or call_id, not both.'),\n call_id: validator\n .string()\n .optional()\n .allow('')\n .description('ToolCall id of an XML artifact produced earlier in this turn.'),\n }),\n artifactConstructor: () => SpooledJsonArtifact,\n handler: async (rawArgs, ctx) => {\n const args = rawArgs as { text?: string; call_id?: string }\n const text = (args.text ?? '').trim()\n const callId = (args.call_id ?? '').trim()\n\n // Validate input\n if (!text && !callId) {\n return 'Error: provide either text or call_id, not both or neither'\n }\n if (text && callId) {\n return 'Error: provide either text or call_id, not both'\n }\n\n let xmlContent: string\n let sourceId: string\n let attributeNamePrefix: string\n let ignoreAttributes: boolean\n\n if (callId) {\n const resolved = resolveArtifactById(ctx, callId, SpooledXmlArtifact)\n if (!resolved) {\n return `Error: no artifact with id ${callId} in this turn`\n }\n const xmlArtifact = resolved.artifact as SpooledXmlArtifact\n xmlContent = await xmlArtifact.asString()\n sourceId = callId\n // Inherit the source artifact's parser configuration\n const sourceOptions = xmlArtifact.getParserOptions()\n attributeNamePrefix = sourceOptions.attributeNamePrefix\n ignoreAttributes = sourceOptions.ignoreAttributes\n } else {\n xmlContent = text\n sourceId = uuidv6()\n // Use defaults for inline conversions\n attributeNamePrefix = '_'\n ignoreAttributes = false\n }\n\n // Parse XML to JSON projection\n const parser = await getXmlParser()\n const xmlParser = new parser.XMLParser({\n ignoreAttributes,\n attributeNamePrefix,\n preserveOrder: false,\n })\n\n let parsed: unknown\n try {\n parsed = xmlParser.parse(xmlContent)\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n return `Error: XML parse failed: ${detail}`\n }\n\n // Convert to JSON string\n const jsonString = JSON.stringify(parsed)\n\n // Spool and return\n const reader = await ctx.storeRetrievableBytes(`${ctx.id}:xml_to_json:${sourceId}`, jsonString)\n return new SpooledJsonArtifact(reader)\n },\n})\n\n/**\n * A tool that converts JSON (inline or from an artifact) to XML.\n *\n * @remarks\n * Input is either `text` (inline JSON) or `call_id` (a JSON artifact from earlier in this turn).\n * Provide exactly one. Returns a new {@link SpooledXmlArtifact}.\n *\n * Note: XML has no faithful JSON inverse. A JSON document that never came from XML may not\n * rebuild into sensible markup. This tool converts on a best-effort basis; the result may not\n * round-trip perfectly back to the original JSON.\n */\nexport const jsonToXmlTool = new Tool({\n name: 'json_to_xml',\n description:\n 'Convert JSON (inline or from an artifact produced earlier in this turn) to XML. ' +\n 'Returns a queryable XML artifact. ' +\n 'Note: XML has no faithful JSON inverse — a JSON document that never came from XML may not rebuild into sensible markup.',\n inputSchema: validator.object({\n text: validator\n .string()\n .optional()\n .allow('')\n .description('Inline JSON text. Provide this or call_id, not both.'),\n call_id: validator\n .string()\n .optional()\n .allow('')\n .description('ToolCall id of a JSON artifact produced earlier in this turn.'),\n }),\n artifactConstructor: () => SpooledXmlArtifact,\n handler: async (rawArgs, ctx) => {\n const args = rawArgs as { text?: string; call_id?: string }\n const text = (args.text ?? '').trim()\n const callId = (args.call_id ?? '').trim()\n\n // Validate input\n if (!text && !callId) {\n return 'Error: provide either text or call_id, not both or neither'\n }\n if (text && callId) {\n return 'Error: provide either text or call_id, not both'\n }\n\n let jsonContent: unknown\n let sourceId: string\n\n if (callId) {\n const resolved = resolveArtifactById(ctx, callId, SpooledJsonArtifact)\n if (!resolved) {\n return `Error: no artifact with id ${callId} in this turn`\n }\n const jsonString = await resolved.artifact.asString()\n try {\n jsonContent = JSON.parse(jsonString)\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n return `Error: JSON parse failed: ${detail}`\n }\n sourceId = callId\n } else {\n try {\n jsonContent = JSON.parse(text)\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n return `Error: JSON parse failed: ${detail}`\n }\n sourceId = uuidv6()\n }\n\n // Convert JSON to XML via builder\n const parser = await getXmlParser()\n const xmlBuilder = new parser.XMLBuilder({\n ignoreAttributes: false,\n attributeNamePrefix: '_',\n format: false,\n })\n\n let xmlString: string\n try {\n xmlString = xmlBuilder.build(jsonContent) as string\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n return `Error: XML build failed: ${detail}`\n }\n\n // Spool and return\n const reader = await ctx.storeRetrievableBytes(`${ctx.id}:json_to_xml:${sourceId}`, xmlString)\n return new SpooledXmlArtifact(reader)\n },\n})\n\n/**\n * Re-export the exceptions for battery-scoped error handling.\n *\n * @remarks\n * Battery exceptions are defined in `exceptions.ts` and re-exported here per the\n * battery-scoped-exceptions pattern — consumers of `@nhtio/adk/batteries/artifacts/xml`\n * can import these exception classes directly.\n */\nexport { E_XML_PARSER_PEER_MISSING, E_XML_PARSE_FAILED } from './exceptions'\n"],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { t as createException } from "./exceptions-DRYLe-J4.mjs";
|
|
2
|
-
import "./factories.mjs";
|
|
3
2
|
import { n as isInstanceOf, r as isObject, t as isError } from "./guards-BEpY7lBI.mjs";
|
|
4
|
-
import { a as resolveArtifactById,
|
|
5
|
-
import "./common-
|
|
6
|
-
import { n as SpooledJsonArtifact } from "./spooled_markdown_artifact-
|
|
7
|
-
import "./
|
|
3
|
+
import { a as resolveArtifactById, f as ArtifactTool, l as resolveSpoolReader, n as collectArtifactCompatibleIds, p as Tool, r as defaultSerialise, t as SpooledArtifact } from "./spooled_artifact-Bw_7swIp.mjs";
|
|
4
|
+
import "./common-oI1niK9Z.mjs";
|
|
5
|
+
import { n as SpooledJsonArtifact } from "./spooled_markdown_artifact-vd6eNtIP.mjs";
|
|
6
|
+
import "./factories.mjs";
|
|
8
7
|
import "./guards.mjs";
|
|
8
|
+
import "./spooled_artifact.mjs";
|
|
9
9
|
import { validator } from "@nhtio/validation";
|
|
10
10
|
import { v6 } from "uuid";
|
|
11
11
|
import { JSONPath } from "jsonpath-plus";
|
|
@@ -519,4 +519,4 @@ var jsonToYamlTool = new Tool({
|
|
|
519
519
|
//#endregion
|
|
520
520
|
export { E_YAML_PEER_MISSING as a, E_YAML_PARSE_ERROR as i, jsonToYamlTool as n, yamlToJsonTool as r, SpooledYamlArtifact as t };
|
|
521
521
|
|
|
522
|
-
//# sourceMappingURL=yaml-
|
|
522
|
+
//# sourceMappingURL=yaml-BPBoiOjx.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml-B1So-pUR.mjs","names":["#options","#resolveDocs","#docs"],"sources":["../src/batteries/artifacts/yaml/exceptions.ts","../src/batteries/artifacts/yaml/index.ts"],"sourcesContent":["import { createException } from '@nhtio/adk/factories'\n\n/**\n * Thrown when YAML parsing fails due to invalid syntax.\n *\n * @remarks\n * The exception message includes the parser's original error reason and line/mark information\n * when available, which enables the model to self-correct malformed YAML.\n */\nexport const E_YAML_PARSE_ERROR = createException<[string]>(\n 'E_YAML_PARSE_ERROR',\n 'YAML parse error: %s',\n 'E_YAML_PARSE_ERROR',\n 422\n)\n\n/**\n * Thrown when the js-yaml peer dependency is missing or fails to load.\n *\n * @remarks\n * This occurs when the battery's consumer has not installed the optional js-yaml peer\n * dependency. The message template includes the package name, a description of its purpose,\n * the underlying error, and the exact install command, so the consumer sees a complete,\n * actionable message regardless of call site.\n */\nexport const E_YAML_PEER_MISSING = createException<[string]>(\n 'E_YAML_PEER_MISSING',\n 'the yaml battery could not load its peer dependency \"js-yaml\" (needed for YAML format artifact queries): %s — install it (pnpm add js-yaml)',\n 'E_YAML_PEER_MISSING',\n 500\n)\n","/**\n * YAML artifact battery: {@link SpooledYamlArtifact} and bidirectional converters.\n *\n * @remarks\n * Provides structured query tools for YAML documents, both single-document and\n * multi-document streams. Includes converter tools to transform between YAML and JSON\n * representations without materialising the artifact contents.\n *\n * Requires the optional peer `js-yaml@^4.1.1`. Install with:\n * ```\n * pnpm add js-yaml\n * ```\n *\n * Note: `decode()` on `SpooledYamlArtifact` instances throws until\n * `registerArtifactEncodables()` has been called.\n *\n * @module @nhtio/adk/batteries/artifacts/yaml\n */\n\nimport { v6 as uuidv6 } from 'uuid'\nimport { JSONPath } from 'jsonpath-plus'\nimport { validator } from '@nhtio/validation'\nimport { resolveSpoolReader } from '@nhtio/adk/common'\nimport { isInstanceOf, isError, isObject } from '@nhtio/adk/guards'\nimport { E_YAML_PARSE_ERROR, E_YAML_PEER_MISSING } from './exceptions'\nimport {\n Tool,\n ArtifactTool,\n ToolRegistry,\n SpooledJsonArtifact,\n ReaderDescriptor,\n} from '@nhtio/adk/common'\n\nimport {\n collectArtifactCompatibleIds,\n resolveArtifactById,\n defaultSerialise,\n SpooledArtifact,\n} from '@nhtio/adk/spooled_artifact'\nimport type { SpoolReader } from '@nhtio/adk/common'\nimport type { ToolMethodDescriptor, DispatchContext } from '@nhtio/adk/types'\n\n// Well-known @nhtio/encoder contract keys, resolved through the global symbol registry.\n// These are identical to the symbols core uses, with no import edge on the optional peer.\nconst ENCODE_METHOD: unique symbol = Symbol.for('@nhtio/encoder:toEncoded')\nconst DECODE_METHOD: unique symbol = Symbol.for('@nhtio/encoder:fromEncoded')\n\n/** Snapshot payload for the encoder contract; the encoder treats it as opaque. */\ntype AdkEncodableSnapshot = unknown\n\n/**\n * Lazy-loaded promise for the js-yaml module.\n *\n * @remarks\n * Caches the result to avoid repeated import attempts. If the import fails, the exception\n * is thrown on subsequent access rather than re-importing.\n */\nlet yamlPromise:\n | Promise<{\n load: (content: string) => unknown\n loadAll: (content: string) => unknown[]\n dump: (data: unknown, options?: Record<string, unknown>) => string\n }>\n | undefined\n\n/**\n * Lazy-loads and caches the js-yaml module.\n *\n * @returns The loaded `js-yaml` module.\n * @throws {@link E_YAML_PEER_MISSING} if the module fails to load.\n */\nasync function getYaml() {\n yamlPromise ??= import('js-yaml').catch((err) => {\n throw new E_YAML_PEER_MISSING([isError(err) ? err.message : String(err)])\n })\n return yamlPromise\n}\n\n/**\n * A {@link SpooledArtifact} specialisation that adds YAML-aware read operations.\n *\n * @remarks\n * Handles both single-document YAML and multi-document streams (delimited by `---`).\n * Parsed documents are cached in a private field for the lifetime of the instance.\n *\n * For multi-document streams:\n * - `yaml_length` reports the document count.\n * - `yaml_keys` returns the deduplicated union of keys across all documents.\n * - `yaml_get` / `yaml_filter` / `yaml_pluck` evaluate paths against all documents and return\n * a flat array of all matches.\n *\n * Non-finite numbers (`.NaN`, `.inf`, `-.inf`) present in the YAML are preserved through the\n * `yaml_to_json` converter using a custom replacer.\n */\nexport class SpooledYamlArtifact extends SpooledArtifact {\n #docs: unknown[] | undefined\n\n /**\n * @param reader - The backing store to read from.\n * @param options - Optional configuration for parsing.\n * @param options.multiDocument - Declares the source's document mode. `true` parses as a\n * stream and makes {@link SpooledYamlArtifact.yaml_type} report `'multi-document'` regardless\n * of the current count. `false` asserts exactly one document and parses with `load`, so a\n * `---` stream raises `E_YAML_PARSE_ERROR` instead of being silently accepted. When omitted,\n * mode is auto-detected\n * by parsing the content with `loadAll`.\n */\n constructor(reader: SpoolReader, options?: { multiDocument?: boolean }) {\n super(reader)\n this.#options = options\n }\n\n #options: { multiDocument?: boolean } | undefined\n\n /**\n * Returns `true` if `value` is a {@link SpooledYamlArtifact} instance.\n *\n * @remarks\n * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard. Safe against the\n * dual-module-copy case where two distinct `SpooledYamlArtifact` classes coexist in the\n * same realm.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link SpooledYamlArtifact} instance.\n */\n public static isSpooledYamlArtifact(value: unknown): value is SpooledYamlArtifact {\n return isInstanceOf(value, 'SpooledYamlArtifact', SpooledYamlArtifact)\n }\n\n /**\n * The YAML-specific artifact-query descriptors this class adds on top of the base set.\n *\n * @remarks\n * Lists `artifact_yaml_type`, `artifact_yaml_keys`, `artifact_yaml_length`,\n * `artifact_yaml_get`, `artifact_yaml_filter`, `artifact_yaml_slice`, `artifact_yaml_pluck`.\n * The base seven descriptors (`artifact_head`, etc.) are NOT included here — they are\n * forged separately by {@link SpooledYamlArtifact.forgeTools}.\n */\n public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n {\n name: 'artifact_yaml_type',\n method: 'yaml_type',\n description:\n 'Return the YAML type (single-document or multi-document) of an artifact produced earlier in this turn.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_yaml_keys',\n method: 'yaml_keys',\n description:\n 'Return the top-level keys of a YAML artifact produced earlier in this turn; for multi-document streams, the deduplicated union across all documents.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_yaml_length',\n method: 'yaml_length',\n description:\n 'Return the document count of a YAML artifact produced earlier in this turn. The count comes from js-yaml parsing; for sources with no actual YAML content (empty, whitespace, or BOM), the result is typically 0 but may be 1 depending on whitespace arrangement. For real YAML documents or multi-document streams separated by ---, the count is exact.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_yaml_get',\n method: 'yaml_get',\n description:\n 'Evaluate a JSONPath expression against a YAML artifact produced earlier in this turn.',\n argsSchema: validator.object({\n path: validator.string().required().description(\"JSONPath expression, e.g. '$.user.name'.\"),\n }),\n },\n {\n name: 'artifact_yaml_filter',\n method: 'yaml_filter',\n description:\n 'Return records of a YAML artifact (produced earlier in this turn) matched by a JSONPath filter.',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description('JSONPath filter expression, e.g. \\'$[?(@.status === \"active\")]\\'.'),\n }),\n },\n {\n name: 'artifact_yaml_slice',\n method: 'yaml_slice',\n description:\n 'Return a slice of documents by index range from a YAML artifact produced earlier in this turn.',\n argsSchema: validator.object({\n start: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start index (inclusive).'),\n end: validator.number().integer().min(0).optional().description('End index (exclusive).'),\n }),\n },\n {\n name: 'artifact_yaml_pluck',\n method: 'yaml_pluck',\n description:\n 'Return all values matched by a JSONPath expression across every document of a YAML artifact produced earlier in this turn.',\n argsSchema: validator.object({\n path: validator.string().required().description(\"JSONPath expression, e.g. '$..name'.\"),\n }),\n },\n ])\n\n /**\n * Forges base-class tools plus YAML-specific tools narrowed to {@link SpooledYamlArtifact}.\n *\n * @remarks\n * Standard subclass extension pattern: call `SpooledArtifact.forgeTools(ctx)` to produce\n * the base seven `artifact_*` tools narrowed to any `SpooledArtifact` in the turn, then\n * register one `ArtifactTool` per YAML-specific descriptor narrowed to YAML artifacts.\n */\n public static override forgeTools(ctx: DispatchContext): ToolRegistry {\n const registry = SpooledArtifact.forgeTools(ctx)\n const requires = SpooledYamlArtifact\n const compatibleIds = collectArtifactCompatibleIds(ctx, requires)\n if (compatibleIds.length === 0) return registry\n\n for (const descriptor of this.toolMethods) {\n const callIdSchema = validator\n .string()\n .valid(...compatibleIds)\n .required()\n .description('ToolCall id of the artifact to query.')\n\n const argsSchema = (\n descriptor.argsSchema ?? validator.object<Record<string, never>>({})\n ).append({\n callId: callIdSchema,\n })\n\n const tool = new ArtifactTool({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: argsSchema,\n ephemeral: true,\n onCollision: 'replace',\n handler: async (rawArgs, ctxInner) => {\n const args = rawArgs as Record<string, unknown> & { callId: string }\n const resolved = resolveArtifactById(ctxInner, args.callId, requires)\n if (!resolved) return `Error: no artifact with id ${args.callId} in this turn`\n const artifact = resolved.artifact\n const methodArgs: unknown[] = []\n if (\n descriptor.method === 'yaml_get' ||\n descriptor.method === 'yaml_filter' ||\n descriptor.method === 'yaml_pluck'\n ) {\n methodArgs.push(args.path as string)\n } else if (descriptor.method === 'yaml_slice') {\n methodArgs.push(args.start as number | undefined, args.end as number | undefined)\n }\n const fn = (artifact as unknown as Record<string, (...a: unknown[]) => unknown>)[\n descriptor.method\n ]\n if (typeof fn !== 'function') {\n return `Error: artifact has no method ${descriptor.method}`\n }\n const result = await Promise.resolve(fn.apply(artifact, methodArgs))\n const serialise = descriptor.serialise ?? defaultSerialise\n return serialise(result)\n },\n })\n registry.register(tool)\n }\n return registry\n }\n\n /**\n * Parses and caches all documents from the artifact.\n *\n * @remarks\n * Uses `js-yaml.loadAll` to extract all documents from the stream. A single-document source\n * yields a one-element array; a multi-document stream yields one element per document. When\n * the constructor declared `multiDocument: false`, `load` is used instead so that a\n * multi-document source is rejected rather than quietly accepted. The parsed result is cached\n * for the lifetime of the instance.\n */\n async #resolveDocs(): Promise<unknown[]> {\n if (this.#docs !== undefined) {\n return this.#docs\n }\n\n const yaml = await getYaml()\n const content = await this.asString()\n try {\n if (this.#options?.multiDocument === false) {\n // The caller asserted this source holds exactly one document. `load` enforces that: it\n // throws \"expected a single document in the stream, but found more\" on a `---` stream,\n // which surfaces below as E_YAML_PARSE_ERROR. Anything weaker would make the option a\n // no-op, which is what it was before.\n this.#docs = [yaml.load(content)]\n } else {\n const loaded = yaml.loadAll(content)\n this.#docs = Array.isArray(loaded) ? loaded : [loaded]\n }\n } catch (err) {\n let detail = isError(err) ? err.message : String(err)\n // Append line and mark information if available for self-correction\n if (isObject(err)) {\n const mark = (err as Record<string, unknown>).mark as Record<string, unknown> | undefined\n if (mark && (mark.line !== undefined || mark.column !== undefined)) {\n const line = typeof mark.line === 'number' ? mark.line + 1 : 0\n const col = typeof mark.column === 'number' ? mark.column + 1 : 0\n detail += ` (line ${line}:${col})`\n }\n }\n throw new E_YAML_PARSE_ERROR([detail])\n }\n return this.#docs\n }\n\n /**\n * Returns whether this artifact contains a single document or multiple documents.\n *\n * @remarks\n * When the constructor was given `multiDocument: true`, the source is treated as a stream and\n * this reports `'multi-document'` even if that stream currently holds one document — a\n * one-element stream is still a stream, and {@link SpooledYamlArtifact.yaml_length} reports the\n * real count either way. `multiDocument: false` cannot disagree with the count, because parsing\n * a `---` stream under it fails outright rather than silently reporting the wrong mode.\n *\n * @returns `'single-document'` or `'multi-document'`.\n */\n async yaml_type(): Promise<'single-document' | 'multi-document'> {\n const docs = await this.#resolveDocs()\n if (this.#options?.multiDocument === true) {\n return 'multi-document'\n }\n return docs.length > 1 ? 'multi-document' : 'single-document'\n }\n\n /**\n * Returns the top-level keys of the parsed content.\n *\n * @remarks\n * For single-document: returns the keys of the root object, or `undefined` when the root\n * is not a plain object.\n * For multi-document: returns the union of keys across all documents that are plain objects.\n * Duplicate keys are deduplicated.\n *\n * @returns Array of key strings, or `undefined` when no object keys are present.\n */\n async yaml_keys(): Promise<string[] | undefined> {\n const docs = await this.#resolveDocs()\n const keySet = new Set<string>()\n\n for (const doc of docs) {\n if (isObject(doc)) {\n for (const key of Object.keys(doc as object)) {\n keySet.add(key)\n }\n }\n }\n\n return keySet.size > 0 ? Array.from(keySet) : undefined\n }\n\n /**\n * Returns the total number of documents in the artifact.\n *\n * @remarks\n * The result comes directly from js-yaml.loadAll(). For sources with no actual YAML content\n * (empty, whitespace-only, or BOM-only), the parser typically returns 0 documents, but certain\n * whitespace arrangements (such as a bare double newline) may yield 1. Do not rely on the exact\n * count to test for emptiness. For real documents, the count is reliable: a single-document\n * YAML returns 1, and a `---`-separated stream returns its exact document count.\n *\n * @returns The document count.\n */\n async yaml_length(): Promise<number> {\n const docs = await this.#resolveDocs()\n return docs.length\n }\n\n /**\n * Evaluates a JSONPath expression against the parsed documents.\n *\n * @remarks\n * For single-document: evaluates the expression against the root value.\n * For multi-document: evaluates the expression against each document and returns a flat\n * array of all matches across all documents.\n *\n * Uses [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath). Full JSONPath syntax is\n * supported.\n *\n * @param path - A JSONPath expression (e.g. `'$.user.address.city'`, `'$..name'`).\n * @returns Array of matched values. Empty array when no matches are found.\n */\n async yaml_get(path: string): Promise<unknown[]> {\n const docs = await this.#resolveDocs()\n return docs.flatMap((doc) => JSONPath({ path, json: doc as object }))\n }\n\n /**\n * Returns documents matched by a JSONPath filter expression.\n *\n * @remarks\n * Evaluates `path` against each document and returns those for which the expression\n * produces at least one match.\n *\n * @param path - A JSONPath expression (e.g. `'$[?(@.status === \"active\")]'`).\n * @returns Array of matching documents.\n */\n async yaml_filter(path: string): Promise<unknown[]> {\n const docs = await this.#resolveDocs()\n return docs.filter((doc) => {\n const matches = JSONPath({ path, json: doc as object })\n return Array.isArray(matches) && matches.length > 0\n })\n }\n\n /**\n * Returns a slice of documents by index range.\n *\n * @remarks\n * Behaves like `Array.prototype.slice` over the document array.\n *\n * @param start - Start index (inclusive). Defaults to `0`.\n * @param end - End index (exclusive). Defaults to the document count.\n * @returns Array of sliced documents.\n */\n async yaml_slice(start?: number, end?: number): Promise<unknown[]> {\n const docs = await this.#resolveDocs()\n return docs.slice(start, end)\n }\n\n /**\n * Returns all values matched by a JSONPath expression across every document.\n *\n * @remarks\n * Convenience over {@link yaml_get} with an identical signature — use whichever name\n * better communicates intent at the call site.\n *\n * @param path - A JSONPath expression (e.g. `'$..name'`).\n * @returns Array of matched values.\n */\n async yaml_pluck(path: string): Promise<unknown[]> {\n return this.yaml_get(path)\n }\n\n /**\n * Serialise this SpooledYamlArtifact into an `@nhtio/encoder` snapshot.\n *\n * @remarks\n * Overrides {@link SpooledArtifact.[ENCODE_METHOD]} to carry the constructor's `multiDocument`\n * option. The parsed-document cache is derived and not encoded. Round-trips via\n * {@link SpooledYamlArtifact.[DECODE_METHOD]}.\n *\n * @returns A snapshot consumed by {@link SpooledYamlArtifact.[DECODE_METHOD]}.\n */\n [ENCODE_METHOD](): AdkEncodableSnapshot {\n return { reader: this.readerDescriptor(), multiDocument: this.#options?.multiDocument }\n }\n\n /**\n * Reconstruct a {@link SpooledYamlArtifact} from a {@link SpooledYamlArtifact.[ENCODE_METHOD]}\n * snapshot.\n *\n * @param data - The snapshot produced by {@link SpooledYamlArtifact.[ENCODE_METHOD]}.\n * @returns A fresh {@link SpooledYamlArtifact}} backed by a freshly-resolved reader.\n */\n static [DECODE_METHOD](data: AdkEncodableSnapshot): SpooledYamlArtifact {\n const snapshot = data as {\n reader: ReaderDescriptor\n multiDocument?: boolean\n }\n return new SpooledYamlArtifact(resolveSpoolReader(snapshot.reader), {\n multiDocument: snapshot.multiDocument,\n })\n }\n}\n\n/**\n * Replacer for {@link JSON.stringify} that preserves non-finite numbers as YAML tokens.\n *\n * @remarks\n * YAML permits `.NaN`, `.inf`, and `-.inf`. {@link JSON.stringify} silently converts these\n * to `null`, losing the original value. This replacer renders non-finite numbers as their\n * YAML string representations so the information survives the JSON round-trip.\n *\n * @internal\n */\nfunction nonFiniteReplacer(_key: string, value: unknown): unknown {\n if (typeof value === 'number' && !Number.isFinite(value)) {\n return Number.isNaN(value) ? '.NaN' : value > 0 ? '.inf' : '-.inf'\n }\n return value\n}\n\n/**\n * Converter tool: YAML → JSON.\n *\n * @remarks\n * Takes either inline YAML text or a reference to a {@link SpooledYamlArtifact} produced\n * earlier in the turn. Converts to JSON and returns a fresh {@link SpooledJsonArtifact}\n * immediately queryable with JSON artifact tools.\n *\n * Non-finite numbers are preserved as their YAML token strings (`.NaN`, `.inf`, `-.inf`).\n * Undefined values are normalised to the JSON string `'null'`.\n */\nexport const yamlToJsonTool = new Tool({\n name: 'yaml_to_json',\n description:\n 'Convert a YAML document to JSON format. Returns a JSON artifact. Provide inline YAML text or a tool call id of a YAML artifact produced earlier in this turn — not both.',\n inputSchema: validator.object({\n text: validator\n .string()\n .optional()\n .allow('')\n .description('Inline YAML text. Provide this or call_id, not both.'),\n call_id: validator\n .string()\n .optional()\n .allow('')\n .description('ToolCall id of a YAML artifact produced earlier in this turn.'),\n }),\n artifactConstructor: () => SpooledJsonArtifact,\n handler: async (args, ctx) => {\n const { text = '', call_id: callId = '' } = args as { text?: string; call_id?: string }\n const hasText = text.trim().length > 0\n const hasCallId = callId.trim().length > 0\n\n if ((!hasText && !hasCallId) || (hasText && hasCallId)) {\n return 'Error: provide either text or call_id, not both or neither'\n }\n\n let sourceDoc: unknown\n let sourceId: string\n\n if (hasCallId) {\n const resolved = resolveArtifactById(ctx, callId, SpooledYamlArtifact)\n if (!resolved) {\n return `Error: no YAML artifact with id ${callId} in this turn`\n }\n const yaml = await getYaml()\n try {\n const yamlText = await resolved.artifact.asString()\n const loaded = yaml.loadAll(yamlText)\n sourceDoc = Array.isArray(loaded) ? (loaded.length === 1 ? loaded[0] : loaded) : loaded\n sourceId = callId\n } catch (err) {\n let detail = isError(err) ? err.message : String(err)\n if (isObject(err)) {\n const mark = (err as Record<string, unknown>).mark as Record<string, unknown> | undefined\n if (mark && (mark.line !== undefined || mark.column !== undefined)) {\n const line = typeof mark.line === 'number' ? mark.line + 1 : 0\n const col = typeof mark.column === 'number' ? mark.column + 1 : 0\n detail += ` (line ${line}:${col})`\n }\n }\n return `Error: Invalid YAML — ${detail}`\n }\n } else {\n const yaml = await getYaml()\n try {\n const loaded = yaml.loadAll(text)\n sourceDoc = Array.isArray(loaded) ? (loaded.length === 1 ? loaded[0] : loaded) : loaded\n sourceId = uuidv6()\n } catch (err) {\n let detail = isError(err) ? err.message : String(err)\n if (isObject(err)) {\n const mark = (err as Record<string, unknown>).mark as Record<string, unknown> | undefined\n if (mark && (mark.line !== undefined || mark.column !== undefined)) {\n const line = typeof mark.line === 'number' ? mark.line + 1 : 0\n const col = typeof mark.column === 'number' ? mark.column + 1 : 0\n detail += ` (line ${line}:${col})`\n }\n }\n return `Error: Invalid YAML — ${detail}`\n }\n }\n\n // Normalise undefined to 'null' string\n const jsonStr =\n sourceDoc === undefined ? 'null' : JSON.stringify(sourceDoc, nonFiniteReplacer, 2)\n const reader = await ctx.storeRetrievableBytes(`${ctx.id}:yaml_to_json:${sourceId}`, jsonStr)\n return new SpooledJsonArtifact(reader)\n },\n})\n\n/**\n * Converter tool: JSON → YAML.\n *\n * @remarks\n * Takes either inline JSON text or a reference to a {@link SpooledJsonArtifact} produced\n * earlier in the turn. Converts to YAML and returns a fresh {@link SpooledYamlArtifact}}\n * immediately queryable with YAML artifact tools.\n */\nexport const jsonToYamlTool = new Tool({\n name: 'json_to_yaml',\n description:\n 'Convert a JSON document to YAML format. Returns a YAML artifact. Provide inline JSON text or a tool call id of a JSON artifact produced earlier in this turn — not both.',\n inputSchema: validator.object({\n text: validator\n .string()\n .optional()\n .allow('')\n .description('Inline JSON text. Provide this or call_id, not both.'),\n call_id: validator\n .string()\n .optional()\n .allow('')\n .description('ToolCall id of a JSON artifact produced earlier in this turn.'),\n }),\n artifactConstructor: () => SpooledYamlArtifact,\n handler: async (args, ctx) => {\n const { text = '', call_id: callId = '' } = args as { text?: string; call_id?: string }\n const hasText = text.trim().length > 0\n const hasCallId = callId.trim().length > 0\n\n if ((!hasText && !hasCallId) || (hasText && hasCallId)) {\n return 'Error: provide either text or call_id, not both or neither'\n }\n\n let sourceData: unknown\n let sourceId: string\n\n if (hasCallId) {\n const resolved = resolveArtifactById(ctx, callId, SpooledJsonArtifact)\n if (!resolved) {\n return `Error: no JSON artifact with id ${callId} in this turn`\n }\n try {\n const jsonText = await resolved.artifact.asString()\n sourceData = JSON.parse(jsonText)\n sourceId = callId\n } catch (err) {\n return `Error: Invalid JSON — ${isError(err) ? err.message : String(err)}`\n }\n } else {\n try {\n sourceData = JSON.parse(text)\n sourceId = uuidv6()\n } catch (err) {\n return `Error: Invalid JSON — ${isError(err) ? err.message : String(err)}`\n }\n }\n\n const yaml = await getYaml()\n const yamlStr = yaml.dump(sourceData, { indent: 2 })\n const reader = await ctx.storeRetrievableBytes(`${ctx.id}:json_to_yaml:${sourceId}`, yamlStr)\n return new SpooledYamlArtifact(reader)\n },\n})\n\n// Re-export exceptions\nexport { E_YAML_PARSE_ERROR, E_YAML_PEER_MISSING }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"yaml-BPBoiOjx.mjs","names":["#options","#resolveDocs","#docs"],"sources":["../src/batteries/artifacts/yaml/exceptions.ts","../src/batteries/artifacts/yaml/index.ts"],"sourcesContent":["import { createException } from '@nhtio/adk/factories'\n\n/**\n * Thrown when YAML parsing fails due to invalid syntax.\n *\n * @remarks\n * The exception message includes the parser's original error reason and line/mark information\n * when available, which enables the model to self-correct malformed YAML.\n */\nexport const E_YAML_PARSE_ERROR = createException<[string]>(\n 'E_YAML_PARSE_ERROR',\n 'YAML parse error: %s',\n 'E_YAML_PARSE_ERROR',\n 422\n)\n\n/**\n * Thrown when the js-yaml peer dependency is missing or fails to load.\n *\n * @remarks\n * This occurs when the battery's consumer has not installed the optional js-yaml peer\n * dependency. The message template includes the package name, a description of its purpose,\n * the underlying error, and the exact install command, so the consumer sees a complete,\n * actionable message regardless of call site.\n */\nexport const E_YAML_PEER_MISSING = createException<[string]>(\n 'E_YAML_PEER_MISSING',\n 'the yaml battery could not load its peer dependency \"js-yaml\" (needed for YAML format artifact queries): %s — install it (pnpm add js-yaml)',\n 'E_YAML_PEER_MISSING',\n 500\n)\n","/**\n * YAML artifact battery: {@link SpooledYamlArtifact} and bidirectional converters.\n *\n * @remarks\n * Provides structured query tools for YAML documents, both single-document and\n * multi-document streams. Includes converter tools to transform between YAML and JSON\n * representations without materialising the artifact contents.\n *\n * Requires the optional peer `js-yaml@^4.1.1`. Install with:\n * ```\n * pnpm add js-yaml\n * ```\n *\n * Note: `decode()` on `SpooledYamlArtifact` instances throws until\n * `registerArtifactEncodables()` has been called.\n *\n * @module @nhtio/adk/batteries/artifacts/yaml\n */\n\nimport { v6 as uuidv6 } from 'uuid'\nimport { JSONPath } from 'jsonpath-plus'\nimport { validator } from '@nhtio/validation'\nimport { resolveSpoolReader } from '@nhtio/adk/common'\nimport { isInstanceOf, isError, isObject } from '@nhtio/adk/guards'\nimport { E_YAML_PARSE_ERROR, E_YAML_PEER_MISSING } from './exceptions'\nimport {\n Tool,\n ArtifactTool,\n ToolRegistry,\n SpooledJsonArtifact,\n ReaderDescriptor,\n} from '@nhtio/adk/common'\n\nimport {\n collectArtifactCompatibleIds,\n resolveArtifactById,\n defaultSerialise,\n SpooledArtifact,\n} from '@nhtio/adk/spooled_artifact'\nimport type { SpoolReader } from '@nhtio/adk/common'\nimport type { ToolMethodDescriptor, DispatchContext } from '@nhtio/adk/types'\n\n// Well-known @nhtio/encoder contract keys, resolved through the global symbol registry.\n// These are identical to the symbols core uses, with no import edge on the optional peer.\nconst ENCODE_METHOD: unique symbol = Symbol.for('@nhtio/encoder:toEncoded')\nconst DECODE_METHOD: unique symbol = Symbol.for('@nhtio/encoder:fromEncoded')\n\n/** Snapshot payload for the encoder contract; the encoder treats it as opaque. */\ntype AdkEncodableSnapshot = unknown\n\n/**\n * Lazy-loaded promise for the js-yaml module.\n *\n * @remarks\n * Caches the result to avoid repeated import attempts. If the import fails, the exception\n * is thrown on subsequent access rather than re-importing.\n */\nlet yamlPromise:\n | Promise<{\n load: (content: string) => unknown\n loadAll: (content: string) => unknown[]\n dump: (data: unknown, options?: Record<string, unknown>) => string\n }>\n | undefined\n\n/**\n * Lazy-loads and caches the js-yaml module.\n *\n * @returns The loaded `js-yaml` module.\n * @throws {@link E_YAML_PEER_MISSING} if the module fails to load.\n */\nasync function getYaml() {\n yamlPromise ??= import('js-yaml').catch((err) => {\n throw new E_YAML_PEER_MISSING([isError(err) ? err.message : String(err)])\n })\n return yamlPromise\n}\n\n/**\n * A {@link SpooledArtifact} specialisation that adds YAML-aware read operations.\n *\n * @remarks\n * Handles both single-document YAML and multi-document streams (delimited by `---`).\n * Parsed documents are cached in a private field for the lifetime of the instance.\n *\n * For multi-document streams:\n * - `yaml_length` reports the document count.\n * - `yaml_keys` returns the deduplicated union of keys across all documents.\n * - `yaml_get` / `yaml_filter` / `yaml_pluck` evaluate paths against all documents and return\n * a flat array of all matches.\n *\n * Non-finite numbers (`.NaN`, `.inf`, `-.inf`) present in the YAML are preserved through the\n * `yaml_to_json` converter using a custom replacer.\n */\nexport class SpooledYamlArtifact extends SpooledArtifact {\n #docs: unknown[] | undefined\n\n /**\n * @param reader - The backing store to read from.\n * @param options - Optional configuration for parsing.\n * @param options.multiDocument - Declares the source's document mode. `true` parses as a\n * stream and makes {@link SpooledYamlArtifact.yaml_type} report `'multi-document'` regardless\n * of the current count. `false` asserts exactly one document and parses with `load`, so a\n * `---` stream raises `E_YAML_PARSE_ERROR` instead of being silently accepted. When omitted,\n * mode is auto-detected\n * by parsing the content with `loadAll`.\n */\n constructor(reader: SpoolReader, options?: { multiDocument?: boolean }) {\n super(reader)\n this.#options = options\n }\n\n #options: { multiDocument?: boolean } | undefined\n\n /**\n * Returns `true` if `value` is a {@link SpooledYamlArtifact} instance.\n *\n * @remarks\n * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard. Safe against the\n * dual-module-copy case where two distinct `SpooledYamlArtifact` classes coexist in the\n * same realm.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link SpooledYamlArtifact} instance.\n */\n public static isSpooledYamlArtifact(value: unknown): value is SpooledYamlArtifact {\n return isInstanceOf(value, 'SpooledYamlArtifact', SpooledYamlArtifact)\n }\n\n /**\n * The YAML-specific artifact-query descriptors this class adds on top of the base set.\n *\n * @remarks\n * Lists `artifact_yaml_type`, `artifact_yaml_keys`, `artifact_yaml_length`,\n * `artifact_yaml_get`, `artifact_yaml_filter`, `artifact_yaml_slice`, `artifact_yaml_pluck`.\n * The base seven descriptors (`artifact_head`, etc.) are NOT included here — they are\n * forged separately by {@link SpooledYamlArtifact.forgeTools}.\n */\n public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n {\n name: 'artifact_yaml_type',\n method: 'yaml_type',\n description:\n 'Return the YAML type (single-document or multi-document) of an artifact produced earlier in this turn.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_yaml_keys',\n method: 'yaml_keys',\n description:\n 'Return the top-level keys of a YAML artifact produced earlier in this turn; for multi-document streams, the deduplicated union across all documents.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_yaml_length',\n method: 'yaml_length',\n description:\n 'Return the document count of a YAML artifact produced earlier in this turn. The count comes from js-yaml parsing; for sources with no actual YAML content (empty, whitespace, or BOM), the result is typically 0 but may be 1 depending on whitespace arrangement. For real YAML documents or multi-document streams separated by ---, the count is exact.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_yaml_get',\n method: 'yaml_get',\n description:\n 'Evaluate a JSONPath expression against a YAML artifact produced earlier in this turn.',\n argsSchema: validator.object({\n path: validator.string().required().description(\"JSONPath expression, e.g. '$.user.name'.\"),\n }),\n },\n {\n name: 'artifact_yaml_filter',\n method: 'yaml_filter',\n description:\n 'Return records of a YAML artifact (produced earlier in this turn) matched by a JSONPath filter.',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description('JSONPath filter expression, e.g. \\'$[?(@.status === \"active\")]\\'.'),\n }),\n },\n {\n name: 'artifact_yaml_slice',\n method: 'yaml_slice',\n description:\n 'Return a slice of documents by index range from a YAML artifact produced earlier in this turn.',\n argsSchema: validator.object({\n start: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start index (inclusive).'),\n end: validator.number().integer().min(0).optional().description('End index (exclusive).'),\n }),\n },\n {\n name: 'artifact_yaml_pluck',\n method: 'yaml_pluck',\n description:\n 'Return all values matched by a JSONPath expression across every document of a YAML artifact produced earlier in this turn.',\n argsSchema: validator.object({\n path: validator.string().required().description(\"JSONPath expression, e.g. '$..name'.\"),\n }),\n },\n ])\n\n /**\n * Forges base-class tools plus YAML-specific tools narrowed to {@link SpooledYamlArtifact}.\n *\n * @remarks\n * Standard subclass extension pattern: call `SpooledArtifact.forgeTools(ctx)` to produce\n * the base seven `artifact_*` tools narrowed to any `SpooledArtifact` in the turn, then\n * register one `ArtifactTool` per YAML-specific descriptor narrowed to YAML artifacts.\n */\n public static override forgeTools(ctx: DispatchContext): ToolRegistry {\n const registry = SpooledArtifact.forgeTools(ctx)\n const requires = SpooledYamlArtifact\n const compatibleIds = collectArtifactCompatibleIds(ctx, requires)\n if (compatibleIds.length === 0) return registry\n\n for (const descriptor of this.toolMethods) {\n const callIdSchema = validator\n .string()\n .valid(...compatibleIds)\n .required()\n .description('ToolCall id of the artifact to query.')\n\n const argsSchema = (\n descriptor.argsSchema ?? validator.object<Record<string, never>>({})\n ).append({\n callId: callIdSchema,\n })\n\n const tool = new ArtifactTool({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: argsSchema,\n ephemeral: true,\n onCollision: 'replace',\n handler: async (rawArgs, ctxInner) => {\n const args = rawArgs as Record<string, unknown> & { callId: string }\n const resolved = resolveArtifactById(ctxInner, args.callId, requires)\n if (!resolved) return `Error: no artifact with id ${args.callId} in this turn`\n const artifact = resolved.artifact\n const methodArgs: unknown[] = []\n if (\n descriptor.method === 'yaml_get' ||\n descriptor.method === 'yaml_filter' ||\n descriptor.method === 'yaml_pluck'\n ) {\n methodArgs.push(args.path as string)\n } else if (descriptor.method === 'yaml_slice') {\n methodArgs.push(args.start as number | undefined, args.end as number | undefined)\n }\n const fn = (artifact as unknown as Record<string, (...a: unknown[]) => unknown>)[\n descriptor.method\n ]\n if (typeof fn !== 'function') {\n return `Error: artifact has no method ${descriptor.method}`\n }\n const result = await Promise.resolve(fn.apply(artifact, methodArgs))\n const serialise = descriptor.serialise ?? defaultSerialise\n return serialise(result)\n },\n })\n registry.register(tool)\n }\n return registry\n }\n\n /**\n * Parses and caches all documents from the artifact.\n *\n * @remarks\n * Uses `js-yaml.loadAll` to extract all documents from the stream. A single-document source\n * yields a one-element array; a multi-document stream yields one element per document. When\n * the constructor declared `multiDocument: false`, `load` is used instead so that a\n * multi-document source is rejected rather than quietly accepted. The parsed result is cached\n * for the lifetime of the instance.\n */\n async #resolveDocs(): Promise<unknown[]> {\n if (this.#docs !== undefined) {\n return this.#docs\n }\n\n const yaml = await getYaml()\n const content = await this.asString()\n try {\n if (this.#options?.multiDocument === false) {\n // The caller asserted this source holds exactly one document. `load` enforces that: it\n // throws \"expected a single document in the stream, but found more\" on a `---` stream,\n // which surfaces below as E_YAML_PARSE_ERROR. Anything weaker would make the option a\n // no-op, which is what it was before.\n this.#docs = [yaml.load(content)]\n } else {\n const loaded = yaml.loadAll(content)\n this.#docs = Array.isArray(loaded) ? loaded : [loaded]\n }\n } catch (err) {\n let detail = isError(err) ? err.message : String(err)\n // Append line and mark information if available for self-correction\n if (isObject(err)) {\n const mark = (err as Record<string, unknown>).mark as Record<string, unknown> | undefined\n if (mark && (mark.line !== undefined || mark.column !== undefined)) {\n const line = typeof mark.line === 'number' ? mark.line + 1 : 0\n const col = typeof mark.column === 'number' ? mark.column + 1 : 0\n detail += ` (line ${line}:${col})`\n }\n }\n throw new E_YAML_PARSE_ERROR([detail])\n }\n return this.#docs\n }\n\n /**\n * Returns whether this artifact contains a single document or multiple documents.\n *\n * @remarks\n * When the constructor was given `multiDocument: true`, the source is treated as a stream and\n * this reports `'multi-document'` even if that stream currently holds one document — a\n * one-element stream is still a stream, and {@link SpooledYamlArtifact.yaml_length} reports the\n * real count either way. `multiDocument: false` cannot disagree with the count, because parsing\n * a `---` stream under it fails outright rather than silently reporting the wrong mode.\n *\n * @returns `'single-document'` or `'multi-document'`.\n */\n async yaml_type(): Promise<'single-document' | 'multi-document'> {\n const docs = await this.#resolveDocs()\n if (this.#options?.multiDocument === true) {\n return 'multi-document'\n }\n return docs.length > 1 ? 'multi-document' : 'single-document'\n }\n\n /**\n * Returns the top-level keys of the parsed content.\n *\n * @remarks\n * For single-document: returns the keys of the root object, or `undefined` when the root\n * is not a plain object.\n * For multi-document: returns the union of keys across all documents that are plain objects.\n * Duplicate keys are deduplicated.\n *\n * @returns Array of key strings, or `undefined` when no object keys are present.\n */\n async yaml_keys(): Promise<string[] | undefined> {\n const docs = await this.#resolveDocs()\n const keySet = new Set<string>()\n\n for (const doc of docs) {\n if (isObject(doc)) {\n for (const key of Object.keys(doc as object)) {\n keySet.add(key)\n }\n }\n }\n\n return keySet.size > 0 ? Array.from(keySet) : undefined\n }\n\n /**\n * Returns the total number of documents in the artifact.\n *\n * @remarks\n * The result comes directly from js-yaml.loadAll(). For sources with no actual YAML content\n * (empty, whitespace-only, or BOM-only), the parser typically returns 0 documents, but certain\n * whitespace arrangements (such as a bare double newline) may yield 1. Do not rely on the exact\n * count to test for emptiness. For real documents, the count is reliable: a single-document\n * YAML returns 1, and a `---`-separated stream returns its exact document count.\n *\n * @returns The document count.\n */\n async yaml_length(): Promise<number> {\n const docs = await this.#resolveDocs()\n return docs.length\n }\n\n /**\n * Evaluates a JSONPath expression against the parsed documents.\n *\n * @remarks\n * For single-document: evaluates the expression against the root value.\n * For multi-document: evaluates the expression against each document and returns a flat\n * array of all matches across all documents.\n *\n * Uses [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath). Full JSONPath syntax is\n * supported.\n *\n * @param path - A JSONPath expression (e.g. `'$.user.address.city'`, `'$..name'`).\n * @returns Array of matched values. Empty array when no matches are found.\n */\n async yaml_get(path: string): Promise<unknown[]> {\n const docs = await this.#resolveDocs()\n return docs.flatMap((doc) => JSONPath({ path, json: doc as object }))\n }\n\n /**\n * Returns documents matched by a JSONPath filter expression.\n *\n * @remarks\n * Evaluates `path` against each document and returns those for which the expression\n * produces at least one match.\n *\n * @param path - A JSONPath expression (e.g. `'$[?(@.status === \"active\")]'`).\n * @returns Array of matching documents.\n */\n async yaml_filter(path: string): Promise<unknown[]> {\n const docs = await this.#resolveDocs()\n return docs.filter((doc) => {\n const matches = JSONPath({ path, json: doc as object })\n return Array.isArray(matches) && matches.length > 0\n })\n }\n\n /**\n * Returns a slice of documents by index range.\n *\n * @remarks\n * Behaves like `Array.prototype.slice` over the document array.\n *\n * @param start - Start index (inclusive). Defaults to `0`.\n * @param end - End index (exclusive). Defaults to the document count.\n * @returns Array of sliced documents.\n */\n async yaml_slice(start?: number, end?: number): Promise<unknown[]> {\n const docs = await this.#resolveDocs()\n return docs.slice(start, end)\n }\n\n /**\n * Returns all values matched by a JSONPath expression across every document.\n *\n * @remarks\n * Convenience over {@link yaml_get} with an identical signature — use whichever name\n * better communicates intent at the call site.\n *\n * @param path - A JSONPath expression (e.g. `'$..name'`).\n * @returns Array of matched values.\n */\n async yaml_pluck(path: string): Promise<unknown[]> {\n return this.yaml_get(path)\n }\n\n /**\n * Serialise this SpooledYamlArtifact into an `@nhtio/encoder` snapshot.\n *\n * @remarks\n * Overrides {@link SpooledArtifact.[ENCODE_METHOD]} to carry the constructor's `multiDocument`\n * option. The parsed-document cache is derived and not encoded. Round-trips via\n * {@link SpooledYamlArtifact.[DECODE_METHOD]}.\n *\n * @returns A snapshot consumed by {@link SpooledYamlArtifact.[DECODE_METHOD]}.\n */\n [ENCODE_METHOD](): AdkEncodableSnapshot {\n return { reader: this.readerDescriptor(), multiDocument: this.#options?.multiDocument }\n }\n\n /**\n * Reconstruct a {@link SpooledYamlArtifact} from a {@link SpooledYamlArtifact.[ENCODE_METHOD]}\n * snapshot.\n *\n * @param data - The snapshot produced by {@link SpooledYamlArtifact.[ENCODE_METHOD]}.\n * @returns A fresh {@link SpooledYamlArtifact}} backed by a freshly-resolved reader.\n */\n static [DECODE_METHOD](data: AdkEncodableSnapshot): SpooledYamlArtifact {\n const snapshot = data as {\n reader: ReaderDescriptor\n multiDocument?: boolean\n }\n return new SpooledYamlArtifact(resolveSpoolReader(snapshot.reader), {\n multiDocument: snapshot.multiDocument,\n })\n }\n}\n\n/**\n * Replacer for {@link JSON.stringify} that preserves non-finite numbers as YAML tokens.\n *\n * @remarks\n * YAML permits `.NaN`, `.inf`, and `-.inf`. {@link JSON.stringify} silently converts these\n * to `null`, losing the original value. This replacer renders non-finite numbers as their\n * YAML string representations so the information survives the JSON round-trip.\n *\n * @internal\n */\nfunction nonFiniteReplacer(_key: string, value: unknown): unknown {\n if (typeof value === 'number' && !Number.isFinite(value)) {\n return Number.isNaN(value) ? '.NaN' : value > 0 ? '.inf' : '-.inf'\n }\n return value\n}\n\n/**\n * Converter tool: YAML → JSON.\n *\n * @remarks\n * Takes either inline YAML text or a reference to a {@link SpooledYamlArtifact} produced\n * earlier in the turn. Converts to JSON and returns a fresh {@link SpooledJsonArtifact}\n * immediately queryable with JSON artifact tools.\n *\n * Non-finite numbers are preserved as their YAML token strings (`.NaN`, `.inf`, `-.inf`).\n * Undefined values are normalised to the JSON string `'null'`.\n */\nexport const yamlToJsonTool = new Tool({\n name: 'yaml_to_json',\n description:\n 'Convert a YAML document to JSON format. Returns a JSON artifact. Provide inline YAML text or a tool call id of a YAML artifact produced earlier in this turn — not both.',\n inputSchema: validator.object({\n text: validator\n .string()\n .optional()\n .allow('')\n .description('Inline YAML text. Provide this or call_id, not both.'),\n call_id: validator\n .string()\n .optional()\n .allow('')\n .description('ToolCall id of a YAML artifact produced earlier in this turn.'),\n }),\n artifactConstructor: () => SpooledJsonArtifact,\n handler: async (args, ctx) => {\n const { text = '', call_id: callId = '' } = args as { text?: string; call_id?: string }\n const hasText = text.trim().length > 0\n const hasCallId = callId.trim().length > 0\n\n if ((!hasText && !hasCallId) || (hasText && hasCallId)) {\n return 'Error: provide either text or call_id, not both or neither'\n }\n\n let sourceDoc: unknown\n let sourceId: string\n\n if (hasCallId) {\n const resolved = resolveArtifactById(ctx, callId, SpooledYamlArtifact)\n if (!resolved) {\n return `Error: no YAML artifact with id ${callId} in this turn`\n }\n const yaml = await getYaml()\n try {\n const yamlText = await resolved.artifact.asString()\n const loaded = yaml.loadAll(yamlText)\n sourceDoc = Array.isArray(loaded) ? (loaded.length === 1 ? loaded[0] : loaded) : loaded\n sourceId = callId\n } catch (err) {\n let detail = isError(err) ? err.message : String(err)\n if (isObject(err)) {\n const mark = (err as Record<string, unknown>).mark as Record<string, unknown> | undefined\n if (mark && (mark.line !== undefined || mark.column !== undefined)) {\n const line = typeof mark.line === 'number' ? mark.line + 1 : 0\n const col = typeof mark.column === 'number' ? mark.column + 1 : 0\n detail += ` (line ${line}:${col})`\n }\n }\n return `Error: Invalid YAML — ${detail}`\n }\n } else {\n const yaml = await getYaml()\n try {\n const loaded = yaml.loadAll(text)\n sourceDoc = Array.isArray(loaded) ? (loaded.length === 1 ? loaded[0] : loaded) : loaded\n sourceId = uuidv6()\n } catch (err) {\n let detail = isError(err) ? err.message : String(err)\n if (isObject(err)) {\n const mark = (err as Record<string, unknown>).mark as Record<string, unknown> | undefined\n if (mark && (mark.line !== undefined || mark.column !== undefined)) {\n const line = typeof mark.line === 'number' ? mark.line + 1 : 0\n const col = typeof mark.column === 'number' ? mark.column + 1 : 0\n detail += ` (line ${line}:${col})`\n }\n }\n return `Error: Invalid YAML — ${detail}`\n }\n }\n\n // Normalise undefined to 'null' string\n const jsonStr =\n sourceDoc === undefined ? 'null' : JSON.stringify(sourceDoc, nonFiniteReplacer, 2)\n const reader = await ctx.storeRetrievableBytes(`${ctx.id}:yaml_to_json:${sourceId}`, jsonStr)\n return new SpooledJsonArtifact(reader)\n },\n})\n\n/**\n * Converter tool: JSON → YAML.\n *\n * @remarks\n * Takes either inline JSON text or a reference to a {@link SpooledJsonArtifact} produced\n * earlier in the turn. Converts to YAML and returns a fresh {@link SpooledYamlArtifact}}\n * immediately queryable with YAML artifact tools.\n */\nexport const jsonToYamlTool = new Tool({\n name: 'json_to_yaml',\n description:\n 'Convert a JSON document to YAML format. Returns a YAML artifact. Provide inline JSON text or a tool call id of a JSON artifact produced earlier in this turn — not both.',\n inputSchema: validator.object({\n text: validator\n .string()\n .optional()\n .allow('')\n .description('Inline JSON text. Provide this or call_id, not both.'),\n call_id: validator\n .string()\n .optional()\n .allow('')\n .description('ToolCall id of a JSON artifact produced earlier in this turn.'),\n }),\n artifactConstructor: () => SpooledYamlArtifact,\n handler: async (args, ctx) => {\n const { text = '', call_id: callId = '' } = args as { text?: string; call_id?: string }\n const hasText = text.trim().length > 0\n const hasCallId = callId.trim().length > 0\n\n if ((!hasText && !hasCallId) || (hasText && hasCallId)) {\n return 'Error: provide either text or call_id, not both or neither'\n }\n\n let sourceData: unknown\n let sourceId: string\n\n if (hasCallId) {\n const resolved = resolveArtifactById(ctx, callId, SpooledJsonArtifact)\n if (!resolved) {\n return `Error: no JSON artifact with id ${callId} in this turn`\n }\n try {\n const jsonText = await resolved.artifact.asString()\n sourceData = JSON.parse(jsonText)\n sourceId = callId\n } catch (err) {\n return `Error: Invalid JSON — ${isError(err) ? err.message : String(err)}`\n }\n } else {\n try {\n sourceData = JSON.parse(text)\n sourceId = uuidv6()\n } catch (err) {\n return `Error: Invalid JSON — ${isError(err) ? err.message : String(err)}`\n }\n }\n\n const yaml = await getYaml()\n const yamlStr = yaml.dump(sourceData, { indent: 2 })\n const reader = await ctx.storeRetrievableBytes(`${ctx.id}:json_to_yaml:${sourceId}`, yamlStr)\n return new SpooledYamlArtifact(reader)\n },\n})\n\n// Re-export exceptions\nexport { E_YAML_PARSE_ERROR, E_YAML_PEER_MISSING }\n"],"mappings":"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"}
|