@nhtio/adk 1.20260913.0 → 1.20260924.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 +78 -0
- package/adk-mcp.cjs +2 -2
- package/{arg_specs-iYmIM3wI.js → arg_specs-iYmIM3wI.cjs} +1 -1
- package/arg_specs-iYmIM3wI.cjs.map +1 -0
- package/artifact_methods-7KatxCSd.cjs +1 -0
- package/artifact_methods-q52ETLwI.mjs +1 -0
- package/batteries/artifacts/ecmascript.cjs +2 -2
- package/batteries/artifacts/ecmascript.mjs +1 -1
- package/batteries/artifacts/toon.cjs +2 -2
- package/batteries/artifacts/toon.mjs +1 -1
- package/batteries/artifacts/xml.cjs +2 -2
- package/batteries/artifacts/xml.mjs +1 -1
- package/batteries/artifacts/yaml.cjs +2 -2
- package/batteries/artifacts/yaml.mjs +1 -1
- package/batteries/artifacts.cjs +5 -5
- package/batteries/artifacts.mjs +4 -4
- package/batteries/context/compact/contracts.cjs +1 -1
- package/batteries/context/compact/summarizer.cjs +1 -1
- package/batteries/context/compact.cjs +1 -1
- package/batteries/context/exceptions.cjs +2 -2
- package/batteries/context/thrift/contracts.cjs +1 -1
- package/batteries/context/thrift/relevance.cjs +1 -1
- package/batteries/context/thrift/subtractive_pass.cjs +1 -1
- package/batteries/context/thrift.cjs +1 -1
- package/batteries/context.cjs +1 -1
- package/batteries/dev-tools/conformance.cjs +2 -2
- package/batteries/dev-tools/forge.cjs +5 -5
- package/batteries/dev-tools/forge.mjs +3 -3
- package/batteries/dev-tools.cjs +10 -10
- package/batteries/dev-tools.mjs +3 -3
- package/batteries/embeddings/ollama/adapter.cjs +2 -2
- package/batteries/embeddings/ollama/exceptions.cjs +2 -2
- package/batteries/embeddings/ollama/types.cjs +1 -1
- package/batteries/embeddings/ollama/validation.cjs +1 -1
- package/batteries/embeddings/ollama.cjs +1 -1
- package/batteries/embeddings/openai/adapter.cjs +2 -2
- package/batteries/embeddings/openai/exceptions.cjs +2 -2
- package/batteries/embeddings/openai/helpers.cjs +1 -1
- package/batteries/embeddings/openai/types.cjs +1 -1
- package/batteries/embeddings/openai/validation.cjs +1 -1
- package/batteries/embeddings/openai.cjs +1 -1
- package/batteries/embeddings/transformers_js/adapter.cjs +3 -3
- package/batteries/embeddings/transformers_js/exceptions.cjs +2 -2
- package/batteries/embeddings/transformers_js/pooling.cjs +1 -1
- package/batteries/embeddings/transformers_js/types.cjs +1 -1
- package/batteries/embeddings/transformers_js/validation.cjs +2 -2
- package/batteries/embeddings/transformers_js.cjs +1 -1
- package/batteries/embeddings/webllm/adapter.cjs +2 -2
- package/batteries/embeddings/webllm/exceptions.cjs +2 -2
- package/batteries/embeddings/webllm/types.cjs +1 -1
- package/batteries/embeddings/webllm/validation.cjs +1 -1
- package/batteries/embeddings/webllm.cjs +1 -1
- package/batteries/embeddings.cjs +1 -1
- package/batteries/encoding.cjs +8 -8
- package/batteries/encoding.mjs +6 -6
- package/batteries/generation/_shared.cjs +2 -2
- package/batteries/generation/gemini/adapter.cjs +3 -3
- package/batteries/generation/gemini/adapter.mjs +1 -1
- package/batteries/generation/gemini/exceptions.cjs +2 -2
- package/batteries/generation/gemini/types.cjs +1 -1
- package/batteries/generation/gemini/validation.cjs +1 -1
- package/batteries/generation/gemini.cjs +1 -1
- package/batteries/generation/local_diffusion/adapter.cjs +4 -4
- package/batteries/generation/local_diffusion/adapter.mjs +1 -1
- package/batteries/generation/local_diffusion/exceptions.cjs +2 -2
- package/batteries/generation/local_diffusion/protocol.cjs +2 -2
- package/batteries/generation/local_diffusion/types.cjs +1 -1
- package/batteries/generation/local_diffusion/validation.cjs +1 -1
- package/batteries/generation/local_diffusion.cjs +1 -1
- package/batteries/generation/openai/adapter.cjs +3 -3
- package/batteries/generation/openai/adapter.mjs +1 -1
- package/batteries/generation/openai/exceptions.cjs +2 -2
- package/batteries/generation/openai/types.cjs +1 -1
- package/batteries/generation/openai/validation.cjs +1 -1
- package/batteries/generation/openai.cjs +1 -1
- package/batteries/generation/transformers_js/adapter.cjs +3 -3
- package/batteries/generation/transformers_js/exceptions.cjs +2 -2
- package/batteries/generation/transformers_js/helpers.cjs +1 -1
- package/batteries/generation/transformers_js/types.cjs +1 -1
- package/batteries/generation/transformers_js/validation.cjs +2 -2
- package/batteries/generation/transformers_js.cjs +1 -1
- package/batteries/generation.cjs +1 -1
- package/batteries/isolation/child_process.cjs +3 -3
- package/batteries/isolation.cjs +2 -2
- package/batteries/llm/anthropic_messages/adapter.cjs +10 -10
- package/batteries/llm/anthropic_messages/adapter.mjs +6 -6
- package/batteries/llm/anthropic_messages/count_tokens.cjs +4 -4
- package/batteries/llm/anthropic_messages/count_tokens.mjs +1 -1
- package/batteries/llm/anthropic_messages/error_translation.cjs +2 -2
- package/batteries/llm/anthropic_messages/exceptions.cjs +2 -2
- package/batteries/llm/anthropic_messages/helpers.cjs +4 -4
- package/batteries/llm/anthropic_messages/helpers.mjs +3 -3
- package/batteries/llm/anthropic_messages/types.cjs +1 -1
- package/batteries/llm/anthropic_messages/validation.cjs +3 -3
- package/batteries/llm/anthropic_messages/validation.mjs +1 -1
- package/batteries/llm/anthropic_messages.cjs +4 -4
- package/batteries/llm/anthropic_messages.mjs +2 -2
- package/batteries/llm/bedrock_converse/adapter.cjs +9 -9
- package/batteries/llm/bedrock_converse/adapter.mjs +6 -6
- package/batteries/llm/bedrock_converse/exceptions.cjs +2 -2
- package/batteries/llm/bedrock_converse/helpers.cjs +3 -3
- package/batteries/llm/bedrock_converse/helpers.mjs +1 -1
- package/batteries/llm/bedrock_converse/types.cjs +1 -1
- package/batteries/llm/bedrock_converse/validation.cjs +3 -3
- package/batteries/llm/bedrock_converse/validation.mjs +1 -1
- package/batteries/llm/bedrock_converse.cjs +3 -3
- package/batteries/llm/bedrock_converse.mjs +2 -2
- package/batteries/llm/chat_common/exceptions.cjs +2 -2
- package/batteries/llm/claude_code_cli/adapter.cjs +290 -31
- package/batteries/llm/claude_code_cli/adapter.cjs.map +1 -1
- package/batteries/llm/claude_code_cli/adapter.d.ts +125 -0
- package/batteries/llm/claude_code_cli/adapter.mjs +288 -31
- package/batteries/llm/claude_code_cli/adapter.mjs.map +1 -1
- package/batteries/llm/claude_code_cli/exceptions.cjs +13 -2
- package/batteries/llm/claude_code_cli/exceptions.cjs.map +1 -1
- package/batteries/llm/claude_code_cli/exceptions.d.ts +12 -0
- package/batteries/llm/claude_code_cli/exceptions.mjs +11 -1
- package/batteries/llm/claude_code_cli/exceptions.mjs.map +1 -1
- package/batteries/llm/claude_code_cli/helpers.cjs +4 -4
- package/batteries/llm/claude_code_cli/helpers.mjs +3 -3
- package/batteries/llm/claude_code_cli/index.d.ts +3 -2
- package/batteries/llm/claude_code_cli/types.cjs +1 -1
- package/batteries/llm/claude_code_cli/types.d.ts +36 -2
- package/batteries/llm/claude_code_cli/validation.cjs +4 -3
- package/batteries/llm/claude_code_cli/validation.cjs.map +1 -1
- package/batteries/llm/claude_code_cli/validation.mjs +2 -1
- package/batteries/llm/claude_code_cli/validation.mjs.map +1 -1
- package/batteries/llm/claude_code_cli/wire.cjs +1 -1
- package/batteries/llm/claude_code_cli.cjs +5 -2
- package/batteries/llm/claude_code_cli.mjs +4 -3
- package/batteries/llm/gemini_generate_content/adapter.cjs +9 -9
- package/batteries/llm/gemini_generate_content/adapter.mjs +6 -6
- package/batteries/llm/gemini_generate_content/exceptions.cjs +2 -2
- package/batteries/llm/gemini_generate_content/helpers.cjs +3 -3
- package/batteries/llm/gemini_generate_content/helpers.mjs +1 -1
- package/batteries/llm/gemini_generate_content/types.cjs +1 -1
- package/batteries/llm/gemini_generate_content/validation.cjs +3 -3
- package/batteries/llm/gemini_generate_content/validation.mjs +1 -1
- package/batteries/llm/gemini_generate_content.cjs +2 -2
- package/batteries/llm/gemini_generate_content.mjs +1 -1
- package/batteries/llm/index.d.ts +1 -1
- package/batteries/llm/litert_lm/adapter.cjs +11 -11
- package/batteries/llm/litert_lm/adapter.mjs +6 -6
- package/batteries/llm/litert_lm/exceptions.cjs +2 -2
- package/batteries/llm/litert_lm/helpers.cjs +7 -7
- package/batteries/llm/litert_lm/helpers.mjs +3 -3
- package/batteries/llm/litert_lm/types.cjs +1 -1
- package/batteries/llm/litert_lm/validation.cjs +4 -4
- package/batteries/llm/litert_lm/validation.mjs +2 -2
- package/batteries/llm/litert_lm.cjs +5 -5
- package/batteries/llm/litert_lm.mjs +1 -1
- package/batteries/llm/ollama/adapter.cjs +9 -9
- package/batteries/llm/ollama/adapter.mjs +6 -6
- package/batteries/llm/ollama/exceptions.cjs +2 -2
- package/batteries/llm/ollama/helpers.cjs +5 -5
- package/batteries/llm/ollama/helpers.mjs +4 -4
- package/batteries/llm/ollama/types.cjs +1 -1
- package/batteries/llm/ollama/validation.cjs +3 -3
- package/batteries/llm/ollama/validation.mjs +1 -1
- package/batteries/llm/ollama.cjs +3 -3
- package/batteries/llm/ollama.mjs +2 -2
- package/batteries/llm/openai_chat_completions/adapter.cjs +9 -9
- package/batteries/llm/openai_chat_completions/adapter.mjs +6 -6
- package/batteries/llm/openai_chat_completions/exceptions.cjs +2 -2
- package/batteries/llm/openai_chat_completions/helpers.cjs +5 -5
- package/batteries/llm/openai_chat_completions/helpers.mjs +4 -4
- package/batteries/llm/openai_chat_completions/types.cjs +1 -1
- package/batteries/llm/openai_chat_completions/validation.cjs +3 -3
- package/batteries/llm/openai_chat_completions/validation.mjs +1 -1
- package/batteries/llm/openai_chat_completions.cjs +3 -3
- package/batteries/llm/openai_chat_completions.mjs +2 -2
- package/batteries/llm/openai_responses/adapter.cjs +9 -9
- package/batteries/llm/openai_responses/adapter.mjs +6 -6
- package/batteries/llm/openai_responses/exceptions.cjs +2 -2
- package/batteries/llm/openai_responses/helpers.cjs +4 -4
- package/batteries/llm/openai_responses/helpers.mjs +3 -3
- package/batteries/llm/openai_responses/types.cjs +1 -1
- package/batteries/llm/openai_responses/validation.cjs +3 -3
- package/batteries/llm/openai_responses/validation.mjs +1 -1
- package/batteries/llm/openai_responses.cjs +3 -3
- package/batteries/llm/openai_responses.mjs +2 -2
- package/batteries/llm/transformers_js/adapter.cjs +11 -11
- package/batteries/llm/transformers_js/adapter.mjs +6 -6
- package/batteries/llm/transformers_js/exceptions.cjs +2 -2
- package/batteries/llm/transformers_js/helpers.cjs +8 -8
- package/batteries/llm/transformers_js/helpers.mjs +3 -3
- package/batteries/llm/transformers_js/model_source.cjs +2 -2
- package/batteries/llm/transformers_js/types.cjs +1 -1
- package/batteries/llm/transformers_js/validation.cjs +4 -4
- package/batteries/llm/transformers_js/validation.mjs +2 -2
- package/batteries/llm/transformers_js.cjs +5 -5
- package/batteries/llm/transformers_js.mjs +1 -1
- package/batteries/llm/webllm_chat_completions/adapter.cjs +10 -10
- package/batteries/llm/webllm_chat_completions/adapter.mjs +6 -6
- package/batteries/llm/webllm_chat_completions/exceptions.cjs +2 -2
- package/batteries/llm/webllm_chat_completions/helpers.cjs +2 -2
- package/batteries/llm/webllm_chat_completions/helpers.mjs +1 -1
- package/batteries/llm/webllm_chat_completions/validation.cjs +3 -3
- package/batteries/llm/webllm_chat_completions/validation.mjs +1 -1
- package/batteries/llm/webllm_chat_completions.cjs +3 -3
- package/batteries/llm/webllm_chat_completions.mjs +2 -2
- package/batteries/llm.cjs +4 -3
- package/batteries/llm.mjs +4 -4
- package/batteries/media/contracts.cjs +2 -2
- package/batteries/media/engines/audio_decode.cjs +3 -3
- package/batteries/media/engines/data.cjs +4 -4
- package/batteries/media/engines/exceljs.cjs +4 -4
- package/batteries/media/engines/execa_executor.cjs +3 -3
- package/batteries/media/engines/fs_workspace.cjs +3 -3
- package/batteries/media/engines/jimp.cjs +3 -3
- package/batteries/media/engines/sharp.cjs +3 -3
- package/batteries/media/engines/sheetjs.cjs +6 -6
- package/batteries/media/engines/sheetjs.cjs.map +1 -1
- package/batteries/media/engines/soffice.cjs +2 -2
- package/batteries/media/engines/tesseract_js.cjs +3 -3
- package/batteries/media/engines/transformers_asr.cjs +3 -3
- package/batteries/media/forge.cjs +8 -8
- package/batteries/media/forge.mjs +4 -4
- package/batteries/media/lint.cjs +2 -2
- package/batteries/media/lint.mjs +1 -1
- package/batteries/media.cjs +6 -6
- package/batteries/orchestration/approval.cjs +2 -2
- package/batteries/orchestration/cells/jexl.cjs +3 -3
- package/batteries/orchestration/cells/lua.cjs +3 -3
- package/batteries/orchestration/cells/structured.cjs +3 -3
- package/batteries/orchestration/conformance.cjs +2 -2
- package/batteries/orchestration/dispatch_reasoner.cjs +6 -6
- package/batteries/orchestration/dispatch_reasoner.mjs +4 -4
- package/batteries/orchestration/encoding.cjs +2 -2
- package/batteries/orchestration/executor.cjs +4 -4
- package/batteries/orchestration/executor.mjs +2 -2
- package/batteries/orchestration/forge.cjs +6 -6
- package/batteries/orchestration/forge.mjs +4 -4
- package/batteries/orchestration/in_memory.cjs +1 -1
- package/batteries/orchestration/ops.cjs +1 -1
- package/batteries/orchestration/outline.cjs +2 -2
- package/batteries/orchestration/plan.cjs +1 -1
- package/batteries/orchestration/raw.cjs +2 -2
- package/batteries/orchestration/reason.cjs +1 -1
- package/batteries/orchestration/render.cjs +2 -2
- package/batteries/orchestration/runs.cjs +1 -1
- package/batteries/orchestration/templates.cjs +2 -2
- package/batteries/orchestration/types.cjs +1 -1
- package/batteries/orchestration/validation.cjs +5 -5
- package/batteries/orchestration/validation.mjs +2 -2
- package/batteries/orchestration.cjs +6 -6
- package/batteries/orchestration.mjs +4 -4
- package/batteries/sandbox/js.cjs +7 -7
- package/batteries/sandbox/js.mjs +2 -2
- package/batteries/sandbox/node.cjs +4 -4
- package/batteries/sandbox/tools.cjs +2 -2
- package/batteries/sandbox/tools.mjs +1 -1
- package/batteries/sandbox.cjs +11 -11
- package/batteries/sandbox.mjs +4 -4
- package/batteries/skills/conformance.cjs +1 -1
- package/batteries/skills/in_memory.cjs +2 -2
- package/batteries/skills.cjs +15 -15
- package/batteries/skills.mjs +10 -10
- package/batteries/specialists/_shared.cjs +2 -2
- package/batteries/specialists/caption/transformers_js/adapter.cjs +3 -3
- package/batteries/specialists/caption/transformers_js/exceptions.cjs +2 -2
- package/batteries/specialists/caption/transformers_js/types.cjs +1 -1
- package/batteries/specialists/caption/transformers_js/validation.cjs +2 -2
- package/batteries/specialists/caption/transformers_js.cjs +1 -1
- package/batteries/specialists/caption.cjs +1 -1
- package/batteries/specialists/ocr/tesseract_js/adapter.cjs +3 -3
- package/batteries/specialists/ocr/tesseract_js/exceptions.cjs +2 -2
- package/batteries/specialists/ocr/tesseract_js/types.cjs +1 -1
- package/batteries/specialists/ocr/tesseract_js/validation.cjs +2 -2
- package/batteries/specialists/ocr/tesseract_js.cjs +1 -1
- package/batteries/specialists/ocr.cjs +1 -1
- package/batteries/specialists/stt/transformers_js.cjs +2 -2
- package/batteries/specialists/stt.cjs +2 -2
- package/batteries/specialists.cjs +2 -2
- package/batteries/storage/flydrive.cjs +2 -2
- package/batteries/storage/in_memory.cjs +2 -2
- package/batteries/storage/opfs.cjs +2 -2
- package/batteries/storage.cjs +1 -1
- package/batteries/tools/_shared.cjs +3 -3
- package/batteries/tools/_shared.mjs +1 -1
- package/batteries/tools/color.cjs +3 -3
- package/batteries/tools/color.mjs +2 -2
- package/batteries/tools/comparison.cjs +4 -4
- package/batteries/tools/comparison.mjs +2 -2
- package/batteries/tools/data_structure.cjs +4 -4
- package/batteries/tools/data_structure.mjs +2 -2
- package/batteries/tools/datetime_extended.cjs +4 -4
- package/batteries/tools/datetime_extended.mjs +3 -3
- package/batteries/tools/datetime_math.cjs +4 -4
- package/batteries/tools/datetime_math.mjs +3 -3
- package/batteries/tools/encoding.cjs +4 -4
- package/batteries/tools/encoding.mjs +2 -2
- package/batteries/tools/formatting.cjs +4 -4
- package/batteries/tools/formatting.mjs +2 -2
- package/batteries/tools/geo_basics.cjs +3 -3
- package/batteries/tools/geo_basics.mjs +2 -2
- package/batteries/tools/math.cjs +4 -4
- package/batteries/tools/math.mjs +2 -2
- package/batteries/tools/memory.cjs +7 -7
- package/batteries/tools/memory.mjs +5 -5
- package/batteries/tools/parsing.cjs +5 -5
- package/batteries/tools/parsing.mjs +3 -3
- package/batteries/tools/retrievables.cjs +7 -7
- package/batteries/tools/retrievables.mjs +5 -5
- package/batteries/tools/scrapper.cjs +2 -2
- package/batteries/tools/scrapper.mjs +1 -1
- package/batteries/tools/searxng.cjs +2 -2
- package/batteries/tools/searxng.mjs +1 -1
- package/batteries/tools/standing_instructions.cjs +5 -5
- package/batteries/tools/standing_instructions.mjs +3 -3
- package/batteries/tools/statistics.cjs +5 -5
- package/batteries/tools/statistics.mjs +3 -3
- package/batteries/tools/string_processing.cjs +4 -4
- package/batteries/tools/string_processing.mjs +2 -2
- package/batteries/tools/structured_data.cjs +4 -4
- package/batteries/tools/structured_data.mjs +2 -2
- package/batteries/tools/text_analysis.cjs +4 -4
- package/batteries/tools/text_analysis.mjs +3 -3
- package/batteries/tools/text_comparison.cjs +3 -3
- package/batteries/tools/text_comparison.mjs +2 -2
- package/batteries/tools/time.cjs +4 -4
- package/batteries/tools/time.mjs +3 -3
- package/batteries/tools/unit_conversion.cjs +3 -3
- package/batteries/tools/unit_conversion.mjs +2 -2
- package/batteries/tools/web_retrieval.cjs +2 -2
- package/batteries/tools.cjs +3 -3
- package/batteries/tools.mjs +2 -2
- package/batteries/tts/_shared.cjs +1 -1
- package/batteries/tts/native/adapter.cjs +2 -2
- package/batteries/tts/native/exceptions.cjs +2 -2
- package/batteries/tts/native/helpers.cjs +1 -1
- package/batteries/tts/native/types.cjs +1 -1
- package/batteries/tts/native/validation.cjs +2 -2
- package/batteries/tts/native.cjs +1 -1
- package/batteries/tts/transformers_js/adapter.cjs +3 -3
- package/batteries/tts/transformers_js/exceptions.cjs +2 -2
- package/batteries/tts/transformers_js/types.cjs +1 -1
- package/batteries/tts/transformers_js/validation.cjs +2 -2
- package/batteries/tts/transformers_js.cjs +1 -1
- package/batteries/tts.cjs +1 -1
- package/batteries/validation/exceptions.cjs +2 -2
- package/batteries/validation/types.cjs +1 -1
- package/batteries/validation/validation.cjs +1 -1
- package/batteries/validation.cjs +7 -7
- package/batteries/validation.mjs +5 -5
- package/batteries/vector/arangodb.cjs +2 -2
- package/batteries/vector/builder.cjs +1 -1
- package/batteries/vector/chroma.cjs +1 -1
- package/batteries/vector/clickhouse.cjs +2 -2
- package/batteries/vector/cloudflare.cjs +2 -2
- package/batteries/vector/conformance.cjs +1 -1
- package/batteries/vector/contract.cjs +1 -1
- package/batteries/vector/couchbase.cjs +2 -2
- package/batteries/vector/duckdb.cjs +2 -2
- package/batteries/vector/elasticsearch.cjs +2 -2
- package/batteries/vector/exceptions.cjs +2 -2
- package/batteries/vector/factory.cjs +1 -1
- package/batteries/vector/filters.cjs +2 -2
- package/batteries/vector/helpers.cjs +1 -1
- package/batteries/vector/hnswlib.cjs +2 -2
- package/batteries/vector/in_memory.cjs +1 -1
- package/batteries/vector/lancedb.cjs +2 -2
- package/batteries/vector/mariadb.cjs +2 -2
- package/batteries/vector/meilisearch.cjs +2 -2
- package/batteries/vector/migrate.cjs +2 -2
- package/batteries/vector/milvus.cjs +1 -1
- package/batteries/vector/mongodb.cjs +2 -2
- package/batteries/vector/neo4j.cjs +2 -2
- package/batteries/vector/opensearch.cjs +2 -2
- package/batteries/vector/oracle23ai.cjs +2 -2
- package/batteries/vector/orama.cjs +1 -1
- package/batteries/vector/pgvector.cjs +1 -1
- package/batteries/vector/pinecone.cjs +2 -2
- package/batteries/vector/plan.cjs +1 -1
- package/batteries/vector/qdrant.cjs +1 -1
- package/batteries/vector/redis.cjs +2 -2
- package/batteries/vector/retrievable.cjs +2 -2
- package/batteries/vector/retrievable.mjs +1 -1
- package/batteries/vector/s3vectors.cjs +2 -2
- package/batteries/vector/schema.cjs +1 -1
- package/batteries/vector/solr.cjs +2 -2
- package/batteries/vector/sqlite_vec.cjs +1 -1
- package/batteries/vector/surrealdb.cjs +2 -2
- package/batteries/vector/types.cjs +1 -1
- package/batteries/vector/typesense.cjs +2 -2
- package/batteries/vector/validation.cjs +1 -1
- package/batteries/vector/vector_store_constructor.cjs +1 -1
- package/batteries/vector/vespa.cjs +2 -2
- package/batteries/vector/weaviate.cjs +2 -2
- package/batteries/vector.cjs +1 -1
- package/batteries.cjs +8 -7
- package/batteries.mjs +6 -6
- package/{chat_common-D7SuSLCM.js → chat_common-B7fvGTKv.cjs} +5 -5
- package/chat_common-B7fvGTKv.cjs.map +1 -0
- package/{chat_common-CJskWIdB.mjs → chat_common-CeoHwSsz.mjs} +2 -2
- package/{chat_common-CJskWIdB.mjs.map → chat_common-CeoHwSsz.mjs.map} +1 -1
- package/claude-code-cli-wrapper.cjs +2 -2
- package/{common-Cb1h54HM.js → common-7gCR3zQu.cjs} +9 -9
- package/common-7gCR3zQu.cjs.map +1 -0
- package/{common-AhsMepUS.mjs → common-B5maOoF_.mjs} +7 -7
- package/{common-AhsMepUS.mjs.map → common-B5maOoF_.mjs.map} +1 -1
- package/{common-BuVhq_3h.js → common-BuVhq_3h.cjs} +1 -1
- package/common-BuVhq_3h.cjs.map +1 -0
- package/common.cjs +8 -8
- package/common.mjs +6 -6
- package/{conformance-T1qEg8Sv.js → conformance-T1qEg8Sv.cjs} +1 -1
- package/conformance-T1qEg8Sv.cjs.map +1 -0
- package/{dispatch_runner-CUOD_SAg.mjs → dispatch_runner-DO7jo_gl.mjs} +5 -5
- package/{dispatch_runner-CUOD_SAg.mjs.map → dispatch_runner-DO7jo_gl.mjs.map} +1 -1
- package/{dispatch_runner-BOfUNRv3.js → dispatch_runner-FlriTyoq.cjs} +7 -7
- package/dispatch_runner-FlriTyoq.cjs.map +1 -0
- package/dispatch_runner.cjs +2 -2
- package/dispatch_runner.mjs +1 -1
- package/{ecmascript-C13G-sie.js → ecmascript-BydSB03Y.cjs} +5 -5
- package/ecmascript-BydSB03Y.cjs.map +1 -0
- package/{ecmascript-qssVTISd.mjs → ecmascript-bgwVyZG1.mjs} +3 -3
- package/{ecmascript-qssVTISd.mjs.map → ecmascript-bgwVyZG1.mjs.map} +1 -1
- package/{error_translation-BCa4wxUL.js → error_translation-D8Ea1_th.cjs} +2 -2
- package/error_translation-D8Ea1_th.cjs.map +1 -0
- package/{escape-COeB923i.js → escape-C12OWStb.cjs} +3 -3
- package/escape-C12OWStb.cjs.map +1 -0
- package/eslint/rules/artifact_tool_forbids_artifact_constructor.cjs +2 -2
- package/eslint/rules/no_model_in_tool_handler.cjs +2 -2
- package/eslint/rules/require_string_empty_disposition.cjs +2 -2
- package/eslint/rules/require_validator_any_required.cjs +2 -2
- package/eslint/rules/thought_payload_requires_replay_tag.cjs +2 -2
- package/eslint/rules/token_encoding_requires_context_window.cjs +2 -2
- package/eslint/rules.cjs +2 -2
- package/eslint/rules.mjs +1 -1
- package/eslint.cjs +3 -3
- package/eslint.mjs +2 -2
- package/{exceptions-Dlw1Jr6E.js → exceptions-Bc1s_ld5.cjs} +2 -2
- package/exceptions-Bc1s_ld5.cjs.map +1 -0
- package/{exceptions-BY1RQNVP.js → exceptions-BwGzlXoz.cjs} +2 -2
- package/exceptions-BwGzlXoz.cjs.map +1 -0
- package/{exceptions-DrHnAGQz.js → exceptions-DrHnAGQz.cjs} +1 -1
- package/exceptions-DrHnAGQz.cjs.map +1 -0
- package/exceptions.cjs +3 -3
- package/factories.cjs +2 -2
- package/forge.cjs +3 -3
- package/forge.mjs +2 -2
- package/{formats-DZVuqZUN.js → formats-DZVuqZUN.cjs} +1 -1
- package/formats-DZVuqZUN.cjs.map +1 -0
- package/{fs_node-WwUEiuo6.js → fs_node-XvgZtNJV.cjs} +2 -2
- package/fs_node-XvgZtNJV.cjs.map +1 -0
- package/{function_serializer-ChL2I8Kq.js → function_serializer-D1Kyicai.cjs} +3 -3
- package/function_serializer-D1Kyicai.cjs.map +1 -0
- package/{gpu_budget-BBIUyLoj.js → gpu_budget-BBIUyLoj.cjs} +1 -1
- package/gpu_budget-BBIUyLoj.cjs.map +1 -0
- package/{guards-05Uq3J4M.js → guards-5-XmJgD2.cjs} +2 -2
- package/guards-5-XmJgD2.cjs.map +1 -0
- package/guards.cjs +10 -10
- package/guards.mjs +7 -7
- package/{helpers-So6bNfJp.mjs → helpers-C1T0DV8Q.mjs} +3 -3
- package/{helpers-So6bNfJp.mjs.map → helpers-C1T0DV8Q.mjs.map} +1 -1
- package/{helpers-C_1dcP_X.js → helpers-Dcp4CrOz.cjs} +4 -4
- package/helpers-Dcp4CrOz.cjs.map +1 -0
- package/index.cjs +14 -14
- package/index.mjs +11 -11
- package/{isolation-7Jrcucgc.js → isolation-B01xCIoV.cjs} +5 -5
- package/isolation-B01xCIoV.cjs.map +1 -0
- package/lib/classes/identity.d.ts +6 -3
- package/lib/helpers/bignum.cjs +1 -1
- package/lib/utils/audio.cjs +1 -1
- package/lib/utils/retry.cjs +1 -1
- package/{lifecycle-vYQJ2rmf.js → lifecycle-vYQJ2rmf.cjs} +1 -1
- package/lifecycle-vYQJ2rmf.cjs.map +1 -0
- package/{manifest-iMAmSDay.js → manifest-IP1IOJcg.cjs} +4 -4
- package/manifest-IP1IOJcg.cjs.map +1 -0
- package/mcp/adk-docs-corpus.json +2 -2
- package/package.json +478 -478
- package/{patch-BXX9Q0FM.js → patch-BXX9Q0FM.cjs} +1 -1
- package/patch-BXX9Q0FM.cjs.map +1 -0
- package/{predicates-f3wvKYT8.js → predicates-Bzaa7gNI.cjs} +3 -3
- package/predicates-Bzaa7gNI.cjs.map +1 -0
- package/{retrievable-CksTfjbY.js → retrievable-BBwiACtw.cjs} +5 -5
- package/retrievable-BBwiACtw.cjs.map +1 -0
- package/{retrievable-HjKe5mOD.mjs → retrievable-CrGKx4sc.mjs} +3 -3
- package/{retrievable-HjKe5mOD.mjs.map → retrievable-CrGKx4sc.mjs.map} +1 -1
- package/{sandbox-utils-DLCceTeU.js → sandbox-utils-D12AZhWE.cjs} +2 -2
- package/sandbox-utils-D12AZhWE.cjs.map +1 -0
- package/{scrapper-CkooTUAD.js → scrapper-BibKj8qE.cjs} +6 -6
- package/scrapper-BibKj8qE.cjs.map +1 -0
- package/{scrapper-_dWwuDJg.mjs → scrapper-_JzgbLG5.mjs} +4 -4
- package/{scrapper-_dWwuDJg.mjs.map → scrapper-_JzgbLG5.mjs.map} +1 -1
- package/{searxng-DXzj0o8E.js → searxng-C6xrLW-v.cjs} +6 -6
- package/searxng-C6xrLW-v.cjs.map +1 -0
- package/{searxng-PnrXrrLE.mjs → searxng-D-nA2gEI.mjs} +4 -4
- package/{searxng-PnrXrrLE.mjs.map → searxng-D-nA2gEI.mjs.map} +1 -1
- package/{server-CnUZcn6e.js → server-CkVjzQaC.cjs} +2 -2
- package/server-CkVjzQaC.cjs.map +1 -0
- package/server.json +2 -2
- package/{shell-quote-CIuPmePF.js → shell-quote-BUxBTn3M.cjs} +2 -2
- package/shell-quote-BUxBTn3M.cjs.map +1 -0
- package/shims.cjs +2 -2
- package/skills/adk-assembly/SKILL.md +2 -2
- package/{spooled_artifact-DKZd7fgs.js → spooled_artifact-BLgbGT8b.cjs} +733 -733
- package/spooled_artifact-BLgbGT8b.cjs.map +1 -0
- package/{spooled_artifact-BMtuIsu6.mjs → spooled_artifact-BkOe4-j-.mjs} +731 -731
- package/spooled_artifact-BkOe4-j-.mjs.map +1 -0
- package/spooled_artifact.cjs +3 -3
- package/spooled_artifact.mjs +2 -2
- package/{spooled_markdown_artifact-BrMoR7ck.js → spooled_markdown_artifact-8zdejfcJ.cjs} +5 -5
- package/spooled_markdown_artifact-8zdejfcJ.cjs.map +1 -0
- package/{spooled_markdown_artifact-g4CPr86y.mjs → spooled_markdown_artifact-Dnl-lCGv.mjs} +3 -3
- package/{spooled_markdown_artifact-g4CPr86y.mjs.map → spooled_markdown_artifact-Dnl-lCGv.mjs.map} +1 -1
- package/{thought-BEsItcp_.mjs → thought-BrQt6HAb.mjs} +47 -6
- package/thought-BrQt6HAb.mjs.map +1 -0
- package/{thought-DTgeATDv.js → thought-COeZTQ-B.cjs} +49 -8
- package/thought-COeZTQ-B.cjs.map +1 -0
- package/{tokenizable-KwA7jyGQ.js → tokenizable-DDIdXbJN.cjs} +3 -3
- package/tokenizable-DDIdXbJN.cjs.map +1 -0
- package/{tool_call-Cahji8ZY.mjs → tool_call-8crmZsO8.mjs} +4 -4
- package/{tool_call-Cahji8ZY.mjs.map → tool_call-8crmZsO8.mjs.map} +1 -1
- package/{tool_call-kx4WQ0-j.js → tool_call-JbjeUpRK.cjs} +6 -6
- package/tool_call-JbjeUpRK.cjs.map +1 -0
- package/{tool_parsers-csSBFWob.js → tool_parsers-8_qO0a_F.cjs} +2 -2
- package/tool_parsers-8_qO0a_F.cjs.map +1 -0
- package/{tools-BepwIVtl.mjs → tools-BC4NJqZD.mjs} +6 -6
- package/{tools-BepwIVtl.mjs.map → tools-BC4NJqZD.mjs.map} +1 -1
- package/{tools-zV-_O2MB.js → tools-D4mdzi0a.cjs} +9 -9
- package/tools-D4mdzi0a.cjs.map +1 -0
- package/{toon-F-e_k2jV.mjs → toon-BA9Q7NHG.mjs} +5 -5
- package/{toon-F-e_k2jV.mjs.map → toon-BA9Q7NHG.mjs.map} +1 -1
- package/{toon-gA82H1sN.js → toon-b-0pFKZ8.cjs} +7 -7
- package/toon-b-0pFKZ8.cjs.map +1 -0
- package/{transformers_js-C050gRfd.js → transformers_js-7OzeS_Tp.cjs} +4 -4
- package/transformers_js-7OzeS_Tp.cjs.map +1 -0
- package/{turn_runner-BdeNNvo0.mjs → turn_runner-BmVXcBZ2.mjs} +5 -5
- package/{turn_runner-BdeNNvo0.mjs.map → turn_runner-BmVXcBZ2.mjs.map} +1 -1
- package/{turn_runner-CF5LExb8.js → turn_runner-DX-3s3ih.cjs} +7 -7
- package/turn_runner-DX-3s3ih.cjs.map +1 -0
- package/turn_runner.cjs +2 -2
- package/turn_runner.mjs +1 -1
- package/{type_guards-BAhiOypL-C2eOOyxU.js → type_guards-BAhiOypL-C2eOOyxU.cjs} +1 -1
- package/{type_guards-BAhiOypL-C2eOOyxU.js.map → type_guards-BAhiOypL-C2eOOyxU.cjs.map} +1 -1
- package/{type_guards-DuKwiYgg.js → type_guards-BWTKysPt.cjs} +2 -2
- package/{types-DrSosVaM.js → types-DWOiL208.cjs} +4 -4
- package/types-DWOiL208.cjs.map +1 -0
- package/types.cjs +1 -1
- package/{validate-CkQI-48O.js → validate-tUm9MY8y.cjs} +3 -3
- package/validate-tUm9MY8y.cjs.map +1 -0
- package/{xlsx-B0sTpEC2.js → xlsx-Dtql4S-9.cjs} +2 -2
- package/xlsx-Dtql4S-9.cjs.map +1 -0
- package/{xlsx.zahl-ZIcUQVv8.js → xlsx.zahl-C9pM7cyt.cjs} +2 -2
- package/xlsx.zahl-C9pM7cyt.cjs.map +1 -0
- package/{xml-CT28gSkh.mjs → xml-B1JIGLpU.mjs} +5 -5
- package/{xml-CT28gSkh.mjs.map → xml-B1JIGLpU.mjs.map} +1 -1
- package/{xml-DVjBQkhb.js → xml-fvwTsoRv.cjs} +7 -7
- package/xml-fvwTsoRv.cjs.map +1 -0
- package/{yaml-DiHPF0nY.mjs → yaml-1mP4uxdf.mjs} +5 -5
- package/{yaml-DiHPF0nY.mjs.map → yaml-1mP4uxdf.mjs.map} +1 -1
- package/{yaml-Dt82CpYv.js → yaml-DPUTumla.cjs} +7 -7
- package/yaml-DPUTumla.cjs.map +1 -0
- package/arg_specs-iYmIM3wI.js.map +0 -1
- package/artifact_methods-CIQgBCKp.mjs +0 -1
- package/artifact_methods-Cjypa7oU.js +0 -1
- package/chat_common-D7SuSLCM.js.map +0 -1
- package/common-BuVhq_3h.js.map +0 -1
- package/common-Cb1h54HM.js.map +0 -1
- package/conformance-T1qEg8Sv.js.map +0 -1
- package/dispatch_runner-BOfUNRv3.js.map +0 -1
- package/ecmascript-C13G-sie.js.map +0 -1
- package/error_translation-BCa4wxUL.js.map +0 -1
- package/escape-COeB923i.js.map +0 -1
- package/exceptions-BY1RQNVP.js.map +0 -1
- package/exceptions-Dlw1Jr6E.js.map +0 -1
- package/exceptions-DrHnAGQz.js.map +0 -1
- package/formats-DZVuqZUN.js.map +0 -1
- package/fs_node-WwUEiuo6.js.map +0 -1
- package/function_serializer-ChL2I8Kq.js.map +0 -1
- package/gpu_budget-BBIUyLoj.js.map +0 -1
- package/guards-05Uq3J4M.js.map +0 -1
- package/helpers-C_1dcP_X.js.map +0 -1
- package/isolation-7Jrcucgc.js.map +0 -1
- package/lifecycle-vYQJ2rmf.js.map +0 -1
- package/manifest-iMAmSDay.js.map +0 -1
- package/patch-BXX9Q0FM.js.map +0 -1
- package/predicates-f3wvKYT8.js.map +0 -1
- package/retrievable-CksTfjbY.js.map +0 -1
- package/sandbox-utils-DLCceTeU.js.map +0 -1
- package/scrapper-CkooTUAD.js.map +0 -1
- package/searxng-DXzj0o8E.js.map +0 -1
- package/server-CnUZcn6e.js.map +0 -1
- package/shell-quote-CIuPmePF.js.map +0 -1
- package/spooled_artifact-BMtuIsu6.mjs.map +0 -1
- package/spooled_artifact-DKZd7fgs.js.map +0 -1
- package/spooled_markdown_artifact-BrMoR7ck.js.map +0 -1
- package/thought-BEsItcp_.mjs.map +0 -1
- package/thought-DTgeATDv.js.map +0 -1
- package/tokenizable-KwA7jyGQ.js.map +0 -1
- package/tool_call-kx4WQ0-j.js.map +0 -1
- package/tool_parsers-csSBFWob.js.map +0 -1
- package/tools-zV-_O2MB.js.map +0 -1
- package/toon-gA82H1sN.js.map +0 -1
- package/transformers_js-C050gRfd.js.map +0 -1
- package/turn_runner-CF5LExb8.js.map +0 -1
- package/types-DrSosVaM.js.map +0 -1
- package/validate-CkQI-48O.js.map +0 -1
- package/xlsx-B0sTpEC2.js.map +0 -1
- package/xlsx.zahl-ZIcUQVv8.js.map +0 -1
- package/xml-DVjBQkhb.js.map +0 -1
- package/yaml-Dt82CpYv.js.map +0 -1
- /package/{chunk-Cek0wNdY.js → chunk-Cek0wNdY.cjs} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tool_parsers-csSBFWob.js","names":[],"sources":["../src/batteries/llm/chat_common/tool_parsers.ts"],"sourcesContent":["/**\n * Runtime-agnostic tool-call text parsers for text-only LLM batteries.\n *\n * @remarks\n * **Why this exists.** On-device runtimes like transformers.js and LiteRT-LM (v0.13.1) are\n * text-in / text-out: they inject tool definitions into the chat template, but the model emits its\n * tool calls as **raw text in the assistant message**, in a format specific to the model family it\n * was fine-tuned on. Unlike the OpenAI/Ollama wire batteries — where the provider returns a\n * structured `tool_calls` array — these batteries must parse the call out of the text themselves.\n *\n * This mirrors how vLLM / SGLang / Ollama do it: one **post-hoc** parser per model family, selected\n * by a flag, run *after* generation (sub-millisecond, fails gracefully, never constrains decoding).\n * Each family parser is anchored on a literal marker (or, for the weak-signal JSON/pythonic forms, on\n * the callee name matching a real tool) so cross-family false positives are structurally impossible.\n *\n * **Formats are model-specific and drift across versions** (e.g. Gemma has three incompatible tool\n * formats across its generations; gpt-oss's Harmony channel ordering is an active upstream bug). The\n * bundled defaults target the small ONNX models that actually run in transformers.js; the `'auto'`\n * driver fails gracefully and a custom {@link ToolCallParserFn} is the escape hatch for anything else.\n *\n * NOT `@module`-tagged: private to the bundled LLM batteries, re-exported through their public\n * surfaces (`transformers_js`, `litert_lm`). Consumers import from those battery subpaths.\n */\n\nimport { isObject } from '@nhtio/adk/guards'\n\n// ─── Contract ─────────────────────────────────────────────────────────────────────────────────────\n\n/** A JSON-serialisable value — the shape of parsed tool-call arguments. */\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue }\n\n/** A single tool call extracted from model output. `arguments` is a parsed object, never a string. */\nexport interface ParsedToolCall {\n /** The tool name the model called. */\n name: string\n /** The parsed argument object (never a JSON string). */\n arguments: Record<string, JsonValue>\n}\n\n/**\n * The result of running a {@link ToolCallParserFn} over assistant text.\n *\n * @remarks\n * `cleanedText` is the prose with every consumed tool-call span removed and trimmed, so the visible\n * assistant message never carries raw markup. On no-match a parser MUST return\n * `{ calls: [], cleanedText: rawText }` verbatim — that is the signal the `'auto'` driver uses to\n * detect \"this parser made no claim\" and move to the next one.\n */\nexport interface ToolCallParseResult {\n /** The tool calls extracted, in document order. Empty when the parser made no claim. */\n calls: ParsedToolCall[]\n /** The assistant prose with every consumed tool-call span removed; equals the input on no-match. */\n cleanedText: string\n}\n\n/** Context passed to a parser: the names of the tools actually offered this turn. */\nexport interface ToolCallParserContext {\n /** The visible tool names this turn — lets a parser reject calls to tools that don't exist. */\n toolNames: ReadonlyArray<string>\n}\n\n/** A synchronous tool-call text parser. */\nexport type ToolCallParserFn = (rawText: string, ctx: ToolCallParserContext) => ToolCallParseResult\n\n/** The bundled family parser names, plus `'auto'` (try-all) and `'none'` (disable). */\nexport type ToolCallParserName =\n | 'auto'\n | 'hermes'\n | 'gemma'\n | 'gpt_oss'\n | 'pythonic'\n | 'bare_pythonic'\n | 'loose_keyed'\n | 'llama3_json'\n | 'mistral'\n | 'qwen3_coder'\n | 'phi'\n | 'none'\n\n// ─── Shared helpers ─────────────────────────────────────────────────────────────────────────────────\n\nconst NO_MATCH = (rawText: string): ToolCallParseResult => ({ calls: [], cleanedText: rawText })\n\nconst asArgsObject = (value: unknown): Record<string, JsonValue> =>\n isObject(value) ? (value as Record<string, JsonValue>) : {}\n\n/**\n * Remove a set of `[start, end)` spans from `text` (descending by start so offsets stay valid),\n * collapse the resulting whitespace seams, and trim.\n */\nconst removeSpans = (text: string, spans: Array<[number, number]>): string => {\n let out = text\n for (const [start, end] of [...spans].sort((a, b) => b[0] - a[0])) {\n out = out.slice(0, start) + out.slice(end)\n }\n return out.replace(/\\n{3,}/g, '\\n\\n').trim()\n}\n\n/** Try to JSON.parse; return undefined on failure (parsers decline rather than throw). */\nconst tryJsonParse = (s: string): unknown => {\n try {\n return JSON.parse(s)\n } catch {\n return undefined\n }\n}\n\n/**\n * From `text`, with `from` pointing AT an opening `open` char, return the index of its matching\n * `close` char — string-aware, so a delimiter inside a JSON string literal (e.g. a `}` or `]` or a\n * `</tool_call>`-shaped substring inside `{\"text\":\"…\"}`) is NOT miscounted. Returns -1 if the run is\n * unbalanced (e.g. a truncated stream). This is the brace/bracket scan that makes the marker-anchored\n * parsers robust to embedded markup in argument values — the dominant failure class the red-team panel\n * found in the old lazy/greedy regexes.\n */\nconst scanBalanced = (text: string, from: number, open: string, close: string): number => {\n let depth = 0\n let inStr = false\n let escaped = false\n for (let i = from; i < text.length; i++) {\n const ch = text[i]\n if (inStr) {\n if (escaped) escaped = false\n else if (ch === '\\\\') escaped = true\n else if (ch === '\"') inStr = false\n continue\n }\n if (ch === '\"') inStr = true\n else if (ch === open) depth++\n else if (ch === close) {\n depth--\n if (depth === 0) return i\n }\n }\n return -1\n}\n\n// ─── Hermes: <tool_call>{json}</tool_call> (Hermes 2/3, Qwen2.5, Qwen3-Instruct) ──────────────────────\n\nconst HERMES_OPEN = '<tool_call>'\n\n/**\n * Parse Hermes-style `<tool_call>{\"name\":…,\"arguments\":{…}}</tool_call>` tags. The de-facto standard,\n * reused by Qwen2.5/Qwen3-Instruct. Anchored on the literal tags — zero collision with bare JSON.\n *\n * @remarks\n * The JSON object after each `<tool_call>` is located by a string-aware balanced-brace scan (not a lazy\n * `</tool_call>` regex), so an embedded `</tool_call>` or `{`/`}` inside a string argument value (e.g.\n * `{\"text\":\"</tool_call>\"}`) survives instead of truncating the call. The literal `</tool_call>` close\n * is still consumed for span removal when present immediately after the object.\n */\nexport const hermesToolCallParser: ToolCallParserFn = (rawText) => {\n const calls: ParsedToolCall[] = []\n const spans: Array<[number, number]> = []\n let searchFrom = 0\n for (;;) {\n const openIdx = rawText.indexOf(HERMES_OPEN, searchFrom)\n if (openIdx === -1) break\n const braceStart = rawText.indexOf('{', openIdx + HERMES_OPEN.length)\n if (braceStart === -1) break\n const braceEnd = scanBalanced(rawText, braceStart, '{', '}')\n if (braceEnd === -1) {\n // Unbalanced (truncated stream) — stop; nothing more is parseable.\n break\n }\n const obj = tryJsonParse(rawText.slice(braceStart, braceEnd + 1))\n // The close tag is REQUIRED and must sit immediately after the object (allowing whitespace). The\n // brace-scan already found the true object end, so an embedded `</tool_call>` inside a string value\n // is BEFORE braceEnd and never consulted — but a genuinely truncated call (no real close) declines.\n const afterObj = rawText.slice(braceEnd + 1)\n const closeRel = /^\\s*<\\/tool_call>/.exec(afterObj)\n if (closeRel && isObject(obj) && typeof obj.name === 'string') {\n const o = obj as { name: string; arguments?: unknown }\n calls.push({ name: o.name, arguments: asArgsObject(o.arguments) })\n spans.push([openIdx, braceEnd + 1 + closeRel[0].length])\n searchFrom = braceEnd + 1 + closeRel[0].length\n } else {\n // Malformed/truncated candidate: skip it but keep scanning for a later valid call.\n searchFrom = braceEnd + 1\n }\n }\n return calls.length > 0 ? { calls, cleanedText: removeSpans(rawText, spans) } : NO_MATCH(rawText)\n}\n\n/** Default {@link hermesToolCallParser}. */\nexport const defaultHermesToolCallParser = hermesToolCallParser\n\n// ─── Gemma E2B/E4B: call:NAME{key:value} (wrapper + <|\"|> tokens are decoder-stripped at runtime) ─────\n// The tokenizer_config TEMPLATE wraps calls as `<|tool_call>call:NAME{k:<|\"|>v<|\"|>}<tool_call|>`, but a\n// REAL onnx-community/gemma-4-E2B-it-ONNX run emits the bare inner form `call:get_weather{city:Paris}` —\n// the `<|tool_call>`/`<tool_call|>`/`<|\"|>` markers are SPECIAL TOKENS the decoder strips. Verified\n// empirically via the real-model matrix (do NOT trust the template's literal tokens for the runtime\n// form). So we accept BOTH: the wrapped template form AND the stripped bare form, with unquoted scalars.\n\n// Anchors locate the call HEAD (`[<|tool_call>] call:NAME`) up to — but not including — the opening\n// `{`; the argument block is then BRACE-SCANNED (string-aware, see scanGemmaArgs) rather than matched\n// by a flat `\\{[^{}]*\\}` regex, so a NESTED block survives. A real E4B `provide_answer` emits\n// `{answer:<|“|>…<|”|>,sources:[{path:<|“|>…<|”|>,title:…}]}` — nested arrays/objects AND curly smart\n// quotes — which the old single-level regex silently dropped (the whole call then leaked as prose).\nconst GEMMA_WRAP_HEAD = /<\\|tool_call>\\s*call:\\s*([A-Za-z_]\\w*)\\s*(?=\\{)/g\nconst GEMMA_BARE_HEAD = /call:\\s*([A-Za-z_]\\w*)\\s*(?=\\{)/g\n// Prefix-LESS bare head: `NAME{` with NO `call:` — a real runtime shape (Gemma E2B/E4B drops the\n// `call:` lead entirely, e.g. `say_i_dont_know{reason: \"…\"}`). Collision-prone (any `word{` in prose\n// matches), so this pass is GATED on ctx.toolNames — only an actual offered tool name is accepted.\nconst GEMMA_NOPREFIX_HEAD = /([A-Za-z_]\\w*)\\s*(?=\\{)/g\nconst GEMMA_WRAP_TAIL = '<tool_call|>'\n\n// Any double-quote glyph that delimits a Gemma string value: ASCII `\"` or the curly pair `“ ”`. The\n// runtime emits curly quotes (both as the `<|“|>` delimiter token and bare inside values); a straight\n// apostrophe `’` is NOT here — it is a literal inside a value, not a delimiter.\nconst GEMMA_DQUOTE = /[\"“”]/\n\n/**\n * Scan a Gemma argument block `{ … }` for the index of its matching `}`, treating string regions as\n * opaque so structural `{ } [ ]` inside a value never unbalance the scan. String state toggles on any\n * {@link GEMMA_DQUOTE} glyph and on a `<|\"|>`/`<|“|>`/`<|”|>` delimiter TOKEN (consumed whole). `from`\n * indexes the opening `{`. Returns the matching close index, or -1 if unterminated.\n */\nconst scanGemmaArgs = (text: string, from: number): number => {\n let depth = 0\n let inStr = false\n for (let i = from; i < text.length; i++) {\n // A quote delimiter — `<|\"|>` (5 chars), curly `“`/`”`, or ASCII `\"`. Collapse a RUN of consecutive\n // delimiters (e.g. the triple-quote `\"\"\"` opener, or a doubled `<|\"|><|\"|>`) into a SINGLE toggle, so\n // string state stays balanced and the matching `}` is found. Without the run-collapse, `\"\"\"` toggles\n // three times → stays \"in string\" → the scan never balances and the whole call is dropped.\n const delimW = gemmaQuoteDelimiterWidth(text, i)\n if (delimW > 0) {\n let j = i + delimW\n for (\n let w = gemmaQuoteDelimiterWidth(text, j);\n w > 0;\n w = gemmaQuoteDelimiterWidth(text, j)\n ) {\n j += w\n }\n inStr = !inStr\n i = j - 1\n continue\n }\n const ch = text[i]\n if (inStr) continue\n if (ch === '{' || ch === '[') depth++\n else if (ch === '}' || ch === ']') {\n depth--\n if (depth === 0) return i\n }\n }\n return -1\n}\n\n/**\n * Whether the delimiter token at `block[i]` is a Gemma string-quote delimiter, and how wide it is. A\n * delimiter is either the 5-char `<|\"|>` / `<|“|>` / `<|”|>` special-token placeholder the decoder leaks,\n * a bare curly smart quote `“`/`”`, or a plain ASCII `\"`. Returns the delimiter width (5, or 1) or 0 if\n * `block[i]` is not a quote delimiter.\n */\nconst gemmaQuoteDelimiterWidth = (block: string, i: number): number => {\n if (\n block[i] === '<' &&\n block[i + 1] === '|' &&\n GEMMA_DQUOTE.test(block[i + 2] ?? '') &&\n block[i + 3] === '|' &&\n block[i + 4] === '>'\n ) {\n return 5\n }\n const ch = block[i]\n if (ch === '\"' || ch === '“' || ch === '”') return 1\n return 0\n}\n\n/**\n * Canonicalise the string delimiters in a Gemma arg block to ASCII `\"`, tracking string state so a\n * `:` `,` `{` `}` `[` `]` (or a smart quote) appearing INSIDE a value is never treated as structure.\n * Handles the `<|\"|>`/`<|“|>`/`<|”|>` delimiter TOKENS and bare curly `“ ”` glyphs (both open and\n * close a string). The straight apostrophe `’` is a literal, not a delimiter. Inside a string, a raw\n * ASCII `\"` is escaped to `\\\"` so the resulting JSON stays valid.\n *\n * A RUN of consecutive quote delimiters (any mix of `\"`, curly, `<|\"|>`) collapses to a SINGLE toggle —\n * so Gemma's Python-style triple-quote opener `answer:\"\"\"…` (and the doubled `<|\"|><|\"|>` the decoder\n * sometimes emits) becomes one `\"` instead of `\"\"\"` (which JSON.parse reads as an empty string `\"\"`\n * followed by garbage). Verified against a real E2B `provide_answer{answer:\"\"\"# …}` capture that failed\n * to parse and surfaced as `E_LLM_EXECUTION_EXECUTOR_ERROR`.\n */\nconst canonicaliseGemmaStrings = (block: string): string => {\n let out = ''\n let inStr = false\n for (let i = 0; i < block.length; i++) {\n const delimW = gemmaQuoteDelimiterWidth(block, i)\n if (delimW > 0) {\n // Collapse a run of consecutive quote delimiters (e.g. `\"\"\"`, `<|\"|><|\"|>`) into a single toggle.\n let j = i + delimW\n while (true) {\n const w = gemmaQuoteDelimiterWidth(block, j)\n if (w === 0) break\n j += w\n }\n out += '\"'\n inStr = !inStr\n i = j - 1\n continue\n }\n const ch = block[i]\n // Inside a string, escape raw JSON control characters. A real multi-paragraph `answer` value carries\n // literal newlines/tabs, which JSON.parse rejects (\"Bad control character in string literal\") unless\n // escaped. A lone backslash is also escaped so it cannot accidentally escape the closing quote.\n if (inStr) {\n if (ch === '\\n') {\n out += '\\\\n'\n continue\n }\n if (ch === '\\r') {\n out += '\\\\r'\n continue\n }\n if (ch === '\\t') {\n out += '\\\\t'\n continue\n }\n if (ch === '\\\\') {\n out += '\\\\\\\\'\n continue\n }\n }\n out += ch\n }\n return out\n}\n\n/** A bare scalar token is \"already JSON\" — a quoted string, a nested `[`/`{` opener, a COMPLETE JSON\n * number, or a literal — and must NOT be re-quoted. Matching a FULL number (not merely a leading digit)\n * is load-bearing: a digit-led non-number like a UUID `1f173d33-…`, a version, or a hash must still be\n * quoted, else the call yields invalid JSON and leaks as prose. */\nconst isJsonReadyScalar = (v: string): boolean =>\n /^[\"[{]/.test(v) ||\n /^-?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$/.test(v) ||\n /^(?:true|false|null)$/.test(v)\n\n/**\n * Quote bare keys (`key:` → `\"key\":`), bare scalar values (`:Paris` → `:\"Paris\"`), and bare array\n * ELEMENTS (`[search_docs_semantic]` → `[\"search_docs_semantic\"]`) that the decoder-stripped form leaves\n * unquoted — but ONLY in structural position (outside quoted strings). Operates on a block whose string\n * delimiters are already canonical ASCII `\"` (see {@link canonicaliseGemmaStrings}), walking it\n * quote-aware so a `:` `,` or word inside a value is left untouched. Tokens already JSON (quoted,\n * number/sign, true/false/null, or a nested `[`/`{`) pass through.\n */\nconst quoteBareGemmaTokens = (block: string): string => {\n let out = ''\n let inStr = false\n for (let i = 0; i < block.length; i++) {\n const ch = block[i]\n if (ch === '\"') {\n inStr = !inStr\n out += ch\n continue\n }\n if (inStr) {\n out += ch\n continue\n }\n // Structural region. Quote a bare key (identifier directly after a `{`/`,`/`[` opener, ws allowed),\n // emitting only the quoted name + ws — the following `:` is left for the next iteration so the value\n // branch below can run on it. `(?=\\s*:)` confirms it is a key, not a bare-word value.\n const keyM = /^([A-Za-z_]\\w*)(\\s*)(?=:)/.exec(block.slice(i))\n if (keyM && /[{,[]\\s*$/.test(out)) {\n out += `\"${keyM[1]}\"${keyM[2]}`\n i += keyM[0].length - 1\n continue\n }\n // Quote a bare scalar value right after a structural ':' — up to the next ',' '}' ']'.\n if (ch === ':') {\n const rest = block.slice(i + 1)\n const valM = /^\\s*([^,}\\]]+?)\\s*(?=[,}\\]])/.exec(rest)\n if (valM && !isJsonReadyScalar(valM[1])) {\n out += `:\"${valM[1]}\"`\n i += 1 + valM[0].length - 1\n continue\n }\n }\n // Quote a bare ARRAY ELEMENT / list member sitting right after a structural `[` or `,` opener\n // (e.g. `tools_to_use:[search_docs_semantic]` or `[a,b]`). The key branch needs a following `:` and\n // the value branch needs a leading `:`, so both miss enum-array elements — the decoder-stripped\n // `make_plan` `tools_to_use:[search_docs_semantic]` stayed unquoted → invalid JSON → the whole\n // planner call failed to parse and leaked as prose. Only fires when `out` ends with a `[`/`,` opener\n // and the element is not already JSON (a nested `{`/`[`, quoted string, number, or literal).\n if (/[[,]\\s*$/.test(out)) {\n const elM = /^([^,{}[\\]\"\\s][^,}\\]]*?)\\s*(?=[,}\\]])/.exec(block.slice(i))\n if (elM && !isJsonReadyScalar(elM[1])) {\n out += `\"${elM[1]}\"`\n i += elM[0].length - 1\n continue\n }\n }\n out += ch\n }\n return out\n}\n\n/**\n * Append any `}`/`]` closers the model dropped, so an under-closed JSON object still parses. Walks the\n * already-canonical (ASCII-quoted) text quote-aware, tracks the structural `{`/`[` stack, and emits the\n * matching closers in reverse order. Real Gemma E4B `provide_answer` output omits the OUTER `}` (the\n * `<tool_call|>` wrapper terminator stands in for it: `…}]<tool_call|>` with two `}` opened but one\n * closed) — without this, the unbalanced object is dropped and the whole cited answer leaks as prose.\n *\n * Also closes an UNTERMINATED string: a long `provide_answer` answer that the model truncates mid-value\n * (the output-token cap cuts it, or the stream ends: `{answer:\"\"\"# Overview…<cut>`) leaves the string\n * open. Verified live (Gemma-4 E2B): a broad \"give me an overview\" request whose answer overran the cap\n * produced exactly this shape, which failed JSON.parse → the call was dropped → the turn errored. When the\n * walk ends INSIDE a string, close it (`\"`) BEFORE emitting the structural closers, so the (truncated)\n * answer still commits instead of taking the whole turn down.\n */\nconst closeUnbalancedJson = (jsonish: string): string => {\n const stack: string[] = []\n let inStr = false\n for (let i = 0; i < jsonish.length; i++) {\n const ch = jsonish[i]\n if (ch === '\"' && jsonish[i - 1] !== '\\\\') {\n inStr = !inStr\n continue\n }\n if (inStr) continue\n if (ch === '{') stack.push('}')\n else if (ch === '[') stack.push(']')\n else if (ch === '}' || ch === ']') stack.pop()\n }\n let out = jsonish\n // A dangling open string (truncated mid-value) must be closed first, else the appended `}`/`]` land\n // inside the string and JSON.parse still fails.\n if (inStr) out += '\"'\n for (let i = stack.length - 1; i >= 0; i--) out += stack[i]\n return out\n}\n\n/**\n * Normalise a Gemma KEY-VALUE SEPARATOR `=` to `:` in structural position. Real Gemma E2B/E4B output\n * sometimes assigns a top-level arg with `=` instead of `:` — observed live: `provide_answer{answer=\"…\",\n * sources:[…]}` (the `answer` key used `=`, while `sources`/`path` used `:`). The rest of the block is\n * valid JSON-ish, but the `=` means the key branch in {@link quoteBareGemmaTokens} (which keys on a\n * following `:`) never quotes that key, so the whole object fails to parse and the cited answer leaks as\n * prose. Rewrite only an `identifier=` sitting in KEY position — directly after a `{`/`,`/`[` opener (ws\n * allowed) — to `identifier:`, walking the block quote-aware so an `=` inside a string value (or a\n * Python-ish `k=v` already handled elsewhere) is left untouched. Runs AFTER string canonicalisation (so\n * `inStr` tracking is reliable) and BEFORE bare-token quoting (so the now-`:` key gets quoted normally).\n */\nconst normaliseGemmaKeySeparators = (block: string): string => {\n let out = ''\n let inStr = false\n for (let i = 0; i < block.length; i++) {\n const ch = block[i]\n if (ch === '\"') {\n inStr = !inStr\n out += ch\n continue\n }\n if (inStr) {\n out += ch\n continue\n }\n // A bare `identifier` directly after a structural opener, followed by `=`, is a key assigned with the\n // wrong separator. Emit the name + ws + `:` and skip the `=`. `(?=\\s*=)`-style intent via an explicit\n // `=` capture; the `out` tail must end with a `{`/`,`/`[` opener (ws allowed) to be a key position.\n const keyEqM = /^([A-Za-z_]\\w*)(\\s*)=/.exec(block.slice(i))\n if (keyEqM && /[{,[]\\s*$/.test(out)) {\n out += `${keyEqM[1]}${keyEqM[2]}:`\n i += keyEqM[0].length - 1\n continue\n }\n out += ch\n }\n return out\n}\n\n/**\n * Normalise a Gemma arg block (`{k:<|\"|>v<|\"|>}`, stripped `{k:v}`, or a nested\n * `{a:<|“|>…<|”|>,b:[{…}]}`) into JSON. Done in quote-aware passes — canonicalise the string delimiters\n * to ASCII `\"`, normalise a wrong `=` key separator to `:`, quote the bare keys/scalars that remain,\n * then close any dropped `}`/`]` — so a `:` `,` or word inside a value (e.g. a `“Class: TurnRunner”`\n * title) is never mistaken for structure and a model that omits the outer closer still parses.\n */\nconst gemmaArgsToJson = (argsBlock: string): unknown => {\n const canonical = canonicaliseGemmaStrings(argsBlock)\n const colonised = normaliseGemmaKeySeparators(canonical)\n const quoted = quoteBareGemmaTokens(colonised)\n const balanced = closeUnbalancedJson(quoted)\n return tryJsonParse(balanced)\n}\n\n/** Collect Gemma calls whose heads match `headRe`; brace-scan each arg block. */\nconst collectGemmaCalls = (\n rawText: string,\n headRe: RegExp,\n wrapped: boolean,\n allowed?: Set<string>\n): { calls: ParsedToolCall[]; spans: Array<[number, number]> } => {\n const calls: ParsedToolCall[] = []\n const spans: Array<[number, number]> = []\n for (const m of rawText.matchAll(headRe)) {\n // When gated (the prefix-less pass), only an actual offered tool name may open a call — otherwise\n // any `word{` in prose would false-match.\n if (allowed && !allowed.has(m[1])) continue\n const headStart = m.index ?? 0\n const braceStart = headStart + m[0].length // lookahead leaves m[0] ending right before `{`\n // Find the arg-block boundary. Normally the matching `}`. But the wrapped form's REAL output drops\n // the outer `}` and lets `<tool_call|>` terminate the call (`…}]<tool_call|>`), so the brace scan\n // never balances — when wrapped, fall back to the wrapper tail as the boundary and let\n // gemmaArgsToJson's `closeUnbalancedJson` repair the missing closer.\n let braceEnd = scanGemmaArgs(rawText, braceStart)\n let spanEnd: number\n let blockEnd: number\n if (braceEnd !== -1) {\n blockEnd = braceEnd + 1\n spanEnd = braceEnd + 1\n // Consume a `<tool_call|>` terminator sitting immediately after the close brace — for the WRAPPED\n // form (`<|tool_call>call:…}<tool_call|>`) AND the bare form, since the decoder strips the leading\n // `<|tool_call>` head but the runtime still emits the trailing `<tool_call|>` (`call:NAME{…}<tool_call|>`).\n // Anchored `^\\s*` right after the brace, so it can only eat a real adjacent terminator, never prose.\n const tail = new RegExp(\n `^\\\\s*${GEMMA_WRAP_TAIL.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}`\n ).exec(rawText.slice(braceEnd + 1))\n if (tail) spanEnd = braceEnd + 1 + tail[0].length\n } else if (wrapped) {\n const tailIdx = rawText.indexOf(GEMMA_WRAP_TAIL, braceStart)\n if (tailIdx !== -1) {\n blockEnd = tailIdx // up to (not including) the `<tool_call|>` terminator\n spanEnd = tailIdx + GEMMA_WRAP_TAIL.length\n } else {\n // TRUNCATION fallback: wrapped head but no matching `}` AND no `<tool_call|>` tail — the call was\n // cut off mid-value (e.g. a long `provide_answer` answer that overran the output-token cap). Take\n // the rest of the string as the block and let gemmaArgsToJson (closeUnbalancedJson) repair the\n // dangling string + missing closers, so the truncated answer still commits instead of the whole\n // call being dropped (which surfaced as a turn-killing error).\n blockEnd = rawText.length\n spanEnd = rawText.length\n }\n } else {\n // Bare/prefix-less head with no matching `}` — same truncation fallback: consume to end and repair.\n blockEnd = rawText.length\n spanEnd = rawText.length\n }\n const parsed = gemmaArgsToJson(rawText.slice(braceStart, blockEnd))\n if (!isObject(parsed)) continue\n calls.push({ name: m[1], arguments: asArgsObject(parsed) })\n spans.push([headStart, spanEnd])\n }\n return { calls, spans }\n}\n\n/**\n * Parse Gemma E2B/E4B tool calls. Accepts the wrapped template form\n * (`<|tool_call>call:NAME{k:<|\"|>v<|\"|>}<tool_call|>`) AND the decoder-stripped runtime form\n * (`call:NAME{k:v}`, special tokens removed, scalars unquoted — the shape a real ONNX run emits),\n * including NESTED argument blocks with curly smart quotes (the form a real E4B `provide_answer`\n * emits: `{answer:<|“|>…<|”|>,sources:[{path:…}]}`), AND the PREFIX-LESS bare form `NAME{…}` with no\n * `call:` lead (e.g. `say_i_dont_know{reason: \"…\"}` — a real E2B/E4B runtime shape), gated on\n * `ctx.toolNames`. Targets the E2B/E4B form only — Gemma 3 (`tool_code` fences) and FunctionGemma\n * (`<start_function_call>`) are out of scope (use a custom {@link ToolCallParserFn}).\n */\nexport const gemmaToolCallParser: ToolCallParserFn = (rawText, ctx) => {\n // Prefer the wrapped form (anchored, collision-free); fall back to the bare `call:NAME{` form, then to\n // the prefix-less `NAME{` form — each only if the previous matched nothing (the earlier anchors also\n // appear inside the later shapes, so never run more than one). The prefix-less pass is GATED on\n // ctx.toolNames since `word{` alone is too weak a signal to claim without an allowlist.\n let { calls, spans } = collectGemmaCalls(rawText, GEMMA_WRAP_HEAD, true)\n if (calls.length === 0) {\n ;({ calls, spans } = collectGemmaCalls(rawText, GEMMA_BARE_HEAD, false))\n }\n if (calls.length === 0 && ctx && ctx.toolNames.length > 0) {\n ;({ calls, spans } = collectGemmaCalls(\n rawText,\n GEMMA_NOPREFIX_HEAD,\n false,\n new Set(ctx.toolNames)\n ))\n }\n return calls.length > 0 ? { calls, cleanedText: removeSpans(rawText, spans) } : NO_MATCH(rawText)\n}\n\n/** Default {@link gemmaToolCallParser}. */\nexport const defaultGemmaToolCallParser = gemmaToolCallParser\n\n// ─── gpt-oss Harmony: <|channel|>commentary to=functions.NAME ...<|message|>{json}<|call|> ─────────────\n\n// Anchor: locates the channel header + callee name + the `<|message|>` marker. The JSON payload that\n// follows is then brace-scanned (string-aware) rather than lazily matched up to `<|call|>` — a `<|call|>`\n// substring inside a JSON string value would otherwise truncate the call.\nconst GPT_OSS_HEAD_RE =\n /<\\|channel\\|>commentary\\s+to=functions\\.([A-Za-z0-9_]+)[\\s\\S]*?<\\|message\\|>/g\nconst GPT_OSS_CALL = '<|call|>'\n\n/**\n * Parse gpt-oss Harmony tool calls on the `commentary` channel:\n * `<|channel|>commentary to=functions.NAME <|constrain|>json<|message|>{…}<|call|>`. The arguments\n * payload after `<|message|>` is JSON, located by a string-aware balanced-brace scan so an embedded\n * `<|call|>` / brace inside a string value survives. Anchored on the literal Harmony markers.\n *\n * @remarks The Harmony channel/constrain ordering has a documented upstream template-vs-spec drift;\n * this matches the common ordering. Verify against a real gpt-oss ONNX run when one is available.\n */\nexport const gptOssToolCallParser: ToolCallParserFn = (rawText) => {\n const calls: ParsedToolCall[] = []\n const spans: Array<[number, number]> = []\n for (const m of rawText.matchAll(GPT_OSS_HEAD_RE)) {\n const headStart = m.index ?? 0\n const afterMsg = headStart + m[0].length\n const braceStart = rawText.indexOf('{', afterMsg)\n if (braceStart === -1) continue\n const braceEnd = scanBalanced(rawText, braceStart, '{', '}')\n if (braceEnd === -1) continue\n const obj = tryJsonParse(rawText.slice(braceStart, braceEnd + 1))\n if (!isObject(obj)) continue\n // The trailing `<|call|>` marker is REQUIRED and must sit right after the object (allowing\n // whitespace). The brace-scan found the true object end, so an embedded `<|call|>` inside a string\n // value is never consulted; a genuinely missing terminator (truncated stream) declines.\n const afterObj = rawText.slice(braceEnd + 1)\n const callRel = new RegExp(`^\\\\s*${GPT_OSS_CALL.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}`).exec(\n afterObj\n )\n if (!callRel) continue\n calls.push({ name: m[1], arguments: asArgsObject(obj) })\n spans.push([headStart, braceEnd + 1 + callRel[0].length])\n }\n return calls.length > 0 ? { calls, cleanedText: removeSpans(rawText, spans) } : NO_MATCH(rawText)\n}\n\n/** Default {@link gptOssToolCallParser}. */\nexport const defaultGptOssToolCallParser = gptOssToolCallParser\n\n// ─── Pythonic: [get_weather(city='SF'), ...] (Llama 3.2/4, Olmo3) ─────────────────────────────────────\n\nconst PYTHONIC_SHAPE_RE = /^\\[\\s*[A-Za-z_]\\w*\\s*\\(.*\\)\\s*\\]$/s\nconst PYTHONIC_CALL_RE = /([A-Za-z_]\\w*)\\s*\\(([^)]*)\\)/g\n\n// Curly/smart quote pairs small models emit instead of ASCII quotes (e.g. Gemma: “…”, ‘…’).\n// Matching them lets us read string literals the model clearly intended as strings.\nconst SMART_QUOTE_PAIRS: ReadonlyArray<[string, string]> = [\n ['“', '”'],\n ['‘', '’'],\n ['「', '」'],\n]\n\n/**\n * Read a single pythonic literal: quoted string (ASCII or smart quotes), number, True/False/None,\n * or a bracketed list of literals (`[a, b]`). Lists recurse so `sources=[“/a”, “/b”]` parses to a\n * real array. Unrecognised tokens fall through to the raw trimmed string.\n */\nconst readPythonLiteral = (raw: string): JsonValue => {\n const t = raw.trim()\n // ASCII-quoted string.\n if (/^(['\"]).*\\1$/s.test(t)) return t.slice(1, -1)\n // Smart/curly-quoted string (small-model output) — strip the matching pair.\n for (const [open, close] of SMART_QUOTE_PAIRS) {\n if (t.length >= 2 && t.startsWith(open) && t.endsWith(close)) return t.slice(1, -1)\n }\n // List literal: `[x, y, …]` → array of recursively-read literals.\n if (t.startsWith('[') && t.endsWith(']')) {\n const inner = t.slice(1, -1).trim()\n if (inner.length === 0) return []\n return splitPythonArgs(inner).map((el) => readPythonLiteral(el))\n }\n if (t === 'True' || t === 'true') return true\n if (t === 'False' || t === 'false') return false\n if (t === 'None' || t === 'null') return null\n const n = Number(t)\n return Number.isFinite(n) ? n : t\n}\n\n/** Split `k=v, k2=v2` on top-level commas (ignores commas inside quotes/brackets). */\nconst splitPythonArgs = (s: string): string[] => {\n const parts: string[] = []\n let depth = 0\n let quote: string | undefined\n let cur = ''\n for (const ch of s) {\n if (quote) {\n cur += ch\n if (ch === quote) quote = undefined\n continue\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch\n cur += ch\n continue\n }\n if (ch === '(' || ch === '[' || ch === '{') depth++\n if (ch === ')' || ch === ']' || ch === '}') depth--\n if (ch === ',' && depth === 0) {\n parts.push(cur)\n cur = ''\n continue\n }\n cur += ch\n }\n if (cur.trim().length > 0) parts.push(cur)\n return parts\n}\n\n/**\n * Parse pythonic tool calls — `[get_weather(city='SF'), get_time()]`. Requires the **whole trimmed\n * output** to be the bracketed call list, so it cannot false-positive on incidental prose. Parallel\n * calls are inherent to the format.\n *\n * **Disambiguation, NOT authorization.** The `[fn(args), …]` shape (whole-output) is the structural\n * signal that this is a call list. It deliberately does NOT check callees against `ctx.toolNames` —\n * whether a tool is *allowed* is the consumer's call, and the dispatch layer already replies \"Tool not\n * found: … Available tools: …\" so the model can self-correct. Dropping an unknown-tool call here would\n * hide the request and that feedback loop.\n */\nexport const pythonicToolCallParser: ToolCallParserFn = (rawText) => {\n const t = rawText.trim()\n if (!PYTHONIC_SHAPE_RE.test(t)) return NO_MATCH(rawText)\n const inner = t.slice(1, -1)\n const calls: ParsedToolCall[] = []\n for (const m of inner.matchAll(PYTHONIC_CALL_RE)) {\n const name = m[1]\n const args: Record<string, JsonValue> = {}\n for (const pair of splitPythonArgs(m[2])) {\n const eq = pair.indexOf('=')\n if (eq < 0) continue\n args[pair.slice(0, eq).trim()] = readPythonLiteral(pair.slice(eq + 1))\n }\n calls.push({ name, arguments: args })\n }\n return calls.length > 0 ? { calls, cleanedText: '' } : NO_MATCH(rawText)\n}\n\n/** Default {@link pythonicToolCallParser}. */\nexport const defaultPythonicToolCallParser = pythonicToolCallParser\n\n// ─── Bare pythonic: NAME(k=v, …) without the [ ] list wrapper (weak signal — gated on toolNames) ──────\n\n// A bare call: optional leading \"/\" or \"call:\" noise, then NAME( … ). Captures name + the paren body.\n// Non-global; we scan with a stateful regex below so we can require the callee ∈ toolNames.\nconst BARE_PYTHONIC_CALL_RE = /(?:^|[\\s>/])(?:call:)?\\s*([A-Za-z_]\\w*)\\s*\\(([^)]*)\\)/g\n\n/**\n * Parse a BARE pythonic call — `provide_answer(answer=“…”, sources=[“/x”])` — i.e. the pythonic\n * `NAME(kwargs)` form WITHOUT the surrounding `[ … ]` list wrapper that {@link pythonicToolCallParser}\n * requires. Small models (observed: Gemma-4 E2B via transformers.js) emit this for a single call,\n * sometimes with a leading `/`, a `call:` prefix, or smart quotes in the args.\n *\n * Because the bare shape is a WEAK signal (it can resemble incidental prose like \"see foo(bar)\"),\n * this parser is gated HARD: it only claims a call whose callee is a real offered tool\n * (`ctx.toolNames`). That gate is what makes dropping the `[ ]` requirement safe. Runs after the\n * strict bracketed pythonic parser in the `'auto'` order.\n */\nexport const barePythonicToolCallParser: ToolCallParserFn = (rawText, ctx) => {\n const allowed = new Set(ctx.toolNames)\n if (allowed.size === 0) return NO_MATCH(rawText)\n const calls: ParsedToolCall[] = []\n const spans: Array<[number, number]> = []\n for (const m of rawText.matchAll(BARE_PYTHONIC_CALL_RE)) {\n const name = m[1]\n if (!allowed.has(name)) continue // gate: only real tools — keeps prose from false-positiving\n const args: Record<string, JsonValue> = {}\n for (const pair of splitPythonArgs(m[2])) {\n const eq = pair.indexOf('=')\n if (eq < 0) continue\n args[pair.slice(0, eq).trim()] = readPythonLiteral(pair.slice(eq + 1))\n }\n calls.push({ name, arguments: args })\n // Span covers just the NAME(...) substring (m[0] may include a leading delimiter char).\n const start = (m.index ?? 0) + m[0].indexOf(name)\n spans.push([start, (m.index ?? 0) + m[0].length])\n }\n if (calls.length === 0) return NO_MATCH(rawText)\n return { calls, cleanedText: removeSpans(rawText, spans) }\n}\n\n/** Default {@link barePythonicToolCallParser}. */\nexport const defaultBarePythonicToolCallParser = barePythonicToolCallParser\n\n// ─── Loose keyed: bare `tool_name` line + `key: value` lines (degenerate small-model form) ────────────\n\n/** Coerce a loose scalar value string into a JSON value (number/bool/null, else the trimmed string). */\nconst readLooseScalar = (raw: string): JsonValue => {\n const s = raw.trim().replace(/,\\s*$/, '')\n if (s === 'true') return true\n if (s === 'false') return false\n if (s === 'null') return null\n if (/^-?\\d+(\\.\\d+)?$/.test(s)) return Number(s)\n // Strip one layer of surrounding quotes if present.\n const m = /^\"([\\s\\S]*)\"$|^'([\\s\\S]*)'$/.exec(s)\n return m ? (m[1] ?? m[2] ?? '') : s\n}\n\n/**\n * Parse the DEGENERATE keyed form a small instruct model emits when it ignores every structured\n * tool-call grammar: the bare tool NAME on its own line, then one or more `argname: value` lines.\n *\n * @remarks\n * Observed verbatim from **Gemma-4 E2B on LiteRT-web** (raw-captured): asked to call an answer tool it\n * emits, with no `call:`/braces/brackets/JSON at all —\n * ```\n * say_i_dont_know\n * reason: The documentation does not contain a definition for that.\n * ```\n * No marker-anchored or pythonic/JSON parser claims this, so the \"call\" leaks into the visible answer as\n * prose AND the turn looks like a refusal (the tool the model meant to invoke never fires). A 2B can't\n * be reliably *instructed* into a format (changing the prompt's documented format did not change the\n * output), so the robust path is to parse the shape it actually produces.\n *\n * WEAK SIGNAL, gated HARD (like {@link barePythonicToolCallParser}): it only claims when the FIRST\n * non-empty line is EXACTLY a real offered tool name (`ctx.toolNames`) and is followed by at least one\n * `key: value` line. That gate is what keeps it from misreading ordinary prose (\"Note: …\", a heading\n * with a colon). Single call only (the degenerate form has no list syntax); runs LAST in `'auto'`.\n */\nexport const looseKeyedToolCallParser: ToolCallParserFn = (rawText, ctx) => {\n const allowed = new Set(ctx.toolNames)\n if (allowed.size === 0) return NO_MATCH(rawText)\n const lines = rawText.split('\\n')\n // Find the first non-empty line; it must be EXACTLY a known tool name (after trimming).\n let i = 0\n while (i < lines.length && lines[i].trim() === '') i++\n if (i >= lines.length) return NO_MATCH(rawText)\n const name = lines[i].trim()\n if (!allowed.has(name)) return NO_MATCH(rawText)\n // Collect the trailing `key: value` lines.\n const args: Record<string, JsonValue> = {}\n let j = i + 1\n let lastConsumed = i\n for (; j < lines.length; j++) {\n const line = lines[j]\n if (line.trim() === '') {\n lastConsumed = j\n continue\n }\n const kv = /^\\s*([A-Za-z_]\\w*)\\s*:\\s*([\\s\\S]*)$/.exec(line)\n if (!kv) break // a non-keyed line ends the call body\n args[kv[1]] = readLooseScalar(kv[2])\n lastConsumed = j\n }\n if (Object.keys(args).length === 0) return NO_MATCH(rawText) // bare name alone is too weak to claim\n // Consume from the name line through the last keyed line.\n let start = 0\n for (let k = 0; k < i; k++) start += lines[k].length + 1\n let end = start\n for (let k = i; k <= lastConsumed; k++) end += lines[k].length + (k < lines.length - 1 ? 1 : 0)\n return { calls: [{ name, arguments: args }], cleanedText: removeSpans(rawText, [[start, end]]) }\n}\n\n/** Default {@link looseKeyedToolCallParser}. */\nexport const defaultLooseKeyedToolCallParser = looseKeyedToolCallParser\n\n// ─── Llama3-JSON: bare {\"name\":…, \"parameters\":…} (weakest signal — runs late) ────────────────────────\n\n/** Strip a single surrounding ```` ```json … ``` ```` (or bare ```` ``` ```` ) fence, if present. */\nconst stripCodeFence = (text: string): string => {\n const m = /^```(?:json)?\\s*\\n?([\\s\\S]*?)\\n?```$/.exec(text.trim())\n return m ? m[1].trim() : text.trim()\n}\n\n/**\n * Parse bare top-level JSON tool call(s) — `{\"name\":\"x\",\"parameters\":{…}}` (or `\"arguments\"`),\n * optionally wrapped in a ```` ```json … ``` ```` fence (a common small-model emission — verified via\n * the real-model matrix on Qwen2.5-Coder-0.5B). The weakest signal, so it is gated hard: after\n * un-fencing, the output must be ONLY top-level JSON object(s) AND every callee must be a real tool\n * (`ctx.toolNames`). Runs after every marker-anchored family in `'auto'`.\n *\n * @remarks\n * **Parallel calls.** Small Llama-family / Qwen-Coder models emit MULTIPLE calls as several top-level\n * objects separated by `,` / `;` / whitespace (verified on the real-model matrix:\n * Llama-3.2-1B → `{…}; {…}`, Qwen2.5-Coder-0.5B → a fenced `{…},\\n{…}`). So we string-aware brace-scan\n * the (un-fenced) text into successive balanced `{…}` objects, accepting only the separators above\n * between them — if any NON-separator prose sits between or around the objects, the whole thing declines\n * (the hard whole-output gate, so this never false-positives on JSON embedded in a sentence).\n *\n * **Disambiguation, NOT authorization.** This parser is marker-free, so it must distinguish a tool call\n * from arbitrary JSON content. It does that STRUCTURALLY: whole-output-is-object(s) + each object has a\n * string `name`. It deliberately does NOT check the callee against `ctx.toolNames` — whether a requested\n * tool is *allowed* is the consumer's decision, not the parser's. An unknown-tool call is surfaced like\n * any other; the dispatch layer already replies \"Tool not found: … Available tools: …\" so the model can\n * self-correct. Silently dropping the call here would hide both the request and that feedback loop.\n */\nexport const llama3JsonToolCallParser: ToolCallParserFn = (rawText) => {\n const t = stripCodeFence(rawText)\n if (!t.startsWith('{') || !t.endsWith('}')) return NO_MATCH(rawText)\n\n const calls: ParsedToolCall[] = []\n let i = 0\n while (i < t.length) {\n // Only object separators (`,`/`;`) and whitespace are allowed between top-level objects.\n if (/[\\s,;]/.test(t[i]!)) {\n i++\n continue\n }\n if (t[i] !== '{') return NO_MATCH(rawText) // non-separator prose → not a pure call list; decline\n const end = scanBalanced(t, i, '{', '}')\n if (end === -1) return NO_MATCH(rawText)\n const obj = tryJsonParse(t.slice(i, end + 1))\n if (!isObject(obj)) return NO_MATCH(rawText)\n const o = obj as { name?: unknown; parameters?: unknown; arguments?: unknown }\n // Structural disambiguation only: a string `name` makes it call-shaped. Authorization is downstream.\n if (typeof o.name !== 'string') return NO_MATCH(rawText)\n calls.push({ name: o.name, arguments: asArgsObject(o.parameters ?? o.arguments) })\n i = end + 1\n }\n return calls.length > 0 ? { calls, cleanedText: '' } : NO_MATCH(rawText)\n}\n\n/** Default {@link llama3JsonToolCallParser}. */\nexport const defaultLlama3JsonToolCallParser = llama3JsonToolCallParser\n\n// ─── Mistral: [TOOL_CALLS] [ {json}, ... ] ────────────────────────────────────────────────────────────\n\nconst MISTRAL_BOT_TOKEN = '[TOOL_CALLS]'\n\n/**\n * Parse Mistral tool calls — the `[TOOL_CALLS]` token followed by a JSON array of\n * `{ name, arguments }`. Anchored on the literal `[TOOL_CALLS]` token.\n *\n * @remarks\n * The array is located by a string-aware balanced-bracket scan from the first `[` after the token (same\n * approach as {@link phiToolCallParser}), so a `]` inside a string argument value (e.g.\n * `{\"text\":\"a]b\"}`) does not truncate the array the way the old greedy `\\[[\\s\\S]*\\]` regex did.\n */\nexport const mistralToolCallParser: ToolCallParserFn = (rawText) => {\n const tokenIdx = rawText.indexOf(MISTRAL_BOT_TOKEN)\n if (tokenIdx === -1) return NO_MATCH(rawText)\n const arrStart = rawText.indexOf('[', tokenIdx + MISTRAL_BOT_TOKEN.length)\n if (arrStart === -1) return NO_MATCH(rawText)\n const arrEnd = scanBalanced(rawText, arrStart, '[', ']')\n if (arrEnd === -1) return NO_MATCH(rawText)\n const arr = tryJsonParse(rawText.slice(arrStart, arrEnd + 1))\n if (!Array.isArray(arr)) return NO_MATCH(rawText)\n const calls: ParsedToolCall[] = []\n for (const entry of arr) {\n if (isObject(entry) && typeof entry.name === 'string') {\n const e = entry as { name: string; arguments?: unknown }\n calls.push({ name: e.name, arguments: asArgsObject(e.arguments) })\n }\n }\n return calls.length > 0\n ? { calls, cleanedText: removeSpans(rawText, [[tokenIdx, arrEnd + 1]]) }\n : NO_MATCH(rawText)\n}\n\n/** Default {@link mistralToolCallParser}. */\nexport const defaultMistralToolCallParser = mistralToolCallParser\n\n// ─── Qwen3-Coder: <tool_call><function=NAME><parameter=k>v</parameter></function></tool_call> ─────────\n\nconst QWEN3_CODER_RE =\n /<tool_call>\\s*<function=([A-Za-z0-9_]+)>([\\s\\S]*?)<\\/function>\\s*<\\/tool_call>/g\nconst QWEN3_PARAM_RE = /<parameter=([A-Za-z0-9_]+)>([\\s\\S]*?)<\\/parameter>/g\n\n/**\n * Parse Qwen3-Coder's custom per-parameter XML — `<tool_call><function=NAME><parameter=k>v</parameter>\n * …</function></tool_call>`. Values are taken as trimmed strings (the format is untyped). Anchored on\n * the literal `<function=` tag, distinct from Hermes's JSON-in-`<tool_call>`.\n */\nexport const qwen3CoderToolCallParser: ToolCallParserFn = (rawText) => {\n const calls: ParsedToolCall[] = []\n const spans: Array<[number, number]> = []\n for (const m of rawText.matchAll(QWEN3_CODER_RE)) {\n const args: Record<string, JsonValue> = {}\n for (const p of m[2].matchAll(QWEN3_PARAM_RE)) {\n args[p[1]] = p[2].trim()\n }\n calls.push({ name: m[1], arguments: args })\n spans.push([m.index ?? 0, (m.index ?? 0) + m[0].length])\n }\n return calls.length > 0 ? { calls, cleanedText: removeSpans(rawText, spans) } : NO_MATCH(rawText)\n}\n\n/** Default {@link qwen3CoderToolCallParser}. */\nexport const defaultQwen3CoderToolCallParser = qwen3CoderToolCallParser\n\n// ─── Phi-4-mini: functools[{\"name\":…,\"arguments\":{…}}, …] ─────────────────────────────────────────────\n// Verified against vLLM's `phi4_mini_json` parser: the begin-of-tool token is the literal `functools`,\n// followed by a JSON ARRAY of {name, arguments} objects (Microsoft's documented Phi-4 emission shape).\n// NOT the `<|tool_calls|>` markers some third-party docs claim — grounded against the real parser.\n\nconst PHI_BOT_TOKEN = 'functools'\n\n/**\n * Parse Phi-4-mini tool calls: the literal `functools` token followed by a JSON array of\n * `{ name, arguments }` objects (e.g. `functools[{\"name\":\"get_weather\",\"arguments\":{\"city\":\"SF\"}}]`).\n *\n * @remarks\n * Anchored on the `functools` begin-of-tool token (vLLM's `phi4_mini_json`). The array is located by\n * scanning for the first `[` after the token and matching to its balanced closing `]`, so trailing\n * prose after the call does not break parsing. Declines (no-match) if the payload is not a JSON array\n * of name-bearing objects.\n */\nexport const phiToolCallParser: ToolCallParserFn = (rawText) => {\n const tokenIdx = rawText.indexOf(PHI_BOT_TOKEN)\n if (tokenIdx === -1) return NO_MATCH(rawText)\n const arrStart = rawText.indexOf('[', tokenIdx + PHI_BOT_TOKEN.length)\n if (arrStart === -1) return NO_MATCH(rawText)\n // Find the balanced closing bracket (string-aware so brackets inside JSON strings don't miscount).\n let depth = 0\n let inStr = false\n let escaped = false\n let arrEnd = -1\n for (let i = arrStart; i < rawText.length; i++) {\n const ch = rawText[i]\n if (inStr) {\n if (escaped) escaped = false\n else if (ch === '\\\\') escaped = true\n else if (ch === '\"') inStr = false\n continue\n }\n if (ch === '\"') inStr = true\n else if (ch === '[') depth++\n else if (ch === ']') {\n depth--\n if (depth === 0) {\n arrEnd = i\n break\n }\n }\n }\n if (arrEnd === -1) return NO_MATCH(rawText)\n const arr = tryJsonParse(rawText.slice(arrStart, arrEnd + 1))\n if (!Array.isArray(arr)) return NO_MATCH(rawText)\n const calls: ParsedToolCall[] = []\n for (const entry of arr) {\n if (isObject(entry) && typeof entry.name === 'string') {\n const e = entry as { name: string; arguments?: unknown }\n calls.push({ name: e.name, arguments: asArgsObject(e.arguments) })\n }\n }\n return calls.length > 0\n ? { calls, cleanedText: removeSpans(rawText, [[tokenIdx, arrEnd + 1]]) }\n : NO_MATCH(rawText)\n}\n\n/** Default {@link phiToolCallParser}. */\nexport const defaultPhiToolCallParser = phiToolCallParser\n\n// ─── none: never matches ──────────────────────────────────────────────────────────────────────────\n\n/** A parser that never extracts anything — disables tool-call parsing entirely. */\nexport const noneToolCallParser: ToolCallParserFn = (rawText) => NO_MATCH(rawText)\n\n/** Default {@link noneToolCallParser}. */\nexport const defaultNoneToolCallParser = noneToolCallParser\n\n// ─── auto: try-all in priority order, first non-empty wins ────────────────────────────────────────\n\n/** The bundled family parsers keyed by name (excluding `'auto'`/`'none'`). */\nexport const BUNDLED_TOOL_CALL_PARSERS: Readonly<\n Record<Exclude<ToolCallParserName, 'auto' | 'none'>, ToolCallParserFn>\n> = {\n hermes: hermesToolCallParser,\n gemma: gemmaToolCallParser,\n gpt_oss: gptOssToolCallParser,\n pythonic: pythonicToolCallParser,\n bare_pythonic: barePythonicToolCallParser,\n loose_keyed: looseKeyedToolCallParser,\n llama3_json: llama3JsonToolCallParser,\n mistral: mistralToolCallParser,\n qwen3_coder: qwen3CoderToolCallParser,\n phi: phiToolCallParser,\n}\n\n/**\n * The default `'auto'` precedence. Marker-anchored families first (collision-free); the weak-signal\n * pythonic/llama3_json forms run last and are gated on callee∈toolNames.\n */\nexport const DEFAULT_TOOL_CALL_PARSER_ORDER: ReadonlyArray<\n Exclude<ToolCallParserName, 'auto' | 'none'>\n> = [\n 'hermes',\n 'gemma',\n 'gpt_oss',\n 'phi',\n 'pythonic',\n 'bare_pythonic',\n 'llama3_json',\n 'mistral',\n 'qwen3_coder',\n 'loose_keyed',\n]\n// (phi is marker-anchored on the `functools` token → placed with the other marker families, ahead of\n// the weak-signal pythonic/llama3_json forms; the rest keep their original precedence. `loose_keyed`\n// is the WEAKEST signal — a bare `name`+`key: value` form — so it runs DEAD LAST, only claiming text\n// whose first line is exactly an offered tool name.)\n\n/**\n * Compose an `'auto'` parser: run each family parser in `order` until one returns a non-empty\n * `calls` array; that result wins. Returns no-match if none claim the text.\n */\nexport const createAutoToolCallParser = (\n parsers: Partial<\n Record<Exclude<ToolCallParserName, 'auto' | 'none'>, ToolCallParserFn>\n > = BUNDLED_TOOL_CALL_PARSERS,\n order: ReadonlyArray<\n Exclude<ToolCallParserName, 'auto' | 'none'>\n > = DEFAULT_TOOL_CALL_PARSER_ORDER\n): ToolCallParserFn => {\n return (rawText, ctx) => {\n for (const name of order) {\n const parser = parsers[name]\n if (!parser) continue\n const result = parser(rawText, ctx)\n if (result.calls.length > 0) return result\n }\n return NO_MATCH(rawText)\n }\n}\n\n/** Default {@link createAutoToolCallParser}. */\nexport const defaultCreateAutoToolCallParser = createAutoToolCallParser\n\n/**\n * Resolve a `toolCallParser` option (a name, `'auto'`, `'none'`, or a custom fn) to a concrete\n * {@link ToolCallParserFn}.\n *\n * @param option - The option value. Defaults to `'auto'` when undefined.\n * @param parsers - Override the bundled family parsers (e.g. swap the Gemma parser).\n */\nexport const resolveToolCallParser = (\n option: ToolCallParserName | ToolCallParserFn | undefined,\n parsers: Partial<\n Record<Exclude<ToolCallParserName, 'auto' | 'none'>, ToolCallParserFn>\n > = BUNDLED_TOOL_CALL_PARSERS\n): ToolCallParserFn => {\n if (typeof option === 'function') return option\n if (option === undefined || option === 'auto') return createAutoToolCallParser(parsers)\n if (option === 'none') return noneToolCallParser\n const parser = parsers[option] ?? BUNDLED_TOOL_CALL_PARSERS[option]\n return parser ?? noneToolCallParser\n}\n\n/** Default {@link resolveToolCallParser}. */\nexport const defaultResolveToolCallParser = resolveToolCallParser\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAuFA,IAAM,YAAY,aAA0C;CAAE,OAAO,CAAC;CAAG,aAAa;AAAQ;AAE9F,IAAM,gBAAgB,UACpB,eAAA,SAAS,KAAK,IAAK,QAAsC,CAAC;;;;;AAM5D,IAAM,eAAe,MAAc,UAA2C;CAC5E,IAAI,MAAM;CACV,KAAK,MAAM,CAAC,OAAO,QAAQ,CAAC,GAAG,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,EAAE,GAC9D,MAAM,IAAI,MAAM,GAAG,KAAK,IAAI,IAAI,MAAM,GAAG;CAE3C,OAAO,IAAI,QAAQ,WAAW,MAAM,EAAE,KAAK;AAC7C;;AAGA,IAAM,gBAAgB,MAAuB;CAC3C,IAAI;EACF,OAAO,KAAK,MAAM,CAAC;CACrB,QAAQ;EACN;CACF;AACF;;;;;;;;;AAUA,IAAM,gBAAgB,MAAc,MAAc,MAAc,UAA0B;CACxF,IAAI,QAAQ;CACZ,IAAI,QAAQ;CACZ,IAAI,UAAU;CACd,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,QAAQ,KAAK;EACvC,MAAM,KAAK,KAAK;EAChB,IAAI,OAAO;GACT,IAAI,SAAS,UAAU;QAClB,IAAI,OAAO,MAAM,UAAU;QAC3B,IAAI,OAAO,MAAK,QAAQ;GAC7B;EACF;EACA,IAAI,OAAO,MAAK,QAAQ;OACnB,IAAI,OAAO,MAAM;OACjB,IAAI,OAAO,OAAO;GACrB;GACA,IAAI,UAAU,GAAG,OAAO;EAC1B;CACF;CACA,OAAO;AACT;AAIA,IAAM,cAAc;;;;;;;;;;;AAYpB,IAAa,wBAA0C,YAAY;CACjE,MAAM,QAA0B,CAAC;CACjC,MAAM,QAAiC,CAAC;CACxC,IAAI,aAAa;CACjB,SAAS;EACP,MAAM,UAAU,QAAQ,QAAQ,aAAa,UAAU;EACvD,IAAI,YAAY,IAAI;EACpB,MAAM,aAAa,QAAQ,QAAQ,KAAK,UAAU,EAAkB;EACpE,IAAI,eAAe,IAAI;EACvB,MAAM,WAAW,aAAa,SAAS,YAAY,KAAK,GAAG;EAC3D,IAAI,aAAa,IAEf;EAEF,MAAM,MAAM,aAAa,QAAQ,MAAM,YAAY,WAAW,CAAC,CAAC;EAIhE,MAAM,WAAW,QAAQ,MAAM,WAAW,CAAC;EAC3C,MAAM,WAAW,oBAAoB,KAAK,QAAQ;EAClD,IAAI,YAAY,eAAA,SAAS,GAAG,KAAK,OAAO,IAAI,SAAS,UAAU;GAC7D,MAAM,IAAI;GACV,MAAM,KAAK;IAAE,MAAM,EAAE;IAAM,WAAW,aAAa,EAAE,SAAS;GAAE,CAAC;GACjE,MAAM,KAAK,CAAC,SAAS,WAAW,IAAI,SAAS,GAAG,MAAM,CAAC;GACvD,aAAa,WAAW,IAAI,SAAS,GAAG;EAC1C,OAEE,aAAa,WAAW;CAE5B;CACA,OAAO,MAAM,SAAS,IAAI;EAAE;EAAO,aAAa,YAAY,SAAS,KAAK;CAAE,IAAI,SAAS,OAAO;AAClG;;AAGA,IAAa,8BAA8B;AAc3C,IAAM,kBAAkB;AACxB,IAAM,kBAAkB;AAIxB,IAAM,sBAAsB;AAC5B,IAAM,kBAAkB;AAKxB,IAAM,eAAe;;;;;;;AAQrB,IAAM,iBAAiB,MAAc,SAAyB;CAC5D,IAAI,QAAQ;CACZ,IAAI,QAAQ;CACZ,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,QAAQ,KAAK;EAKvC,MAAM,SAAS,yBAAyB,MAAM,CAAC;EAC/C,IAAI,SAAS,GAAG;GACd,IAAI,IAAI,IAAI;GACZ,KACE,IAAI,IAAI,yBAAyB,MAAM,CAAC,GACxC,IAAI,GACJ,IAAI,yBAAyB,MAAM,CAAC,GAEpC,KAAK;GAEP,QAAQ,CAAC;GACT,IAAI,IAAI;GACR;EACF;EACA,MAAM,KAAK,KAAK;EAChB,IAAI,OAAO;EACX,IAAI,OAAO,OAAO,OAAO,KAAK;OACzB,IAAI,OAAO,OAAO,OAAO,KAAK;GACjC;GACA,IAAI,UAAU,GAAG,OAAO;EAC1B;CACF;CACA,OAAO;AACT;;;;;;;AAQA,IAAM,4BAA4B,OAAe,MAAsB;CACrE,IACE,MAAM,OAAO,OACb,MAAM,IAAI,OAAO,OACjB,aAAa,KAAK,MAAM,IAAI,MAAM,EAAE,KACpC,MAAM,IAAI,OAAO,OACjB,MAAM,IAAI,OAAO,KAEjB,OAAO;CAET,MAAM,KAAK,MAAM;CACjB,IAAI,OAAO,QAAO,OAAO,OAAO,OAAO,KAAK,OAAO;CACnD,OAAO;AACT;;;;;;;;;;;;;;AAeA,IAAM,4BAA4B,UAA0B;CAC1D,IAAI,MAAM;CACV,IAAI,QAAQ;CACZ,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,SAAS,yBAAyB,OAAO,CAAC;EAChD,IAAI,SAAS,GAAG;GAEd,IAAI,IAAI,IAAI;GACZ,OAAO,MAAM;IACX,MAAM,IAAI,yBAAyB,OAAO,CAAC;IAC3C,IAAI,MAAM,GAAG;IACb,KAAK;GACP;GACA,OAAO;GACP,QAAQ,CAAC;GACT,IAAI,IAAI;GACR;EACF;EACA,MAAM,KAAK,MAAM;EAIjB,IAAI,OAAO;GACT,IAAI,OAAO,MAAM;IACf,OAAO;IACP;GACF;GACA,IAAI,OAAO,MAAM;IACf,OAAO;IACP;GACF;GACA,IAAI,OAAO,KAAM;IACf,OAAO;IACP;GACF;GACA,IAAI,OAAO,MAAM;IACf,OAAO;IACP;GACF;EACF;EACA,OAAO;CACT;CACA,OAAO;AACT;;;;;AAMA,IAAM,qBAAqB,MACzB,SAAS,KAAK,CAAC,KACf,qCAAqC,KAAK,CAAC,KAC3C,wBAAwB,KAAK,CAAC;;;;;;;;;AAUhC,IAAM,wBAAwB,UAA0B;CACtD,IAAI,MAAM;CACV,IAAI,QAAQ;CACZ,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,KAAK,MAAM;EACjB,IAAI,OAAO,MAAK;GACd,QAAQ,CAAC;GACT,OAAO;GACP;EACF;EACA,IAAI,OAAO;GACT,OAAO;GACP;EACF;EAIA,MAAM,OAAO,4BAA4B,KAAK,MAAM,MAAM,CAAC,CAAC;EAC5D,IAAI,QAAQ,YAAY,KAAK,GAAG,GAAG;GACjC,OAAO,IAAI,KAAK,GAAG,GAAG,KAAK;GAC3B,KAAK,KAAK,GAAG,SAAS;GACtB;EACF;EAEA,IAAI,OAAO,KAAK;GACd,MAAM,OAAO,MAAM,MAAM,IAAI,CAAC;GAC9B,MAAM,OAAO,+BAA+B,KAAK,IAAI;GACrD,IAAI,QAAQ,CAAC,kBAAkB,KAAK,EAAE,GAAG;IACvC,OAAO,KAAK,KAAK,GAAG;IACpB,KAAK,IAAI,KAAK,GAAG,SAAS;IAC1B;GACF;EACF;EAOA,IAAI,WAAW,KAAK,GAAG,GAAG;GACxB,MAAM,MAAM,wCAAwC,KAAK,MAAM,MAAM,CAAC,CAAC;GACvE,IAAI,OAAO,CAAC,kBAAkB,IAAI,EAAE,GAAG;IACrC,OAAO,IAAI,IAAI,GAAG;IAClB,KAAK,IAAI,GAAG,SAAS;IACrB;GACF;EACF;EACA,OAAO;CACT;CACA,OAAO;AACT;;;;;;;;;;;;;;;AAgBA,IAAM,uBAAuB,YAA4B;CACvD,MAAM,QAAkB,CAAC;CACzB,IAAI,QAAQ;CACZ,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;EACvC,MAAM,KAAK,QAAQ;EACnB,IAAI,OAAO,QAAO,QAAQ,IAAI,OAAO,MAAM;GACzC,QAAQ,CAAC;GACT;EACF;EACA,IAAI,OAAO;EACX,IAAI,OAAO,KAAK,MAAM,KAAK,GAAG;OACzB,IAAI,OAAO,KAAK,MAAM,KAAK,GAAG;OAC9B,IAAI,OAAO,OAAO,OAAO,KAAK,MAAM,IAAI;CAC/C;CACA,IAAI,MAAM;CAGV,IAAI,OAAO,OAAO;CAClB,KAAK,IAAI,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK,OAAO,MAAM;CACzD,OAAO;AACT;;;;;;;;;;;;AAaA,IAAM,+BAA+B,UAA0B;CAC7D,IAAI,MAAM;CACV,IAAI,QAAQ;CACZ,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,KAAK,MAAM;EACjB,IAAI,OAAO,MAAK;GACd,QAAQ,CAAC;GACT,OAAO;GACP;EACF;EACA,IAAI,OAAO;GACT,OAAO;GACP;EACF;EAIA,MAAM,SAAS,wBAAwB,KAAK,MAAM,MAAM,CAAC,CAAC;EAC1D,IAAI,UAAU,YAAY,KAAK,GAAG,GAAG;GACnC,OAAO,GAAG,OAAO,KAAK,OAAO,GAAG;GAChC,KAAK,OAAO,GAAG,SAAS;GACxB;EACF;EACA,OAAO;CACT;CACA,OAAO;AACT;;;;;;;;AASA,IAAM,mBAAmB,cAA+B;CAKtD,OAAO,aADU,oBADF,qBADG,4BADA,yBAAyB,SACG,CACV,CACC,CACjB,CAAQ;AAC9B;;AAGA,IAAM,qBACJ,SACA,QACA,SACA,YACgE;CAChE,MAAM,QAA0B,CAAC;CACjC,MAAM,QAAiC,CAAC;CACxC,KAAK,MAAM,KAAK,QAAQ,SAAS,MAAM,GAAG;EAGxC,IAAI,WAAW,CAAC,QAAQ,IAAI,EAAE,EAAE,GAAG;EACnC,MAAM,YAAY,EAAE,SAAS;EAC7B,MAAM,aAAa,YAAY,EAAE,GAAG;EAKpC,IAAI,WAAW,cAAc,SAAS,UAAU;EAChD,IAAI;EACJ,IAAI;EACJ,IAAI,aAAa,IAAI;GACnB,WAAW,WAAW;GACtB,UAAU,WAAW;GAKrB,MAAM,OAAO,IAAI,OACf,QAAQ,gBAAgB,QAAQ,uBAAuB,MAAM,GAC/D,EAAE,KAAK,QAAQ,MAAM,WAAW,CAAC,CAAC;GAClC,IAAI,MAAM,UAAU,WAAW,IAAI,KAAK,GAAG;EAC7C,OAAO,IAAI,SAAS;GAClB,MAAM,UAAU,QAAQ,QAAQ,iBAAiB,UAAU;GAC3D,IAAI,YAAY,IAAI;IAClB,WAAW;IACX,UAAU,UAAU;GACtB,OAAO;IAML,WAAW,QAAQ;IACnB,UAAU,QAAQ;GACpB;EACF,OAAO;GAEL,WAAW,QAAQ;GACnB,UAAU,QAAQ;EACpB;EACA,MAAM,SAAS,gBAAgB,QAAQ,MAAM,YAAY,QAAQ,CAAC;EAClE,IAAI,CAAC,eAAA,SAAS,MAAM,GAAG;EACvB,MAAM,KAAK;GAAE,MAAM,EAAE;GAAI,WAAW,aAAa,MAAM;EAAE,CAAC;EAC1D,MAAM,KAAK,CAAC,WAAW,OAAO,CAAC;CACjC;CACA,OAAO;EAAE;EAAO;CAAM;AACxB;;;;;;;;;;;AAYA,IAAa,uBAAyC,SAAS,QAAQ;CAKrE,IAAI,EAAE,OAAO,UAAU,kBAAkB,SAAS,iBAAiB,IAAI;CACvE,IAAI,MAAM,WAAW,GAClB,CAAC,CAAE,OAAO,SAAU,kBAAkB,SAAS,iBAAiB,KAAK;CAExE,IAAI,MAAM,WAAW,KAAK,OAAO,IAAI,UAAU,SAAS,GACrD,CAAC,CAAE,OAAO,SAAU,kBACnB,SACA,qBACA,OACA,IAAI,IAAI,IAAI,SAAS,CACvB;CAEF,OAAO,MAAM,SAAS,IAAI;EAAE;EAAO,aAAa,YAAY,SAAS,KAAK;CAAE,IAAI,SAAS,OAAO;AAClG;;AAGA,IAAa,6BAA6B;AAO1C,IAAM,kBACJ;AACF,IAAM,eAAe;;;;;;;;;;AAWrB,IAAa,wBAA0C,YAAY;CACjE,MAAM,QAA0B,CAAC;CACjC,MAAM,QAAiC,CAAC;CACxC,KAAK,MAAM,KAAK,QAAQ,SAAS,eAAe,GAAG;EACjD,MAAM,YAAY,EAAE,SAAS;EAC7B,MAAM,WAAW,YAAY,EAAE,GAAG;EAClC,MAAM,aAAa,QAAQ,QAAQ,KAAK,QAAQ;EAChD,IAAI,eAAe,IAAI;EACvB,MAAM,WAAW,aAAa,SAAS,YAAY,KAAK,GAAG;EAC3D,IAAI,aAAa,IAAI;EACrB,MAAM,MAAM,aAAa,QAAQ,MAAM,YAAY,WAAW,CAAC,CAAC;EAChE,IAAI,CAAC,eAAA,SAAS,GAAG,GAAG;EAIpB,MAAM,WAAW,QAAQ,MAAM,WAAW,CAAC;EAC3C,MAAM,UAAU,IAAI,OAAO,QAAQ,aAAa,QAAQ,uBAAuB,MAAM,GAAG,EAAE,KACxF,QACF;EACA,IAAI,CAAC,SAAS;EACd,MAAM,KAAK;GAAE,MAAM,EAAE;GAAI,WAAW,aAAa,GAAG;EAAE,CAAC;EACvD,MAAM,KAAK,CAAC,WAAW,WAAW,IAAI,QAAQ,GAAG,MAAM,CAAC;CAC1D;CACA,OAAO,MAAM,SAAS,IAAI;EAAE;EAAO,aAAa,YAAY,SAAS,KAAK;CAAE,IAAI,SAAS,OAAO;AAClG;;AAGA,IAAa,8BAA8B;AAI3C,IAAM,oBAAoB;AAC1B,IAAM,mBAAmB;AAIzB,IAAM,oBAAqD;CACzD,CAAC,KAAK,GAAG;CACT,CAAC,KAAK,GAAG;CACT,CAAC,KAAK,GAAG;AACX;;;;;;AAOA,IAAM,qBAAqB,QAA2B;CACpD,MAAM,IAAI,IAAI,KAAK;CAEnB,IAAI,gBAAgB,KAAK,CAAC,GAAG,OAAO,EAAE,MAAM,GAAG,EAAE;CAEjD,KAAK,MAAM,CAAC,MAAM,UAAU,mBAC1B,IAAI,EAAE,UAAU,KAAK,EAAE,WAAW,IAAI,KAAK,EAAE,SAAS,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,EAAE;CAGpF,IAAI,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,GAAG;EACxC,MAAM,QAAQ,EAAE,MAAM,GAAG,EAAE,EAAE,KAAK;EAClC,IAAI,MAAM,WAAW,GAAG,OAAO,CAAC;EAChC,OAAO,gBAAgB,KAAK,EAAE,KAAK,OAAO,kBAAkB,EAAE,CAAC;CACjE;CACA,IAAI,MAAM,UAAU,MAAM,QAAQ,OAAO;CACzC,IAAI,MAAM,WAAW,MAAM,SAAS,OAAO;CAC3C,IAAI,MAAM,UAAU,MAAM,QAAQ,OAAO;CACzC,MAAM,IAAI,OAAO,CAAC;CAClB,OAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AAClC;;AAGA,IAAM,mBAAmB,MAAwB;CAC/C,MAAM,QAAkB,CAAC;CACzB,IAAI,QAAQ;CACZ,IAAI;CACJ,IAAI,MAAM;CACV,KAAK,MAAM,MAAM,GAAG;EAClB,IAAI,OAAO;GACT,OAAO;GACP,IAAI,OAAO,OAAO,QAAQ,KAAA;GAC1B;EACF;EACA,IAAI,OAAO,QAAO,OAAO,KAAK;GAC5B,QAAQ;GACR,OAAO;GACP;EACF;EACA,IAAI,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK;EAC5C,IAAI,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK;EAC5C,IAAI,OAAO,OAAO,UAAU,GAAG;GAC7B,MAAM,KAAK,GAAG;GACd,MAAM;GACN;EACF;EACA,OAAO;CACT;CACA,IAAI,IAAI,KAAK,EAAE,SAAS,GAAG,MAAM,KAAK,GAAG;CACzC,OAAO;AACT;;;;;;;;;;;;AAaA,IAAa,0BAA4C,YAAY;CACnE,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,CAAC,kBAAkB,KAAK,CAAC,GAAG,OAAO,SAAS,OAAO;CACvD,MAAM,QAAQ,EAAE,MAAM,GAAG,EAAE;CAC3B,MAAM,QAA0B,CAAC;CACjC,KAAK,MAAM,KAAK,MAAM,SAAS,gBAAgB,GAAG;EAChD,MAAM,OAAO,EAAE;EACf,MAAM,OAAkC,CAAC;EACzC,KAAK,MAAM,QAAQ,gBAAgB,EAAE,EAAE,GAAG;GACxC,MAAM,KAAK,KAAK,QAAQ,GAAG;GAC3B,IAAI,KAAK,GAAG;GACZ,KAAK,KAAK,MAAM,GAAG,EAAE,EAAE,KAAK,KAAK,kBAAkB,KAAK,MAAM,KAAK,CAAC,CAAC;EACvE;EACA,MAAM,KAAK;GAAE;GAAM,WAAW;EAAK,CAAC;CACtC;CACA,OAAO,MAAM,SAAS,IAAI;EAAE;EAAO,aAAa;CAAG,IAAI,SAAS,OAAO;AACzE;;AAGA,IAAa,gCAAgC;AAM7C,IAAM,wBAAwB;;;;;;;;;;;;AAa9B,IAAa,8BAAgD,SAAS,QAAQ;CAC5E,MAAM,UAAU,IAAI,IAAI,IAAI,SAAS;CACrC,IAAI,QAAQ,SAAS,GAAG,OAAO,SAAS,OAAO;CAC/C,MAAM,QAA0B,CAAC;CACjC,MAAM,QAAiC,CAAC;CACxC,KAAK,MAAM,KAAK,QAAQ,SAAS,qBAAqB,GAAG;EACvD,MAAM,OAAO,EAAE;EACf,IAAI,CAAC,QAAQ,IAAI,IAAI,GAAG;EACxB,MAAM,OAAkC,CAAC;EACzC,KAAK,MAAM,QAAQ,gBAAgB,EAAE,EAAE,GAAG;GACxC,MAAM,KAAK,KAAK,QAAQ,GAAG;GAC3B,IAAI,KAAK,GAAG;GACZ,KAAK,KAAK,MAAM,GAAG,EAAE,EAAE,KAAK,KAAK,kBAAkB,KAAK,MAAM,KAAK,CAAC,CAAC;EACvE;EACA,MAAM,KAAK;GAAE;GAAM,WAAW;EAAK,CAAC;EAEpC,MAAM,SAAS,EAAE,SAAS,KAAK,EAAE,GAAG,QAAQ,IAAI;EAChD,MAAM,KAAK,CAAC,QAAQ,EAAE,SAAS,KAAK,EAAE,GAAG,MAAM,CAAC;CAClD;CACA,IAAI,MAAM,WAAW,GAAG,OAAO,SAAS,OAAO;CAC/C,OAAO;EAAE;EAAO,aAAa,YAAY,SAAS,KAAK;CAAE;AAC3D;;AAGA,IAAa,oCAAoC;;AAKjD,IAAM,mBAAmB,QAA2B;CAClD,MAAM,IAAI,IAAI,KAAK,EAAE,QAAQ,SAAS,EAAE;CACxC,IAAI,MAAM,QAAQ,OAAO;CACzB,IAAI,MAAM,SAAS,OAAO;CAC1B,IAAI,MAAM,QAAQ,OAAO;CACzB,IAAI,kBAAkB,KAAK,CAAC,GAAG,OAAO,OAAO,CAAC;CAE9C,MAAM,IAAI,8BAA8B,KAAK,CAAC;CAC9C,OAAO,IAAK,EAAE,MAAM,EAAE,MAAM,KAAM;AACpC;;;;;;;;;;;;;;;;;;;;;;AAuBA,IAAa,4BAA8C,SAAS,QAAQ;CAC1E,MAAM,UAAU,IAAI,IAAI,IAAI,SAAS;CACrC,IAAI,QAAQ,SAAS,GAAG,OAAO,SAAS,OAAO;CAC/C,MAAM,QAAQ,QAAQ,MAAM,IAAI;CAEhC,IAAI,IAAI;CACR,OAAO,IAAI,MAAM,UAAU,MAAM,GAAG,KAAK,MAAM,IAAI;CACnD,IAAI,KAAK,MAAM,QAAQ,OAAO,SAAS,OAAO;CAC9C,MAAM,OAAO,MAAM,GAAG,KAAK;CAC3B,IAAI,CAAC,QAAQ,IAAI,IAAI,GAAG,OAAO,SAAS,OAAO;CAE/C,MAAM,OAAkC,CAAC;CACzC,IAAI,IAAI,IAAI;CACZ,IAAI,eAAe;CACnB,OAAO,IAAI,MAAM,QAAQ,KAAK;EAC5B,MAAM,OAAO,MAAM;EACnB,IAAI,KAAK,KAAK,MAAM,IAAI;GACtB,eAAe;GACf;EACF;EACA,MAAM,KAAK,sCAAsC,KAAK,IAAI;EAC1D,IAAI,CAAC,IAAI;EACT,KAAK,GAAG,MAAM,gBAAgB,GAAG,EAAE;EACnC,eAAe;CACjB;CACA,IAAI,OAAO,KAAK,IAAI,EAAE,WAAW,GAAG,OAAO,SAAS,OAAO;CAE3D,IAAI,QAAQ;CACZ,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK,SAAS,MAAM,GAAG,SAAS;CACvD,IAAI,MAAM;CACV,KAAK,IAAI,IAAI,GAAG,KAAK,cAAc,KAAK,OAAO,MAAM,GAAG,UAAU,IAAI,MAAM,SAAS,IAAI,IAAI;CAC7F,OAAO;EAAE,OAAO,CAAC;GAAE;GAAM,WAAW;EAAK,CAAC;EAAG,aAAa,YAAY,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC;CAAE;AACjG;;AAGA,IAAa,kCAAkC;;AAK/C,IAAM,kBAAkB,SAAyB;CAC/C,MAAM,IAAI,uCAAuC,KAAK,KAAK,KAAK,CAAC;CACjE,OAAO,IAAI,EAAE,GAAG,KAAK,IAAI,KAAK,KAAK;AACrC;;;;;;;;;;;;;;;;;;;;;;;AAwBA,IAAa,4BAA8C,YAAY;CACrE,MAAM,IAAI,eAAe,OAAO;CAChC,IAAI,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC,EAAE,SAAS,GAAG,GAAG,OAAO,SAAS,OAAO;CAEnE,MAAM,QAA0B,CAAC;CACjC,IAAI,IAAI;CACR,OAAO,IAAI,EAAE,QAAQ;EAEnB,IAAI,SAAS,KAAK,EAAE,EAAG,GAAG;GACxB;GACA;EACF;EACA,IAAI,EAAE,OAAO,KAAK,OAAO,SAAS,OAAO;EACzC,MAAM,MAAM,aAAa,GAAG,GAAG,KAAK,GAAG;EACvC,IAAI,QAAQ,IAAI,OAAO,SAAS,OAAO;EACvC,MAAM,MAAM,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;EAC5C,IAAI,CAAC,eAAA,SAAS,GAAG,GAAG,OAAO,SAAS,OAAO;EAC3C,MAAM,IAAI;EAEV,IAAI,OAAO,EAAE,SAAS,UAAU,OAAO,SAAS,OAAO;EACvD,MAAM,KAAK;GAAE,MAAM,EAAE;GAAM,WAAW,aAAa,EAAE,cAAc,EAAE,SAAS;EAAE,CAAC;EACjF,IAAI,MAAM;CACZ;CACA,OAAO,MAAM,SAAS,IAAI;EAAE;EAAO,aAAa;CAAG,IAAI,SAAS,OAAO;AACzE;;AAGA,IAAa,kCAAkC;AAI/C,IAAM,oBAAoB;;;;;;;;;;AAW1B,IAAa,yBAA2C,YAAY;CAClE,MAAM,WAAW,QAAQ,QAAQ,iBAAiB;CAClD,IAAI,aAAa,IAAI,OAAO,SAAS,OAAO;CAC5C,MAAM,WAAW,QAAQ,QAAQ,KAAK,WAAW,EAAwB;CACzE,IAAI,aAAa,IAAI,OAAO,SAAS,OAAO;CAC5C,MAAM,SAAS,aAAa,SAAS,UAAU,KAAK,GAAG;CACvD,IAAI,WAAW,IAAI,OAAO,SAAS,OAAO;CAC1C,MAAM,MAAM,aAAa,QAAQ,MAAM,UAAU,SAAS,CAAC,CAAC;CAC5D,IAAI,CAAC,MAAM,QAAQ,GAAG,GAAG,OAAO,SAAS,OAAO;CAChD,MAAM,QAA0B,CAAC;CACjC,KAAK,MAAM,SAAS,KAClB,IAAI,eAAA,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS,UAAU;EACrD,MAAM,IAAI;EACV,MAAM,KAAK;GAAE,MAAM,EAAE;GAAM,WAAW,aAAa,EAAE,SAAS;EAAE,CAAC;CACnE;CAEF,OAAO,MAAM,SAAS,IAClB;EAAE;EAAO,aAAa,YAAY,SAAS,CAAC,CAAC,UAAU,SAAS,CAAC,CAAC,CAAC;CAAE,IACrE,SAAS,OAAO;AACtB;;AAGA,IAAa,+BAA+B;AAI5C,IAAM,iBACJ;AACF,IAAM,iBAAiB;;;;;;AAOvB,IAAa,4BAA8C,YAAY;CACrE,MAAM,QAA0B,CAAC;CACjC,MAAM,QAAiC,CAAC;CACxC,KAAK,MAAM,KAAK,QAAQ,SAAS,cAAc,GAAG;EAChD,MAAM,OAAkC,CAAC;EACzC,KAAK,MAAM,KAAK,EAAE,GAAG,SAAS,cAAc,GAC1C,KAAK,EAAE,MAAM,EAAE,GAAG,KAAK;EAEzB,MAAM,KAAK;GAAE,MAAM,EAAE;GAAI,WAAW;EAAK,CAAC;EAC1C,MAAM,KAAK,CAAC,EAAE,SAAS,IAAI,EAAE,SAAS,KAAK,EAAE,GAAG,MAAM,CAAC;CACzD;CACA,OAAO,MAAM,SAAS,IAAI;EAAE;EAAO,aAAa,YAAY,SAAS,KAAK;CAAE,IAAI,SAAS,OAAO;AAClG;;AAGA,IAAa,kCAAkC;AAO/C,IAAM,gBAAgB;;;;;;;;;;;AAYtB,IAAa,qBAAuC,YAAY;CAC9D,MAAM,WAAW,QAAQ,QAAQ,aAAa;CAC9C,IAAI,aAAa,IAAI,OAAO,SAAS,OAAO;CAC5C,MAAM,WAAW,QAAQ,QAAQ,KAAK,WAAW,CAAoB;CACrE,IAAI,aAAa,IAAI,OAAO,SAAS,OAAO;CAE5C,IAAI,QAAQ;CACZ,IAAI,QAAQ;CACZ,IAAI,UAAU;CACd,IAAI,SAAS;CACb,KAAK,IAAI,IAAI,UAAU,IAAI,QAAQ,QAAQ,KAAK;EAC9C,MAAM,KAAK,QAAQ;EACnB,IAAI,OAAO;GACT,IAAI,SAAS,UAAU;QAClB,IAAI,OAAO,MAAM,UAAU;QAC3B,IAAI,OAAO,MAAK,QAAQ;GAC7B;EACF;EACA,IAAI,OAAO,MAAK,QAAQ;OACnB,IAAI,OAAO,KAAK;OAChB,IAAI,OAAO,KAAK;GACnB;GACA,IAAI,UAAU,GAAG;IACf,SAAS;IACT;GACF;EACF;CACF;CACA,IAAI,WAAW,IAAI,OAAO,SAAS,OAAO;CAC1C,MAAM,MAAM,aAAa,QAAQ,MAAM,UAAU,SAAS,CAAC,CAAC;CAC5D,IAAI,CAAC,MAAM,QAAQ,GAAG,GAAG,OAAO,SAAS,OAAO;CAChD,MAAM,QAA0B,CAAC;CACjC,KAAK,MAAM,SAAS,KAClB,IAAI,eAAA,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS,UAAU;EACrD,MAAM,IAAI;EACV,MAAM,KAAK;GAAE,MAAM,EAAE;GAAM,WAAW,aAAa,EAAE,SAAS;EAAE,CAAC;CACnE;CAEF,OAAO,MAAM,SAAS,IAClB;EAAE;EAAO,aAAa,YAAY,SAAS,CAAC,CAAC,UAAU,SAAS,CAAC,CAAC,CAAC;CAAE,IACrE,SAAS,OAAO;AACtB;;AAGA,IAAa,2BAA2B;;AAKxC,IAAa,sBAAwC,YAAY,SAAS,OAAO;;AAGjF,IAAa,4BAA4B;;AAKzC,IAAa,4BAET;CACF,QAAQ;CACR,OAAO;CACP,SAAS;CACT,UAAU;CACV,eAAe;CACf,aAAa;CACb,aAAa;CACb,SAAS;CACT,aAAa;CACb,KAAK;AACP;;;;;AAMA,IAAa,iCAET;CACF;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;AAUA,IAAa,4BACX,UAEI,2BACJ,QAEI,mCACiB;CACrB,QAAQ,SAAS,QAAQ;EACvB,KAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,SAAS,QAAQ;GACvB,IAAI,CAAC,QAAQ;GACb,MAAM,SAAS,OAAO,SAAS,GAAG;GAClC,IAAI,OAAO,MAAM,SAAS,GAAG,OAAO;EACtC;EACA,OAAO,SAAS,OAAO;CACzB;AACF;;AAGA,IAAa,kCAAkC;;;;;;;;AAS/C,IAAa,yBACX,QACA,UAEI,8BACiB;CACrB,IAAI,OAAO,WAAW,YAAY,OAAO;CACzC,IAAI,WAAW,KAAA,KAAa,WAAW,QAAQ,OAAO,yBAAyB,OAAO;CACtF,IAAI,WAAW,QAAQ,OAAO;CAE9B,OADe,QAAQ,WAAW,0BAA0B,WAC3C;AACnB;;AAGA,IAAa,+BAA+B"}
|
package/tools-zV-_O2MB.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tools-zV-_O2MB.js","names":["#formats"],"sources":["../src/batteries/sandbox/narrator.ts","../src/batteries/sandbox/media_reader.ts","../src/batteries/sandbox/defaults/extension_mime.ts","../src/batteries/sandbox/defaults/default_minter.ts","../src/batteries/sandbox/tools/index.ts"],"sourcesContent":["import type { ModelPath, ModelWriteRoot } from './types'\n\n/** Exhaustive model-facing sandbox outcome. */\nexport type SandboxOutcome =\n | { kind: 'not-found'; path: string }\n | { kind: 'denied-by-policy'; path: string; axis: 'read' | 'write' }\n | { kind: 'gate-declined'; note?: string }\n | { kind: 'gate-unavailable'; reason: 'timeout' | 'error' }\n | {\n kind: 'over-budget'\n bound: 'maxTerminalPayloadBytes'\n observedAtLeast: number\n limit: number\n }\n | { kind: 'scope-limited'; shown: number; atDepth: number; bound: 'maxDepth' }\n | { kind: 'result-limited'; shown: number; limit: number; bound: 'limit' }\n | { kind: 'not-a-regular-file'; path: string; kind_: string }\n | { kind: 'is-a-directory'; path: string }\n | {\n kind: 'path-rejected'\n input: string\n reason: 'escape' | 'absolute-host' | 'home' | 'unc' | 'device' | 'nul'\n }\n /** Model-facing root, conventionally `/`; NEVER the configured absolute host path. */\n | { kind: 'outside-write-root'; path: ModelPath; writeRoot: ModelWriteRoot }\n | { kind: 'sandbox-violation'; violations: readonly string[]; exitCode: number }\n | { kind: 'nonzero-exit'; exitCode: number }\n | { kind: 'no-matches'; pattern: string; scope: string }\n | { kind: 'unknown-media'; mediaId: string }\n | { kind: 'invalid-pattern'; pattern: string; detail: string }\n | { kind: 'not-a-directory'; path: string }\n | { kind: 'io-failure'; path?: string; detail: string }\n | { kind: 'aborted' }\n | { kind: 'timed-out'; bound: 'timeout_seconds'; limitSeconds: number }\n/** Model-facing narration seam; implementations must be total over {@link SandboxOutcome}. */\nexport type SandboxNarrator = (outcome: SandboxOutcome) => string\n/**\n * Render a path rejection with the remedy that fits its REASON.\n *\n * @remarks\n * Rule 2 of the LLM-operator rules: a failure is actionable or it is a loop. \"Use a workspace-relative\n * path\" is right for a `../` escape and useless for a NUL byte — the model cannot act on it, so it\n * retries a variation that fails identically. Each arm states the accepted form and echoes the input\n * as understood. Extracted rather than nested so exhaustiveness is enforced by this function's own\n * return type, with no `default` arm to silently mis-narrate a future reason.\n *\n * @param reason - Why the path was refused.\n * @param input - The model's path, echoed back.\n * @returns The model-facing message.\n */\nconst narratePathRejection = (\n reason: Extract<SandboxOutcome, { kind: 'path-rejected' }>['reason'],\n input: string\n): string => {\n switch (reason) {\n case 'nul':\n return `Path rejected: it contains a NUL byte, which cannot appear in a filename. Remove it and try again (${JSON.stringify(input)}).`\n case 'home':\n return `Path rejected: '~' is not expanded here. Paths are relative to the workspace root, so name the directory directly (${input}).`\n case 'absolute-host':\n return `Path rejected: a drive letter names a host path, which is outside the workspace. Use a workspace-relative path (${input}).`\n case 'device':\n return `Path rejected: device and verbatim prefixes are not addressable here. Use a workspace-relative path (${input}).`\n case 'unc':\n return `Path rejected: a network share is outside the workspace. Use a workspace-relative path (${input}).`\n case 'escape':\n return `Path rejected: '../' leads outside the workspace root. Try a path within it, such as 'src/index.ts' (${input}).`\n }\n}\n\n/** Existence-blind default narrator; not-found and denied-by-policy intentionally share wording. */\nexport const defaultSandboxNarrator: SandboxNarrator = (o) => {\n switch (o.kind) {\n case 'not-found':\n case 'denied-by-policy':\n return `No readable entry at <${o.path}>; retry with a known sandbox-relative path or provide a valid handle.`\n case 'gate-declined':\n return o.note\n ? `Approval was declined: ${o.note}; request approval again or retry without the declined option.`\n : 'Approval was declined; request approval and try again.'\n case 'gate-unavailable':\n return `Sandbox gate ${o.reason}; retry when available.`\n case 'over-budget':\n return `Output exceeded ${o.bound} (${o.observedAtLeast}+ bytes; limit ${o.limit}); retry with a smaller request or raise the limit.`\n case 'scope-limited':\n return `Search stopped at depth ${o.atDepth}; raise max_depth and try again.`\n case 'result-limited':\n return `Search stopped after ${o.shown} results; raise the limit (${o.limit}) and try again.`\n case 'not-a-regular-file':\n return `Not a regular file: <${o.path}>; retry with a regular file or use the directory operation.`\n case 'is-a-directory':\n return `Path is a directory: <${o.path}>; retry with a file path or use a directory operation if available.`\n case 'path-rejected':\n return narratePathRejection(o.reason, o.input)\n case 'outside-write-root':\n // `createModelWriteRoot` normalises the sandbox root to the empty relative string; render it as\n // `/` — the model-facing \"top of what you can see\" — so the message never reads `outside <>`.\n return `Write path <${o.path}> is outside <${o.writeRoot === '' ? '/' : o.writeRoot}>; choose a path inside it.`\n case 'sandbox-violation':\n return `Sandbox blocked the command (exit ${o.exitCode}): ${o.violations.join('; ')}; narrow the command to an allowed path or request access.`\n case 'nonzero-exit':\n return `Command exited with status ${o.exitCode}; inspect the command arguments and retry with a narrower operation.`\n case 'no-matches':\n return `No matches for pattern <${o.pattern}> in scope <${o.scope}>; use a narrower operation or try a different pattern or scope.`\n case 'unknown-media':\n return `Unknown media: ${o.mediaId}; retry with a valid media handle or use a media-discovery operation if available.`\n case 'invalid-pattern':\n return `Invalid pattern ${o.pattern}: ${o.detail}; correct the pattern and retry.`\n case 'not-a-directory':\n return `Not a directory: <${o.path}>; choose a directory path and retry.`\n case 'io-failure':\n return `I/O failure${o.path ? ` at <${o.path}>` : ''}: ${o.detail}; retry the operation or choose a narrower path.`\n case 'aborted':\n return 'Operation aborted; try again.'\n case 'timed-out':\n return `Operation timed out after ${o.limitSeconds} seconds; raise timeout_seconds and try again.`\n }\n const exhaustive: never = o\n return exhaustive\n}\n","import { Media } from '../../common'\nimport { E_SANDBOX_FAILED, E_SANDBOX_NOT_INITIALIZED } from './exceptions'\nimport type { SandboxEpoch } from './types'\nimport type { SandboxFileSystem } from './contracts/file_system'\nimport type { MediaKind, MediaReader, MediaTrustTier } from '../../common'\n\n/** The capability needed to decide whether a sandbox handle is still alive. */\nexport type SandboxEpochIsLive = (epoch: SandboxEpoch) => boolean\n\n/** Arguments for {@link createSandboxMediaReader}. */\nexport interface SandboxMediaReaderOptions {\n /** The filesystem capability belonging to the sandbox handle. */\n fileSystem: SandboxFileSystem\n /** The already translated backend path. */\n path: string\n /** The epoch held by the sandbox handle when this reader was issued. */\n epoch: SandboxEpoch\n /** Predicate owned by the sandbox manager; this reader never issues or invalidates epochs. */\n isEpochLive: SandboxEpochIsLive\n}\n\nconst assertLive = (options: SandboxMediaReaderOptions): void => {\n if (!options.isEpochLive(options.epoch)) throw new E_SANDBOX_NOT_INITIALIZED(['sandbox handle'])\n}\n\nconst statRegularFile = async (options: SandboxMediaReaderOptions) => {\n assertLive(options)\n const metadata = await options.fileSystem.stat(options.path)\n if (metadata.kind !== 'file') {\n throw new E_SANDBOX_FAILED([\n `Sandbox path is not a regular file (kind: ${metadata.kind}): ${options.path}`,\n ])\n }\n return metadata\n}\n\n/**\n * Create a non-describable, replayable reader over a sandbox file.\n *\n * @remarks\n * Every operation checks the owning epoch, stats the path, and refuses anything whose filesystem\n * kind is not `file` before opening it. Every stream call then asks the injected filesystem for a\n * fresh stream; this reader deliberately has no byte cap and does not import a host filesystem.\n * The reader omits `describe()` because approval-bound sandbox capabilities must not cross a\n * serialisation boundary.\n *\n * @param options - The sandbox filesystem, translated path, epoch, and liveness predicate.\n * @returns A file-backed {@link MediaReader}.\n */\nexport const createSandboxMediaReader = (options: SandboxMediaReaderOptions): MediaReader => ({\n async stream(): Promise<ReadableStream<Uint8Array>> {\n await statRegularFile(options)\n assertLive(options)\n return options.fileSystem.read(options.path)\n },\n async byteLength(): Promise<number> {\n const metadata = await statRegularFile(options)\n assertLive(options)\n return metadata.size\n },\n})\n\n/** Arguments for {@link createSandboxMedia}. */\nexport interface SandboxMediaOptions extends SandboxMediaReaderOptions {\n /** Media modality assigned by the stage operation. */\n kind: MediaKind\n /** MIME type resolved by the stage operation. */\n mimeType: string\n /** Model-visible source filename. */\n filename: string\n /** Configuration-supplied provenance tier. */\n trustTier: MediaTrustTier\n /** Optional provenance label retained on the Media value. */\n source?: string\n}\n\n/**\n * Construct the staged media value returned by a mutating sandbox operation.\n *\n * @remarks\n * The shipped Media factories supply the conservative modality hazard and keep the trust-tier\n * choice explicit at this call site. The reader remains deliberately non-describable.\n *\n * @param options - File-reader and media labelling options.\n * @returns A staged {@link Media} value.\n */\nexport const createSandboxMedia = (options: SandboxMediaOptions): Media => {\n const args = {\n kind: options.kind,\n mimeType: options.mimeType,\n filename: options.filename,\n source: options.source,\n reader: createSandboxMediaReader(options),\n }\n switch (options.trustTier) {\n case 'first-party':\n return Media.toolGenerated(args)\n case 'third-party-public':\n return Media.retrievedPublic(args)\n case 'third-party-private':\n return Media.retrievedPrivate(args)\n }\n}\n","/** Pure extension-based MIME defaults for the sandbox file tools. */\nimport type { MimeResolver } from '@nhtio/adk/batteries/sandbox/contracts/mime_resolver'\n\n/** The default prefix available to a custom resolver. */\nexport const DEFAULT_MIME_PEEK_BYTES = 512\n\n/** Extension to MIME mappings used by the default resolver. */\nexport const SANDBOX_EXTENSION_MIME: Readonly<Record<string, string>> = {\n pdf: 'application/pdf',\n doc: 'application/msword',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xls: 'application/vnd.ms-excel',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n ppt: 'application/vnd.ms-powerpoint',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n csv: 'text/csv',\n txt: 'text/plain',\n md: 'text/markdown',\n html: 'text/html',\n htm: 'text/html',\n json: 'application/json',\n yaml: 'application/yaml',\n yml: 'application/yaml',\n rtf: 'application/rtf',\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n webp: 'image/webp',\n gif: 'image/gif',\n tiff: 'image/tiff',\n tif: 'image/tiff',\n avif: 'image/avif',\n wav: 'audio/wav',\n mp3: 'audio/mpeg',\n ogg: 'audio/ogg',\n flac: 'audio/flac',\n ts: 'text/plain',\n tsx: 'text/plain',\n js: 'text/plain',\n jsx: 'text/plain',\n mjs: 'text/plain',\n cjs: 'text/plain',\n py: 'text/plain',\n rb: 'text/plain',\n go: 'text/plain',\n rs: 'text/plain',\n java: 'text/plain',\n kt: 'text/plain',\n swift: 'text/plain',\n c: 'text/plain',\n h: 'text/plain',\n cc: 'text/plain',\n cpp: 'text/plain',\n hpp: 'text/plain',\n cs: 'text/plain',\n php: 'text/plain',\n sh: 'text/plain',\n bash: 'text/plain',\n zsh: 'text/plain',\n sql: 'text/plain',\n toml: 'text/plain',\n ini: 'text/plain',\n cfg: 'text/plain',\n conf: 'text/plain',\n lua: 'text/plain',\n pl: 'text/plain',\n r: 'text/plain',\n scala: 'text/plain',\n dart: 'text/plain',\n vue: 'text/plain',\n svelte: 'text/plain',\n css: 'text/plain',\n scss: 'text/plain',\n less: 'text/plain',\n xml: 'application/xml',\n svg: 'image/svg+xml',\n}\n\nconst extensionOf = (path: string): string | undefined => {\n const name = path.split(/[\\\\/?#]/).pop() ?? ''\n const dot = name.lastIndexOf('.')\n if (dot <= 0 || dot === name.length - 1) return undefined\n return name.slice(dot + 1).toLowerCase()\n}\n\n/** Resolve a MIME type from a filename, without sniffing bytes. */\nexport const extensionMimeResolver: MimeResolver = ({ path, declared }) => {\n if (declared !== undefined && declared.trim() !== '') return declared\n return SANDBOX_EXTENSION_MIME[extensionOf(path) ?? '']\n}\n\n/** The default resolver, also exported under the concise name used by consumers. */\nexport const defaultMimeResolver = extensionMimeResolver\n\n/**\n * Run a resolver and fall back to the extension resolver when it declines.\n * The callback supplied to consumer code is always bounded by `maxPeekBytes`.\n */\nexport const resolveMime = async (\n path: string,\n resolver?: MimeResolver,\n options: {\n declared?: string\n maxPeekBytes?: number\n peek?: (bytes: number) => Promise<Uint8Array>\n } = {}\n): Promise<string | undefined> => {\n const maxPeekBytes = Math.max(0, Math.floor(options.maxPeekBytes ?? DEFAULT_MIME_PEEK_BYTES))\n const sourcePeek = options.peek ?? (async () => new Uint8Array(0))\n const peek = async (bytes: number): Promise<Uint8Array> =>\n sourcePeek(Math.min(maxPeekBytes, Math.max(0, Math.floor(bytes))))\n if (resolver !== undefined) {\n const detected = await resolver({\n path,\n declared: options.declared,\n peek: async (bytes) => peek(Math.min(maxPeekBytes, Math.max(0, Math.floor(bytes)))),\n })\n if (detected !== undefined) return detected\n }\n return extensionMimeResolver({ path, declared: options.declared, peek })\n}\n","/** Pure default artifact-format registry for sandbox query results. */\nimport { extensionMimeResolver } from './extension_mime'\nimport { SpooledArtifact, SpooledJsonArtifact, SpooledMarkdownArtifact } from '@nhtio/adk/common'\nimport type { SpooledArtifactConstructor } from '@nhtio/adk/common'\nimport type { ArtifactMinter } from '@nhtio/adk/batteries/sandbox/contracts/artifact_minter'\n\n/** A format declaration accepted by the default minter. */\nexport type ArtifactFormat = {\n /** Stable identifier for the format. */\n id: string\n /** MIME types handled by the format. */\n mime: string[]\n /** Filename extensions handled by the format. */\n extensions: string[]\n /** Lazy constructor loader; it is called only after the format is selected. */\n ctor: () => Promise<unknown>\n}\n\nconst builtInFormats: ArtifactFormat[] = [\n {\n id: 'json',\n mime: ['application/json'],\n extensions: ['json'],\n ctor: async () => SpooledJsonArtifact,\n },\n {\n id: 'markdown',\n mime: ['text/markdown'],\n extensions: ['md', 'markdown'],\n ctor: async () => SpooledMarkdownArtifact,\n },\n]\n\n/** A pure minter with optional, lazily loaded consumer formats. */\nexport class DefaultArtifactMinter implements ArtifactMinter {\n readonly #formats: readonly ArtifactFormat[]\n\n constructor(formats: readonly ArtifactFormat[] = []) {\n this.#formats = [...builtInFormats, ...formats]\n }\n\n /** Return format metadata without invoking any constructor thunk. */\n async formats(): Promise<ArtifactFormat[]> {\n return this.#formats.map((format) => ({\n ...format,\n mime: [...format.mime],\n extensions: [...format.extensions],\n }))\n }\n\n /** Resolve the constructor for a MIME type; unknown types use the base artifact. */\n async constructorForMime(mime: string | undefined): Promise<SpooledArtifactConstructor> {\n const normalized = mime?.toLowerCase().split(';')[0].trim()\n const format = this.#formats.find((entry) =>\n entry.mime.some((item) => item.toLowerCase() === normalized)\n )\n if (format === undefined) return SpooledArtifact\n try {\n const resolved = await format.ctor()\n return isArtifactConstructor(resolved) ? resolved : SpooledArtifact\n } catch {\n return SpooledArtifact\n }\n }\n\n /** Resolve the constructor from a MIME type, then an extension, without validating content. */\n async constructorForPath(path: string, mime?: string): Promise<SpooledArtifactConstructor> {\n const detected =\n mime ?? (await extensionMimeResolver({ path, peek: async () => new Uint8Array(0) }))\n return this.constructorForMime(detected)\n }\n}\n\n/** The shared default registry. Its format thunks remain lazy until selected. */\nexport const defaultArtifactMinter = new DefaultArtifactMinter()\n\n/** Select the default artifact constructor for a path. */\nexport const artifactConstructorForPath = (path: string, mime?: string) =>\n defaultArtifactMinter.constructorForPath(path, mime)\n\n/** Select a constructor from a caller-provided minter, never throwing on bad metadata. */\nexport const constructorFromMinter = async (\n minter: ArtifactMinter,\n mime: string | undefined\n): Promise<SpooledArtifactConstructor> => {\n try {\n const normalized = mime?.toLowerCase().split(';')[0].trim()\n const formats = await minter.formats()\n const format = formats.find((entry) =>\n entry.mime.some((candidate) => candidate.toLowerCase() === normalized)\n )\n if (format === undefined) return SpooledArtifact\n const resolved = await format.ctor()\n return isArtifactConstructor(resolved) ? resolved : SpooledArtifact\n } catch {\n return SpooledArtifact\n }\n}\n\nconst isArtifactConstructor = (value: unknown): value is SpooledArtifactConstructor =>\n SpooledArtifact.isSpooledArtifactConstructor(value)\n","/** @module @nhtio/adk/batteries/sandbox/tools */\nimport { validator } from '@nhtio/validation'\nimport { isInstanceOf } from '../../../guards'\nimport { createSandboxMedia } from '../media_reader'\nimport { defaultSandboxNarrator } from '../narrator'\nimport { classifySandboxPathRejection } from '../paths'\nimport { resolveMime } from '../defaults/extension_mime'\nimport { createModelPath, createModelWriteRoot } from '../types'\nimport { defaultArtifactMinter } from '../defaults/default_minter'\nimport { E_TURN_GATE_ABORTED, E_TURN_GATE_TIMEOUT } from '../../../lib/exceptions/runtime'\nimport { E_SANDBOX_FAILED, E_SANDBOX_GATE_REQUIRED, E_SANDBOX_REFUSED } from '../exceptions'\nimport {\n Tool,\n Media,\n SpooledArtifact,\n SpooledJsonArtifact,\n SpooledMarkdownArtifact,\n} from '../../../common'\nimport type { DerivedRules } from '../types'\nimport type { SandboxHandle } from '../manager'\nimport type { SandboxOutcome } from '../narrator'\nimport type { SandboxSearch } from '../contracts/search'\nimport type { MimeResolver } from '../contracts/mime_resolver'\nimport type { Tool as AdkTool } from '../../../lib/classes/tool'\nimport type { MediaTrustTier, MediaKind } from '../../../common'\nimport type { SandboxFileSystem } from '../contracts/file_system'\nimport type { PathTranslator } from '../contracts/path_translator'\nimport type { ArtifactMinter } from '../contracts/artifact_minter'\nimport type { DispatchContext } from '../../../lib/contracts/dispatch_context'\n\ntype GateVerdict = { approved: true } | { approved: false; note?: string }\ntype Gate = (\n ctx: DispatchContext,\n call: { tool: string; args: unknown }\n) => GateVerdict | void | Promise<GateVerdict | void>\n/** Options for constructing the sandbox's eight untrusted filesystem tools. */\nexport interface SandboxToolsOptions {\n /**\n * The handle that owns this tool set and issues its reader epoch.\n *\n * @remarks\n * File-backed readers retain this epoch and check it before every operation. After\n * {@link SandboxHandle.dispose} they fail with `E_SANDBOX_NOT_INITIALIZED` rather than\n * falling through to the host filesystem.\n */\n handle: SandboxHandle\n /** The filesystem capability used for stat, traversal, reads, and writes. */\n fileSystem: SandboxFileSystem\n /** Translates model-visible paths into the sandbox backend and back. */\n pathTranslator: PathTranslator\n /**\n * Required approval callback for every tool, including reads and searches.\n *\n * @remarks\n * A read of `.env` is an exfiltration event, and `search_files` is a secret-discovery\n * primitive, so construction rejects a missing gate with `E_SANDBOX_GATE_REQUIRED`.\n * Calling the gate is a real suspension: a harness without a decider leaves the turn\n * waiting rather than silently allowing the operation.\n */\n gate: Gate\n /**\n * Search backend for `search_files` and `find_files`.\n *\n * @remarks\n * These tools spawn `rg` through the sandbox enforcer and are OS-enforced; they do not\n * have the in-process filesystem tools' weaker enforcement boundary.\n */\n search?: SandboxSearch\n /** Factory for artifacts returned by file-query tools; defaults to the battery minter. */\n artifactMinter?: ArtifactMinter\n /** Resolves MIME types while staging a file; defaults to the extension resolver. */\n mimeResolver?: MimeResolver\n /** Explicit host write root; it is never inferred. */\n writeRoot: string\n /**\n * Configuration-supplied provenance for staged media.\n *\n * @remarks\n * This value cannot be inferred from `source`: core requires an explicit trust tier and\n * batteries must not auto-classify content.\n */\n trustTier: MediaTrustTier\n /** Tools which are not registered are not named in descriptions. */\n registeredTools?: readonly string[]\n}\n\nconst argsPath = (extra: Record<string, unknown> = {}) =>\n validator.object({ path: validator.string().required(), ...extra })\nconst depth = validator.number().integer().min(0).default(20)\nconst json = (value: unknown): string => JSON.stringify(value)\nconst relativeFramePath = (root: string, value: string): string => {\n const prefix = root === '/' ? '/' : `${root}/`\n return value === root ? '' : value.startsWith(prefix) ? value.slice(prefix.length) : value\n}\nconst isDenied = (\n rules: DerivedRules | undefined,\n path: string,\n axis: 'read' | 'write'\n): boolean => {\n if (!rules || rules.filesystemDisabled) return false\n const under = (rule: string): boolean =>\n rule === '/' || path === rule || path.startsWith(`${rule}/`)\n const list = axis === 'read' ? rules.read.denyOnly : rules.write.denyWithinAllow\n if (axis === 'read')\n return rules.read.denyOnly.some(under) && !rules.read.allowWithinDeny.some(under)\n return !rules.write.allowOnly.some(under) || list.some(under)\n}\nconst narrateThrow = (outcome: SandboxOutcome, refused = true): never => {\n const message = defaultSandboxNarrator(outcome)\n if (refused) throw new E_SANDBOX_REFUSED([message])\n throw new E_SANDBOX_FAILED([message])\n}\n\n/**\n * Run a `PathTranslator` operation and narrate any refusal it raises.\n *\n * @remarks\n * EVERY translator call must go through here, not just the obvious `toRelative`. `toBackendPath` and\n * `assertNoSymlinkComponents` both reject — the latter is the symlinked-component refusal, which is a\n * security control — and a bare call lets that escape as the translator's native error, bypassing the\n * narrator seam the whole battery depends on. The model then receives an unactionable message for the\n * one class of failure it could actually correct.\n *\n * An already-narrated exception passes through untouched, so wrapping a call that itself narrates is\n * safe and the outcome is never rendered twice.\n *\n * @param operation - The translator call.\n * @param input - The model-supplied path, echoed back in the outcome.\n * @param reason - The `path-rejected` reason to narrate.\n * @returns The operation's result.\n */\nexport const narratingPath = async <T>(\n operation: () => T | Promise<T>,\n input: string\n): Promise<T> => {\n try {\n return await operation()\n } catch (error) {\n if (\n isInstanceOf(error, 'E_SANDBOX_REFUSED', E_SANDBOX_REFUSED) ||\n isInstanceOf(error, 'E_SANDBOX_FAILED', E_SANDBOX_FAILED)\n )\n throw error\n // The REASON is classified from the input rather than assumed. Hardcoding `'escape'` told a model\n // that supplied a NUL byte or a UNC path to \"use a workspace-relative path\", which is unactionable\n // advice for those mistakes — and the plan asks for one distinct case per reason.\n return narrateThrow(\n { kind: 'path-rejected', input, reason: classifySandboxPathRejection(input) ?? 'escape' },\n false\n )\n }\n}\n/**\n * Classify an unexpected fault as `io-failure`, PRESERVING any already-narrated outcome.\n *\n * @remarks\n * A catch that wraps unconditionally destroys the classification the seam just made: a per-child\n * `path-rejected` inside a traversal would reach the model as \"the listing broke\" — wrong, and\n * unactionable. Only genuinely unclassified faults become `io-failure`.\n *\n * @param error - The caught value.\n * @param path - The model-facing path for the outcome.\n * @returns Never; always throws.\n */\nconst rethrowAsIoFailure: (error: unknown, path: string) => never = (error, path) => {\n if (\n isInstanceOf(error, 'E_SANDBOX_REFUSED', E_SANDBOX_REFUSED) ||\n isInstanceOf(error, 'E_SANDBOX_FAILED', E_SANDBOX_FAILED)\n )\n throw error\n throw new E_SANDBOX_FAILED([\n defaultSandboxNarrator({ kind: 'io-failure', path, detail: String(error) }),\n ])\n}\n\nconst regular = async (options: SandboxToolsOptions, relative: string, axis: 'read' | 'write') => {\n // Also narrated: this is the shared pre-flight for `open_file*` and `stage_file`, so an unguarded\n // translation here would bypass the seam on the two most-used tools rather than just one.\n const backend = await narratingPath(\n () => options.pathTranslator.toBackendPath(relative),\n relative\n )\n if (isDenied(options.handle.effectivePolicy(), backend, axis))\n narrateThrow({ kind: 'denied-by-policy', path: relative, axis })\n let stat\n try {\n stat = await options.fileSystem.stat(backend)\n } catch {\n narrateThrow({ kind: 'not-found', path: relative })\n }\n if (stat!.kind === 'dir') narrateThrow({ kind: 'is-a-directory', path: relative })\n if (stat!.kind !== 'file')\n narrateThrow({ kind: 'not-a-regular-file', path: relative, kind_: stat!.kind })\n return backend\n}\nconst gated = async (\n options: SandboxToolsOptions,\n ctx: DispatchContext,\n tool: string,\n args: unknown\n) => {\n try {\n const verdict = await options.gate(ctx, { tool, args })\n if (verdict && !verdict.approved) narrateThrow({ kind: 'gate-declined', note: verdict.note })\n } catch (error) {\n if (\n isInstanceOf(error, 'E_SANDBOX_REFUSED', E_SANDBOX_REFUSED) ||\n isInstanceOf(error, 'E_SANDBOX_FAILED', E_SANDBOX_FAILED)\n )\n throw error\n // THE THREE-CASE ABORT SPLIT. Both a turn-level abort and `TurnGate.abort()` reject with the\n // SAME `E_TURN_GATE_ABORTED`, so the error type cannot tell them apart — only the signal can,\n // and only best-effort (two benign races are named in the plan; neither can approve work).\n // · signal already set ⇒ the dispatch is unwinding and there is no reader ⇒ rethrow RAW;\n // · signal not yet set ⇒ the gate alone was cancelled and the model IS reading ⇒ narrate.\n // Collapsing both into `gate-unavailable` would narrate into a torn-down dispatch and mislabel\n // a cancellation as a broken gate.\n if (isInstanceOf(error, 'E_TURN_GATE_ABORTED', E_TURN_GATE_ABORTED)) {\n if (ctx.abortSignal?.aborted) throw error\n narrateThrow({ kind: 'aborted' })\n }\n // A gate TIMEOUT is its own cause and its own reason. Reporting it as `'error'` tells the\n // operator the gate broke when in fact nobody answered it — the headless-decider trap.\n narrateThrow({\n kind: 'gate-unavailable',\n reason: isInstanceOf(error, 'E_TURN_GATE_TIMEOUT', E_TURN_GATE_TIMEOUT) ? 'timeout' : 'error',\n })\n }\n}\nconst makeOpen = (\n options: SandboxToolsOptions,\n name: string,\n ctor: typeof SpooledArtifact,\n description: string\n) =>\n new Tool({\n name,\n description,\n trusted: false,\n artifactConstructor: () => ctor,\n inputSchema: argsPath(),\n handler: async (raw, ctx) => {\n await gated(options, ctx, name, raw)\n let path!: string\n try {\n path = await options.pathTranslator.toRelative((raw as { path: string }).path)\n } catch {\n narrateThrow({\n kind: 'path-rejected',\n input: (raw as { path: string }).path,\n reason: classifySandboxPathRejection((raw as { path: string }).path) ?? 'escape',\n })\n }\n const backend = await regular(options, path!, 'read')\n try {\n const reader = await ctx.storeRetrievableBytes(\n `${ctx.id}:${name}:${path}`,\n await options.fileSystem.read(backend, { signal: ctx.abortSignal })\n )\n return new ctor(reader)\n } catch (error) {\n rethrowAsIoFailure(error, path)\n }\n },\n })\nconst framesArtifact = async (\n ctx: DispatchContext,\n id: string,\n frames: unknown[],\n note?: string\n) => {\n const body = `${note ? `${note}\\n` : ''}${frames.map(json).join('\\n')}${frames.length ? '\\n' : ''}`\n const reader = await ctx.storeRetrievableBytes(id, body)\n return new SpooledJsonArtifact(reader)\n}\nconst descriptions = {\n open: 'Read a file from disk into the turn to query, not to change. Use artifact_* tools; use stage_file to change it.',\n stage:\n 'Change a file: use stage_file, then media verbs and save_media; mutations are in memory until saved. Use open_file to read or grep first; no artifact_* tools attach.',\n save: 'Write to a file on disk: save bytes already in this turn, produced by media verbs; you cannot author content here. This overwrites and makes a stage_file edit real.',\n}\n/**\n * Construct the sandbox's file, media, directory, and search tools.\n *\n * @remarks\n * All returned tools are untrusted and gate their operations, including reads. The factory\n * keeps the supplied handle, filesystem, path translator, search backend, and configuration\n * together so the tools cannot accidentally bypass the sandbox boundary.\n *\n * @param options - Capabilities and configuration for the sandbox tool set.\n * @returns The eight tools registered for a sandbox handle.\n */\nexport const createSandboxTools = async (options: SandboxToolsOptions): Promise<AdkTool[]> => {\n if (typeof options.gate !== 'function')\n throw new E_SANDBOX_GATE_REQUIRED(['A gate is required for every sandbox tool'])\n const minter = options.artifactMinter ?? defaultArtifactMinter\n void minter\n const open = makeOpen(\n options,\n 'open_file',\n SpooledArtifact,\n `${descriptions.open} open_file works for any regular file and provides generic query tools.`\n )\n const openJson = makeOpen(\n options,\n 'open_json_file',\n SpooledJsonArtifact,\n `${descriptions.open} This format-specific tool provides artifact_json_*; invalid JSON remains queryable as text.`\n )\n const openMarkdown = makeOpen(\n options,\n 'open_markdown_file',\n SpooledMarkdownArtifact,\n `${descriptions.open} This format-specific tool provides markdown query tools.`\n )\n const stage = new Tool({\n name: 'stage_file',\n description: descriptions.stage,\n trusted: false,\n inputSchema: argsPath(),\n handler: async (raw, ctx) => {\n await gated(options, ctx, 'stage_file', raw)\n let path!: string\n try {\n path = await options.pathTranslator.toRelative((raw as { path: string }).path)\n } catch {\n narrateThrow({\n kind: 'path-rejected',\n input: (raw as { path: string }).path,\n reason: classifySandboxPathRejection((raw as { path: string }).path) ?? 'escape',\n })\n }\n const backend = await regular(options, path!, 'read')\n let mime: string | undefined\n try {\n mime = await resolveMime(path, options.mimeResolver, {\n peek: async (n) => {\n const stream = await options.fileSystem.read(backend)\n const r = stream.getReader()\n const x = await r.read()\n r.releaseLock()\n return (x.value ?? new Uint8Array()).slice(0, n)\n },\n })\n } catch (error) {\n rethrowAsIoFailure(error, path)\n }\n const kind: MediaKind = mime?.startsWith('image/')\n ? 'image'\n : mime?.startsWith('audio/')\n ? 'audio'\n : mime?.startsWith('video/')\n ? 'video'\n : 'document'\n return createSandboxMedia({\n fileSystem: options.fileSystem,\n path: backend,\n epoch: options.handle.epoch,\n isEpochLive: options.handle.isEpochLive,\n kind,\n mimeType: mime ?? 'application/octet-stream',\n filename: path,\n trustTier: options.trustTier,\n })\n },\n })\n const save = new Tool({\n name: 'save_media',\n description: descriptions.save,\n trusted: false,\n inputSchema: validator.object({\n media_id: validator.string().required(),\n path: validator.string().required(),\n }),\n handler: async (raw, ctx) => {\n await gated(options, ctx, 'save_media', raw)\n const a = raw as { media_id: string; path: string }\n let path!: string\n try {\n path = await options.pathTranslator.toRelative(a.path)\n } catch {\n narrateThrow({\n kind: 'path-rejected',\n input: a.path,\n reason: classifySandboxPathRejection(a.path) ?? 'escape',\n })\n }\n let root!: string\n try {\n root = await options.pathTranslator.toRelative(options.writeRoot)\n } catch {\n narrateThrow({\n kind: 'path-rejected',\n input: options.writeRoot,\n reason: classifySandboxPathRejection(options.writeRoot) ?? 'escape',\n })\n }\n if (!(root === '' || path === root || path.startsWith(`${root}/`)))\n narrateThrow({\n kind: 'outside-write-root',\n path: createModelPath(path),\n writeRoot: createModelWriteRoot(root),\n })\n const mediaResults = [...ctx.turnToolCalls]\n .map((call) => call.results)\n .flatMap((result) => (Array.isArray(result) ? result : [result]))\n const media = mediaResults.find(\n (result): result is Media => Media.isMedia(result) && result.id === a.media_id\n )\n if (!Media.isMedia(media)) narrateThrow({ kind: 'unknown-media', mediaId: a.media_id })\n const backend = await narratingPath(() => options.pathTranslator.toBackendPath(path), a.path)\n if (isDenied(options.handle.effectivePolicy(), backend, 'write'))\n narrateThrow({ kind: 'denied-by-policy', path, axis: 'write' })\n // The symlinked-component refusal is a SECURITY control, so its rejection must reach the model\n // as an actionable `path-rejected` rather than the translator's native error.\n await narratingPath(() => options.pathTranslator.assertNoSymlinkComponents(path), a.path)\n try {\n await options.fileSystem.write(backend, await media!.stream(), {\n signal: ctx.abortSignal,\n })\n const written = await options.fileSystem.stat(backend)\n return `Saved ${path} (${written.size} bytes)`\n } catch (error) {\n rethrowAsIoFailure(error, path)\n }\n },\n })\n const list = new Tool({\n name: 'list_directory',\n description:\n 'Return a complete queryable JSON listing. The only boundary is max_depth; raise it to inspect an unexplored subtree. Prefer find_files for names and list_media for media already in the turn.',\n trusted: false,\n inputSchema: argsPath({ max_depth: depth }),\n handler: async (raw, ctx) => {\n await gated(options, ctx, 'list_directory', raw)\n const a = raw as { path: string; max_depth: number }\n let root!: string\n try {\n root = await options.pathTranslator.toRelative(a.path)\n } catch {\n narrateThrow({\n kind: 'path-rejected',\n input: a.path,\n reason: classifySandboxPathRejection(a.path) ?? 'escape',\n })\n }\n const backend = await narratingPath(() => options.pathTranslator.toBackendPath(root!), a.path)\n if (isDenied(options.handle.effectivePolicy(), backend, 'read'))\n narrateThrow({ kind: 'denied-by-policy', path: root, axis: 'read' })\n let frames: unknown[] = []\n let limited = false\n let sawDone = false\n try {\n for await (const frame of options.fileSystem.list(backend, {\n maxDepth: a.max_depth,\n signal: ctx.abortSignal,\n })) {\n if (\n frame.kind === 'item' &&\n !isDenied(\n options.handle.effectivePolicy(),\n // Per CHILD, inside the traversal: a refusal here must still narrate rather than\n // surface as the directory's I/O failure carrying the translator's native text.\n await narratingPath(\n () => options.pathTranslator.toBackendPath(relativeFramePath(backend, frame.path)),\n frame.path\n ),\n 'read'\n )\n )\n frames.push({ ...frame, path: relativeFramePath(backend, frame.path) })\n if (frame.kind === 'done') {\n // `list_directory` HAS NO `limit` — its only boundary is max_depth — so a\n // `bound: 'limit'` frame cannot be a legitimate truncation here and means the backend\n // is broken. `Done` is a union shared with the search frames, which is the only reason\n // the shape is expressible at all.\n //\n // This is deliberately the OPPOSITE of `search_files`/`find_files` (see `makeSearch`\n // below): those take a required `limit`, so the same frame is their ORDINARY\n // truncation outcome and narrates `result-limited`. The rule is per-operation, not\n // per-frame, and this throw belongs to `list_directory` alone — a copy of it inside\n // `makeSearch` made every broad `find_files` query fail on its own limit.\n if (!frame.complete && frame.bound === 'limit')\n throw new Error('list backend emitted an over-limit frame')\n sawDone = true\n limited = !frame.complete\n }\n }\n if (!sawDone) throw new Error('listing ended without a done frame')\n } catch (error) {\n rethrowAsIoFailure(error, root)\n }\n return framesArtifact(\n ctx,\n `${ctx.id}:list:${root}`,\n frames,\n limited\n ? defaultSandboxNarrator({\n kind: 'scope-limited',\n shown: 0,\n atDepth: a.max_depth,\n bound: 'maxDepth',\n })\n : undefined\n )\n },\n })\n /**\n * `follow` is deliberately schema-VALID while the bundled ripgrep adapter refuses it. The schema\n * is shared by every deployment, and a BYO `SandboxSearch` that has verified its own containment\n * of symlinked descendants may honour the flag; narrowing the schema to `valid(false)` would make\n * it unreachable for them too. The bundled refusal is adapter-specific and names the pending\n * containment audit, so a caller learns why rather than finding the option silently absent.\n */\n // `follow` traverses symlinked DESCENDANTS, which never pass through the path translator, so\n // an uncontained backend turns it into an unbounded read. The tools layer cannot see what is\n // behind `SandboxSearch`, so the ADAPTER declares whether it contains them. Undeclared, the\n // schema rejects `follow: true` at validation rather than advertising an option that fails at\n // execution — a narrowed COPY of the permissive rule, so an adapter that HAS verified\n // containment still gets the full option.\n // Over-limit is the ORDINARY outcome for these two: `limit` is required, so exceeding it\n // narrates `result-limited` and returns the bounded results. Contrast `list_directory` above,\n // which has no `limit` and treats the same frame as a backend protocol violation.\n const permissiveFollow = validator.boolean().default(false)\n // REJECTS `follow: true` unless the adapter declared containment. `.valid(false)` on a COPY,\n // so an adapter that DID declare it still gets the permissive rule.\n const followRejectedUnlessDeclared = options.search?.supportsFollow\n ? permissiveFollow\n : permissiveFollow.valid(false)\n const makeSearch = (name: string, content: boolean) =>\n new Tool({\n name,\n description: content\n ? 'Search file contents on disk that you have not opened; artifact_grep searches one artifact you already opened. Every whole hit is queryable JSON. Bounded by max_depth and a required limit; exceeding limit returns the bounded hits with a result-limited note, not an error. follow (symlink traversal) is not available in this deployment.'\n : 'Find file names across the disk tree, rather than searching contents. Every result is queryable JSON. Bounded by max_depth and a required limit; exceeding limit returns the bounded paths with a result-limited note, not an error. follow (symlink traversal) is not available in this deployment.',\n trusted: false,\n inputSchema: validator.object({\n [content ? 'pattern' : 'glob']: validator.string().required(),\n path: validator.string().allow('').default(''),\n max_depth: depth,\n limit: validator.number().integer().min(1).required(),\n ...(content\n ? {\n ignore_case: validator.boolean().default(false),\n literal: validator.boolean().default(false),\n glob: validator.string().allow('').optional(),\n iglob: validator.string().allow('').optional(),\n // Rejects `true` at validation unless the adapter set `supportsFollow` (see above).\n follow: followRejectedUnlessDeclared,\n hidden: validator.boolean().default(false),\n no_ignore: validator.boolean().default(false),\n }\n : {\n iglob: validator.string().allow('').optional(),\n // Rejects `true` at validation unless the adapter set `supportsFollow` (see above).\n follow: followRejectedUnlessDeclared,\n hidden: validator.boolean().default(false),\n no_ignore: validator.boolean().default(false),\n }),\n }),\n handler: async (raw, ctx) => {\n await gated(options, ctx, name, raw)\n const a = raw as {\n pattern?: string\n glob?: string\n path: string\n max_depth: number\n limit: number\n ignore_case?: boolean\n literal?: boolean\n iglob?: string\n follow?: boolean\n hidden?: boolean\n no_ignore?: boolean\n }\n const root = await narratingPath(() => options.pathTranslator.toRelative(a.path), a.path)\n const search = options.search\n if (!search)\n narrateThrow(\n { kind: 'io-failure', path: root, detail: 'search backend unavailable' },\n false\n )\n // Translated ONCE, through the seam. Three separate bare calls previously let a translator\n // refusal escape as a generic downstream error instead of a narrated `path-rejected`.\n const backendRoot = await narratingPath(\n () => options.pathTranslator.toBackendPath(root),\n a.path\n )\n const iterable = content\n ? search!.searchContent({\n root: backendRoot,\n pattern: a.pattern!,\n maxDepth: a.max_depth,\n limit: a.limit,\n ignoreCase: a.ignore_case,\n literal: a.literal,\n glob: a.glob,\n iglob: a.iglob,\n follow: a.follow,\n hidden: a.hidden,\n noIgnore: a.no_ignore,\n signal: ctx.abortSignal,\n })\n : search!.findPaths({\n root: backendRoot,\n glob: a.glob!,\n maxDepth: a.max_depth,\n limit: a.limit,\n iglob: a.iglob,\n follow: a.follow,\n hidden: a.hidden,\n noIgnore: a.no_ignore,\n signal: ctx.abortSignal,\n })\n const frames: unknown[] = []\n let terminal:\n | Extract<typeof iterable extends AsyncIterable<infer F> ? F : never, { kind: 'done' }>\n | undefined\n let sawDone = false\n try {\n for await (const frame of iterable) {\n if (frame.kind === 'item')\n frames.push({\n ...frame,\n path: relativeFramePath(backendRoot, frame.path),\n })\n else {\n sawDone = true\n terminal = frame\n }\n }\n if (!sawDone) throw new Error('search ended without a done frame')\n } catch (error) {\n rethrowAsIoFailure(error, root)\n }\n const note = frames.length\n ? undefined\n : defaultSandboxNarrator({\n kind: 'no-matches',\n pattern: content ? a.pattern! : a.glob!,\n scope: root,\n })\n return framesArtifact(\n ctx,\n `${ctx.id}:${name}:${root}`,\n frames,\n terminal && !terminal.complete\n ? // `limit` is REQUIRED on both search tools, so an over-limit terminal frame is the\n // ordinary truncation outcome: narrate it and return the bounded results. It is NOT\n // an error here, unlike `list_directory`, which has no `limit` and treats the same\n // frame as a backend protocol violation.\n terminal.bound === 'limit'\n ? defaultSandboxNarrator({\n kind: 'result-limited',\n shown: terminal.shown,\n limit: a.limit,\n bound: 'limit',\n })\n : defaultSandboxNarrator({\n kind: 'scope-limited',\n shown: frames.length,\n atDepth: terminal.atDepth,\n bound: 'maxDepth',\n })\n : note\n )\n },\n })\n return [\n open,\n openJson,\n openMarkdown,\n stage,\n save,\n list,\n makeSearch('search_files', true),\n makeSearch('find_files', false),\n ]\n}\n/** Alias for {@link createSandboxTools}, used by tool-forging integrations. */\nexport const forgeSandboxTools = createSandboxTools\n/** Human-readable descriptions shared by the sandbox's workspace tools. */\nexport { descriptions as sandboxToolDescriptions }\n"],"mappings":"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"}
|
package/toon-gA82H1sN.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"toon-gA82H1sN.js","names":["#options","#resolveParsed","#hasParsed","#parsed","#loadToonModule","#formatToonError"],"sources":["../src/batteries/artifacts/toon/exceptions.ts","../src/batteries/artifacts/toon/index.ts"],"sourcesContent":["/**\n * Battery-scoped exceptions for the TOON artifact battery.\n *\n * @remarks\n * Internal sibling of the `@nhtio/adk/batteries/artifacts/toon` entry — re-exported from the\n * battery's 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 TOON peer dependency cannot be loaded.\n *\n * @remarks\n * The @toon-format/toon package is an optional peer. If it is not installed, methods requiring\n * it throw this exception with installation instructions. The message template includes the package\n * name, a description of its purpose, the underlying error, and the exact install command, so the\n * consumer sees a complete, actionable message regardless of call site.\n */\nexport const E_TOON_PEER_MISSING = createException<[string]>(\n 'E_TOON_PEER_MISSING',\n 'the toon battery could not load its peer dependency \"@toon-format/toon\" (needed for TOON format artifact queries): %s — install it (pnpm add @toon-format/toon)',\n 'E_TOON_PEER_MISSING',\n 500\n)\n\n/**\n * Thrown when TOON decoding fails.\n *\n * @remarks\n * Wraps the underlying `ToonDecodeError` from the `@toon-format/toon` package, surfacing its\n * `line` and `source` properties so the model can self-correct.\n */\nexport const E_TOON_DECODE_FAILED = createException<[string]>(\n 'E_TOON_DECODE_FAILED',\n 'TOON decode error: %s',\n 'E_TOON_DECODE_FAILED',\n 422\n)\n","/**\n * TOON artifact battery — structured queries over TOON format artifacts.\n *\n * @module @nhtio/adk/batteries/artifacts/toon\n *\n * @remarks\n * Adds {@link SpooledToonArtifact}, a {@link @nhtio/adk!SpooledArtifact} specialisation for\n * structured TOON queries. TOON encodes the JSON data model in a compact text format; parsing\n * produces the same values as decoding JSON, so queries use {@link https://github.com/JSONPath-Plus/JSONPath JSONPath-Plus} for path navigation, exactly as {@link @nhtio/adk!SpooledJsonArtifact} does.\n *\n * Requires the optional peer `@toon-format/toon` (version `^4.1.1`). If it is not installed,\n * methods requiring it throw {@link E_TOON_PEER_MISSING} with installation instructions.\n *\n * Export note: {@link registerArtifactEncodables} must be called before any attempt to\n * `decode()` a spooled TOON artifact. Call it once at startup:\n *\n * ```ts\n * import { registerArtifactEncodables } from '@nhtio/adk/batteries/artifacts'\n * await registerArtifactEncodables()\n * ```\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, isObject } from '@nhtio/adk/guards'\nimport { E_TOON_PEER_MISSING, E_TOON_DECODE_FAILED } from './exceptions'\nimport {\n ArtifactTool,\n SpooledJsonArtifact,\n Tool,\n ToolRegistry,\n ReaderDescriptor,\n} 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')\n\n/**\n * Lazily-loaded TOON module, cached as a module-level promise.\n *\n * @remarks\n * Shared across all instances of SpooledToonArtifact. Once the promise resolves or rejects,\n * the same promise is reused for all subsequent calls, ensuring the in-flight promise and\n * any error state are preserved globally.\n */\nlet toonModulePromise: Promise<Record<string, unknown>> | undefined\nimport {\n SpooledArtifact,\n collectArtifactCompatibleIds,\n resolveArtifactById,\n defaultSerialise,\n} from '@nhtio/adk/spooled_artifact'\nimport type { SpoolReader, 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 * TOON decode options.\n *\n * @remarks\n * Passed to the `@toon-format/toon` `decode` function.\n */\nexport interface ToonDecodeOptions {\n /** The indent size used in the TOON encoding (default: 2). */\n indentSize?: number\n /** When `true`, reject non-standard TOON (default: `true`). */\n strict?: boolean\n}\n\n/**\n * A {@link @nhtio/adk!SpooledArtifact} specialisation that adds TOON-aware read operations.\n *\n * @remarks\n * Construct with an optional `options` object to control decoding. When omitted, the TOON is\n * decoded with `strict: true` (default). Once decoded (on first access), the parsed value is\n * cached for the lifetime of the instance.\n *\n * All TOON methods are async, consistent with {@link @nhtio/adk!SpooledArtifact}.\n *\n * Path-based methods (`toon_get`, `toon_filter`, `toon_pluck`) use\n * [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath) expressions. Full JSONPath syntax\n * is supported, including recursive descent (`..`), filter expressions (`[?(@.age > 18)]`),\n * and union selectors.\n */\nexport class SpooledToonArtifact extends SpooledArtifact {\n #parsed: unknown\n #hasParsed: boolean = false\n #options: ToonDecodeOptions | undefined\n\n /**\n * @param reader - The backing store to read from.\n * @param options - Optional TOON decode options.\n */\n constructor(reader: SpoolReader, options?: ToonDecodeOptions) {\n super(reader)\n this.#options = options\n }\n\n /**\n * Returns `true` if `value` is a {@link SpooledToonArtifact} instance.\n *\n * @remarks\n * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard: `instanceof` first, then\n * `Symbol.hasInstance`, then a `constructor.name` fallback. Matches the pattern used by every\n * other class guard in the ADK; safe against the dual-module-copy case where two distinct\n * `SpooledToonArtifact` classes coexist in the same realm.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link SpooledToonArtifact} instance.\n */\n public static isSpooledToonArtifact(value: unknown): value is SpooledToonArtifact {\n return isInstanceOf(value, 'SpooledToonArtifact', SpooledToonArtifact)\n }\n\n /**\n * The TOON-specific artifact-query descriptors this class adds on top of the base set.\n *\n * @remarks\n * Lists `artifact_toon_type`, `artifact_toon_keys`, `artifact_toon_length`,\n * `artifact_toon_get`, `artifact_toon_filter`, `artifact_toon_slice`, `artifact_toon_pluck`.\n * The base seven descriptors (`artifact_head`, etc.) are NOT included here — they are\n * forged separately by {@link SpooledToonArtifact.forgeTools}, which calls\n * `SpooledArtifact.forgeTools(ctx)` to produce the base-narrowed tools and then registers\n * its own TOON tools on the result. Downstream consumers building custom subclasses\n * should follow the same pattern: own only your own descriptors; override `forgeTools` to\n * compose with the base output.\n */\n public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n {\n name: 'artifact_toon_type',\n method: 'toon_type',\n description: 'Return the format of a TOON artifact produced earlier in this turn.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_toon_keys',\n method: 'toon_keys',\n description: 'Return the top-level keys of a TOON artifact produced earlier in this turn.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_toon_length',\n method: 'toon_length',\n description:\n 'Return the element count of a TOON artifact produced earlier in this turn (1 if the root is not an array).',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_toon_get',\n method: 'toon_get',\n description:\n 'Evaluate a JSONPath expression against a TOON 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_toon_filter',\n method: 'toon_filter',\n description:\n 'Return elements of a TOON 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. '$[?(@.age>18)]'.\"),\n }),\n },\n {\n name: 'artifact_toon_slice',\n method: 'toon_slice',\n description:\n 'Return a slice of elements by index range from a TOON 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_toon_pluck',\n method: 'toon_pluck',\n description:\n 'Return all values matched by a JSONPath expression across a TOON 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 TOON-specific tools narrowed to {@link SpooledToonArtifact}.\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 TOON-specific descriptor narrowed to TOON artifacts.\n * Downstream consumers building their own subclasses should follow the same shape.\n */\n public static override forgeTools(ctx: DispatchContext): ToolRegistry {\n const registry = SpooledArtifact.forgeTools(ctx)\n const requires = SpooledToonArtifact\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 === 'toon_get' ||\n descriptor.method === 'toon_filter' ||\n descriptor.method === 'toon_pluck'\n ) {\n methodArgs.push(args.path as string)\n } else if (descriptor.method === 'toon_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 the TOON content.\n *\n * @remarks\n * On first access, decodes the TOON source and caches the parsed value. Subsequent calls\n * return the cached value without re-parsing.\n *\n * @returns The parsed TOON value.\n */\n async #resolveParsed(): Promise<unknown> {\n if (this.#hasParsed) {\n return this.#parsed\n }\n const toonModule = await this.#loadToonModule()\n const text = await this.asString()\n try {\n const decode = toonModule.decode as (text: string, opts: Record<string, unknown>) => unknown\n this.#parsed = decode(text, {\n indentSize: this.#options?.indentSize ?? 2,\n strict: this.#options?.strict ?? true,\n })\n } catch (err) {\n const message = this.#formatToonError(err)\n throw new E_TOON_DECODE_FAILED([message])\n }\n this.#hasParsed = true\n return this.#parsed\n }\n\n /**\n * Formats an error from the TOON decoder, including line number and source.\n */\n #formatToonError(err: unknown): string {\n if (isObject(err) && (err as Record<string, unknown>).name === 'ToonDecodeError') {\n const toonErr = err as { line?: number; source?: string; message?: string }\n const line = toonErr.line ?? '?'\n const source = toonErr.source ?? '(no source)'\n return `line ${line}: ${source}`\n }\n return String((err as Record<string, unknown>).message ?? err)\n }\n\n /**\n * Loads the TOON module lazily, with error handling.\n *\n * @remarks\n * Uses the module-level `toonModulePromise` to ensure the in-flight promise and error state\n * are shared across all instances of SpooledToonArtifact.\n */\n async #loadToonModule() {\n toonModulePromise ??= import('@toon-format/toon').catch((err: unknown) => {\n throw new E_TOON_PEER_MISSING([String(err)])\n })\n return (await toonModulePromise) as Record<string, unknown>\n }\n\n /**\n * Returns the format of a TOON artifact.\n *\n * @remarks\n * Reports only the format name. The delimiter is deliberately not reported: the TOON decoder\n * exposes no delimiter information, and every method of inferring one from the source proved\n * unreliable for some class of strict-valid document. Four distinct approaches were attempted,\n * each defeated by its own edge case:\n * - Lexical scanning for the delimiter character failed on unquoted pipes inside values\n * - Anchored header regex requiring a word key failed on quoted keys and keyless root arrays\n * - Widened regex accepting quoted keys failed on escaped quotes within the key (e.g., \"a\\\"b\")\n * - Byte-exact round-trip re-encoding failed on non-canonical formatting (indentation, line\n * endings, trailing newlines)\n *\n * Delimiter inference is no longer attempted: nothing in the model's workflow needs it, and\n * the TOON decoder is the source of truth for all document metadata.\n *\n * This result is cached after the first parse and returned identically on every call.\n *\n * @returns An object with `format: 'toon'`.\n */\n async toon_type(): Promise<{ format: string }> {\n await this.#resolveParsed()\n return { format: 'toon' }\n }\n\n /**\n * Returns the top-level keys of the parsed TOON content.\n *\n * @remarks\n * - If the root is an object, returns its keys.\n * - If the root is not a plain object (e.g. an array or scalar), returns `undefined`.\n *\n * @returns Array of key strings, or `undefined` when the root is not an object.\n */\n async toon_keys(): Promise<string[] | undefined> {\n const value = await this.#resolveParsed()\n if (isObject(value)) {\n return Object.keys(value as object)\n }\n return undefined\n }\n\n /**\n * Returns the element count of the parsed TOON content.\n *\n * @remarks\n * - If the root is an array, returns the array length.\n * - Otherwise, returns `1` (the root is a single element).\n *\n * @returns The element count.\n */\n async toon_length(): Promise<number> {\n const value = await this.#resolveParsed()\n if (Array.isArray(value)) {\n return value.length\n }\n return 1\n }\n\n /**\n * Evaluates a JSONPath expression against the parsed TOON content.\n *\n * @remarks\n * Uses [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath). Full JSONPath syntax is\n * supported: recursive descent (`$..*`), filter expressions (`$[?(@.age > 18)]`), union\n * selectors, and more.\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 toon_get(path: string): Promise<unknown[]> {\n const value = await this.#resolveParsed()\n return JSONPath({ path, json: value as object })\n }\n\n /**\n * Returns elements matched by a JSONPath filter expression.\n *\n * @remarks\n * Evaluates `path` against the root value and returns it in an array if matched.\n *\n * @param path - A JSONPath expression (e.g. `'$[?(@.status === \"active\")]'`).\n * @returns Array of matching elements (at most one element, the root if matched).\n */\n async toon_filter(path: string): Promise<unknown[]> {\n const value = await this.#resolveParsed()\n const matches = JSONPath({ path, json: value as object })\n return Array.isArray(matches) && matches.length > 0 ? [value] : []\n }\n\n /**\n * Returns a slice of the parsed content by index range.\n *\n * @remarks\n * - If the root is an array, behaves like `Array.prototype.slice`.\n * - If the root is not an array, returns the entire root in an array.\n *\n * @param start - Start index (inclusive). Defaults to `0`.\n * @param end - End index (exclusive). Defaults to the element count.\n * @returns Array of sliced elements.\n */\n async toon_slice(start?: number, end?: number): Promise<unknown[]> {\n const value = await this.#resolveParsed()\n if (Array.isArray(value)) {\n return value.slice(start, end)\n }\n return [value]\n }\n\n /**\n * Returns all values matched by a JSONPath expression.\n *\n * @remarks\n * Convenience over {@link SpooledToonArtifact.toon_get} with an identical signature — use\n * whichever name better communicates intent at the call site. `toon_pluck` reads well for\n * extracting a single field; `toon_get` reads well for structured queries.\n *\n * @param path - A JSONPath expression (e.g. `'$..name'`).\n * @returns Array of matched values.\n */\n async toon_pluck(path: string): Promise<unknown[]> {\n return this.toon_get(path)\n }\n\n /**\n * Serialise this SpooledToonArtifact into an `@nhtio/encoder` snapshot — the reader **handle** plus\n * the decode `options`.\n *\n * @remarks\n * Overrides {@link SpooledArtifact.[ENCODE_METHOD]} to carry the constructor's `options` (the\n * parsed-value cache is derived and not encoded). Round-trips via\n * {@link SpooledToonArtifact.[DECODE_METHOD]}.\n *\n * @returns A snapshot consumed by {@link SpooledToonArtifact.[DECODE_METHOD]}.\n */\n [ENCODE_METHOD](): AdkEncodableSnapshot {\n return { reader: this.readerDescriptor(), options: this.#options }\n }\n\n /**\n * Reconstruct a {@link SpooledToonArtifact} from a {@link SpooledToonArtifact.[ENCODE_METHOD]}\n * snapshot.\n *\n * @param data - The snapshot produced by {@link SpooledToonArtifact.[ENCODE_METHOD]}.\n * @returns A fresh {@link SpooledToonArtifact}} backed by a freshly-resolved reader.\n */\n static [DECODE_METHOD](data: AdkEncodableSnapshot): SpooledToonArtifact {\n const snapshot = data as {\n reader: ReaderDescriptor\n options?: ToonDecodeOptions\n }\n return new SpooledToonArtifact(resolveSpoolReader(snapshot.reader), snapshot.options)\n }\n}\n\n/**\n * Converter tool: TOON to JSON.\n *\n * @remarks\n * Accepts either inline TOON text or a reference to an artifact produced earlier in this turn.\n * Converts to JSON and returns a new {@link @nhtio/adk!SpooledJsonArtifact}.\n *\n * This is a plain {@link @nhtio/adk!Tool}, not an {@link @nhtio/adk!ArtifactTool} — the handler\n * returns the new artifact directly, allowing the forge to discover and query it on the next\n * iteration without explicit wiring.\n */\nexport const toonToJsonTool: Tool = new Tool({\n name: 'toon_to_json',\n description: 'Convert inline TOON text or a TOON artifact to JSON.',\n inputSchema: validator.object({\n text: validator\n .string()\n .optional()\n .allow('')\n .description('Inline TOON text. Provide this or call_id, not both.'),\n call_id: validator\n .string()\n .optional()\n .allow('')\n .description('ToolCall id of a TOON artifact produced earlier in this turn.'),\n }),\n artifactConstructor: () => SpooledJsonArtifact,\n handler: async (rawArgs: unknown, ctx: DispatchContext) => {\n const args = rawArgs as { text?: string; call_id?: string }\n const text = args.text ?? ''\n const callId = args.call_id ?? ''\n\n const hasText = text.length > 0\n const hasCallId = callId.length > 0\n\n if (!hasText && !hasCallId) {\n return 'Error: provide either text or call_id, not neither'\n }\n if (hasText && hasCallId) {\n return 'Error: provide either text or call_id, not both'\n }\n\n let toonContent: string\n if (hasCallId) {\n const resolved = resolveArtifactById(ctx, callId, SpooledToonArtifact)\n if (!resolved) {\n return `Error: no TOON artifact with id ${callId} in this turn`\n }\n toonContent = await resolved.artifact.asString()\n } else {\n toonContent = text\n }\n\n const toonModule = await import('@toon-format/toon').catch((err: unknown) => {\n throw new E_TOON_PEER_MISSING([String(err)])\n })\n\n let parsed: unknown\n try {\n const decode = toonModule.decode as (text: string, opts: Record<string, unknown>) => unknown\n parsed = decode(toonContent, { indentSize: 2, strict: true })\n } catch (err) {\n const message =\n isObject(err) && (err as Record<string, unknown>).name === 'ToonDecodeError'\n ? `line ${(err as { line?: number }).line ?? '?'}: ${(err as { source?: string }).source ?? '(no source)'}`\n : String((err as Record<string, unknown>).message ?? err)\n return `Error: failed to decode TOON: ${message}`\n }\n\n const json = JSON.stringify(parsed, null, 2)\n const sourceId = hasCallId ? callId : uuidv6()\n const reader = await ctx.storeRetrievableBytes(`${ctx.id}:toon_to_json:${sourceId}`, json)\n return new SpooledJsonArtifact(reader)\n },\n})\n\n/**\n * Converter tool: JSON to TOON.\n *\n * @remarks\n * Accepts either inline JSON text or a reference to a JSON artifact produced earlier in this turn.\n * Converts to TOON and returns a new {@link SpooledToonArtifact}.\n *\n * This is a plain {@link @nhtio/adk!Tool}, not an {@link @nhtio/adk!ArtifactTool} — the handler\n * returns the new artifact directly, allowing the forge to discover and query it on the next\n * iteration without explicit wiring.\n */\nexport const jsonToToonTool: Tool = new Tool({\n name: 'json_to_toon',\n description: 'Convert inline JSON text or a JSON artifact to TOON.',\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: () => SpooledToonArtifact,\n handler: async (rawArgs: unknown, ctx: DispatchContext) => {\n const args = rawArgs as { text?: string; call_id?: string }\n const text = args.text ?? ''\n const callId = args.call_id ?? ''\n\n const hasText = text.length > 0\n const hasCallId = callId.length > 0\n\n if (!hasText && !hasCallId) {\n return 'Error: provide either text or call_id, not neither'\n }\n if (hasText && hasCallId) {\n return 'Error: provide either text or call_id, not both'\n }\n\n let jsonContent: string\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 jsonContent = await resolved.artifact.asString()\n } else {\n jsonContent = text\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(jsonContent)\n } catch (err) {\n return `Error: failed to parse JSON: ${String((err as Record<string, unknown>).message ?? err)}`\n }\n\n const toonModule = await import('@toon-format/toon').catch((err: unknown) => {\n throw new E_TOON_PEER_MISSING([String(err)])\n })\n\n let toon: string\n try {\n const encode = toonModule.encode as (val: unknown, opts: Record<string, unknown>) => string\n toon = encode(parsed, { indentSize: 2 })\n } catch (err) {\n return `Error: failed to encode TOON: ${String((err as Record<string, unknown>).message ?? err)}`\n }\n\n const sourceId = hasCallId ? callId : uuidv6()\n const reader = await ctx.storeRetrievableBytes(`${ctx.id}:json_to_toon:${sourceId}`, toon)\n return new SpooledToonArtifact(reader)\n },\n})\n\n/**\n * Exports for the public barrel.\n */\nexport { E_TOON_PEER_MISSING, E_TOON_DECODE_FAILED } from './exceptions'\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transformers_js-C050gRfd.js","names":["#options","#pipeline","#resolvePipeline","#pipelinePromise","#toPcm16k"],"sources":["../src/batteries/specialists/stt/transformers_js/exceptions.ts","../src/batteries/specialists/stt/transformers_js/validation.ts","../src/batteries/specialists/stt/transformers_js/adapter.ts"],"sourcesContent":["/**\n * Battery-scoped exception constructors for the transformers.js STT adapter.\n *\n * @remarks\n * Battery-scoped exception classes for the transformers.js (`@huggingface/transformers`)\n * speech-to-text adapter, minted via `createException` from `@nhtio/adk/factories`. Categories mirror\n * the transformers.js Embeddings battery one-to-one — only the engine-specific failure differs.\n */\n\nimport { createException } from '@nhtio/adk/factories'\n\n/**\n * Thrown when the resolved adapter options fail validation against\n * `transformersJsSttAdapterOptionsSchema` — e.g. a missing/empty `model` or an unknown option key.\n * Fatal: config bugs fail loud, not at transcribe time.\n */\nexport const E_INVALID_TRANSFORMERS_JS_STT_OPTIONS = createException<[string]>(\n 'E_INVALID_TRANSFORMERS_JS_STT_OPTIONS',\n 'Invalid transformers.js STT adapter options: %s',\n 'E_INVALID_TRANSFORMERS_JS_STT_OPTIONS',\n 529,\n true\n)\n\n/**\n * Thrown when the transformers.js pipeline fails to load (e.g. the `@huggingface/transformers` peer\n * is not installed) or the `automatic-speech-recognition` call throws/returns a malformed result.\n * Non-fatal. Printf arg: `[detail]`.\n */\nexport const E_TRANSFORMERS_JS_STT_ENGINE_ERROR = createException<[string]>(\n 'E_TRANSFORMERS_JS_STT_ENGINE_ERROR',\n 'transformers.js STT engine error: %s',\n 'E_TRANSFORMERS_JS_STT_ENGINE_ERROR',\n 502,\n false\n)\n","/**\n * Runtime validation schema and wrapper for transformers.js STT adapter options.\n *\n * @remarks\n * Validates `TransformersJsSttAdapterOptions` at construction time. Throws\n * `E_INVALID_TRANSFORMERS_JS_STT_OPTIONS` on failure. `model` is required; unknown top-level keys are\n * rejected so typos fail loud.\n */\n\nimport { isError } from '@nhtio/adk/guards'\nimport { validator, ValidationError } from '@nhtio/validation'\nimport { E_INVALID_TRANSFORMERS_JS_STT_OPTIONS } from './exceptions'\nimport type { TransformersJsSttAdapterOptions } from './types'\n\n/** Validator schema for `TransformersJsSttAdapterOptions`. Rejects unknown top-level keys. */\nexport const transformersJsSttAdapterOptionsSchema = validator\n .object<TransformersJsSttAdapterOptions>({\n model: validator.string().min(1).required(),\n // Pipeline knobs (the transformers.js pipeline is a callable object — accept function or object)\n pipeline: validator\n .alternatives(validator.function(), validator.object().unknown(true))\n .optional(),\n createPipeline: validator.function().optional(),\n device: validator.string().optional(),\n dtype: validator.string().optional(),\n chunkLengthS: validator.number().positive().default(30),\n decodeAudio: validator.function().optional(),\n modelSource: validator.function().optional(),\n onInitProgress: validator.function().optional(),\n isAvailable: validator.function().optional(),\n // ── Lifecycle hooks (opt-in, normalized phase machine; additive over onInitProgress) ──\n onLifecycle: validator.function().optional(),\n onLoading: validator.function().optional(),\n onCompiling: validator.function().optional(),\n onReady: validator.function().optional(),\n onGenerating: validator.function().optional(),\n onComplete: validator.function().optional(),\n onError: validator.function().optional(),\n })\n .unknown(false)\n\nconst isValidationError = (value: unknown): value is ValidationError =>\n isError(value) && Array.isArray((value as ValidationError).details)\n\nconst formatValidationDetails = (err: ValidationError): string =>\n err.details.map((d) => d.message).join(' and ')\n\n/**\n * Validates an arbitrary input against `transformersJsSttAdapterOptionsSchema`.\n *\n * @param input - The raw options object to validate.\n * @returns The resolved options object with defaults filled in.\n * @throws {@link @nhtio/adk/batteries!E_INVALID_TRANSFORMERS_JS_STT_OPTIONS} when invalid.\n */\nexport const validateOptions = (input: unknown): TransformersJsSttAdapterOptions => {\n const { value, error } = transformersJsSttAdapterOptionsSchema.validate(input, {\n abortEarly: false,\n convert: false,\n })\n if (error && isValidationError(error)) {\n throw new E_INVALID_TRANSFORMERS_JS_STT_OPTIONS([formatValidationDetails(error)], {\n cause: error,\n })\n }\n return value as TransformersJsSttAdapterOptions\n}\n","/**\n * transformers.js (ONNX, dual-environment) STT (speech-to-text) adapter battery.\n *\n * @remarks\n * Specialist battery backed by transformers.js's `automatic-speech-recognition` (Whisper-family)\n * pipeline. **Environment-neutral** — runs in Node (via `onnxruntime-node`) and the browser (via\n * `onnxruntime-web` / WebGPU), auto-selected by the package; there is no WebGPU requirement, mirroring\n * the transformers.js Embeddings battery this adapter is modeled on.\n *\n * Accepts any {@link @nhtio/adk/batteries/specialists/_shared!SpecialistAudioInput} form: already-\n * decoded mono PCM (skips decoding), or an encoded container (bytes / bytes+mime / a duck-typed\n * `Media`) decoded via an injectable {@link DecodeAudioFn}. Either path is resampled to the 16 kHz mono\n * PCM Whisper expects before the pipeline call.\n *\n * `@huggingface/transformers` is an optional peer dependency, imported lazily.\n */\n\nimport { isError } from '@nhtio/adk/guards'\nimport { validateOptions } from './validation'\nimport { resampleTo } from '../../../../lib/utils/audio'\nimport { emitLifecycle } from '../../../llm/chat_common/lifecycle'\nimport { isPcmInput, toBytes, defaultDecodeAudio } from '../../_shared'\nimport { withModelSource } from '../../../llm/transformers_js/model_source'\nimport {\n E_INVALID_TRANSFORMERS_JS_STT_OPTIONS,\n E_TRANSFORMERS_JS_STT_ENGINE_ERROR,\n} from './exceptions'\nimport type { SpecialistAudioInput } from '../../_shared'\nimport type {\n TransformersJsSttAdapterOptions,\n TransformersJsSttPipeline,\n CreateTransformersJsSttPipeline,\n TranscribeOptions,\n TranscribeResult,\n SttSegment,\n} from './types'\n\n/** The shape the transformers.js ASR pipeline resolves to (a subset of its documented output). */\ninterface AsrChunk {\n /** `[start, end]` in seconds; `end` may be `null` when the engine cannot bound the chunk. */\n timestamp: [number, number | null]\n /** The chunk's recognized text. */\n text: string\n}\n\ninterface AsrPipelineOutput {\n text: string\n chunks?: AsrChunk[]\n}\n\nconst makeDefaultCreatePipeline = (\n modelSource: TransformersJsSttAdapterOptions['modelSource']\n): CreateTransformersJsSttPipeline => {\n return async ({ model, device, dtype, onInitProgress }) => {\n const transformers = await import('@huggingface/transformers')\n const { pipeline, env } = transformers\n const load = async () =>\n (await pipeline('automatic-speech-recognition', model, {\n ...(device ? { device } : {}),\n ...(dtype ? { dtype } : {}),\n ...(onInitProgress ? { progress_callback: onInitProgress } : {}),\n } as never)) as unknown as TransformersJsSttPipeline\n // When a custom model source is configured, serve files through it behind the global-`env` mutex.\n return modelSource ? withModelSource(env as never, modelSource, load) : load()\n }\n}\n\n/**\n * STT adapter for transformers.js's automatic-speech-recognition (Whisper-family) pipeline.\n *\n * @remarks\n * Reusable: construct once, call {@link TransformersJsSttAdapter.transcribe} as many times as needed.\n * The pipeline is resolved lazily on first use (or via {@link preload}) and cached with single-flight\n * semantics so concurrent calls share one load.\n */\nexport class TransformersJsSttAdapter {\n readonly #options: TransformersJsSttAdapterOptions\n #pipeline: TransformersJsSttPipeline | undefined\n #pipelinePromise: Promise<TransformersJsSttPipeline> | undefined\n\n /**\n * Whether this battery is available. transformers.js is environment-neutral (Node + browser), so\n * this is `true` whenever the runtime can import the peer — there is no WebGPU requirement.\n */\n public static isAvailable(): boolean {\n return true\n }\n\n /**\n * @param options - Constructor options. Validated eagerly.\n * @throws {@link @nhtio/adk/batteries!E_INVALID_TRANSFORMERS_JS_STT_OPTIONS} when invalid.\n */\n constructor(options: unknown) {\n this.#options = validateOptions(options)\n this.#pipeline = this.#options.pipeline\n }\n\n /** Instance availability probe (honours an injected `isAvailable`). */\n isAvailable(): boolean {\n return (this.#options.isAvailable ?? TransformersJsSttAdapter.isAvailable)()\n }\n\n /** Eagerly loads (and caches) the pipeline so the first `transcribe` call is fast. Idempotent. */\n async preload(): Promise<void> {\n await this.#resolvePipeline()\n }\n\n /** Drops the cached pipeline and in-flight load so the next call reloads. */\n reset(): void {\n this.#pipeline = undefined\n this.#pipelinePromise = undefined\n }\n\n /**\n * Release the loaded model's ONNX sessions + GPU/wasm buffers, then drop the cached pipeline.\n *\n * @remarks\n * `reset()` only nulls the JS reference; the native ONNX Runtime sessions and WebGPU/wasm device\n * memory stay alive until GC. `AutomaticSpeechRecognitionPipeline` extends `Pipeline`, which exposes\n * `dispose()` — this awaits it so the memory is reclaimed between loads, swallows a disposal error\n * (teardown must not throw), and finishes with `reset()`. Idempotent.\n */\n async dispose(): Promise<void> {\n const pipeline = this.#pipeline ?? (await this.#pipelinePromise?.catch(() => undefined))\n const pipeWithDispose = pipeline as { dispose?: () => Promise<unknown> } | undefined\n if (typeof pipeWithDispose?.dispose === 'function') {\n await Promise.resolve(pipeWithDispose.dispose()).catch(() => undefined)\n }\n this.reset()\n }\n\n async #resolvePipeline(): Promise<TransformersJsSttPipeline> {\n if (this.#pipeline) return this.#pipeline\n if (!this.isAvailable()) {\n throw new E_INVALID_TRANSFORMERS_JS_STT_OPTIONS([\n 'the transformers.js STT battery is not available in this runtime',\n ])\n }\n const opts = this.#options\n this.#pipelinePromise ??= (async () => {\n emitLifecycle(opts, 'transformers_js_stt', opts.model, 'loading', {\n detail: 'loading automatic-speech-recognition pipeline',\n })\n // Forward each provider download event into a normalized `loading` lifecycle report.\n const hasLifecycle =\n opts.onLifecycle ?? opts.onLoading ?? opts.onReady ?? opts.onGenerating ?? opts.onError\n const forwardedInitProgress = hasLifecycle\n ? (info: unknown) => {\n const p = (info as { progress?: number } | undefined)?.progress\n emitLifecycle(opts, 'transformers_js_stt', opts.model, 'loading', {\n ...(typeof p === 'number' ? { progress: p / 100 } : {}),\n raw: info,\n })\n opts.onInitProgress?.(info as never)\n }\n : opts.onInitProgress\n const createPipeline = opts.createPipeline ?? makeDefaultCreatePipeline(opts.modelSource)\n try {\n // `from_pretrained` covers both fetch (reported via progress_callback → `loading`) and the\n // ONNX-graph / WebGPU-WASM warmup. Mark the latter as `compiling` — a COARSE upper-bound marker\n // (fetch + compile overlap inside the call), consistent with the LLM/embeddings batteries.\n emitLifecycle(opts, 'transformers_js_stt', opts.model, 'compiling', {\n detail: 'compiling automatic-speech-recognition graph',\n })\n const pipe = await createPipeline({\n model: opts.model,\n device: opts.device,\n dtype: opts.dtype,\n onInitProgress: forwardedInitProgress,\n })\n this.#pipeline = pipe\n emitLifecycle(opts, 'transformers_js_stt', opts.model, 'ready', {\n detail: 'automatic-speech-recognition pipeline ready',\n })\n return pipe\n } catch (err) {\n this.#pipelinePromise = undefined\n emitLifecycle(opts, 'transformers_js_stt', opts.model, 'error', { error: err })\n throw new E_TRANSFORMERS_JS_STT_ENGINE_ERROR([\n `could not load the transformers.js pipeline: ${isError(err) ? err.message : String(err)} — install the peer dependency (pnpm add @huggingface/transformers)`,\n ])\n }\n })()\n return this.#pipelinePromise\n }\n\n /**\n * Normalizes any accepted audio input form to 16 kHz mono PCM, the shape the Whisper pipeline\n * expects.\n *\n * @remarks\n * Already-decoded {@link @nhtio/adk/batteries/specialists/_shared!SpecialistPcmInput} is resampled\n * directly (a no-op when already 16 kHz — {@link resampleTo} returns the same reference in that\n * case). Any encoded-container form is normalized to bytes via\n * {@link @nhtio/adk/batteries/specialists/_shared!toBytes}, decoded via the injected/default\n * {@link @nhtio/adk/batteries/specialists/_shared!DecodeAudioFn} (already mono per that seam's\n * contract), then resampled.\n *\n * @param input - The audio input in any accepted form.\n * @returns 16 kHz mono PCM samples.\n */\n async #toPcm16k(input: SpecialistAudioInput): Promise<Float32Array> {\n if (isPcmInput(input)) {\n return resampleTo(input.pcm, input.sampleRate, 16000)\n }\n const { bytes } = await toBytes(input)\n const decode = this.#options.decodeAudio ?? defaultDecodeAudio\n const decoded = await decode(bytes)\n return resampleTo(decoded.pcm, decoded.sampleRate, 16000)\n }\n\n /**\n * Transcribes an audio clip.\n *\n * @param input - The audio input, in any {@link @nhtio/adk/batteries/specialists/_shared!SpecialistAudioInput}\n * form (pre-decoded PCM or an encoded container).\n * @param opts - Per-call transcription options (language / translate / timestamps).\n * @returns The recognized text, plus per-segment timing when `opts.timestamps` was set.\n * @throws {@link @nhtio/adk/batteries!E_TRANSFORMERS_JS_STT_ENGINE_ERROR} when the pipeline fails to\n * load or the transcription call fails.\n */\n async transcribe(\n input: SpecialistAudioInput,\n opts?: TranscribeOptions\n ): Promise<TranscribeResult> {\n const pcm = await this.#toPcm16k(input)\n const pipe = await this.#resolvePipeline()\n const chunkLengthS = this.#options.chunkLengthS ?? 30\n\n emitLifecycle(this.#options, 'transformers_js_stt', this.#options.model, 'generating')\n\n let output: AsrPipelineOutput\n try {\n const result = await (\n pipe as unknown as (\n audio: Float32Array,\n options: Record<string, unknown>\n ) => Promise<AsrPipelineOutput | AsrPipelineOutput[]>\n )(pcm, {\n chunk_length_s: chunkLengthS,\n ...(opts?.language ? { language: opts.language } : {}),\n ...(opts?.translate ? { task: 'translate' } : {}),\n ...(opts?.timestamps ? { return_timestamps: true } : {}),\n })\n output = Array.isArray(result) ? result[0] : result\n } catch (err) {\n emitLifecycle(this.#options, 'transformers_js_stt', this.#options.model, 'error', {\n error: err,\n })\n throw new E_TRANSFORMERS_JS_STT_ENGINE_ERROR([isError(err) ? err.message : String(err)])\n }\n\n if (!output || typeof output.text !== 'string') {\n emitLifecycle(this.#options, 'transformers_js_stt', this.#options.model, 'error', {\n error: new Error('automatic-speech-recognition returned a malformed result'),\n })\n throw new E_TRANSFORMERS_JS_STT_ENGINE_ERROR([\n 'automatic-speech-recognition returned a malformed result',\n ])\n }\n\n let segments: SttSegment[] | undefined\n if (opts?.timestamps && Array.isArray(output.chunks)) {\n segments = output.chunks.map((chunk) => ({\n start: chunk.timestamp[0],\n end: chunk.timestamp[1] ?? null,\n text: chunk.text,\n }))\n }\n\n emitLifecycle(this.#options, 'transformers_js_stt', this.#options.model, 'complete')\n return segments ? { text: output.text, segments } : { text: output.text }\n }\n}\n"],"mappings":"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"}
|