@nhtio/adk 1.20260607.2 → 1.20260609.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 +185 -0
- package/batteries/embeddings/openai/adapter.cjs +1 -1
- package/batteries/embeddings/openai/adapter.mjs +1 -1
- package/batteries/embeddings/openai/exceptions.cjs +1 -1
- package/batteries/embeddings/openai/exceptions.mjs +1 -1
- package/batteries/embeddings/openai/types.d.ts +7 -0
- package/batteries/embeddings/webllm/adapter.cjs +1 -1
- package/batteries/embeddings/webllm/adapter.mjs +1 -1
- package/batteries/embeddings/webllm/exceptions.cjs +1 -1
- package/batteries/embeddings/webllm/exceptions.mjs +1 -1
- package/batteries/llm/chat_common/helpers.d.ts +165 -0
- package/batteries/llm/chat_common/types.d.ts +309 -0
- package/batteries/llm/index.d.ts +5 -0
- package/batteries/llm/ollama/adapter.cjs +736 -0
- package/batteries/llm/ollama/adapter.cjs.map +1 -0
- package/batteries/llm/ollama/adapter.d.ts +64 -0
- package/batteries/llm/ollama/adapter.mjs +734 -0
- package/batteries/llm/ollama/adapter.mjs.map +1 -0
- package/batteries/llm/ollama/exceptions.cjs +105 -0
- package/batteries/llm/ollama/exceptions.cjs.map +1 -0
- package/batteries/llm/ollama/exceptions.d.ts +112 -0
- package/batteries/llm/ollama/exceptions.mjs +96 -0
- package/batteries/llm/ollama/exceptions.mjs.map +1 -0
- package/batteries/llm/ollama/helpers.cjs +487 -0
- package/batteries/llm/ollama/helpers.cjs.map +1 -0
- package/batteries/llm/ollama/helpers.d.ts +158 -0
- package/batteries/llm/ollama/helpers.mjs +450 -0
- package/batteries/llm/ollama/helpers.mjs.map +1 -0
- package/batteries/llm/ollama/index.d.ts +29 -0
- package/batteries/llm/ollama/types.cjs +2 -0
- package/batteries/llm/ollama/types.d.ts +334 -0
- package/batteries/llm/ollama/types.mjs +0 -0
- package/batteries/llm/ollama/validation.cjs +130 -0
- package/batteries/llm/ollama/validation.cjs.map +1 -0
- package/batteries/llm/ollama/validation.d.ts +31 -0
- package/batteries/llm/ollama/validation.mjs +127 -0
- package/batteries/llm/ollama/validation.mjs.map +1 -0
- package/batteries/llm/ollama.cjs +54 -0
- package/batteries/llm/ollama.mjs +6 -0
- package/batteries/llm/openai_chat_completions/adapter.cjs +36 -19
- package/batteries/llm/openai_chat_completions/adapter.cjs.map +1 -1
- package/batteries/llm/openai_chat_completions/adapter.mjs +23 -6
- package/batteries/llm/openai_chat_completions/adapter.mjs.map +1 -1
- package/batteries/llm/openai_chat_completions/exceptions.cjs +1 -1
- package/batteries/llm/openai_chat_completions/exceptions.mjs +1 -1
- package/batteries/llm/openai_chat_completions/helpers.cjs +80 -320
- package/batteries/llm/openai_chat_completions/helpers.cjs.map +1 -1
- package/batteries/llm/openai_chat_completions/helpers.d.ts +68 -144
- package/batteries/llm/openai_chat_completions/helpers.mjs +40 -280
- package/batteries/llm/openai_chat_completions/helpers.mjs.map +1 -1
- package/batteries/llm/openai_chat_completions/types.d.ts +273 -181
- package/batteries/llm/openai_chat_completions/validation.cjs +2 -2
- package/batteries/llm/openai_chat_completions/validation.cjs.map +1 -1
- package/batteries/llm/openai_chat_completions/validation.mjs +2 -2
- package/batteries/llm/openai_chat_completions/validation.mjs.map +1 -1
- package/batteries/llm/openai_chat_completions.cjs +29 -28
- package/batteries/llm/openai_chat_completions.mjs +2 -1
- package/batteries/llm/webllm_chat_completions/adapter.cjs +38 -19
- package/batteries/llm/webllm_chat_completions/adapter.cjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/adapter.d.ts +18 -0
- package/batteries/llm/webllm_chat_completions/adapter.mjs +25 -6
- package/batteries/llm/webllm_chat_completions/adapter.mjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/exceptions.cjs +1 -1
- package/batteries/llm/webllm_chat_completions/exceptions.mjs +1 -1
- package/batteries/llm/webllm_chat_completions/helpers.cjs +29 -28
- package/batteries/llm/webllm_chat_completions/helpers.mjs +2 -1
- package/batteries/llm/webllm_chat_completions/types.d.ts +21 -0
- package/batteries/llm/webllm_chat_completions/validation.cjs +13 -1
- package/batteries/llm/webllm_chat_completions/validation.cjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/validation.d.ts +12 -0
- package/batteries/llm/webllm_chat_completions/validation.mjs +13 -1
- package/batteries/llm/webllm_chat_completions/validation.mjs.map +1 -1
- package/batteries/llm/webllm_chat_completions.cjs +29 -28
- package/batteries/llm/webllm_chat_completions.mjs +2 -1
- package/batteries/llm.cjs +44 -28
- package/batteries/llm.mjs +9 -4
- package/batteries/storage/flydrive.cjs +1 -1
- package/batteries/storage/flydrive.mjs +1 -1
- package/batteries/storage/in_memory/index.d.ts +1 -1
- package/batteries/storage/in_memory.cjs +2 -2
- package/batteries/storage/in_memory.cjs.map +1 -1
- package/batteries/storage/in_memory.mjs +2 -2
- package/batteries/storage/in_memory.mjs.map +1 -1
- package/batteries/storage/opfs/index.d.ts +19 -0
- package/batteries/storage/opfs.cjs +1 -1
- package/batteries/storage/opfs.cjs.map +1 -1
- package/batteries/storage/opfs.mjs +1 -1
- package/batteries/storage/opfs.mjs.map +1 -1
- package/batteries/tools/color.cjs +3 -2
- package/batteries/tools/color.cjs.map +1 -1
- package/batteries/tools/color.mjs +3 -2
- package/batteries/tools/color.mjs.map +1 -1
- package/batteries/tools/comparison.cjs +4 -3
- package/batteries/tools/comparison.cjs.map +1 -1
- package/batteries/tools/comparison.mjs +4 -3
- package/batteries/tools/comparison.mjs.map +1 -1
- package/batteries/tools/data_structure.cjs +30 -10
- package/batteries/tools/data_structure.cjs.map +1 -1
- package/batteries/tools/data_structure.mjs +30 -10
- package/batteries/tools/data_structure.mjs.map +1 -1
- package/batteries/tools/datetime_extended.cjs +5 -10
- package/batteries/tools/datetime_extended.cjs.map +1 -1
- package/batteries/tools/datetime_extended.mjs +5 -10
- package/batteries/tools/datetime_extended.mjs.map +1 -1
- package/batteries/tools/datetime_math.cjs +2 -2
- package/batteries/tools/datetime_math.mjs +2 -2
- package/batteries/tools/encoding.cjs +13 -4
- package/batteries/tools/encoding.cjs.map +1 -1
- package/batteries/tools/encoding.mjs +13 -4
- package/batteries/tools/encoding.mjs.map +1 -1
- package/batteries/tools/formatting.cjs +4 -4
- package/batteries/tools/formatting.cjs.map +1 -1
- package/batteries/tools/formatting.mjs +4 -4
- package/batteries/tools/formatting.mjs.map +1 -1
- package/batteries/tools/geo_basics.cjs +2 -2
- package/batteries/tools/geo_basics.mjs +2 -2
- package/batteries/tools/index.d.ts +1 -0
- package/batteries/tools/math.cjs +10 -8
- package/batteries/tools/math.cjs.map +1 -1
- package/batteries/tools/math.mjs +10 -8
- package/batteries/tools/math.mjs.map +1 -1
- package/batteries/tools/memory.cjs +5 -5
- package/batteries/tools/memory.mjs +5 -5
- package/batteries/tools/parsing.cjs +9 -5
- package/batteries/tools/parsing.cjs.map +1 -1
- package/batteries/tools/parsing.mjs +9 -5
- package/batteries/tools/parsing.mjs.map +1 -1
- package/batteries/tools/retrievables.cjs +4 -4
- package/batteries/tools/retrievables.mjs +4 -4
- package/batteries/tools/searxng/exceptions.d.ts +21 -0
- package/batteries/tools/searxng/index.d.ts +150 -0
- package/batteries/tools/searxng.cjs +5 -0
- package/batteries/tools/searxng.mjs +2 -0
- package/batteries/tools/standing_instructions.cjs +4 -4
- package/batteries/tools/standing_instructions.mjs +4 -4
- package/batteries/tools/statistics.cjs +54 -43
- package/batteries/tools/statistics.cjs.map +1 -1
- package/batteries/tools/statistics.mjs +54 -43
- package/batteries/tools/statistics.mjs.map +1 -1
- package/batteries/tools/string_processing.cjs +5 -5
- package/batteries/tools/string_processing.cjs.map +1 -1
- package/batteries/tools/string_processing.mjs +5 -5
- package/batteries/tools/string_processing.mjs.map +1 -1
- package/batteries/tools/structured_data.cjs +8 -13
- package/batteries/tools/structured_data.cjs.map +1 -1
- package/batteries/tools/structured_data.mjs +8 -13
- package/batteries/tools/structured_data.mjs.map +1 -1
- package/batteries/tools/text_analysis.cjs +3 -3
- package/batteries/tools/text_analysis.mjs +3 -3
- package/batteries/tools/text_comparison.cjs +2 -2
- package/batteries/tools/text_comparison.mjs +2 -2
- package/batteries/tools/time.cjs +2 -2
- package/batteries/tools/time.mjs +2 -2
- package/batteries/tools/unit_conversion.cjs +10 -8
- package/batteries/tools/unit_conversion.cjs.map +1 -1
- package/batteries/tools/unit_conversion.mjs +10 -8
- package/batteries/tools/unit_conversion.mjs.map +1 -1
- package/batteries/tools.cjs +3 -0
- package/batteries/tools.mjs +2 -1
- package/batteries/vector/arangodb/index.d.ts +2 -0
- package/batteries/vector/arangodb.cjs +2 -1
- package/batteries/vector/arangodb.cjs.map +1 -1
- package/batteries/vector/arangodb.mjs +2 -1
- package/batteries/vector/arangodb.mjs.map +1 -1
- package/batteries/vector/builder.cjs +31 -0
- package/batteries/vector/builder.cjs.map +1 -1
- package/batteries/vector/builder.d.ts +58 -0
- package/batteries/vector/builder.mjs +31 -0
- package/batteries/vector/builder.mjs.map +1 -1
- package/batteries/vector/chroma/index.d.ts +4 -0
- package/batteries/vector/chroma.cjs +3 -0
- package/batteries/vector/chroma.cjs.map +1 -1
- package/batteries/vector/chroma.mjs +3 -0
- package/batteries/vector/chroma.mjs.map +1 -1
- package/batteries/vector/clickhouse/index.d.ts +2 -0
- package/batteries/vector/clickhouse.cjs +2 -1
- package/batteries/vector/clickhouse.cjs.map +1 -1
- package/batteries/vector/clickhouse.mjs +2 -1
- package/batteries/vector/clickhouse.mjs.map +1 -1
- package/batteries/vector/cloudflare/index.d.ts +2 -0
- package/batteries/vector/cloudflare.cjs +2 -1
- package/batteries/vector/cloudflare.cjs.map +1 -1
- package/batteries/vector/cloudflare.mjs +2 -1
- package/batteries/vector/cloudflare.mjs.map +1 -1
- package/batteries/vector/conformance/index.d.ts +22 -0
- package/batteries/vector/conformance.cjs +22 -0
- package/batteries/vector/conformance.cjs.map +1 -1
- package/batteries/vector/conformance.mjs +22 -0
- package/batteries/vector/conformance.mjs.map +1 -1
- package/batteries/vector/contract.cjs +22 -0
- package/batteries/vector/contract.cjs.map +1 -1
- package/batteries/vector/contract.d.ts +51 -0
- package/batteries/vector/contract.mjs +22 -0
- package/batteries/vector/contract.mjs.map +1 -1
- package/batteries/vector/couchbase/index.d.ts +2 -0
- package/batteries/vector/couchbase.cjs +2 -1
- package/batteries/vector/couchbase.cjs.map +1 -1
- package/batteries/vector/couchbase.mjs +2 -1
- package/batteries/vector/couchbase.mjs.map +1 -1
- package/batteries/vector/duckdb/index.d.ts +2 -0
- package/batteries/vector/duckdb.cjs +2 -1
- package/batteries/vector/duckdb.cjs.map +1 -1
- package/batteries/vector/duckdb.mjs +2 -1
- package/batteries/vector/duckdb.mjs.map +1 -1
- package/batteries/vector/elasticsearch/index.d.ts +2 -0
- package/batteries/vector/elasticsearch.cjs +2 -1
- package/batteries/vector/elasticsearch.cjs.map +1 -1
- package/batteries/vector/elasticsearch.mjs +2 -1
- package/batteries/vector/elasticsearch.mjs.map +1 -1
- package/batteries/vector/exceptions.cjs +1 -1
- package/batteries/vector/exceptions.mjs +1 -1
- package/batteries/vector/factory.cjs +6 -0
- package/batteries/vector/factory.cjs.map +1 -1
- package/batteries/vector/factory.d.ts +14 -0
- package/batteries/vector/factory.mjs +6 -0
- package/batteries/vector/factory.mjs.map +1 -1
- package/batteries/vector/filters.cjs +22 -1
- package/batteries/vector/filters.cjs.map +1 -1
- package/batteries/vector/filters.d.ts +38 -0
- package/batteries/vector/filters.mjs +22 -1
- package/batteries/vector/filters.mjs.map +1 -1
- package/batteries/vector/helpers.cjs +13 -0
- package/batteries/vector/helpers.cjs.map +1 -1
- package/batteries/vector/helpers.d.ts +14 -0
- package/batteries/vector/helpers.mjs +13 -0
- package/batteries/vector/helpers.mjs.map +1 -1
- package/batteries/vector/hnswlib/index.d.ts +2 -0
- package/batteries/vector/hnswlib.cjs +2 -1
- package/batteries/vector/hnswlib.cjs.map +1 -1
- package/batteries/vector/hnswlib.mjs +2 -1
- package/batteries/vector/hnswlib.mjs.map +1 -1
- package/batteries/vector/in_memory/index.d.ts +1 -0
- package/batteries/vector/in_memory.cjs +1 -0
- package/batteries/vector/in_memory.cjs.map +1 -1
- package/batteries/vector/in_memory.mjs +1 -0
- package/batteries/vector/in_memory.mjs.map +1 -1
- package/batteries/vector/lancedb/index.d.ts +2 -0
- package/batteries/vector/lancedb.cjs +2 -1
- package/batteries/vector/lancedb.cjs.map +1 -1
- package/batteries/vector/lancedb.mjs +2 -1
- package/batteries/vector/lancedb.mjs.map +1 -1
- package/batteries/vector/mariadb/index.d.ts +2 -0
- package/batteries/vector/mariadb.cjs +2 -1
- package/batteries/vector/mariadb.cjs.map +1 -1
- package/batteries/vector/mariadb.mjs +2 -1
- package/batteries/vector/mariadb.mjs.map +1 -1
- package/batteries/vector/meilisearch/index.d.ts +2 -0
- package/batteries/vector/meilisearch.cjs +2 -1
- package/batteries/vector/meilisearch.cjs.map +1 -1
- package/batteries/vector/meilisearch.mjs +2 -1
- package/batteries/vector/meilisearch.mjs.map +1 -1
- package/batteries/vector/migrate.cjs +18 -1
- package/batteries/vector/migrate.cjs.map +1 -1
- package/batteries/vector/migrate.d.ts +31 -0
- package/batteries/vector/migrate.mjs +18 -1
- package/batteries/vector/migrate.mjs.map +1 -1
- package/batteries/vector/milvus/index.d.ts +5 -0
- package/batteries/vector/milvus.cjs +4 -0
- package/batteries/vector/milvus.cjs.map +1 -1
- package/batteries/vector/milvus.mjs +4 -0
- package/batteries/vector/milvus.mjs.map +1 -1
- package/batteries/vector/mongodb/index.d.ts +2 -0
- package/batteries/vector/mongodb.cjs +2 -1
- package/batteries/vector/mongodb.cjs.map +1 -1
- package/batteries/vector/mongodb.mjs +2 -1
- package/batteries/vector/mongodb.mjs.map +1 -1
- package/batteries/vector/neo4j/index.d.ts +2 -0
- package/batteries/vector/neo4j.cjs +2 -1
- package/batteries/vector/neo4j.cjs.map +1 -1
- package/batteries/vector/neo4j.mjs +2 -1
- package/batteries/vector/neo4j.mjs.map +1 -1
- package/batteries/vector/opensearch/index.d.ts +2 -0
- package/batteries/vector/opensearch.cjs +2 -1
- package/batteries/vector/opensearch.cjs.map +1 -1
- package/batteries/vector/opensearch.mjs +2 -1
- package/batteries/vector/opensearch.mjs.map +1 -1
- package/batteries/vector/oracle23ai/index.d.ts +2 -0
- package/batteries/vector/oracle23ai.cjs +2 -1
- package/batteries/vector/oracle23ai.cjs.map +1 -1
- package/batteries/vector/oracle23ai.mjs +2 -1
- package/batteries/vector/oracle23ai.mjs.map +1 -1
- package/batteries/vector/orama/index.d.ts +1 -0
- package/batteries/vector/orama.cjs +1 -0
- package/batteries/vector/orama.cjs.map +1 -1
- package/batteries/vector/orama.mjs +1 -0
- package/batteries/vector/orama.mjs.map +1 -1
- package/batteries/vector/pgvector/index.d.ts +9 -2
- package/batteries/vector/pgvector.cjs +4 -0
- package/batteries/vector/pgvector.cjs.map +1 -1
- package/batteries/vector/pgvector.mjs +4 -0
- package/batteries/vector/pgvector.mjs.map +1 -1
- package/batteries/vector/pinecone/index.d.ts +5 -0
- package/batteries/vector/pinecone.cjs +3 -1
- package/batteries/vector/pinecone.cjs.map +1 -1
- package/batteries/vector/pinecone.mjs +3 -1
- package/batteries/vector/pinecone.mjs.map +1 -1
- package/batteries/vector/plan.d.ts +27 -0
- package/batteries/vector/qdrant/index.d.ts +5 -0
- package/batteries/vector/qdrant.cjs +4 -0
- package/batteries/vector/qdrant.cjs.map +1 -1
- package/batteries/vector/qdrant.mjs +4 -0
- package/batteries/vector/qdrant.mjs.map +1 -1
- package/batteries/vector/redis/index.d.ts +2 -0
- package/batteries/vector/redis.cjs +2 -1
- package/batteries/vector/redis.cjs.map +1 -1
- package/batteries/vector/redis.mjs +2 -1
- package/batteries/vector/redis.mjs.map +1 -1
- package/batteries/vector/retrievable.cjs +9 -1
- package/batteries/vector/retrievable.cjs.map +1 -1
- package/batteries/vector/retrievable.mjs +9 -1
- package/batteries/vector/retrievable.mjs.map +1 -1
- package/batteries/vector/retrievable_glue.d.ts +21 -0
- package/batteries/vector/s3vectors/index.d.ts +2 -0
- package/batteries/vector/s3vectors.cjs +2 -1
- package/batteries/vector/s3vectors.cjs.map +1 -1
- package/batteries/vector/s3vectors.mjs +2 -1
- package/batteries/vector/s3vectors.mjs.map +1 -1
- package/batteries/vector/schema.cjs +28 -0
- package/batteries/vector/schema.cjs.map +1 -1
- package/batteries/vector/schema.d.ts +39 -0
- package/batteries/vector/schema.mjs +28 -0
- package/batteries/vector/schema.mjs.map +1 -1
- package/batteries/vector/solr/index.d.ts +2 -0
- package/batteries/vector/solr.cjs +2 -1
- package/batteries/vector/solr.cjs.map +1 -1
- package/batteries/vector/solr.mjs +2 -1
- package/batteries/vector/solr.mjs.map +1 -1
- package/batteries/vector/sqlite_vec/index.d.ts +6 -3
- package/batteries/vector/sqlite_vec.cjs +2 -0
- package/batteries/vector/sqlite_vec.cjs.map +1 -1
- package/batteries/vector/sqlite_vec.mjs +2 -0
- package/batteries/vector/sqlite_vec.mjs.map +1 -1
- package/batteries/vector/surrealdb/index.d.ts +2 -0
- package/batteries/vector/surrealdb.cjs +2 -1
- package/batteries/vector/surrealdb.cjs.map +1 -1
- package/batteries/vector/surrealdb.mjs +2 -1
- package/batteries/vector/surrealdb.mjs.map +1 -1
- package/batteries/vector/types.d.ts +27 -0
- package/batteries/vector/typesense/index.d.ts +2 -0
- package/batteries/vector/typesense.cjs +2 -1
- package/batteries/vector/typesense.cjs.map +1 -1
- package/batteries/vector/typesense.mjs +2 -1
- package/batteries/vector/typesense.mjs.map +1 -1
- package/batteries/vector/validation.cjs +14 -0
- package/batteries/vector/validation.cjs.map +1 -1
- package/batteries/vector/validation.d.ts +14 -0
- package/batteries/vector/validation.mjs +14 -0
- package/batteries/vector/validation.mjs.map +1 -1
- package/batteries/vector/vector_store_constructor.cjs +1 -1
- package/batteries/vector/vector_store_constructor.cjs.map +1 -1
- package/batteries/vector/vector_store_constructor.d.ts +1 -1
- package/batteries/vector/vector_store_constructor.mjs +1 -1
- package/batteries/vector/vector_store_constructor.mjs.map +1 -1
- package/batteries/vector/vespa/index.d.ts +2 -0
- package/batteries/vector/vespa.cjs +2 -1
- package/batteries/vector/vespa.cjs.map +1 -1
- package/batteries/vector/vespa.mjs +2 -1
- package/batteries/vector/vespa.mjs.map +1 -1
- package/batteries/vector/weaviate/index.d.ts +2 -0
- package/batteries/vector/weaviate.cjs +2 -1
- package/batteries/vector/weaviate.cjs.map +1 -1
- package/batteries/vector/weaviate.mjs +2 -1
- package/batteries/vector/weaviate.mjs.map +1 -1
- package/batteries.cjs +46 -28
- package/batteries.mjs +10 -5
- package/{common-BT0nfCi9.mjs → common-DYDUi99O.mjs} +9 -9
- package/common-DYDUi99O.mjs.map +1 -0
- package/{common-Cj8TaQ9U.js → common-DZl3ADJs.js} +9 -9
- package/common-DZl3ADJs.js.map +1 -0
- package/common.cjs +7 -7
- package/common.d.ts +1 -1
- package/common.mjs +7 -7
- package/{dispatch_runner-DPcS7Y_M.mjs → dispatch_runner--ZhdDWRZ.mjs} +27 -5
- package/{dispatch_runner-DPcS7Y_M.mjs.map → dispatch_runner--ZhdDWRZ.mjs.map} +1 -1
- package/{dispatch_runner-BHBNupqp.js → dispatch_runner-nHDKkxye.js} +27 -5
- package/{dispatch_runner-BHBNupqp.js.map → dispatch_runner-nHDKkxye.js.map} +1 -1
- package/dispatch_runner.cjs +1 -1
- package/dispatch_runner.d.ts +1 -1
- package/dispatch_runner.mjs +1 -1
- package/eslint/rules/artifact_tool_forbids_artifact_constructor.cjs +1 -0
- package/eslint/rules/artifact_tool_forbids_artifact_constructor.cjs.map +1 -1
- package/eslint/rules/artifact_tool_forbids_artifact_constructor.d.ts +1 -0
- package/eslint/rules/artifact_tool_forbids_artifact_constructor.mjs +1 -0
- package/eslint/rules/artifact_tool_forbids_artifact_constructor.mjs.map +1 -1
- package/eslint/rules/no_model_in_tool_handler.cjs +1 -0
- package/eslint/rules/no_model_in_tool_handler.cjs.map +1 -1
- package/eslint/rules/no_model_in_tool_handler.d.ts +1 -0
- package/eslint/rules/no_model_in_tool_handler.mjs +1 -0
- package/eslint/rules/no_model_in_tool_handler.mjs.map +1 -1
- package/eslint/rules/require_validator_any_required.cjs +1 -0
- package/eslint/rules/require_validator_any_required.cjs.map +1 -1
- package/eslint/rules/require_validator_any_required.d.ts +1 -0
- package/eslint/rules/require_validator_any_required.mjs +1 -0
- package/eslint/rules/require_validator_any_required.mjs.map +1 -1
- package/eslint/rules/thought_payload_requires_replay_tag.cjs +1 -0
- package/eslint/rules/thought_payload_requires_replay_tag.cjs.map +1 -1
- package/eslint/rules/thought_payload_requires_replay_tag.d.ts +1 -0
- package/eslint/rules/thought_payload_requires_replay_tag.mjs +1 -0
- package/eslint/rules/thought_payload_requires_replay_tag.mjs.map +1 -1
- package/eslint/rules/token_encoding_requires_context_window.cjs +1 -0
- package/eslint/rules/token_encoding_requires_context_window.cjs.map +1 -1
- package/eslint/rules/token_encoding_requires_context_window.d.ts +1 -0
- package/eslint/rules/token_encoding_requires_context_window.mjs +1 -0
- package/eslint/rules/token_encoding_requires_context_window.mjs.map +1 -1
- package/eslint.cjs +1 -1
- package/eslint.mjs +1 -1
- package/{exceptions-BeWH2FwP.mjs → exceptions-BDhN0Xzr.mjs} +3 -2
- package/exceptions-BDhN0Xzr.mjs.map +1 -0
- package/{exceptions-CitH5wZI.js → exceptions-BRXrUKiW.js} +3 -2
- package/exceptions-BRXrUKiW.js.map +1 -0
- package/exceptions.cjs +2 -2
- package/exceptions.mjs +2 -2
- package/factories.cjs +1 -1
- package/factories.mjs +1 -1
- package/forge.cjs +4 -4
- package/forge.d.ts +1 -1
- package/forge.mjs +4 -4
- package/guards.cjs +9 -9
- package/guards.mjs +9 -9
- package/helpers-DSTFxTiC.js +497 -0
- package/helpers-DSTFxTiC.js.map +1 -0
- package/helpers-xhrQbMAG.mjs +306 -0
- package/helpers-xhrQbMAG.mjs.map +1 -0
- package/index.cjs +13 -13
- package/index.mjs +13 -13
- package/lib/classes/base_exception.d.ts +1 -0
- package/lib/classes/media.d.ts +10 -0
- package/lib/classes/retrievable.d.ts +1 -1
- package/lib/classes/spooled_json_artifact.d.ts +1 -1
- package/lib/classes/spooled_markdown_artifact.d.ts +1 -0
- package/lib/classes/tokenizable.d.ts +3 -0
- package/lib/classes/tool.d.ts +8 -0
- package/lib/classes/turn_gate.d.ts +6 -0
- package/lib/dispatch_runner.d.ts +4 -32
- package/lib/helpers/bignum.cjs +82 -0
- package/lib/helpers/bignum.cjs.map +1 -0
- package/lib/helpers/bignum.d.ts +52 -0
- package/lib/helpers/bignum.mjs +74 -0
- package/lib/helpers/bignum.mjs.map +1 -0
- package/lib/turn_runner.d.ts +1 -1
- package/lib/types/dispatch_runner.d.ts +83 -0
- package/lib/utils/exceptions.d.ts +1 -1
- package/lib/utils/retry.cjs.map +1 -1
- package/lib/utils/retry.d.ts +2 -0
- package/lib/utils/retry.mjs.map +1 -1
- package/mcp/adk-docs-corpus.json +1 -1
- package/package.json +264 -224
- package/{runtime-j92CNi5z.mjs → runtime-Bz5zA8wc.mjs} +2 -2
- package/{runtime-j92CNi5z.mjs.map → runtime-Bz5zA8wc.mjs.map} +1 -1
- package/{runtime-MFFcJrRv.js → runtime-DslE1aBw.js} +2 -2
- package/{runtime-MFFcJrRv.js.map → runtime-DslE1aBw.js.map} +1 -1
- package/searxng-Bkrwhwhw.js +269 -0
- package/searxng-Bkrwhwhw.js.map +1 -0
- package/searxng-CyA-nEu5.mjs +257 -0
- package/searxng-CyA-nEu5.mjs.map +1 -0
- package/skills/adk-assembly/SKILL.md +2 -2
- package/{spooled_artifact-CHoZgWwI.mjs → spooled_artifact-7eePq7JA.mjs} +5 -5
- package/{spooled_artifact-CHoZgWwI.mjs.map → spooled_artifact-7eePq7JA.mjs.map} +1 -1
- package/{spooled_artifact-BTq6Nzfy.js → spooled_artifact-DX8LLyUX.js} +5 -5
- package/{spooled_artifact-BTq6Nzfy.js.map → spooled_artifact-DX8LLyUX.js.map} +1 -1
- package/spooled_artifact.cjs +2 -2
- package/spooled_artifact.mjs +2 -2
- package/{spooled_markdown_artifact-CALSDxIx.js → spooled_markdown_artifact-ClX72lek.js} +4 -4
- package/spooled_markdown_artifact-ClX72lek.js.map +1 -0
- package/{spooled_markdown_artifact-Ci5UL7l4.mjs → spooled_markdown_artifact-wkrBF3oX.mjs} +4 -4
- package/spooled_markdown_artifact-wkrBF3oX.mjs.map +1 -0
- package/{thought-D34QQZZ9.mjs → thought-B_vxAiKU.mjs} +5 -5
- package/{thought-D34QQZZ9.mjs.map → thought-B_vxAiKU.mjs.map} +1 -1
- package/{thought-BbwhJ1wb.js → thought-DLwpF7MI.js} +5 -5
- package/{thought-BbwhJ1wb.js.map → thought-DLwpF7MI.js.map} +1 -1
- package/{tool-CVyZkFC7.js → tool-D5WGVIcI.js} +4 -4
- package/{tool-CVyZkFC7.js.map → tool-D5WGVIcI.js.map} +1 -1
- package/{tool-CMhaDRNd.mjs → tool-wMYMVl60.mjs} +4 -4
- package/{tool-CMhaDRNd.mjs.map → tool-wMYMVl60.mjs.map} +1 -1
- package/{tool_call-CV5qVNlb.mjs → tool_call-B4-_-vjG.mjs} +5 -5
- package/tool_call-B4-_-vjG.mjs.map +1 -0
- package/{tool_call-Db68hB7y.js → tool_call-DixVlW40.js} +5 -5
- package/tool_call-DixVlW40.js.map +1 -0
- package/{tool_registry-D1pSSlsd.mjs → tool_registry-791Vrjtf.mjs} +4 -3
- package/tool_registry-791Vrjtf.mjs.map +1 -0
- package/{tool_registry-DYUYqXvo.js → tool_registry-CKJPze3j.js} +4 -3
- package/tool_registry-CKJPze3j.js.map +1 -0
- package/{turn_runner-DqWHNP80.js → turn_runner-HXImLGIn.js} +7 -7
- package/turn_runner-HXImLGIn.js.map +1 -0
- package/{turn_runner-fg1Wc3dK.mjs → turn_runner-ZyYO-Kti.mjs} +7 -7
- package/turn_runner-ZyYO-Kti.mjs.map +1 -0
- package/turn_runner.cjs +1 -1
- package/turn_runner.mjs +1 -1
- package/types.d.ts +1 -1
- package/common-BT0nfCi9.mjs.map +0 -1
- package/common-Cj8TaQ9U.js.map +0 -1
- package/exceptions-BeWH2FwP.mjs.map +0 -1
- package/exceptions-CitH5wZI.js.map +0 -1
- package/spooled_markdown_artifact-CALSDxIx.js.map +0 -1
- package/spooled_markdown_artifact-Ci5UL7l4.mjs.map +0 -1
- package/tool_call-CV5qVNlb.mjs.map +0 -1
- package/tool_call-Db68hB7y.js.map +0 -1
- package/tool_registry-D1pSSlsd.mjs.map +0 -1
- package/tool_registry-DYUYqXvo.js.map +0 -1
- package/turn_runner-DqWHNP80.js.map +0 -1
- package/turn_runner-fg1Wc3dK.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-CMhaDRNd.mjs","names":["#name","#description","#inputSchema","#handler","#artifactConstructor","#meta","#ephemeral","#trusted","#onCollision"],"sources":["../src/lib/contracts/spooled_artifact_constructor.ts","../src/lib/classes/tool.ts"],"sourcesContent":["import { validator } from '@nhtio/validation'\nimport { passesSchema } from '../utils/validation'\nimport type { SpooledArtifact } from '../classes/spooled_artifact'\n\n/**\n * Constructor signature for any {@link @nhtio/adk!SpooledArtifact} (the class itself or a subclass).\n *\n * @remarks\n * Re-declared here at the contract level so consumers — and the `Tool.artifactConstructor`\n * resolver validator in particular — can talk about the constructor shape without value-importing\n * the {@link @nhtio/adk!SpooledArtifact} class (which would close the `tool.ts` ↔ `spooled_artifact.ts` ↔\n * `artifact_tool.ts` module cycle at load time and TDZ-crash `ArtifactTool extends Tool`).\n *\n * @typeParam A - The {@link @nhtio/adk!SpooledArtifact} subtype the constructor produces.\n */\nexport type SpooledArtifactConstructorLike<A extends SpooledArtifact = SpooledArtifact> = new (\n ...args: any[]\n) => A\n\nconst ARTIFACT_METHODS = [\n 'head',\n 'tail',\n 'grep',\n 'cat',\n 'byteLength',\n 'lineCount',\n 'estimateTokens',\n] as const\n\n/**\n * Validator schema used to validate a {@link SpooledArtifactConstructorLike} value.\n *\n * @remarks\n * Because the validator is invoked at validate-time (not at module-load), it is safe to inspect\n * the constructor's prototype here. The check is duck-typed: the value must be a function whose\n * `prototype` carries every canonical artifact instance method (`head`, `tail`, `grep`, `cat`,\n * `byteLength`, `lineCount`, `estimateTokens`). This mirrors {@link spoolReaderSchema}'s\n * cross-realm-safe duck-type pattern — `instanceof SpooledArtifact` would be tighter but would\n * force a value-import of the class and reopen the module cycle.\n */\nexport const spooledArtifactConstructorSchema = validator\n .any()\n .required()\n .custom((value, helpers) => {\n if (typeof value !== 'function') return helpers.error('any.invalid')\n const proto = (value as { prototype?: unknown }).prototype\n if (proto === undefined || proto === null) return helpers.error('any.invalid')\n if (\n ARTIFACT_METHODS.every((m) => typeof (proto as Record<string, unknown>)[m] === 'function')\n ) {\n return value\n }\n return helpers.error('any.invalid')\n })\n\n/**\n * Returns `true` if `value` is a constructor whose prototype carries every canonical\n * {@link @nhtio/adk!SpooledArtifact} instance method.\n *\n * @remarks\n * Duck-typed; does not use `instanceof SpooledArtifact`. Used by the `Tool.artifactConstructor`\n * resolver validator and any other site that needs to recognise a `SpooledArtifact`-like\n * constructor without pulling the class into its module-load graph.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a `SpooledArtifact`-shaped constructor.\n */\nexport const implementsSpooledArtifactConstructor = (\n value: unknown\n): value is SpooledArtifactConstructorLike => {\n return passesSchema(spooledArtifactConstructorSchema, value)\n}\n","import { DateTime } from 'luxon'\nimport { sha256 } from 'js-sha256'\nimport { Registry } from './registry'\nimport { validator } from '@nhtio/validation'\nimport { isInstanceOf, isError } from '../utils/guards'\nimport { canonicalStringify } from '../utils/canonical_json'\nimport { validateOrThrow, asyncValidateOrThrow, ValidationException } from '../utils/validation'\nimport { implementsSpooledArtifactConstructor } from '../contracts/spooled_artifact_constructor'\nimport {\n E_INVALID_INITIAL_TOOL_VALUE,\n E_INVALID_TOOL_ARGS,\n E_TOOL_DOWNSTREAM_ERROR,\n} from '../exceptions/runtime'\nimport type { Media } from './media'\nimport type { Schema, Description } from '@nhtio/validation'\nimport type { DispatchContext } from '../contracts/dispatch_context'\nimport type { SpooledArtifact, SpooledArtifactConstructor } from './spooled_artifact'\n\n/**\n * A zero-arg function that returns the {@link @nhtio/adk!SpooledArtifactConstructor} the consumer should\n * use when wrapping this tool's serialised output into a `ToolCall.results` field.\n *\n * @remarks\n * Why a resolver (and not the constructor itself)? `tool.ts` participates in a module-load\n * cycle with `spooled_artifact.ts` and `artifact_tool.ts` (`ArtifactTool extends Tool` closes\n * the loop). Any eager value-level reference to `SpooledArtifact` in `tool.ts` would crash the\n * cycle with a TDZ error. A resolver lets `tool.ts` validate \"is a function\" at module-load\n * time and defer the actual constructor check to validate-time (which always runs after every\n * module body has executed). Wrap-sites invoke `tool.artifactConstructor?.() ?? SpooledArtifact`\n * to obtain the final constructor.\n */\nexport type ArtifactConstructorResolver<A extends SpooledArtifact = SpooledArtifact> =\n () => SpooledArtifactConstructor<A>\n\n/**\n * The execution function for a {@link Tool}.\n *\n * @remarks\n * Receives the raw arguments passed to the executor, the active {@link @nhtio/adk!DispatchContext}, and the\n * tool's metadata registry.\n *\n * Return shapes:\n * - `string` / `Uint8Array` — opaque serialised output. The ADK does not persist the bytes\n * itself; the consumer's executor middleware is responsible for storing them and wrapping\n * them via `tool.artifactConstructor?.() ?? SpooledArtifact` when assembling the `ToolCall`\n * record.\n * - {@link @nhtio/adk!Media} / `Media[]` — explicit-modality silo. Bypasses\n * {@link Tool.artifactConstructor} — the handler returns the final result shape directly.\n * The LLM battery renders each `Media` as a provider-specific content block.\n */\nexport type ToolHandler = (\n args: unknown,\n ctx: DispatchContext,\n meta: Registry\n) => string | Uint8Array | Media | Media[] | Promise<string | Uint8Array | Media | Media[]>\n\n/**\n * Plain input object supplied to {@link Tool} at construction time.\n *\n * @typeParam A - The {@link @nhtio/adk!SpooledArtifact} subtype used to wrap this tool's results when\n * the consumer assembles a `ToolCall.results` field. Defaults to {@link @nhtio/adk!SpooledArtifact}\n * (plain text). Tools producing JSON output should set this to `SpooledJsonArtifact`; tools\n * producing markdown should set it to `SpooledMarkdownArtifact`; consumers can also pass a\n * custom subclass.\n */\nexport interface RawTool<A extends SpooledArtifact = SpooledArtifact> {\n /** Unique identifier used in LLM tool definitions. Recommend lowercase snake_case. */\n name: string\n /** Human-readable description passed to the model to explain what the tool does. */\n description: string\n /** @nhtio/validation schema for the tool's input arguments. Annotate with `.description()`, `.note()`, `.example()` etc. to produce rich LLM tool definitions via `.describe()`. */\n inputSchema: Schema\n /** Execution function. Not exposed as a public property — invoke via `executor()`. */\n handler: ToolHandler\n /**\n * Zero-arg resolver returning the {@link @nhtio/adk!SpooledArtifactConstructor} the consumer should use\n * when wrapping this tool's serialised output into a `ToolCall.results` field. Optional —\n * when omitted, wrap-sites fall back to {@link @nhtio/adk!SpooledArtifact} (plain text).\n *\n * @remarks\n * Recommended call shape: `artifactConstructor: () => SpooledJsonArtifact`. The closure is\n * the indirection that lets `tool.ts` validate this field without eagerly importing\n * `SpooledArtifact` (which would crash the `tool.ts ↔ spooled_artifact.ts ↔ artifact_tool.ts`\n * module-load cycle). At validate time the schema invokes the resolver and verifies its\n * return value is a `SpooledArtifact`-derived constructor — wrong-shape resolvers throw\n * {@link @nhtio/adk!E_INVALID_INITIAL_TOOL_VALUE}.\n *\n * Wrap-sites (storage batteries, scripted executors) read the constructor via\n * `tool.artifactConstructor?.() ?? SpooledArtifact`.\n */\n artifactConstructor?: ArtifactConstructorResolver<A>\n /** Optional arbitrary metadata for this tool (e.g. RBAC scopes, feature flags). Defaults to `{}`. Stored in a {@link @nhtio/adk!Registry} for dot-path access. */\n meta?: Record<string, unknown>\n /**\n * When `true`, marks this tool as owned by a specific {@link @nhtio/adk!DispatchContext} so that\n * `ToolRegistry.pruneEphemeral()` will drop it at ctx-completion.\n *\n * @remarks\n * The flag is advisory at the `Tool` level — registries decide what to do with it. The canonical\n * producer of ephemeral tools is `SpooledArtifact.forgeTools(ctx)`, which sets this to `true`\n * on every artifact-query tool it emits.\n *\n * @defaultValue `false`\n */\n ephemeral?: boolean\n /**\n * When `true`, declares that this tool's output should be treated as **trusted developer/user\n * intent** rather than as untrusted third-party text when surfaced to the model.\n *\n * @remarks\n * LLM batteries read this flag per call when rendering tool-call results. The default\n * untrusted envelope (e.g. `<untrusted_content>` in the OpenAI Chat Completions battery) is the\n * secure-by-default treatment for arbitrary tool output. A tool whose output is authored by the\n * user or operator (Q&A tools surfacing user-authored answers, human-in-the-loop approval\n * gates, feedback-collection tools, configuration tools returning developer-authored\n * constants) sets this to `true` so the LLM battery routes the result through its trusted\n * envelope (`<trusted_content>` in the OpenAI Chat Completions battery).\n *\n * Trust is a property of the tool's output, not a property of how a particular battery is\n * wired — putting the flag here means the trust signal travels with the tool wherever it is\n * registered, no per-battery string lists, no name-matching to fail-open on typos.\n *\n * @defaultValue `false`\n */\n trusted?: boolean\n /**\n * Self-declared merge collision policy. Honoured by `ToolRegistry.merge` (NOT by\n * `ToolRegistry.register`) when this tool collides with another of the same name.\n *\n * @remarks\n * - `'throw'` (default): defer to the merge-level `options.onCollision`. If that is also\n * `'throw'`, the merge raises `E_TOOL_ALREADY_REGISTERED`. This matches the default behaviour\n * of `ToolRegistry.register`.\n * - `'replace'`: this tool always wins the collision, regardless of the merge-level option.\n * - `'keep'`: this tool always loses to any previously-registered tool of the same name.\n *\n * Forged artifact-query tools set this to `'replace'` so that merging multiple\n * `Subclass.forgeTools(ctx)` outputs (whose base-method tools overlap by name) resolves\n * silently — the descriptors, snapshot, and handler behaviour are interchangeable across\n * subclasses, so replacement is a behavioural no-op.\n *\n * @defaultValue `'throw'`\n */\n onCollision?: 'throw' | 'replace' | 'keep'\n}\n\n/**\n * Validator schema for a {@link RawTool}.\n */\nconst rawToolSchema = validator.object<RawTool>({\n name: validator.string().required(),\n description: validator.string().required(),\n inputSchema: validator\n .any()\n .custom((value, helpers) => {\n if (validator.isSchema(value) && (value as any).type === 'object') return value\n return helpers.error('any.invalid')\n })\n .required(),\n handler: validator.function().required(),\n artifactConstructor: validator\n .any()\n .custom((value, helpers) => {\n if (typeof value !== 'function') return helpers.error('any.invalid')\n // The resolver runs at validate time — well after the tool.ts ↔ spooled_artifact.ts ↔\n // artifact_tool.ts module cycle has fully unwound — so invoking it is safe. Delegate the\n // \"is this a SpooledArtifact-shaped constructor?\" check to the contract-level guard so\n // there's one canonical duck-type test (mirrors `implementsSpoolReader`'s pattern).\n let resolved: unknown\n try {\n resolved = (value as () => unknown)()\n } catch {\n return helpers.error('any.invalid')\n }\n if (implementsSpooledArtifactConstructor(resolved)) return value\n return helpers.error('any.invalid')\n })\n .optional(),\n // eslint-disable-next-line adk/require-validator-any-required -- map value type-arg: meta holds arbitrary values; disposition is set by .default({}) on the object\n meta: validator.object().pattern(validator.string(), validator.any()).default({}),\n ephemeral: validator.boolean().default(false),\n trusted: validator.boolean().default(false),\n onCollision: validator.string().valid('throw', 'replace', 'keep').default('throw'),\n})\n\n/**\n * A tool definition that serves as the single source of truth for a callable tool: its name,\n * description, input schema, execution handler, and the {@link @nhtio/adk!SpooledArtifact} subclass that\n * wraps its serialised output.\n *\n * @typeParam A - The {@link @nhtio/adk!SpooledArtifact} subtype this tool's results should be wrapped in.\n * Defaults to {@link @nhtio/adk!SpooledArtifact}.\n *\n * @remarks\n * The `inputSchema` is a `@nhtio/validation` schema. It is used at runtime to validate incoming\n * arguments before the handler is called, and its `.describe()` output provides all the metadata\n * needed to build a provider-specific LLM tool definition — annotate the schema with\n * `.description()`, `.note()`, `.example()` etc. once, and that information is available in both\n * contexts without duplication.\n *\n * The handler is private — invoke it only through `executor(ctx)` which validates args, fires\n * observability events (with a stable `callId` derived from the tool name and arguments), and\n * wraps handler errors in {@link @nhtio/adk!E_TOOL_DOWNSTREAM_ERROR}. The handler returns serialised bytes\n * (`string | Uint8Array`); persistence is the consumer's responsibility.\n *\n * `artifactConstructor` is the {@link @nhtio/adk!SpooledArtifact} subclass the consumer should use when\n * wrapping the handler's output into a `ToolCall.results` field. The author declares it once\n * on the tool instance; the consumer reads it when assembling persisted records.\n */\nexport class Tool<A extends SpooledArtifact = SpooledArtifact> {\n /**\n * Validator schema that accepts a {@link RawTool} object.\n *\n * @remarks\n * Reusable fragment for any schema that needs to validate or nest a tool entry\n * (e.g. `TurnRunnerConfig.tools`).\n */\n public static schema = rawToolSchema\n\n /**\n * Returns `true` if `value` is a {@link Tool} instance.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link Tool} instance.\n */\n public static isTool(value: unknown): value is Tool {\n return isInstanceOf(value, 'Tool', Tool)\n }\n\n declare readonly name: string\n declare readonly description: string\n declare readonly inputSchema: Schema\n declare readonly artifactConstructor: ArtifactConstructorResolver<A> | undefined\n declare readonly meta: Registry\n declare readonly ephemeral: boolean\n declare readonly trusted: boolean\n declare readonly onCollision: 'throw' | 'replace' | 'keep'\n\n #name: string\n #description: string\n #inputSchema: Schema\n #handler: ToolHandler\n #artifactConstructor: ArtifactConstructorResolver<A> | undefined\n #meta: Registry\n #ephemeral: boolean\n #trusted: boolean\n #onCollision: 'throw' | 'replace' | 'keep'\n\n /**\n * @param raw - The raw tool input validated against `rawToolSchema`.\n * @throws {@link @nhtio/adk!E_INVALID_INITIAL_TOOL_VALUE} when `raw` does not satisfy the schema.\n */\n constructor(raw: RawTool<A>) {\n let resolved: RawTool<A> & {\n meta: Record<string, unknown>\n ephemeral: boolean\n trusted: boolean\n onCollision: 'throw' | 'replace' | 'keep'\n }\n try {\n resolved = validateOrThrow<typeof resolved>(\n rawToolSchema,\n raw as RawTool,\n true\n ) as typeof resolved\n } catch (err) {\n throw new E_INVALID_INITIAL_TOOL_VALUE({ cause: isError(err) ? err : undefined })\n }\n\n this.#name = resolved.name\n this.#description = resolved.description\n this.#inputSchema = resolved.inputSchema\n this.#handler = resolved.handler\n this.#artifactConstructor = resolved.artifactConstructor as\n | ArtifactConstructorResolver<A>\n | undefined\n this.#meta = new Registry(resolved.meta)\n this.#ephemeral = resolved.ephemeral\n this.#trusted = resolved.trusted\n this.#onCollision = resolved.onCollision\n\n Object.defineProperties(this, {\n name: {\n get: () => this.#name,\n enumerable: true,\n configurable: false,\n },\n description: {\n get: () => this.#description,\n enumerable: true,\n configurable: false,\n },\n inputSchema: {\n get: () => this.#inputSchema,\n enumerable: true,\n configurable: false,\n },\n artifactConstructor: {\n get: () => this.#artifactConstructor,\n enumerable: true,\n configurable: false,\n },\n meta: {\n get: () => this.#meta,\n enumerable: true,\n configurable: false,\n },\n ephemeral: {\n get: () => this.#ephemeral,\n enumerable: true,\n configurable: false,\n },\n trusted: {\n get: () => this.#trusted,\n enumerable: true,\n configurable: false,\n },\n onCollision: {\n get: () => this.#onCollision,\n enumerable: true,\n configurable: false,\n },\n })\n }\n\n /**\n * Validates `args` against the tool's input schema asynchronously.\n *\n * @remarks\n * Async to support schemas with external validators (e.g. database lookups, API calls).\n * A validation failure throws {@link @nhtio/adk!E_INVALID_TOOL_ARGS} — this indicates a programming error\n * in the tool call loop, not a downstream failure.\n *\n * @param args - The arguments to validate.\n * @returns The validated (and coerced) arguments.\n * @throws {@link @nhtio/adk!E_INVALID_TOOL_ARGS} when `args` does not satisfy the input schema.\n */\n async validate(args: unknown): Promise<unknown> {\n try {\n return await asyncValidateOrThrow(this.#inputSchema, args)\n } catch (err) {\n if (isInstanceOf(err, 'ValidationException', ValidationException)) {\n throw new E_INVALID_TOOL_ARGS({ cause: err })\n }\n throw err\n }\n }\n\n /**\n * Returns a bound executor function for this tool against the given turn context.\n *\n * @remarks\n * The executor: (1) computes a stable `callId` as `sha256(canonicalStringify({tool, args}))`\n * over the **raw, pre-validation args**, (2) validates `args` via {@link Tool.validate},\n * (3) emits `toolExecutionStart` on the context (with the computed `callId`), (4) calls the\n * handler, (5) emits `toolExecutionEnd` (with the same `callId`), (6) wraps any handler error\n * in {@link @nhtio/adk!E_TOOL_DOWNSTREAM_ERROR} before re-throwing.\n *\n * The handler returns serialised bytes (`string | Uint8Array`) — persistence is the consumer's\n * concern. Use {@link Tool.artifactConstructor} when wrapping the bytes into a\n * `ToolCall.results` field.\n *\n * Pattern mirrors `Middleware.runner()` — call once per turn, reuse the returned function.\n *\n * @param ctx - The active turn context. Provides emit functions and turn ID.\n * @returns An async function `(args) => Promise<string | Uint8Array>`.\n */\n executor(\n ctx: DispatchContext\n ): (args: unknown) => Promise<string | Uint8Array | Media | Media[]> {\n return async (args: unknown): Promise<string | Uint8Array | Media | Media[]> => {\n // Compute callId over raw args (pre-validation) so two invocations with the same\n // (tool, raw args) produce the same identifier even if validation coerces values.\n const callId = sha256(canonicalStringify({ tool: this.#name, args }))\n const validatedArgs = await this.validate(args)\n const startedAt = DateTime.now()\n ctx.emitToolExecutionStart({\n toolName: this.#name,\n turnId: ctx.id,\n callId,\n args: validatedArgs,\n startedAt,\n })\n try {\n const result = await this.#handler(validatedArgs, ctx, this.#meta)\n const endedAt = DateTime.now()\n ctx.emitToolExecutionEnd({\n toolName: this.#name,\n turnId: ctx.id,\n callId,\n startedAt,\n endedAt,\n durationMs: endedAt.diff(startedAt).milliseconds,\n isError: false,\n })\n return result\n } catch (err) {\n const endedAt = DateTime.now()\n ctx.emitToolExecutionEnd({\n toolName: this.#name,\n turnId: ctx.id,\n callId,\n startedAt,\n endedAt,\n durationMs: endedAt.diff(startedAt).milliseconds,\n isError: true,\n })\n throw new E_TOOL_DOWNSTREAM_ERROR({ cause: isError(err) ? err : undefined })\n }\n }\n }\n\n /**\n * Returns a fully serialisable snapshot of this tool's definition.\n *\n * @remarks\n * The `inputSchema` property is the result of calling `.describe()` on the raw schema — a plain\n * object carrying all the annotation metadata (descriptions, notes, examples, types) without any\n * validator functions. Use this to build provider-specific LLM tool definitions.\n *\n * @returns `{ name, description, inputSchema }` where `inputSchema` is the schema description.\n */\n describe(): { name: string; description: string; inputSchema: Description } {\n return {\n name: this.#name,\n description: this.#description,\n inputSchema: this.#inputSchema.describe(),\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tool-wMYMVl60.mjs","names":["#name","#description","#inputSchema","#handler","#artifactConstructor","#meta","#ephemeral","#trusted","#onCollision"],"sources":["../src/lib/contracts/spooled_artifact_constructor.ts","../src/lib/classes/tool.ts"],"sourcesContent":["import { validator } from '@nhtio/validation'\nimport { passesSchema } from '../utils/validation'\nimport type { SpooledArtifact } from '../classes/spooled_artifact'\n\n/**\n * Constructor signature for any {@link @nhtio/adk!SpooledArtifact} (the class itself or a subclass).\n *\n * @remarks\n * Re-declared here at the contract level so consumers — and the `Tool.artifactConstructor`\n * resolver validator in particular — can talk about the constructor shape without value-importing\n * the {@link @nhtio/adk!SpooledArtifact} class (which would close the `tool.ts` ↔ `spooled_artifact.ts` ↔\n * `artifact_tool.ts` module cycle at load time and TDZ-crash `ArtifactTool extends Tool`).\n *\n * @typeParam A - The {@link @nhtio/adk!SpooledArtifact} subtype the constructor produces.\n */\nexport type SpooledArtifactConstructorLike<A extends SpooledArtifact = SpooledArtifact> = new (\n ...args: any[]\n) => A\n\nconst ARTIFACT_METHODS = [\n 'head',\n 'tail',\n 'grep',\n 'cat',\n 'byteLength',\n 'lineCount',\n 'estimateTokens',\n] as const\n\n/**\n * Validator schema used to validate a {@link SpooledArtifactConstructorLike} value.\n *\n * @remarks\n * Because the validator is invoked at validate-time (not at module-load), it is safe to inspect\n * the constructor's prototype here. The check is duck-typed: the value must be a function whose\n * `prototype` carries every canonical artifact instance method (`head`, `tail`, `grep`, `cat`,\n * `byteLength`, `lineCount`, `estimateTokens`). This mirrors {@link spoolReaderSchema}'s\n * cross-realm-safe duck-type pattern — `instanceof SpooledArtifact` would be tighter but would\n * force a value-import of the class and reopen the module cycle.\n */\nexport const spooledArtifactConstructorSchema = validator\n .any()\n .required()\n .custom((value, helpers) => {\n if (typeof value !== 'function') return helpers.error('any.invalid')\n const proto = (value as { prototype?: unknown }).prototype\n if (proto === undefined || proto === null) return helpers.error('any.invalid')\n if (\n ARTIFACT_METHODS.every((m) => typeof (proto as Record<string, unknown>)[m] === 'function')\n ) {\n return value\n }\n return helpers.error('any.invalid')\n })\n\n/**\n * Returns `true` if `value` is a constructor whose prototype carries every canonical\n * {@link @nhtio/adk!SpooledArtifact} instance method.\n *\n * @remarks\n * Duck-typed; does not use `instanceof SpooledArtifact`. Used by the `Tool.artifactConstructor`\n * resolver validator and any other site that needs to recognise a `SpooledArtifact`-like\n * constructor without pulling the class into its module-load graph.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a `SpooledArtifact`-shaped constructor.\n */\nexport const implementsSpooledArtifactConstructor = (\n value: unknown\n): value is SpooledArtifactConstructorLike => {\n return passesSchema(spooledArtifactConstructorSchema, value)\n}\n","import { DateTime } from 'luxon'\nimport { sha256 } from 'js-sha256'\nimport { Registry } from './registry'\nimport { validator } from '@nhtio/validation'\nimport { isInstanceOf, isError } from '../utils/guards'\nimport { canonicalStringify } from '../utils/canonical_json'\nimport { validateOrThrow, asyncValidateOrThrow, ValidationException } from '../utils/validation'\nimport { implementsSpooledArtifactConstructor } from '../contracts/spooled_artifact_constructor'\nimport {\n E_INVALID_INITIAL_TOOL_VALUE,\n E_INVALID_TOOL_ARGS,\n E_TOOL_DOWNSTREAM_ERROR,\n} from '../exceptions/runtime'\nimport type { Media } from './media'\nimport type { Schema, Description } from '@nhtio/validation'\nimport type { DispatchContext } from '../contracts/dispatch_context'\nimport type { SpooledArtifact, SpooledArtifactConstructor } from './spooled_artifact'\n\n/**\n * A zero-arg function that returns the {@link @nhtio/adk!SpooledArtifactConstructor} the consumer should\n * use when wrapping this tool's serialised output into a `ToolCall.results` field.\n *\n * @remarks\n * Why a resolver (and not the constructor itself)? `tool.ts` participates in a module-load\n * cycle with `spooled_artifact.ts` and `artifact_tool.ts` (`ArtifactTool extends Tool` closes\n * the loop). Any eager value-level reference to `SpooledArtifact` in `tool.ts` would crash the\n * cycle with a TDZ error. A resolver lets `tool.ts` validate \"is a function\" at module-load\n * time and defer the actual constructor check to validate-time (which always runs after every\n * module body has executed). Wrap-sites invoke `tool.artifactConstructor?.() ?? SpooledArtifact`\n * to obtain the final constructor.\n */\nexport type ArtifactConstructorResolver<A extends SpooledArtifact = SpooledArtifact> =\n () => SpooledArtifactConstructor<A>\n\n/**\n * The execution function for a {@link Tool}.\n *\n * @remarks\n * Receives the raw arguments passed to the executor, the active {@link @nhtio/adk!DispatchContext}, and the\n * tool's metadata registry.\n *\n * Return shapes:\n * - `string` / `Uint8Array` — opaque serialised output. The ADK does not persist the bytes\n * itself; the consumer's executor middleware is responsible for storing them and wrapping\n * them via `tool.artifactConstructor?.() ?? SpooledArtifact` when assembling the `ToolCall`\n * record.\n * - {@link @nhtio/adk!Media} / `Media[]` — explicit-modality silo. Bypasses\n * {@link Tool.artifactConstructor} — the handler returns the final result shape directly.\n * The LLM battery renders each `Media` as a provider-specific content block.\n */\nexport type ToolHandler = (\n args: unknown,\n ctx: DispatchContext,\n meta: Registry\n) => string | Uint8Array | Media | Media[] | Promise<string | Uint8Array | Media | Media[]>\n\n/**\n * Plain input object supplied to {@link Tool} at construction time.\n *\n * @typeParam A - The {@link @nhtio/adk!SpooledArtifact} subtype used to wrap this tool's results when\n * the consumer assembles a `ToolCall.results` field. Defaults to {@link @nhtio/adk!SpooledArtifact}\n * (plain text). Tools producing JSON output should set this to `SpooledJsonArtifact`; tools\n * producing markdown should set it to `SpooledMarkdownArtifact`; consumers can also pass a\n * custom subclass.\n */\nexport interface RawTool<A extends SpooledArtifact = SpooledArtifact> {\n /** Unique identifier used in LLM tool definitions. Recommend lowercase snake_case. */\n name: string\n /** Human-readable description passed to the model to explain what the tool does. */\n description: string\n /** @nhtio/validation schema for the tool's input arguments. Annotate with `.description()`, `.note()`, `.example()` etc. to produce rich LLM tool definitions via `.describe()`. */\n inputSchema: Schema\n /** Execution function. Not exposed as a public property — invoke via `executor()`. */\n handler: ToolHandler\n /**\n * Zero-arg resolver returning the {@link @nhtio/adk!SpooledArtifactConstructor} the consumer should use\n * when wrapping this tool's serialised output into a `ToolCall.results` field. Optional —\n * when omitted, wrap-sites fall back to {@link @nhtio/adk!SpooledArtifact} (plain text).\n *\n * @remarks\n * Recommended call shape: `artifactConstructor: () => SpooledJsonArtifact`. The closure is\n * the indirection that lets `tool.ts` validate this field without eagerly importing\n * `SpooledArtifact` (which would crash the `tool.ts ↔ spooled_artifact.ts ↔ artifact_tool.ts`\n * module-load cycle). At validate time the schema invokes the resolver and verifies its\n * return value is a `SpooledArtifact`-derived constructor — wrong-shape resolvers throw\n * {@link @nhtio/adk!E_INVALID_INITIAL_TOOL_VALUE}.\n *\n * Wrap-sites (storage batteries, scripted executors) read the constructor via\n * `tool.artifactConstructor?.() ?? SpooledArtifact`.\n */\n artifactConstructor?: ArtifactConstructorResolver<A>\n /** Optional arbitrary metadata for this tool (e.g. RBAC scopes, feature flags). Defaults to `{}`. Stored in a {@link @nhtio/adk!Registry} for dot-path access. */\n meta?: Record<string, unknown>\n /**\n * When `true`, marks this tool as owned by a specific {@link @nhtio/adk!DispatchContext} so that\n * `ToolRegistry.pruneEphemeral()` will drop it at ctx-completion.\n *\n * @remarks\n * The flag is advisory at the `Tool` level — registries decide what to do with it. The canonical\n * producer of ephemeral tools is `SpooledArtifact.forgeTools(ctx)`, which sets this to `true`\n * on every artifact-query tool it emits.\n *\n * @defaultValue `false`\n */\n ephemeral?: boolean\n /**\n * When `true`, declares that this tool's output should be treated as **trusted developer/user\n * intent** rather than as untrusted third-party text when surfaced to the model.\n *\n * @remarks\n * LLM batteries read this flag per call when rendering tool-call results. The default\n * untrusted envelope (e.g. `<untrusted_content>` in the OpenAI Chat Completions battery) is the\n * secure-by-default treatment for arbitrary tool output. A tool whose output is authored by the\n * user or operator (Q&A tools surfacing user-authored answers, human-in-the-loop approval\n * gates, feedback-collection tools, configuration tools returning developer-authored\n * constants) sets this to `true` so the LLM battery routes the result through its trusted\n * envelope (`<trusted_content>` in the OpenAI Chat Completions battery).\n *\n * Trust is a property of the tool's output, not a property of how a particular battery is\n * wired — putting the flag here means the trust signal travels with the tool wherever it is\n * registered, no per-battery string lists, no name-matching to fail-open on typos.\n *\n * @defaultValue `false`\n */\n trusted?: boolean\n /**\n * Self-declared merge collision policy. Honoured by `ToolRegistry.merge` (NOT by\n * `ToolRegistry.register`) when this tool collides with another of the same name.\n *\n * @remarks\n * - `'throw'` (default): defer to the merge-level `options.onCollision`. If that is also\n * `'throw'`, the merge raises `E_TOOL_ALREADY_REGISTERED`. This matches the default behaviour\n * of `ToolRegistry.register`.\n * - `'replace'`: this tool always wins the collision, regardless of the merge-level option.\n * - `'keep'`: this tool always loses to any previously-registered tool of the same name.\n *\n * Forged artifact-query tools set this to `'replace'` so that merging multiple\n * `Subclass.forgeTools(ctx)` outputs (whose base-method tools overlap by name) resolves\n * silently — the descriptors, snapshot, and handler behaviour are interchangeable across\n * subclasses, so replacement is a behavioural no-op.\n *\n * @defaultValue `'throw'`\n */\n onCollision?: 'throw' | 'replace' | 'keep'\n}\n\n/**\n * Validator schema for a {@link RawTool}.\n */\nconst rawToolSchema = validator.object<RawTool>({\n name: validator.string().required(),\n description: validator.string().required(),\n inputSchema: validator\n .any()\n .custom((value, helpers) => {\n if (validator.isSchema(value) && (value as any).type === 'object') return value\n return helpers.error('any.invalid')\n })\n .required(),\n handler: validator.function().required(),\n artifactConstructor: validator\n .any()\n .custom((value, helpers) => {\n if (typeof value !== 'function') return helpers.error('any.invalid')\n // The resolver runs at validate time — well after the tool.ts ↔ spooled_artifact.ts ↔\n // artifact_tool.ts module cycle has fully unwound — so invoking it is safe. Delegate the\n // \"is this a SpooledArtifact-shaped constructor?\" check to the contract-level guard so\n // there's one canonical duck-type test (mirrors `implementsSpoolReader`'s pattern).\n let resolved: unknown\n try {\n resolved = (value as () => unknown)()\n } catch {\n return helpers.error('any.invalid')\n }\n if (implementsSpooledArtifactConstructor(resolved)) return value\n return helpers.error('any.invalid')\n })\n .optional(),\n // eslint-disable-next-line adk/require-validator-any-required -- map value type-arg: meta holds arbitrary values; disposition is set by .default({}) on the object\n meta: validator.object().pattern(validator.string(), validator.any()).default({}),\n ephemeral: validator.boolean().default(false),\n trusted: validator.boolean().default(false),\n onCollision: validator.string().valid('throw', 'replace', 'keep').default('throw'),\n})\n\n/**\n * A tool definition that serves as the single source of truth for a callable tool: its name,\n * description, input schema, execution handler, and the {@link @nhtio/adk!SpooledArtifact} subclass that\n * wraps its serialised output.\n *\n * @typeParam A - The {@link @nhtio/adk!SpooledArtifact} subtype this tool's results should be wrapped in.\n * Defaults to {@link @nhtio/adk!SpooledArtifact}.\n *\n * @remarks\n * The `inputSchema` is a `@nhtio/validation` schema. It is used at runtime to validate incoming\n * arguments before the handler is called, and its `.describe()` output provides all the metadata\n * needed to build a provider-specific LLM tool definition — annotate the schema with\n * `.description()`, `.note()`, `.example()` etc. once, and that information is available in both\n * contexts without duplication.\n *\n * The handler is private — invoke it only through `executor(ctx)` which validates args, fires\n * observability events (with a stable `callId` derived from the tool name and arguments), and\n * wraps handler errors in {@link @nhtio/adk!E_TOOL_DOWNSTREAM_ERROR}. The handler returns serialised bytes\n * (`string | Uint8Array`); persistence is the consumer's responsibility.\n *\n * `artifactConstructor` is the {@link @nhtio/adk!SpooledArtifact} subclass the consumer should use when\n * wrapping the handler's output into a `ToolCall.results` field. The author declares it once\n * on the tool instance; the consumer reads it when assembling persisted records.\n */\nexport class Tool<A extends SpooledArtifact = SpooledArtifact> {\n /**\n * Validator schema that accepts a {@link RawTool} object.\n *\n * @remarks\n * Reusable fragment for any schema that needs to validate or nest a tool entry\n * (e.g. `TurnRunnerConfig.tools`).\n */\n public static schema = rawToolSchema\n\n /**\n * Returns `true` if `value` is a {@link Tool} instance.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link Tool} instance.\n */\n public static isTool(value: unknown): value is Tool {\n return isInstanceOf(value, 'Tool', Tool)\n }\n\n /** The tool's unique name, as exposed to the model in the tool definition. */\n declare readonly name: string\n /** Human/model-facing description of what the tool does. */\n declare readonly description: string\n /** Validation schema for the tool's arguments; also drives the generated parameter definition. */\n declare readonly inputSchema: Schema\n /** Resolver for the artifact constructor used to wrap the handler's output, if any. */\n declare readonly artifactConstructor: ArtifactConstructorResolver<A> | undefined\n /** Arbitrary per-tool metadata registry, passed through to the handler. */\n declare readonly meta: Registry\n /** When `true`, the tool's results are not persisted to history (transient/one-shot). */\n declare readonly ephemeral: boolean\n /** When `true`, the tool's output is treated as trusted content by the LLM battery's envelopes. */\n declare readonly trusted: boolean\n /** How registration resolves a name clash in a {@link ToolRegistry}: throw, replace, or keep the existing. */\n declare readonly onCollision: 'throw' | 'replace' | 'keep'\n\n #name: string\n #description: string\n #inputSchema: Schema\n #handler: ToolHandler\n #artifactConstructor: ArtifactConstructorResolver<A> | undefined\n #meta: Registry\n #ephemeral: boolean\n #trusted: boolean\n #onCollision: 'throw' | 'replace' | 'keep'\n\n /**\n * @param raw - The raw tool input validated against `rawToolSchema`.\n * @throws {@link @nhtio/adk!E_INVALID_INITIAL_TOOL_VALUE} when `raw` does not satisfy the schema.\n */\n constructor(raw: RawTool<A>) {\n let resolved: RawTool<A> & {\n meta: Record<string, unknown>\n ephemeral: boolean\n trusted: boolean\n onCollision: 'throw' | 'replace' | 'keep'\n }\n try {\n resolved = validateOrThrow<typeof resolved>(\n rawToolSchema,\n raw as RawTool,\n true\n ) as typeof resolved\n } catch (err) {\n throw new E_INVALID_INITIAL_TOOL_VALUE({ cause: isError(err) ? err : undefined })\n }\n\n this.#name = resolved.name\n this.#description = resolved.description\n this.#inputSchema = resolved.inputSchema\n this.#handler = resolved.handler\n this.#artifactConstructor = resolved.artifactConstructor as\n | ArtifactConstructorResolver<A>\n | undefined\n this.#meta = new Registry(resolved.meta)\n this.#ephemeral = resolved.ephemeral\n this.#trusted = resolved.trusted\n this.#onCollision = resolved.onCollision\n\n Object.defineProperties(this, {\n name: {\n get: () => this.#name,\n enumerable: true,\n configurable: false,\n },\n description: {\n get: () => this.#description,\n enumerable: true,\n configurable: false,\n },\n inputSchema: {\n get: () => this.#inputSchema,\n enumerable: true,\n configurable: false,\n },\n artifactConstructor: {\n get: () => this.#artifactConstructor,\n enumerable: true,\n configurable: false,\n },\n meta: {\n get: () => this.#meta,\n enumerable: true,\n configurable: false,\n },\n ephemeral: {\n get: () => this.#ephemeral,\n enumerable: true,\n configurable: false,\n },\n trusted: {\n get: () => this.#trusted,\n enumerable: true,\n configurable: false,\n },\n onCollision: {\n get: () => this.#onCollision,\n enumerable: true,\n configurable: false,\n },\n })\n }\n\n /**\n * Validates `args` against the tool's input schema asynchronously.\n *\n * @remarks\n * Async to support schemas with external validators (e.g. database lookups, API calls).\n * A validation failure throws {@link @nhtio/adk!E_INVALID_TOOL_ARGS} — this indicates a programming error\n * in the tool call loop, not a downstream failure.\n *\n * @param args - The arguments to validate.\n * @returns The validated (and coerced) arguments.\n * @throws {@link @nhtio/adk!E_INVALID_TOOL_ARGS} when `args` does not satisfy the input schema.\n */\n async validate(args: unknown): Promise<unknown> {\n try {\n return await asyncValidateOrThrow(this.#inputSchema, args)\n } catch (err) {\n if (isInstanceOf(err, 'ValidationException', ValidationException)) {\n throw new E_INVALID_TOOL_ARGS({ cause: err })\n }\n throw err\n }\n }\n\n /**\n * Returns a bound executor function for this tool against the given turn context.\n *\n * @remarks\n * The executor: (1) computes a stable `callId` as `sha256(canonicalStringify({tool, args}))`\n * over the **raw, pre-validation args**, (2) validates `args` via {@link Tool.validate},\n * (3) emits `toolExecutionStart` on the context (with the computed `callId`), (4) calls the\n * handler, (5) emits `toolExecutionEnd` (with the same `callId`), (6) wraps any handler error\n * in {@link @nhtio/adk!E_TOOL_DOWNSTREAM_ERROR} before re-throwing.\n *\n * The handler returns serialised bytes (`string | Uint8Array`) — persistence is the consumer's\n * concern. Use {@link Tool.artifactConstructor} when wrapping the bytes into a\n * `ToolCall.results` field.\n *\n * Pattern mirrors `Middleware.runner()` — call once per turn, reuse the returned function.\n *\n * @param ctx - The active turn context. Provides emit functions and turn ID.\n * @returns An async function `(args) => Promise<string | Uint8Array>`.\n */\n executor(\n ctx: DispatchContext\n ): (args: unknown) => Promise<string | Uint8Array | Media | Media[]> {\n return async (args: unknown): Promise<string | Uint8Array | Media | Media[]> => {\n // Compute callId over raw args (pre-validation) so two invocations with the same\n // (tool, raw args) produce the same identifier even if validation coerces values.\n const callId = sha256(canonicalStringify({ tool: this.#name, args }))\n const validatedArgs = await this.validate(args)\n const startedAt = DateTime.now()\n ctx.emitToolExecutionStart({\n toolName: this.#name,\n turnId: ctx.id,\n callId,\n args: validatedArgs,\n startedAt,\n })\n try {\n const result = await this.#handler(validatedArgs, ctx, this.#meta)\n const endedAt = DateTime.now()\n ctx.emitToolExecutionEnd({\n toolName: this.#name,\n turnId: ctx.id,\n callId,\n startedAt,\n endedAt,\n durationMs: endedAt.diff(startedAt).milliseconds,\n isError: false,\n })\n return result\n } catch (err) {\n const endedAt = DateTime.now()\n ctx.emitToolExecutionEnd({\n toolName: this.#name,\n turnId: ctx.id,\n callId,\n startedAt,\n endedAt,\n durationMs: endedAt.diff(startedAt).milliseconds,\n isError: true,\n })\n throw new E_TOOL_DOWNSTREAM_ERROR({ cause: isError(err) ? err : undefined })\n }\n }\n }\n\n /**\n * Returns a fully serialisable snapshot of this tool's definition.\n *\n * @remarks\n * The `inputSchema` property is the result of calling `.describe()` on the raw schema — a plain\n * object carrying all the annotation metadata (descriptions, notes, examples, types) without any\n * validator functions. Use this to build provider-specific LLM tool definitions.\n *\n * @returns `{ name, description, inputSchema }` where `inputSchema` is the schema description.\n */\n describe(): { name: string; description: string; inputSchema: Description } {\n return {\n name: this.#name,\n description: this.#description,\n inputSchema: this.#inputSchema.describe(),\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as validateOrThrow, i as passesSchema } from "./exceptions-
|
|
2
|
-
import { a as Tokenizable, c as isObject, o as isError, r as Registry, s as isInstanceOf } from "./tool_registry-
|
|
3
|
-
import { S as E_NOT_A_MEDIA_READER, i as E_INVALID_INITIAL_MEDIA_VALUE, u as E_INVALID_INITIAL_TOOL_CALL_VALUE } from "./runtime-
|
|
4
|
-
import { t as SpooledArtifact } from "./spooled_artifact-
|
|
1
|
+
import { a as validateOrThrow, i as passesSchema } from "./exceptions-BDhN0Xzr.mjs";
|
|
2
|
+
import { a as Tokenizable, c as isObject, o as isError, r as Registry, s as isInstanceOf } from "./tool_registry-791Vrjtf.mjs";
|
|
3
|
+
import { S as E_NOT_A_MEDIA_READER, i as E_INVALID_INITIAL_MEDIA_VALUE, u as E_INVALID_INITIAL_TOOL_CALL_VALUE } from "./runtime-Bz5zA8wc.mjs";
|
|
4
|
+
import { t as SpooledArtifact } from "./spooled_artifact-7eePq7JA.mjs";
|
|
5
5
|
import { validator } from "@nhtio/validation";
|
|
6
6
|
import { v6 } from "uuid";
|
|
7
7
|
//#region src/lib/contracts/media_reader.ts
|
|
@@ -575,4 +575,4 @@ var ToolCall = class ToolCall {
|
|
|
575
575
|
//#endregion
|
|
576
576
|
export { mediaReaderSchema as a, implementsMediaReader as i, Media as n, isMedia as r, ToolCall as t };
|
|
577
577
|
|
|
578
|
-
//# sourceMappingURL=tool_call-
|
|
578
|
+
//# sourceMappingURL=tool_call-B4-_-vjG.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool_call-B4-_-vjG.mjs","names":["#id","#kind","#mimeType","#filename","#source","#trustTier","#modalityHazard","#reader","#stash","#id","#tool","#args","#checksum","#isComplete","#isError","#results","#fromArtifactTool","#inline","#createdAt","#updatedAt","#completedAt"],"sources":["../src/lib/contracts/media_reader.ts","../src/lib/classes/media.ts","../src/lib/classes/tool_call.ts"],"sourcesContent":["import { validator } from '@nhtio/validation'\nimport { passesSchema } from '../utils/validation'\n\n/**\n * Re-openable byte source contract for a Media instance.\n *\n * @remarks\n * Peer to {@link @nhtio/adk!SpoolReader} but tuned for binary streaming rather than line-indexed text.\n * Each `stream()` call must return a fresh, drainable `ReadableStream` over the same underlying\n * bytes — implementations model replay: in-memory readers reconstitute the stream from the\n * buffer, file-backed readers reopen the file handle, HTTP-backed readers re-issue the fetch,\n * cloud blob readers re-issue the GET. The implementor owns the storage and the cost of keeping\n * the underlying source addressable. Implementors whose underlying source is genuinely\n * non-replayable (a raw HTTP body they were handed once) are responsible for caching locally\n * before constructing the Media.\n *\n * Both methods may be synchronous or asynchronous to accommodate both in-memory and I/O-backed\n * implementations without forcing unnecessary promise overhead on simple cases.\n */\nexport interface MediaReader {\n /**\n * Re-opens the underlying byte source and returns a fresh ReadableStream.\n *\n * @remarks\n * Each call yields a new, drainable stream over the same bytes. Render code that needs the\n * full buffer (e.g. base64-encoding an inline image_url) drains the stream; render code that\n * can forward the stream (e.g. multipart upload) passes the stream through without buffering.\n *\n * @returns A drainable ReadableStream of Uint8Array chunks over the underlying bytes.\n */\n stream(): ReadableStream<Uint8Array> | Promise<ReadableStream<Uint8Array>>\n\n /**\n * Returns the total number of bytes in the underlying data, or `undefined` if unknown.\n *\n * @remarks\n * Used for telemetry, budget checks, and pre-flight provider size validation without forcing\n * a stream drain. Sources of unknown length may return `undefined` — absence is treated as\n * \"unknown\", not \"zero\".\n *\n * @returns The byte length of the underlying data, or `undefined` when unknown.\n */\n byteLength(): number | undefined | Promise<number | undefined>\n}\n\n/**\n * Validator schema used to validate a MediaReader value.\n *\n * @remarks\n * Because MediaReader is a structural interface with no associated constructor, validation is\n * duck-typed: the value must be an object, class instance, or function with `stream` and\n * `byteLength` present as callable properties. Arity is not enforced.\n */\nexport const mediaReaderSchema = validator\n .any()\n .required()\n .custom((value, helpers) => {\n if (\n value !== null &&\n value !== undefined &&\n typeof (value as any).stream === 'function' &&\n typeof (value as any).byteLength === 'function'\n ) {\n return value as MediaReader\n }\n return helpers.error('any.invalid')\n })\n\n/**\n * Returns `true` if `value` implements the MediaReader interface.\n *\n * @remarks\n * Duck-typed: checks that `value` is non-null with `stream` and `byteLength` as callable\n * functions. Does not use `instanceof` — there is no MediaReader constructor.\n *\n * @param value - The value to test.\n * @returns `true` when `value` conforms to the MediaReader interface.\n */\nexport const implementsMediaReader = (value: unknown): value is MediaReader => {\n return passesSchema(mediaReaderSchema, value)\n}\n","import { v6 as uuidv6 } from 'uuid'\nimport { Registry } from './registry'\nimport { isError } from '../utils/guards'\nimport { validator } from '@nhtio/validation'\nimport { isInstanceOf } from '../utils/guards'\nimport { validateOrThrow } from '../utils/validation'\nimport { implementsMediaReader, mediaReaderSchema } from '../contracts/media_reader'\nimport { E_INVALID_INITIAL_MEDIA_VALUE, E_NOT_A_MEDIA_READER } from '../exceptions/runtime'\nimport type { MediaReader } from '../contracts/media_reader'\n\n/**\n * The set of supported media kinds.\n *\n * @remarks\n * Modality coverage is asymmetric across providers. The framework defines no\n * `supportedModalities` field — how a battery handles a modality it cannot natively render is\n * the battery author's call (see `unsupportedMediaPolicy` on the OpenAI Chat Completions\n * battery).\n */\nexport const MediaKind = ['image', 'audio', 'video', 'document'] as const\n\n/**\n * Union of all recognised media kind identifier strings.\n */\nexport type MediaKind = (typeof MediaKind)[number]\n\n/**\n * Provenance axis. *Who is the framework willing to vouch for as the source of these bytes?*\n *\n * @remarks\n * Mirrors `RetrievableTrustTier` deliberately — same vocabulary, same question:\n * *did this content come from a place the agent should treat as authoritative?*\n *\n * - `'first-party'` — deployer-vetted bytes (tool output the operator authored, signed\n * internal assets).\n * - `'third-party-public'` — open-web fetches, public APIs, public corpora.\n * - `'third-party-private'` — user uploads, partner APIs, private corpora.\n */\nexport const MediaTrustTier = ['first-party', 'third-party-public', 'third-party-private'] as const\nexport type MediaTrustTier = (typeof MediaTrustTier)[number]\n\n/**\n * Modality-hazard axis. *How dangerous is it to let the model decode these bytes?*\n *\n * @remarks\n * Orthogonal to provenance — a first-party trusted PDF can still carry hidden text layers; a\n * third-party-public raw image can still be encoded as opaque pixels with adversarial\n * perturbations.\n *\n * - `'inert'` — bytes the model never decodes as instructions (e.g. a handle that is never\n * inlined into the prompt).\n * - `'extractable-instructions'` — text-bearing media: PDFs, screenshots with UI text, documents.\n * Hazard is OCR / embedded-text-layer reads.\n * - `'opaque-perceptual'` — raw vision/audio/video the model encodes directly. Hazard is\n * steganographic LSB prompts, adversarial perturbations, ultrasonic audio — invisible to any\n * pre-screen.\n *\n * See `/the-loop/trust-tiers/media` and its research sub-page `/the-loop/trust-tiers/media/research`.\n */\nexport const MediaModalityHazard = [\n 'inert',\n 'extractable-instructions',\n 'opaque-perceptual',\n] as const\nexport type MediaModalityHazard = (typeof MediaModalityHazard)[number]\n\n/**\n * Per-entry shape stored in a {@link Media}'s `stash` register.\n *\n * @remarks\n * Each entry carries its own trust tier so render code can route derived text (OCR, captions,\n * transcripts) through its own envelope independent of the parent media. How a battery or\n * middleware assigns those entry-level tiers is the implementor's call — the primitive contract\n * does not enforce a \"downgrade derived interpretation from possibly-adversarial bytes\" policy.\n */\nexport interface MediaStashEntry {\n /** The value of the entry — any serialisable shape the consumer wants to store. */\n value: unknown\n /** Trust tier for this specific entry; routed independently of the parent media. */\n trustTier: MediaTrustTier\n /** Optional pointer to the parent Media id this entry was derived from. */\n derivedFromMedia?: string\n}\n\n/**\n * Plain input object supplied to {@link Media} at construction time.\n *\n * @remarks\n * Validated against `rawMediaSchema` before the `Media` instance is created.\n */\nexport interface RawMedia {\n /**\n * Stable unique identifier for this media instance. Required for strict symmetry with\n * `Message.id` and `ToolCall.id`. When omitted, a fresh UUIDv6 is assigned at construction\n * time.\n */\n id?: string\n /** The media kind. See {@link MediaKind}. */\n kind: MediaKind\n /** The MIME type of the underlying bytes. */\n mimeType: string\n /** Filename used by providers that key on it (e.g. OpenAI `file.filename`). */\n filename: string\n /** Re-openable byte source. See {@link @nhtio/adk!MediaReader}. */\n reader: MediaReader\n /**\n * Trust tier declared at construction time. Required — there is NO default.\n * See {@link MediaTrustTier}.\n */\n trustTier: MediaTrustTier\n /**\n * Modality hazard declared at construction time. Required — there is NO default.\n * See {@link MediaModalityHazard}.\n */\n modalityHazard: MediaModalityHazard\n /** Optional provenance pointer (URL, tool name, etc.) for audit / events. */\n source?: string\n /**\n * Free-form per-instance metadata register. Middleware pipelines append to this — typically\n * with a text description, transcript, caption, or alt-text — so downstream code that cannot\n * consume the media natively has a model-readable fallback. No keys are reserved by the\n * framework. Defaults to `{}`.\n */\n stash?: Record<string, MediaStashEntry>\n}\n\nconst stashEntrySchema = validator\n .object<MediaStashEntry>({\n value: validator.any().required(),\n trustTier: validator\n .string()\n .valid(...MediaTrustTier)\n .required(),\n derivedFromMedia: validator.string().optional(),\n })\n .unknown(false)\n\n/**\n * Validator schema used to validate a {@link RawMedia} before constructing a {@link Media}.\n */\nconst rawMediaSchema = validator.object<RawMedia>({\n id: validator.string().optional(),\n kind: validator\n .string()\n .valid(...MediaKind)\n .required(),\n mimeType: validator.string().required(),\n filename: validator.string().required(),\n reader: mediaReaderSchema.required(),\n trustTier: validator\n .string()\n .valid(...MediaTrustTier)\n .required(),\n modalityHazard: validator\n .string()\n .valid(...MediaModalityHazard)\n .required(),\n source: validator.string().optional(),\n stash: validator.object().pattern(validator.string(), stashEntrySchema).optional(),\n})\n\ninterface ResolvedMedia {\n id?: string\n kind: MediaKind\n mimeType: string\n filename: string\n reader: MediaReader\n trustTier: MediaTrustTier\n modalityHazard: MediaModalityHazard\n source?: string\n stash?: Record<string, MediaStashEntry>\n}\n\nconst conservativeHazardForKind = (kind: MediaKind): MediaModalityHazard => {\n return kind === 'document' ? 'extractable-instructions' : 'opaque-perceptual'\n}\n\n/**\n * Shape returned by {@link Media.toJSON}. Metadata-only — bytes and the reader are stripped so\n * naive event/log serialisation never materialises bytes.\n */\n/** The plain-object, JSON-safe form of a {@link Media} produced by {@link Media.toJSON}. */\nexport interface SerializedMedia {\n /** Stable identifier for this media asset. */\n id: string\n /** High-level modality of the asset (e.g. image, audio, document). */\n kind: MediaKind\n /** MIME type of the underlying bytes (e.g. `image/png`). */\n mimeType: string\n /** Original or suggested file name for the asset. */\n filename: string\n /** Optional provenance string (URL, path, or other origin marker). */\n source?: string\n /** Trust tier governing how the asset's content is framed to the model. */\n trustTier: MediaTrustTier\n /** Whether the modality can carry hidden instructions (`extractable-instructions`) or is opaque-perceptual. */\n modalityHazard: MediaModalityHazard\n /** Adapter-scoped side-channel data keyed by name (e.g. provider upload handles). */\n stash: Record<string, MediaStashEntry>\n /** Size of the underlying bytes in bytes, when known. */\n byteLength?: number\n}\n\n/**\n * Cross-environment base64 encoder for a `Uint8Array`.\n *\n * @remarks\n * Prefers Node's `Buffer.from(buf).toString('base64')` when `globalThis.Buffer` exists; otherwise\n * chunk-encodes through `btoa` with a 0x8000-byte window to avoid `Maximum call stack size\n * exceeded` on large buffers.\n */\nconst encodeBase64 = (bytes: Uint8Array): string => {\n const maybeBuffer = (\n globalThis as { Buffer?: { from(b: Uint8Array): { toString(enc: string): string } } }\n ).Buffer\n if (maybeBuffer && typeof maybeBuffer.from === 'function') {\n return maybeBuffer.from(bytes).toString('base64')\n }\n const chunkSize = 0x8000\n let binary = ''\n for (let i = 0; i < bytes.length; i += chunkSize) {\n const chunk = bytes.subarray(i, i + chunkSize)\n binary += String.fromCharCode.apply(null, Array.from(chunk) as number[])\n }\n return btoa(binary)\n}\n\n/**\n * Lazy, re-openable view over a binary asset (image, audio, video, document).\n *\n * @remarks\n * Dual-peer to {@link @nhtio/adk!Tokenizable} (silo) and {@link @nhtio/adk!SpooledArtifact}\n * (handle). Wraps a {@link @nhtio/adk!MediaReader} contract — the framework owns the contract, the\n * implementor owns the storage backend. Bytes are reached only through the reader; the primitive\n * itself never inlines bytes.\n *\n * Construction requires `trustTier` and `modalityHazard` — the framework refuses to guess\n * provenance or decoding hazard. Ergonomic factories ({@link Media.userAttachment},\n * {@link Media.toolGenerated}, {@link Media.retrievedPublic}, {@link Media.retrievedPrivate})\n * force the labelling decision at the call site without becoming defaults on the bare\n * constructor.\n */\nexport class Media {\n /**\n * Validator schema that accepts a {@link RawMedia} object.\n */\n public static schema = rawMediaSchema\n\n /**\n * The set of recognised media kinds. Exposed for downstream schemas that need to discriminate\n * on `kind`.\n */\n public static MediaKind = MediaKind\n\n /**\n * The set of recognised trust tiers.\n */\n public static MediaTrustTier = MediaTrustTier\n\n /**\n * The set of recognised modality hazards.\n */\n public static MediaModalityHazard = MediaModalityHazard\n\n /**\n * Returns `true` if `value` is a {@link Media} instance.\n *\n * @remarks\n * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link Media} instance.\n */\n public static isMedia(value: unknown): value is Media {\n return isInstanceOf(value, 'Media', Media)\n }\n\n /** Stable unique identifier. */\n declare readonly id: string\n /** Media kind. */\n declare readonly kind: MediaKind\n /** MIME type of the underlying bytes. */\n declare readonly mimeType: string\n /** Filename surfaced to providers that key on it. */\n declare readonly filename: string\n /** Optional provenance pointer. */\n declare readonly source: string | undefined\n /** Trust tier declared at construction time. */\n declare readonly trustTier: MediaTrustTier\n /** Modality hazard declared at construction time. */\n declare readonly modalityHazard: MediaModalityHazard\n /** Mutable per-instance metadata register; middleware pipelines append to this. */\n declare readonly stash: Registry\n\n #id: string\n #kind: MediaKind\n #mimeType: string\n #filename: string\n #source?: string\n #trustTier: MediaTrustTier\n #modalityHazard: MediaModalityHazard\n #reader: MediaReader\n #stash: Registry\n\n /**\n * @param raw - The raw media input validated against `rawMediaSchema`.\n * @throws {@link @nhtio/adk/exceptions!E_INVALID_INITIAL_MEDIA_VALUE} when `raw` does not satisfy the schema.\n * @throws {@link @nhtio/adk/exceptions!E_NOT_A_MEDIA_READER} when `raw.reader` does not implement {@link @nhtio/adk!MediaReader}.\n */\n constructor(raw: RawMedia) {\n let resolved: ResolvedMedia\n try {\n resolved = validateOrThrow<ResolvedMedia>(rawMediaSchema, raw, true)\n } catch (err) {\n throw new E_INVALID_INITIAL_MEDIA_VALUE({ cause: isError(err) ? err : undefined })\n }\n if (!implementsMediaReader(resolved.reader)) {\n throw new E_NOT_A_MEDIA_READER()\n }\n this.#id = resolved.id ?? uuidv6()\n this.#kind = resolved.kind\n this.#mimeType = resolved.mimeType\n this.#filename = resolved.filename\n this.#source = resolved.source\n this.#trustTier = resolved.trustTier\n this.#modalityHazard = resolved.modalityHazard\n this.#reader = resolved.reader\n this.#stash = new Registry(resolved.stash as Record<string, unknown> | undefined)\n\n Object.defineProperties(this, {\n id: {\n get: () => this.#id,\n enumerable: true,\n configurable: false,\n },\n kind: {\n get: () => this.#kind,\n enumerable: true,\n configurable: false,\n },\n mimeType: {\n get: () => this.#mimeType,\n enumerable: true,\n configurable: false,\n },\n filename: {\n get: () => this.#filename,\n enumerable: true,\n configurable: false,\n },\n source: {\n get: () => this.#source,\n enumerable: true,\n configurable: false,\n },\n trustTier: {\n get: () => this.#trustTier,\n enumerable: true,\n configurable: false,\n },\n modalityHazard: {\n get: () => this.#modalityHazard,\n enumerable: true,\n configurable: false,\n },\n stash: {\n get: () => this.#stash,\n enumerable: true,\n configurable: false,\n },\n })\n }\n\n /**\n * Re-opens the underlying byte source and returns a fresh ReadableStream.\n *\n * @returns A drainable `ReadableStream` over the underlying bytes.\n */\n async stream(): Promise<ReadableStream<Uint8Array>> {\n return this.#reader.stream()\n }\n\n /**\n * Returns the total number of bytes in the underlying data, or `undefined` if unknown.\n *\n * @returns The byte length, or `undefined` when the underlying source cannot report it.\n */\n async byteLength(): Promise<number | undefined> {\n return this.#reader.byteLength()\n }\n\n /**\n * Drains the reader's stream and returns the underlying bytes as a single `Uint8Array`.\n *\n * @remarks\n * Convenience for callers that need the full buffer (e.g. inline base64 encoding). Forces\n * full materialisation — large assets should be piped through {@link Media.stream} instead.\n */\n async asBytes(): Promise<Uint8Array> {\n const stream = await this.stream()\n const reader = stream.getReader()\n const chunks: Uint8Array[] = []\n let total = 0\n while (true) {\n const { value, done } = await reader.read()\n if (done) break\n if (value) {\n chunks.push(value)\n total += value.byteLength\n }\n }\n const out = new Uint8Array(total)\n let offset = 0\n for (const chunk of chunks) {\n out.set(chunk, offset)\n offset += chunk.byteLength\n }\n return out\n }\n\n /**\n * Drains the reader's stream and returns the underlying bytes as a base64 string.\n *\n * @remarks\n * Cross-environment: prefers Node's `Buffer.from(buf).toString('base64')` when available;\n * otherwise chunk-encodes through `btoa` with a 0x8000-byte window to avoid stack overflow\n * on large buffers.\n */\n async asBase64(): Promise<string> {\n const bytes = await this.asBytes()\n return encodeBase64(bytes)\n }\n\n /**\n * Returns the metadata-only serialisation of this Media. Bytes and the reader are stripped\n * so naive event/log serialisation never materialises bytes.\n *\n * @remarks\n * Implementations that have cheap, already-cached `byteLength` may opt to include it; this\n * default implementation omits it to preserve the \"lazy by default\" invariant. Consumers that\n * need byteLength on the serialised payload should call `await media.byteLength()` and merge\n * the result.\n */\n toJSON(): SerializedMedia {\n return {\n id: this.#id,\n kind: this.#kind,\n mimeType: this.#mimeType,\n filename: this.#filename,\n source: this.#source,\n trustTier: this.#trustTier,\n modalityHazard: this.#modalityHazard,\n stash: this.#stash.all() as Record<string, MediaStashEntry>,\n }\n }\n\n /**\n * Factory: constructs a {@link Media} representing a user-supplied attachment.\n *\n * @remarks\n * Pre-fills `trustTier: 'third-party-private'` and derives `modalityHazard` from `kind`\n * (`document` → `'extractable-instructions'`; everything else → `'opaque-perceptual'`).\n * Use the bare constructor when the conservative kind→hazard mapping is wrong for your case.\n */\n public static userAttachment(args: {\n id?: string\n kind: MediaKind\n mimeType: string\n filename: string\n reader: MediaReader\n source?: string\n stash?: Record<string, MediaStashEntry>\n }): Media {\n return new Media({\n ...args,\n trustTier: 'third-party-private',\n modalityHazard: conservativeHazardForKind(args.kind),\n })\n }\n\n /**\n * Factory: constructs a {@link Media} produced by a first-party tool.\n *\n * @remarks\n * Pre-fills `trustTier: 'first-party'` and derives `modalityHazard` from `kind`.\n */\n public static toolGenerated(args: {\n id?: string\n kind: MediaKind\n mimeType: string\n filename: string\n reader: MediaReader\n source?: string\n stash?: Record<string, MediaStashEntry>\n }): Media {\n return new Media({\n ...args,\n trustTier: 'first-party',\n modalityHazard: conservativeHazardForKind(args.kind),\n })\n }\n\n /**\n * Factory: constructs a {@link Media} retrieved from a public third-party source.\n *\n * @remarks\n * Pre-fills `trustTier: 'third-party-public'` and derives `modalityHazard` from `kind`.\n */\n public static retrievedPublic(args: {\n id?: string\n kind: MediaKind\n mimeType: string\n filename: string\n reader: MediaReader\n source?: string\n stash?: Record<string, MediaStashEntry>\n }): Media {\n return new Media({\n ...args,\n trustTier: 'third-party-public',\n modalityHazard: conservativeHazardForKind(args.kind),\n })\n }\n\n /**\n * Factory: constructs a {@link Media} retrieved from a private third-party source.\n *\n * @remarks\n * Pre-fills `trustTier: 'third-party-private'` and derives `modalityHazard` from `kind`.\n */\n public static retrievedPrivate(args: {\n id?: string\n kind: MediaKind\n mimeType: string\n filename: string\n reader: MediaReader\n source?: string\n stash?: Record<string, MediaStashEntry>\n }): Media {\n return new Media({\n ...args,\n trustTier: 'third-party-private',\n modalityHazard: conservativeHazardForKind(args.kind),\n })\n }\n}\n\n/**\n * Returns `true` if `value` is a {@link Media} instance.\n *\n * @remarks\n * Module-level convenience alias for {@link Media.isMedia}. Uses {@link @nhtio/adk!isInstanceOf} for\n * cross-realm safety.\n */\nexport const isMedia = (value: unknown): value is Media => {\n return isInstanceOf(value, 'Media', Media)\n}\n","import { Media } from './media'\nimport { Tokenizable } from './tokenizable'\nimport { validator } from '@nhtio/validation'\nimport { SpooledArtifact } from './spooled_artifact'\nimport { validateOrThrow } from '../utils/validation'\nimport { isObject, isInstanceOf, isError } from '../utils/guards'\nimport { E_INVALID_INITIAL_TOOL_CALL_VALUE } from '../exceptions/runtime'\nimport type { DateTime } from 'luxon'\n\n/**\n * Union of every shape a {@link ToolCall.results} field may carry.\n *\n * @remarks\n * Three silos with distinct render-time semantics:\n *\n * - {@link @nhtio/adk!Tokenizable} — always singular. The {@link @nhtio/adk!ArtifactTool}\n * carve-out: a model-visible text answer that explicitly opts out of artifact wrapping to\n * break the recursive grep-on-the-grep-result loop.\n * - {@link @nhtio/adk!SpooledArtifact} or `SpooledArtifact[]` — bounded text output spooled to durable\n * storage. A single tool call may legitimately produce multiple artifacts (e.g. one tool\n * that returns N PR bodies). LLM adapters render either inline (full body in trust envelope)\n * or as a handle reference (forged artifact-query tools).\n * - {@link @nhtio/adk!Media} or `Media[]` — binary modality output (image, audio, video, document).\n * Adapters render as provider-specific content blocks (`image_url`, `input_audio`, `file`,\n * etc.). Bytes are lazy — reached only through {@link @nhtio/adk!Media.stream}.\n */\nexport type ToolCallResults = Tokenizable | SpooledArtifact | SpooledArtifact[] | Media | Media[]\n\nconst isToolCallResults = (value: unknown): value is ToolCallResults => {\n if (Tokenizable.isTokenizable(value)) return true\n if (SpooledArtifact.isSpooledArtifact(value)) return true\n if (Media.isMedia(value)) return true\n if (Array.isArray(value) && value.length > 0) {\n const allMedia = value.every((entry) => Media.isMedia(entry))\n if (allMedia) return true\n const allSpooled = value.every((entry) => SpooledArtifact.isSpooledArtifact(entry))\n if (allSpooled) return true\n }\n return false\n}\n\n/**\n * Plain input object supplied to {@link ToolCall} at construction time.\n *\n * @remarks\n * Validated against `rawToolCallSchema` before the `ToolCall` instance is created.\n * Temporal fields accept any value that Luxon can parse — ISO strings, Unix timestamps,\n * `Date` objects, or existing `DateTime` instances.\n */\nexport interface RawToolCall {\n /** Stable unique identifier for this tool call; correlates the request with its result. */\n id: string\n /** Name of the tool the model has requested. */\n tool: string\n /**\n * Arguments the model supplied for this tool call.\n *\n * @remarks\n * Accepts either a plain object or a JSON-encoded string that deserialises to an object.\n * Always exposed as a plain object on the constructed {@link ToolCall} instance.\n */\n args: string | Record<string, unknown>\n /** Integrity checksum over `tool` and `args`; can be used to detect tampering before execution. */\n checksum: string\n /** `true` once the tool call has finished (successfully or not). */\n isComplete: boolean\n /** `true` when the tool execution produced an error; inspect `results` for detail. */\n isError: boolean\n /**\n * Result returned by the tool, or error detail when `isError` is `true`.\n *\n * @remarks\n * Three silos with distinct render-time semantics — see {@link ToolCallResults}:\n *\n * - For a normal {@link @nhtio/adk!Tool} call whose handler returned `string` or\n * `Uint8Array`, this is a {@link @nhtio/adk!SpooledArtifact} (or one of its subclasses) wrapping the\n * spooled bytes. Tools that legitimately produce multiple bounded artifacts may return\n * a `SpooledArtifact[]`.\n * - For a `Tool` call whose handler returned a {@link @nhtio/adk!Media} or `Media[]`, this is the same\n * media handle(s) — the explicit-modality silo bypasses `SpooledArtifact` wrapping because\n * the bytes are binary and rendered as provider-specific content blocks, not text.\n * - For an {@link @nhtio/adk!ArtifactTool} call (a forged artifact-query tool),\n * this is a {@link @nhtio/adk!Tokenizable} holding the raw model-visible answer — `ArtifactTool`\n * explicitly opts out of wrapping to break the recursive grep-on-the-grep-result loop.\n *\n * The ADK sets {@link RawToolCall.fromArtifactTool} on calls produced by an\n * `ArtifactTool` so subsequent `forgeTools(ctx)` invocations can filter them out of the\n * `callId` enum.\n */\n results: ToolCallResults\n /**\n * `true` when this tool call originated from an {@link @nhtio/adk!ArtifactTool}\n * invocation. Defaults to `false`.\n *\n * @remarks\n * Set by the ADK's result-wrapping touch sites when `ArtifactTool.isArtifactTool(tool)`\n * holds. Read by `SpooledArtifact.forgeTools(ctx)` when building each descriptor's `callId`\n * enum — calls with this flag set are excluded so the model can't `artifact_grep` on a\n * previous `artifact_grep` result. Optional in the raw shape (defaults to `false`); always\n * defined on the constructed {@link ToolCall}.\n *\n * @defaultValue `false`\n */\n fromArtifactTool?: boolean\n /**\n * When `true` (default), LLM adapters render this tool call's result inline — the full\n * stringified body is wrapped in the adapter's trust envelope and sent to the model as the\n * `tool` role content. When `false`, the adapter surfaces the result as a \"handle\" — a\n * directions-bearing envelope that tells the model which forged artifact-query tools to call\n * against this `tc.id` to read the content incrementally.\n *\n * @remarks\n * Policy is the producer's or middleware's call:\n * - A normal tool returns its result with `inline: true` by default so its output is shown\n * verbatim.\n * - Middleware that wants to keep large results out of the model's prompt sets `inline: false`\n * (typically via `ctx.mutateToolCall(tc.id, { inline: false })`) before yielding.\n * - LLM adapters do not override the flag, do not size-check the result, and do not silently\n * switch to the handle pattern.\n *\n * For {@link @nhtio/adk!Tokenizable} results, the flag is effectively informational — handles only make\n * sense for {@link @nhtio/adk!SpooledArtifact} (which is the only result kind the forged artifact-query\n * tools can read). When `inline: false` is set on a call whose `results` is a `Tokenizable`,\n * the adapter renders inline anyway and may log a warning.\n *\n * @defaultValue `true`\n */\n inline?: boolean\n /** When this tool call was first created. */\n createdAt: string | number | Date | DateTime\n /** When this tool call was last modified. */\n updatedAt: string | number | Date | DateTime\n /** When the tool call completed. */\n completedAt: string | number | Date | DateTime\n}\n\n/**\n * A fully-resolved {@link RawToolCall} where temporal fields have been normalised to Luxon\n * `DateTime` instances.\n *\n * @remarks\n * Used internally by the {@link ToolCall} constructor to assign private fields with\n * guaranteed types.\n */\ninterface ResolvedToolCall {\n id: string\n tool: string\n args: Record<string, unknown>\n checksum: string\n isComplete: boolean\n isError: boolean\n results: ToolCallResults\n fromArtifactTool: boolean\n inline: boolean\n createdAt: DateTime\n updatedAt: DateTime\n completedAt: DateTime\n}\n\n/**\n * Validator schema used to validate a {@link RawToolCall} before constructing a {@link ToolCall}.\n *\n * @remarks\n * Validates all fields of {@link RawToolCall}:\n * - `id` — required non-empty string.\n * - `tool` — required non-empty string.\n * - `args` — required; either a plain object or a JSON string that deserialises to an object.\n * Strings are parsed and the resulting object is stored.\n * - `checksum` — required string.\n * - `isComplete` — required boolean.\n * - `isError` — required boolean.\n * - `results` — required; one of {@link @nhtio/adk!Tokenizable}, {@link @nhtio/adk!SpooledArtifact}, a non-empty\n * `SpooledArtifact[]`, {@link @nhtio/adk!Media}, or a non-empty `Media[]`. Arrays must be homogeneous.\n * - `createdAt` / `updatedAt` / `completedAt` — required datetime-parseable values, normalised to `DateTime`.\n *\n * Throws {@link @nhtio/adk!E_INVALID_INITIAL_TOOL_CALL_VALUE} (via the {@link ToolCall} constructor) when\n * validation fails.\n */\nconst rawToolCallSchema = validator.object<RawToolCall>({\n id: validator.string().required(),\n tool: validator.string().required(),\n args: validator\n .alternatives(\n validator.object().unknown(true),\n validator.string().custom((value, helpers) => {\n try {\n const parsed = JSON.parse(value)\n if (!isObject(parsed)) {\n return helpers.error('any.invalid')\n }\n return parsed\n } catch {\n return helpers.error('any.invalid')\n }\n })\n )\n .required(),\n checksum: validator.string().required(),\n isComplete: validator.boolean().required(),\n isError: validator.boolean().required(),\n results: validator\n .any()\n .custom((value, helpers) => {\n if (isToolCallResults(value)) {\n return value\n }\n return helpers.error('any.invalid')\n })\n .required(),\n fromArtifactTool: validator.boolean().default(false),\n inline: validator.boolean().default(true),\n createdAt: validator.datetime().required(),\n updatedAt: validator.datetime().required(),\n completedAt: validator.datetime().required(),\n})\n\n/**\n * An immutable, validated tool call record associated with a turn.\n *\n * @remarks\n * Represents a completed tool invocation from the conversation history — `results`,\n * `completedAt`, `isComplete`, and `isError` are all present and required.\n * Temporal fields are normalised to Luxon `DateTime` instances at construction time.\n */\nexport class ToolCall {\n /**\n * Validator schema that accepts a {@link RawToolCall} object.\n *\n * @remarks\n * Reusable fragment for any schema that needs to validate or nest a tool call entry.\n */\n public static schema = rawToolCallSchema\n\n /**\n * Returns `true` if `value` is a {@link ToolCall} instance.\n *\n * @remarks\n * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety — `instanceof` would fail for instances\n * created in a different module copy or VM context.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link ToolCall} instance.\n */\n public static isToolCall(value: unknown): value is ToolCall {\n return isInstanceOf(value, 'ToolCall', ToolCall)\n }\n\n /** Stable unique identifier for this tool call; correlates the request with its result. */\n declare readonly id: string\n /** Name of the tool the model has requested. */\n declare readonly tool: string\n /** Arguments the model supplied for this tool call, always as a plain object. */\n declare readonly args: Record<string, unknown>\n /** Integrity checksum over `tool` and `args`. */\n declare readonly checksum: string\n /** `true` once the tool call has finished (successfully or not). */\n declare readonly isComplete: boolean\n /** `true` when the tool execution produced an error; inspect `results` for detail. */\n declare readonly isError: boolean\n /**\n * Result returned by the tool, or error detail when `isError` is `true`.\n *\n * @remarks\n * One of three silos — see {@link ToolCallResults}. {@link @nhtio/adk!SpooledArtifact} or\n * `SpooledArtifact[]` for normal text-output {@link @nhtio/adk!Tool} calls;\n * {@link @nhtio/adk!Media} or `Media[]` for tool calls whose handler returned binary modality output;\n * {@link @nhtio/adk!Tokenizable} for {@link @nhtio/adk!ArtifactTool} calls\n * (see {@link ToolCall.fromArtifactTool}).\n */\n declare readonly results: ToolCallResults\n /**\n * `true` when this tool call originated from an {@link @nhtio/adk!ArtifactTool}\n * invocation. Used by `SpooledArtifact.forgeTools(ctx)` to filter out forged-tool results from\n * the `callId` enum it builds.\n */\n declare readonly fromArtifactTool: boolean\n /**\n * `true` (default) renders this tool call's result inline in the prompt; `false` instructs LLM\n * adapters to surface the result as a handle reference. See {@link RawToolCall.inline}.\n */\n declare readonly inline: boolean\n /** When this tool call was first created. */\n declare readonly createdAt: DateTime\n /** When this tool call was last modified. */\n declare readonly updatedAt: DateTime\n /** When the tool call completed. */\n declare readonly completedAt: DateTime\n\n #id: string\n #tool: string\n #args: Record<string, unknown>\n #checksum: string\n #isComplete: boolean\n #isError: boolean\n #results: ToolCallResults\n #fromArtifactTool: boolean\n #inline: boolean\n #createdAt: DateTime\n #updatedAt: DateTime\n #completedAt: DateTime\n\n /**\n * @param raw - The raw tool call input validated against `rawToolCallSchema`.\n * @throws {@link @nhtio/adk!E_INVALID_INITIAL_TOOL_CALL_VALUE} when `raw` does not satisfy the schema.\n */\n constructor(raw: RawToolCall) {\n let resolved: ResolvedToolCall\n try {\n resolved = validateOrThrow<ResolvedToolCall>(rawToolCallSchema, raw, true)\n } catch (err) {\n throw new E_INVALID_INITIAL_TOOL_CALL_VALUE({ cause: isError(err) ? err : undefined })\n }\n this.#id = resolved.id\n this.#tool = resolved.tool\n this.#args = resolved.args\n this.#checksum = resolved.checksum\n this.#isComplete = resolved.isComplete\n this.#isError = resolved.isError\n this.#results = resolved.results\n this.#fromArtifactTool = resolved.fromArtifactTool\n this.#inline = resolved.inline\n this.#createdAt = resolved.createdAt\n this.#updatedAt = resolved.updatedAt\n this.#completedAt = resolved.completedAt\n\n Object.defineProperties(this, {\n id: {\n get: () => this.#id,\n enumerable: true,\n configurable: false,\n },\n tool: {\n get: () => this.#tool,\n enumerable: true,\n configurable: false,\n },\n args: {\n get: () => this.#args,\n enumerable: true,\n configurable: false,\n },\n checksum: {\n get: () => this.#checksum,\n enumerable: true,\n configurable: false,\n },\n isComplete: {\n get: () => this.#isComplete,\n enumerable: true,\n configurable: false,\n },\n isError: {\n get: () => this.#isError,\n enumerable: true,\n configurable: false,\n },\n results: {\n get: () => this.#results,\n enumerable: true,\n configurable: false,\n },\n fromArtifactTool: {\n get: () => this.#fromArtifactTool,\n enumerable: true,\n configurable: false,\n },\n inline: {\n get: () => this.#inline,\n enumerable: true,\n configurable: false,\n },\n createdAt: {\n get: () => this.#createdAt,\n enumerable: true,\n configurable: false,\n },\n updatedAt: {\n get: () => this.#updatedAt,\n enumerable: true,\n configurable: false,\n },\n completedAt: {\n get: () => this.#completedAt,\n enumerable: true,\n configurable: false,\n },\n })\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
require("./chunk-Ble4zEEl.js");
|
|
2
|
-
const require_exceptions = require("./exceptions-
|
|
3
|
-
const require_tool_registry = require("./tool_registry-
|
|
4
|
-
const require_runtime = require("./runtime-
|
|
5
|
-
const require_spooled_artifact = require("./spooled_artifact-
|
|
2
|
+
const require_exceptions = require("./exceptions-BRXrUKiW.js");
|
|
3
|
+
const require_tool_registry = require("./tool_registry-CKJPze3j.js");
|
|
4
|
+
const require_runtime = require("./runtime-DslE1aBw.js");
|
|
5
|
+
const require_spooled_artifact = require("./spooled_artifact-DX8LLyUX.js");
|
|
6
6
|
let _nhtio_validation = require("@nhtio/validation");
|
|
7
7
|
let uuid = require("uuid");
|
|
8
8
|
//#region src/lib/contracts/media_reader.ts
|
|
@@ -605,4 +605,4 @@ Object.defineProperty(exports, "mediaReaderSchema", {
|
|
|
605
605
|
}
|
|
606
606
|
});
|
|
607
607
|
|
|
608
|
-
//# sourceMappingURL=tool_call-
|
|
608
|
+
//# sourceMappingURL=tool_call-DixVlW40.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool_call-DixVlW40.js","names":["#id","#kind","#mimeType","#filename","#source","#trustTier","#modalityHazard","#reader","#stash","#id","#tool","#args","#checksum","#isComplete","#isError","#results","#fromArtifactTool","#inline","#createdAt","#updatedAt","#completedAt"],"sources":["../src/lib/contracts/media_reader.ts","../src/lib/classes/media.ts","../src/lib/classes/tool_call.ts"],"sourcesContent":["import { validator } from '@nhtio/validation'\nimport { passesSchema } from '../utils/validation'\n\n/**\n * Re-openable byte source contract for a Media instance.\n *\n * @remarks\n * Peer to {@link @nhtio/adk!SpoolReader} but tuned for binary streaming rather than line-indexed text.\n * Each `stream()` call must return a fresh, drainable `ReadableStream` over the same underlying\n * bytes — implementations model replay: in-memory readers reconstitute the stream from the\n * buffer, file-backed readers reopen the file handle, HTTP-backed readers re-issue the fetch,\n * cloud blob readers re-issue the GET. The implementor owns the storage and the cost of keeping\n * the underlying source addressable. Implementors whose underlying source is genuinely\n * non-replayable (a raw HTTP body they were handed once) are responsible for caching locally\n * before constructing the Media.\n *\n * Both methods may be synchronous or asynchronous to accommodate both in-memory and I/O-backed\n * implementations without forcing unnecessary promise overhead on simple cases.\n */\nexport interface MediaReader {\n /**\n * Re-opens the underlying byte source and returns a fresh ReadableStream.\n *\n * @remarks\n * Each call yields a new, drainable stream over the same bytes. Render code that needs the\n * full buffer (e.g. base64-encoding an inline image_url) drains the stream; render code that\n * can forward the stream (e.g. multipart upload) passes the stream through without buffering.\n *\n * @returns A drainable ReadableStream of Uint8Array chunks over the underlying bytes.\n */\n stream(): ReadableStream<Uint8Array> | Promise<ReadableStream<Uint8Array>>\n\n /**\n * Returns the total number of bytes in the underlying data, or `undefined` if unknown.\n *\n * @remarks\n * Used for telemetry, budget checks, and pre-flight provider size validation without forcing\n * a stream drain. Sources of unknown length may return `undefined` — absence is treated as\n * \"unknown\", not \"zero\".\n *\n * @returns The byte length of the underlying data, or `undefined` when unknown.\n */\n byteLength(): number | undefined | Promise<number | undefined>\n}\n\n/**\n * Validator schema used to validate a MediaReader value.\n *\n * @remarks\n * Because MediaReader is a structural interface with no associated constructor, validation is\n * duck-typed: the value must be an object, class instance, or function with `stream` and\n * `byteLength` present as callable properties. Arity is not enforced.\n */\nexport const mediaReaderSchema = validator\n .any()\n .required()\n .custom((value, helpers) => {\n if (\n value !== null &&\n value !== undefined &&\n typeof (value as any).stream === 'function' &&\n typeof (value as any).byteLength === 'function'\n ) {\n return value as MediaReader\n }\n return helpers.error('any.invalid')\n })\n\n/**\n * Returns `true` if `value` implements the MediaReader interface.\n *\n * @remarks\n * Duck-typed: checks that `value` is non-null with `stream` and `byteLength` as callable\n * functions. Does not use `instanceof` — there is no MediaReader constructor.\n *\n * @param value - The value to test.\n * @returns `true` when `value` conforms to the MediaReader interface.\n */\nexport const implementsMediaReader = (value: unknown): value is MediaReader => {\n return passesSchema(mediaReaderSchema, value)\n}\n","import { v6 as uuidv6 } from 'uuid'\nimport { Registry } from './registry'\nimport { isError } from '../utils/guards'\nimport { validator } from '@nhtio/validation'\nimport { isInstanceOf } from '../utils/guards'\nimport { validateOrThrow } from '../utils/validation'\nimport { implementsMediaReader, mediaReaderSchema } from '../contracts/media_reader'\nimport { E_INVALID_INITIAL_MEDIA_VALUE, E_NOT_A_MEDIA_READER } from '../exceptions/runtime'\nimport type { MediaReader } from '../contracts/media_reader'\n\n/**\n * The set of supported media kinds.\n *\n * @remarks\n * Modality coverage is asymmetric across providers. The framework defines no\n * `supportedModalities` field — how a battery handles a modality it cannot natively render is\n * the battery author's call (see `unsupportedMediaPolicy` on the OpenAI Chat Completions\n * battery).\n */\nexport const MediaKind = ['image', 'audio', 'video', 'document'] as const\n\n/**\n * Union of all recognised media kind identifier strings.\n */\nexport type MediaKind = (typeof MediaKind)[number]\n\n/**\n * Provenance axis. *Who is the framework willing to vouch for as the source of these bytes?*\n *\n * @remarks\n * Mirrors `RetrievableTrustTier` deliberately — same vocabulary, same question:\n * *did this content come from a place the agent should treat as authoritative?*\n *\n * - `'first-party'` — deployer-vetted bytes (tool output the operator authored, signed\n * internal assets).\n * - `'third-party-public'` — open-web fetches, public APIs, public corpora.\n * - `'third-party-private'` — user uploads, partner APIs, private corpora.\n */\nexport const MediaTrustTier = ['first-party', 'third-party-public', 'third-party-private'] as const\nexport type MediaTrustTier = (typeof MediaTrustTier)[number]\n\n/**\n * Modality-hazard axis. *How dangerous is it to let the model decode these bytes?*\n *\n * @remarks\n * Orthogonal to provenance — a first-party trusted PDF can still carry hidden text layers; a\n * third-party-public raw image can still be encoded as opaque pixels with adversarial\n * perturbations.\n *\n * - `'inert'` — bytes the model never decodes as instructions (e.g. a handle that is never\n * inlined into the prompt).\n * - `'extractable-instructions'` — text-bearing media: PDFs, screenshots with UI text, documents.\n * Hazard is OCR / embedded-text-layer reads.\n * - `'opaque-perceptual'` — raw vision/audio/video the model encodes directly. Hazard is\n * steganographic LSB prompts, adversarial perturbations, ultrasonic audio — invisible to any\n * pre-screen.\n *\n * See `/the-loop/trust-tiers/media` and its research sub-page `/the-loop/trust-tiers/media/research`.\n */\nexport const MediaModalityHazard = [\n 'inert',\n 'extractable-instructions',\n 'opaque-perceptual',\n] as const\nexport type MediaModalityHazard = (typeof MediaModalityHazard)[number]\n\n/**\n * Per-entry shape stored in a {@link Media}'s `stash` register.\n *\n * @remarks\n * Each entry carries its own trust tier so render code can route derived text (OCR, captions,\n * transcripts) through its own envelope independent of the parent media. How a battery or\n * middleware assigns those entry-level tiers is the implementor's call — the primitive contract\n * does not enforce a \"downgrade derived interpretation from possibly-adversarial bytes\" policy.\n */\nexport interface MediaStashEntry {\n /** The value of the entry — any serialisable shape the consumer wants to store. */\n value: unknown\n /** Trust tier for this specific entry; routed independently of the parent media. */\n trustTier: MediaTrustTier\n /** Optional pointer to the parent Media id this entry was derived from. */\n derivedFromMedia?: string\n}\n\n/**\n * Plain input object supplied to {@link Media} at construction time.\n *\n * @remarks\n * Validated against `rawMediaSchema` before the `Media` instance is created.\n */\nexport interface RawMedia {\n /**\n * Stable unique identifier for this media instance. Required for strict symmetry with\n * `Message.id` and `ToolCall.id`. When omitted, a fresh UUIDv6 is assigned at construction\n * time.\n */\n id?: string\n /** The media kind. See {@link MediaKind}. */\n kind: MediaKind\n /** The MIME type of the underlying bytes. */\n mimeType: string\n /** Filename used by providers that key on it (e.g. OpenAI `file.filename`). */\n filename: string\n /** Re-openable byte source. See {@link @nhtio/adk!MediaReader}. */\n reader: MediaReader\n /**\n * Trust tier declared at construction time. Required — there is NO default.\n * See {@link MediaTrustTier}.\n */\n trustTier: MediaTrustTier\n /**\n * Modality hazard declared at construction time. Required — there is NO default.\n * See {@link MediaModalityHazard}.\n */\n modalityHazard: MediaModalityHazard\n /** Optional provenance pointer (URL, tool name, etc.) for audit / events. */\n source?: string\n /**\n * Free-form per-instance metadata register. Middleware pipelines append to this — typically\n * with a text description, transcript, caption, or alt-text — so downstream code that cannot\n * consume the media natively has a model-readable fallback. No keys are reserved by the\n * framework. Defaults to `{}`.\n */\n stash?: Record<string, MediaStashEntry>\n}\n\nconst stashEntrySchema = validator\n .object<MediaStashEntry>({\n value: validator.any().required(),\n trustTier: validator\n .string()\n .valid(...MediaTrustTier)\n .required(),\n derivedFromMedia: validator.string().optional(),\n })\n .unknown(false)\n\n/**\n * Validator schema used to validate a {@link RawMedia} before constructing a {@link Media}.\n */\nconst rawMediaSchema = validator.object<RawMedia>({\n id: validator.string().optional(),\n kind: validator\n .string()\n .valid(...MediaKind)\n .required(),\n mimeType: validator.string().required(),\n filename: validator.string().required(),\n reader: mediaReaderSchema.required(),\n trustTier: validator\n .string()\n .valid(...MediaTrustTier)\n .required(),\n modalityHazard: validator\n .string()\n .valid(...MediaModalityHazard)\n .required(),\n source: validator.string().optional(),\n stash: validator.object().pattern(validator.string(), stashEntrySchema).optional(),\n})\n\ninterface ResolvedMedia {\n id?: string\n kind: MediaKind\n mimeType: string\n filename: string\n reader: MediaReader\n trustTier: MediaTrustTier\n modalityHazard: MediaModalityHazard\n source?: string\n stash?: Record<string, MediaStashEntry>\n}\n\nconst conservativeHazardForKind = (kind: MediaKind): MediaModalityHazard => {\n return kind === 'document' ? 'extractable-instructions' : 'opaque-perceptual'\n}\n\n/**\n * Shape returned by {@link Media.toJSON}. Metadata-only — bytes and the reader are stripped so\n * naive event/log serialisation never materialises bytes.\n */\n/** The plain-object, JSON-safe form of a {@link Media} produced by {@link Media.toJSON}. */\nexport interface SerializedMedia {\n /** Stable identifier for this media asset. */\n id: string\n /** High-level modality of the asset (e.g. image, audio, document). */\n kind: MediaKind\n /** MIME type of the underlying bytes (e.g. `image/png`). */\n mimeType: string\n /** Original or suggested file name for the asset. */\n filename: string\n /** Optional provenance string (URL, path, or other origin marker). */\n source?: string\n /** Trust tier governing how the asset's content is framed to the model. */\n trustTier: MediaTrustTier\n /** Whether the modality can carry hidden instructions (`extractable-instructions`) or is opaque-perceptual. */\n modalityHazard: MediaModalityHazard\n /** Adapter-scoped side-channel data keyed by name (e.g. provider upload handles). */\n stash: Record<string, MediaStashEntry>\n /** Size of the underlying bytes in bytes, when known. */\n byteLength?: number\n}\n\n/**\n * Cross-environment base64 encoder for a `Uint8Array`.\n *\n * @remarks\n * Prefers Node's `Buffer.from(buf).toString('base64')` when `globalThis.Buffer` exists; otherwise\n * chunk-encodes through `btoa` with a 0x8000-byte window to avoid `Maximum call stack size\n * exceeded` on large buffers.\n */\nconst encodeBase64 = (bytes: Uint8Array): string => {\n const maybeBuffer = (\n globalThis as { Buffer?: { from(b: Uint8Array): { toString(enc: string): string } } }\n ).Buffer\n if (maybeBuffer && typeof maybeBuffer.from === 'function') {\n return maybeBuffer.from(bytes).toString('base64')\n }\n const chunkSize = 0x8000\n let binary = ''\n for (let i = 0; i < bytes.length; i += chunkSize) {\n const chunk = bytes.subarray(i, i + chunkSize)\n binary += String.fromCharCode.apply(null, Array.from(chunk) as number[])\n }\n return btoa(binary)\n}\n\n/**\n * Lazy, re-openable view over a binary asset (image, audio, video, document).\n *\n * @remarks\n * Dual-peer to {@link @nhtio/adk!Tokenizable} (silo) and {@link @nhtio/adk!SpooledArtifact}\n * (handle). Wraps a {@link @nhtio/adk!MediaReader} contract — the framework owns the contract, the\n * implementor owns the storage backend. Bytes are reached only through the reader; the primitive\n * itself never inlines bytes.\n *\n * Construction requires `trustTier` and `modalityHazard` — the framework refuses to guess\n * provenance or decoding hazard. Ergonomic factories ({@link Media.userAttachment},\n * {@link Media.toolGenerated}, {@link Media.retrievedPublic}, {@link Media.retrievedPrivate})\n * force the labelling decision at the call site without becoming defaults on the bare\n * constructor.\n */\nexport class Media {\n /**\n * Validator schema that accepts a {@link RawMedia} object.\n */\n public static schema = rawMediaSchema\n\n /**\n * The set of recognised media kinds. Exposed for downstream schemas that need to discriminate\n * on `kind`.\n */\n public static MediaKind = MediaKind\n\n /**\n * The set of recognised trust tiers.\n */\n public static MediaTrustTier = MediaTrustTier\n\n /**\n * The set of recognised modality hazards.\n */\n public static MediaModalityHazard = MediaModalityHazard\n\n /**\n * Returns `true` if `value` is a {@link Media} instance.\n *\n * @remarks\n * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link Media} instance.\n */\n public static isMedia(value: unknown): value is Media {\n return isInstanceOf(value, 'Media', Media)\n }\n\n /** Stable unique identifier. */\n declare readonly id: string\n /** Media kind. */\n declare readonly kind: MediaKind\n /** MIME type of the underlying bytes. */\n declare readonly mimeType: string\n /** Filename surfaced to providers that key on it. */\n declare readonly filename: string\n /** Optional provenance pointer. */\n declare readonly source: string | undefined\n /** Trust tier declared at construction time. */\n declare readonly trustTier: MediaTrustTier\n /** Modality hazard declared at construction time. */\n declare readonly modalityHazard: MediaModalityHazard\n /** Mutable per-instance metadata register; middleware pipelines append to this. */\n declare readonly stash: Registry\n\n #id: string\n #kind: MediaKind\n #mimeType: string\n #filename: string\n #source?: string\n #trustTier: MediaTrustTier\n #modalityHazard: MediaModalityHazard\n #reader: MediaReader\n #stash: Registry\n\n /**\n * @param raw - The raw media input validated against `rawMediaSchema`.\n * @throws {@link @nhtio/adk/exceptions!E_INVALID_INITIAL_MEDIA_VALUE} when `raw` does not satisfy the schema.\n * @throws {@link @nhtio/adk/exceptions!E_NOT_A_MEDIA_READER} when `raw.reader` does not implement {@link @nhtio/adk!MediaReader}.\n */\n constructor(raw: RawMedia) {\n let resolved: ResolvedMedia\n try {\n resolved = validateOrThrow<ResolvedMedia>(rawMediaSchema, raw, true)\n } catch (err) {\n throw new E_INVALID_INITIAL_MEDIA_VALUE({ cause: isError(err) ? err : undefined })\n }\n if (!implementsMediaReader(resolved.reader)) {\n throw new E_NOT_A_MEDIA_READER()\n }\n this.#id = resolved.id ?? uuidv6()\n this.#kind = resolved.kind\n this.#mimeType = resolved.mimeType\n this.#filename = resolved.filename\n this.#source = resolved.source\n this.#trustTier = resolved.trustTier\n this.#modalityHazard = resolved.modalityHazard\n this.#reader = resolved.reader\n this.#stash = new Registry(resolved.stash as Record<string, unknown> | undefined)\n\n Object.defineProperties(this, {\n id: {\n get: () => this.#id,\n enumerable: true,\n configurable: false,\n },\n kind: {\n get: () => this.#kind,\n enumerable: true,\n configurable: false,\n },\n mimeType: {\n get: () => this.#mimeType,\n enumerable: true,\n configurable: false,\n },\n filename: {\n get: () => this.#filename,\n enumerable: true,\n configurable: false,\n },\n source: {\n get: () => this.#source,\n enumerable: true,\n configurable: false,\n },\n trustTier: {\n get: () => this.#trustTier,\n enumerable: true,\n configurable: false,\n },\n modalityHazard: {\n get: () => this.#modalityHazard,\n enumerable: true,\n configurable: false,\n },\n stash: {\n get: () => this.#stash,\n enumerable: true,\n configurable: false,\n },\n })\n }\n\n /**\n * Re-opens the underlying byte source and returns a fresh ReadableStream.\n *\n * @returns A drainable `ReadableStream` over the underlying bytes.\n */\n async stream(): Promise<ReadableStream<Uint8Array>> {\n return this.#reader.stream()\n }\n\n /**\n * Returns the total number of bytes in the underlying data, or `undefined` if unknown.\n *\n * @returns The byte length, or `undefined` when the underlying source cannot report it.\n */\n async byteLength(): Promise<number | undefined> {\n return this.#reader.byteLength()\n }\n\n /**\n * Drains the reader's stream and returns the underlying bytes as a single `Uint8Array`.\n *\n * @remarks\n * Convenience for callers that need the full buffer (e.g. inline base64 encoding). Forces\n * full materialisation — large assets should be piped through {@link Media.stream} instead.\n */\n async asBytes(): Promise<Uint8Array> {\n const stream = await this.stream()\n const reader = stream.getReader()\n const chunks: Uint8Array[] = []\n let total = 0\n while (true) {\n const { value, done } = await reader.read()\n if (done) break\n if (value) {\n chunks.push(value)\n total += value.byteLength\n }\n }\n const out = new Uint8Array(total)\n let offset = 0\n for (const chunk of chunks) {\n out.set(chunk, offset)\n offset += chunk.byteLength\n }\n return out\n }\n\n /**\n * Drains the reader's stream and returns the underlying bytes as a base64 string.\n *\n * @remarks\n * Cross-environment: prefers Node's `Buffer.from(buf).toString('base64')` when available;\n * otherwise chunk-encodes through `btoa` with a 0x8000-byte window to avoid stack overflow\n * on large buffers.\n */\n async asBase64(): Promise<string> {\n const bytes = await this.asBytes()\n return encodeBase64(bytes)\n }\n\n /**\n * Returns the metadata-only serialisation of this Media. Bytes and the reader are stripped\n * so naive event/log serialisation never materialises bytes.\n *\n * @remarks\n * Implementations that have cheap, already-cached `byteLength` may opt to include it; this\n * default implementation omits it to preserve the \"lazy by default\" invariant. Consumers that\n * need byteLength on the serialised payload should call `await media.byteLength()` and merge\n * the result.\n */\n toJSON(): SerializedMedia {\n return {\n id: this.#id,\n kind: this.#kind,\n mimeType: this.#mimeType,\n filename: this.#filename,\n source: this.#source,\n trustTier: this.#trustTier,\n modalityHazard: this.#modalityHazard,\n stash: this.#stash.all() as Record<string, MediaStashEntry>,\n }\n }\n\n /**\n * Factory: constructs a {@link Media} representing a user-supplied attachment.\n *\n * @remarks\n * Pre-fills `trustTier: 'third-party-private'` and derives `modalityHazard` from `kind`\n * (`document` → `'extractable-instructions'`; everything else → `'opaque-perceptual'`).\n * Use the bare constructor when the conservative kind→hazard mapping is wrong for your case.\n */\n public static userAttachment(args: {\n id?: string\n kind: MediaKind\n mimeType: string\n filename: string\n reader: MediaReader\n source?: string\n stash?: Record<string, MediaStashEntry>\n }): Media {\n return new Media({\n ...args,\n trustTier: 'third-party-private',\n modalityHazard: conservativeHazardForKind(args.kind),\n })\n }\n\n /**\n * Factory: constructs a {@link Media} produced by a first-party tool.\n *\n * @remarks\n * Pre-fills `trustTier: 'first-party'` and derives `modalityHazard` from `kind`.\n */\n public static toolGenerated(args: {\n id?: string\n kind: MediaKind\n mimeType: string\n filename: string\n reader: MediaReader\n source?: string\n stash?: Record<string, MediaStashEntry>\n }): Media {\n return new Media({\n ...args,\n trustTier: 'first-party',\n modalityHazard: conservativeHazardForKind(args.kind),\n })\n }\n\n /**\n * Factory: constructs a {@link Media} retrieved from a public third-party source.\n *\n * @remarks\n * Pre-fills `trustTier: 'third-party-public'` and derives `modalityHazard` from `kind`.\n */\n public static retrievedPublic(args: {\n id?: string\n kind: MediaKind\n mimeType: string\n filename: string\n reader: MediaReader\n source?: string\n stash?: Record<string, MediaStashEntry>\n }): Media {\n return new Media({\n ...args,\n trustTier: 'third-party-public',\n modalityHazard: conservativeHazardForKind(args.kind),\n })\n }\n\n /**\n * Factory: constructs a {@link Media} retrieved from a private third-party source.\n *\n * @remarks\n * Pre-fills `trustTier: 'third-party-private'` and derives `modalityHazard` from `kind`.\n */\n public static retrievedPrivate(args: {\n id?: string\n kind: MediaKind\n mimeType: string\n filename: string\n reader: MediaReader\n source?: string\n stash?: Record<string, MediaStashEntry>\n }): Media {\n return new Media({\n ...args,\n trustTier: 'third-party-private',\n modalityHazard: conservativeHazardForKind(args.kind),\n })\n }\n}\n\n/**\n * Returns `true` if `value` is a {@link Media} instance.\n *\n * @remarks\n * Module-level convenience alias for {@link Media.isMedia}. Uses {@link @nhtio/adk!isInstanceOf} for\n * cross-realm safety.\n */\nexport const isMedia = (value: unknown): value is Media => {\n return isInstanceOf(value, 'Media', Media)\n}\n","import { Media } from './media'\nimport { Tokenizable } from './tokenizable'\nimport { validator } from '@nhtio/validation'\nimport { SpooledArtifact } from './spooled_artifact'\nimport { validateOrThrow } from '../utils/validation'\nimport { isObject, isInstanceOf, isError } from '../utils/guards'\nimport { E_INVALID_INITIAL_TOOL_CALL_VALUE } from '../exceptions/runtime'\nimport type { DateTime } from 'luxon'\n\n/**\n * Union of every shape a {@link ToolCall.results} field may carry.\n *\n * @remarks\n * Three silos with distinct render-time semantics:\n *\n * - {@link @nhtio/adk!Tokenizable} — always singular. The {@link @nhtio/adk!ArtifactTool}\n * carve-out: a model-visible text answer that explicitly opts out of artifact wrapping to\n * break the recursive grep-on-the-grep-result loop.\n * - {@link @nhtio/adk!SpooledArtifact} or `SpooledArtifact[]` — bounded text output spooled to durable\n * storage. A single tool call may legitimately produce multiple artifacts (e.g. one tool\n * that returns N PR bodies). LLM adapters render either inline (full body in trust envelope)\n * or as a handle reference (forged artifact-query tools).\n * - {@link @nhtio/adk!Media} or `Media[]` — binary modality output (image, audio, video, document).\n * Adapters render as provider-specific content blocks (`image_url`, `input_audio`, `file`,\n * etc.). Bytes are lazy — reached only through {@link @nhtio/adk!Media.stream}.\n */\nexport type ToolCallResults = Tokenizable | SpooledArtifact | SpooledArtifact[] | Media | Media[]\n\nconst isToolCallResults = (value: unknown): value is ToolCallResults => {\n if (Tokenizable.isTokenizable(value)) return true\n if (SpooledArtifact.isSpooledArtifact(value)) return true\n if (Media.isMedia(value)) return true\n if (Array.isArray(value) && value.length > 0) {\n const allMedia = value.every((entry) => Media.isMedia(entry))\n if (allMedia) return true\n const allSpooled = value.every((entry) => SpooledArtifact.isSpooledArtifact(entry))\n if (allSpooled) return true\n }\n return false\n}\n\n/**\n * Plain input object supplied to {@link ToolCall} at construction time.\n *\n * @remarks\n * Validated against `rawToolCallSchema` before the `ToolCall` instance is created.\n * Temporal fields accept any value that Luxon can parse — ISO strings, Unix timestamps,\n * `Date` objects, or existing `DateTime` instances.\n */\nexport interface RawToolCall {\n /** Stable unique identifier for this tool call; correlates the request with its result. */\n id: string\n /** Name of the tool the model has requested. */\n tool: string\n /**\n * Arguments the model supplied for this tool call.\n *\n * @remarks\n * Accepts either a plain object or a JSON-encoded string that deserialises to an object.\n * Always exposed as a plain object on the constructed {@link ToolCall} instance.\n */\n args: string | Record<string, unknown>\n /** Integrity checksum over `tool` and `args`; can be used to detect tampering before execution. */\n checksum: string\n /** `true` once the tool call has finished (successfully or not). */\n isComplete: boolean\n /** `true` when the tool execution produced an error; inspect `results` for detail. */\n isError: boolean\n /**\n * Result returned by the tool, or error detail when `isError` is `true`.\n *\n * @remarks\n * Three silos with distinct render-time semantics — see {@link ToolCallResults}:\n *\n * - For a normal {@link @nhtio/adk!Tool} call whose handler returned `string` or\n * `Uint8Array`, this is a {@link @nhtio/adk!SpooledArtifact} (or one of its subclasses) wrapping the\n * spooled bytes. Tools that legitimately produce multiple bounded artifacts may return\n * a `SpooledArtifact[]`.\n * - For a `Tool` call whose handler returned a {@link @nhtio/adk!Media} or `Media[]`, this is the same\n * media handle(s) — the explicit-modality silo bypasses `SpooledArtifact` wrapping because\n * the bytes are binary and rendered as provider-specific content blocks, not text.\n * - For an {@link @nhtio/adk!ArtifactTool} call (a forged artifact-query tool),\n * this is a {@link @nhtio/adk!Tokenizable} holding the raw model-visible answer — `ArtifactTool`\n * explicitly opts out of wrapping to break the recursive grep-on-the-grep-result loop.\n *\n * The ADK sets {@link RawToolCall.fromArtifactTool} on calls produced by an\n * `ArtifactTool` so subsequent `forgeTools(ctx)` invocations can filter them out of the\n * `callId` enum.\n */\n results: ToolCallResults\n /**\n * `true` when this tool call originated from an {@link @nhtio/adk!ArtifactTool}\n * invocation. Defaults to `false`.\n *\n * @remarks\n * Set by the ADK's result-wrapping touch sites when `ArtifactTool.isArtifactTool(tool)`\n * holds. Read by `SpooledArtifact.forgeTools(ctx)` when building each descriptor's `callId`\n * enum — calls with this flag set are excluded so the model can't `artifact_grep` on a\n * previous `artifact_grep` result. Optional in the raw shape (defaults to `false`); always\n * defined on the constructed {@link ToolCall}.\n *\n * @defaultValue `false`\n */\n fromArtifactTool?: boolean\n /**\n * When `true` (default), LLM adapters render this tool call's result inline — the full\n * stringified body is wrapped in the adapter's trust envelope and sent to the model as the\n * `tool` role content. When `false`, the adapter surfaces the result as a \"handle\" — a\n * directions-bearing envelope that tells the model which forged artifact-query tools to call\n * against this `tc.id` to read the content incrementally.\n *\n * @remarks\n * Policy is the producer's or middleware's call:\n * - A normal tool returns its result with `inline: true` by default so its output is shown\n * verbatim.\n * - Middleware that wants to keep large results out of the model's prompt sets `inline: false`\n * (typically via `ctx.mutateToolCall(tc.id, { inline: false })`) before yielding.\n * - LLM adapters do not override the flag, do not size-check the result, and do not silently\n * switch to the handle pattern.\n *\n * For {@link @nhtio/adk!Tokenizable} results, the flag is effectively informational — handles only make\n * sense for {@link @nhtio/adk!SpooledArtifact} (which is the only result kind the forged artifact-query\n * tools can read). When `inline: false` is set on a call whose `results` is a `Tokenizable`,\n * the adapter renders inline anyway and may log a warning.\n *\n * @defaultValue `true`\n */\n inline?: boolean\n /** When this tool call was first created. */\n createdAt: string | number | Date | DateTime\n /** When this tool call was last modified. */\n updatedAt: string | number | Date | DateTime\n /** When the tool call completed. */\n completedAt: string | number | Date | DateTime\n}\n\n/**\n * A fully-resolved {@link RawToolCall} where temporal fields have been normalised to Luxon\n * `DateTime` instances.\n *\n * @remarks\n * Used internally by the {@link ToolCall} constructor to assign private fields with\n * guaranteed types.\n */\ninterface ResolvedToolCall {\n id: string\n tool: string\n args: Record<string, unknown>\n checksum: string\n isComplete: boolean\n isError: boolean\n results: ToolCallResults\n fromArtifactTool: boolean\n inline: boolean\n createdAt: DateTime\n updatedAt: DateTime\n completedAt: DateTime\n}\n\n/**\n * Validator schema used to validate a {@link RawToolCall} before constructing a {@link ToolCall}.\n *\n * @remarks\n * Validates all fields of {@link RawToolCall}:\n * - `id` — required non-empty string.\n * - `tool` — required non-empty string.\n * - `args` — required; either a plain object or a JSON string that deserialises to an object.\n * Strings are parsed and the resulting object is stored.\n * - `checksum` — required string.\n * - `isComplete` — required boolean.\n * - `isError` — required boolean.\n * - `results` — required; one of {@link @nhtio/adk!Tokenizable}, {@link @nhtio/adk!SpooledArtifact}, a non-empty\n * `SpooledArtifact[]`, {@link @nhtio/adk!Media}, or a non-empty `Media[]`. Arrays must be homogeneous.\n * - `createdAt` / `updatedAt` / `completedAt` — required datetime-parseable values, normalised to `DateTime`.\n *\n * Throws {@link @nhtio/adk!E_INVALID_INITIAL_TOOL_CALL_VALUE} (via the {@link ToolCall} constructor) when\n * validation fails.\n */\nconst rawToolCallSchema = validator.object<RawToolCall>({\n id: validator.string().required(),\n tool: validator.string().required(),\n args: validator\n .alternatives(\n validator.object().unknown(true),\n validator.string().custom((value, helpers) => {\n try {\n const parsed = JSON.parse(value)\n if (!isObject(parsed)) {\n return helpers.error('any.invalid')\n }\n return parsed\n } catch {\n return helpers.error('any.invalid')\n }\n })\n )\n .required(),\n checksum: validator.string().required(),\n isComplete: validator.boolean().required(),\n isError: validator.boolean().required(),\n results: validator\n .any()\n .custom((value, helpers) => {\n if (isToolCallResults(value)) {\n return value\n }\n return helpers.error('any.invalid')\n })\n .required(),\n fromArtifactTool: validator.boolean().default(false),\n inline: validator.boolean().default(true),\n createdAt: validator.datetime().required(),\n updatedAt: validator.datetime().required(),\n completedAt: validator.datetime().required(),\n})\n\n/**\n * An immutable, validated tool call record associated with a turn.\n *\n * @remarks\n * Represents a completed tool invocation from the conversation history — `results`,\n * `completedAt`, `isComplete`, and `isError` are all present and required.\n * Temporal fields are normalised to Luxon `DateTime` instances at construction time.\n */\nexport class ToolCall {\n /**\n * Validator schema that accepts a {@link RawToolCall} object.\n *\n * @remarks\n * Reusable fragment for any schema that needs to validate or nest a tool call entry.\n */\n public static schema = rawToolCallSchema\n\n /**\n * Returns `true` if `value` is a {@link ToolCall} instance.\n *\n * @remarks\n * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety — `instanceof` would fail for instances\n * created in a different module copy or VM context.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link ToolCall} instance.\n */\n public static isToolCall(value: unknown): value is ToolCall {\n return isInstanceOf(value, 'ToolCall', ToolCall)\n }\n\n /** Stable unique identifier for this tool call; correlates the request with its result. */\n declare readonly id: string\n /** Name of the tool the model has requested. */\n declare readonly tool: string\n /** Arguments the model supplied for this tool call, always as a plain object. */\n declare readonly args: Record<string, unknown>\n /** Integrity checksum over `tool` and `args`. */\n declare readonly checksum: string\n /** `true` once the tool call has finished (successfully or not). */\n declare readonly isComplete: boolean\n /** `true` when the tool execution produced an error; inspect `results` for detail. */\n declare readonly isError: boolean\n /**\n * Result returned by the tool, or error detail when `isError` is `true`.\n *\n * @remarks\n * One of three silos — see {@link ToolCallResults}. {@link @nhtio/adk!SpooledArtifact} or\n * `SpooledArtifact[]` for normal text-output {@link @nhtio/adk!Tool} calls;\n * {@link @nhtio/adk!Media} or `Media[]` for tool calls whose handler returned binary modality output;\n * {@link @nhtio/adk!Tokenizable} for {@link @nhtio/adk!ArtifactTool} calls\n * (see {@link ToolCall.fromArtifactTool}).\n */\n declare readonly results: ToolCallResults\n /**\n * `true` when this tool call originated from an {@link @nhtio/adk!ArtifactTool}\n * invocation. Used by `SpooledArtifact.forgeTools(ctx)` to filter out forged-tool results from\n * the `callId` enum it builds.\n */\n declare readonly fromArtifactTool: boolean\n /**\n * `true` (default) renders this tool call's result inline in the prompt; `false` instructs LLM\n * adapters to surface the result as a handle reference. See {@link RawToolCall.inline}.\n */\n declare readonly inline: boolean\n /** When this tool call was first created. */\n declare readonly createdAt: DateTime\n /** When this tool call was last modified. */\n declare readonly updatedAt: DateTime\n /** When the tool call completed. */\n declare readonly completedAt: DateTime\n\n #id: string\n #tool: string\n #args: Record<string, unknown>\n #checksum: string\n #isComplete: boolean\n #isError: boolean\n #results: ToolCallResults\n #fromArtifactTool: boolean\n #inline: boolean\n #createdAt: DateTime\n #updatedAt: DateTime\n #completedAt: DateTime\n\n /**\n * @param raw - The raw tool call input validated against `rawToolCallSchema`.\n * @throws {@link @nhtio/adk!E_INVALID_INITIAL_TOOL_CALL_VALUE} when `raw` does not satisfy the schema.\n */\n constructor(raw: RawToolCall) {\n let resolved: ResolvedToolCall\n try {\n resolved = validateOrThrow<ResolvedToolCall>(rawToolCallSchema, raw, true)\n } catch (err) {\n throw new E_INVALID_INITIAL_TOOL_CALL_VALUE({ cause: isError(err) ? err : undefined })\n }\n this.#id = resolved.id\n this.#tool = resolved.tool\n this.#args = resolved.args\n this.#checksum = resolved.checksum\n this.#isComplete = resolved.isComplete\n this.#isError = resolved.isError\n this.#results = resolved.results\n this.#fromArtifactTool = resolved.fromArtifactTool\n this.#inline = resolved.inline\n this.#createdAt = resolved.createdAt\n this.#updatedAt = resolved.updatedAt\n this.#completedAt = resolved.completedAt\n\n Object.defineProperties(this, {\n id: {\n get: () => this.#id,\n enumerable: true,\n configurable: false,\n },\n tool: {\n get: () => this.#tool,\n enumerable: true,\n configurable: false,\n },\n args: {\n get: () => this.#args,\n enumerable: true,\n configurable: false,\n },\n checksum: {\n get: () => this.#checksum,\n enumerable: true,\n configurable: false,\n },\n isComplete: {\n get: () => this.#isComplete,\n enumerable: true,\n configurable: false,\n },\n isError: {\n get: () => this.#isError,\n enumerable: true,\n configurable: false,\n },\n results: {\n get: () => this.#results,\n enumerable: true,\n configurable: false,\n },\n fromArtifactTool: {\n get: () => this.#fromArtifactTool,\n enumerable: true,\n configurable: false,\n },\n inline: {\n get: () => this.#inline,\n enumerable: true,\n configurable: false,\n },\n createdAt: {\n get: () => this.#createdAt,\n enumerable: true,\n configurable: false,\n },\n updatedAt: {\n get: () => this.#updatedAt,\n enumerable: true,\n configurable: false,\n },\n completedAt: {\n get: () => this.#completedAt,\n enumerable: true,\n configurable: false,\n },\n })\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as passesSchema } from "./exceptions-
|
|
2
|
-
import { E as E_TOOL_ALREADY_REGISTERED, s as E_INVALID_INITIAL_REGISTRY_VALUE } from "./runtime-
|
|
1
|
+
import { i as passesSchema } from "./exceptions-BDhN0Xzr.mjs";
|
|
2
|
+
import { E as E_TOOL_ALREADY_REGISTERED, s as E_INVALID_INITIAL_REGISTRY_VALUE } from "./runtime-Bz5zA8wc.mjs";
|
|
3
3
|
import { getEncoding } from "js-tiktoken";
|
|
4
4
|
import { validator } from "@nhtio/validation";
|
|
5
5
|
import { LlamaTokenizer } from "llama-tokenizer-js";
|
|
@@ -125,6 +125,7 @@ var getLlamaTokenizer = () => {
|
|
|
125
125
|
* transparently as strings in most contexts.
|
|
126
126
|
*/
|
|
127
127
|
var Tokenizable = class Tokenizable {
|
|
128
|
+
/** The set of supported token-encoding identifiers, re-exposed as a static for convenience. */
|
|
128
129
|
static TokenEncoding = TokenEncoding;
|
|
129
130
|
/**
|
|
130
131
|
* Validator schema that accepts a plain `string` or a {@link Tokenizable} instance.
|
|
@@ -676,4 +677,4 @@ var ToolRegistry = class ToolRegistry {
|
|
|
676
677
|
//#endregion
|
|
677
678
|
export { Tokenizable as a, isObject as c, TokenEncoding as i, canonicalStringify as n, isError as o, Registry as r, isInstanceOf as s, ToolRegistry as t };
|
|
678
679
|
|
|
679
|
-
//# sourceMappingURL=tool_registry-
|
|
680
|
+
//# sourceMappingURL=tool_registry-791Vrjtf.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool_registry-791Vrjtf.mjs","names":["#value","#cache","#store","#tools","#hidden"],"sources":["../src/lib/utils/guards.ts","../src/lib/classes/tokenizable.ts","../src/lib/classes/registry.ts","../src/lib/utils/canonical_json.ts","../src/lib/classes/tool_registry.ts"],"sourcesContent":["import { passesSchema } from './validation'\nimport { validator } from '@nhtio/validation'\n\n/**\n * Returns `true` if `value` is an instance of the class identified by `type` (and optionally `ctor`).\n *\n * @remarks\n * Performs three checks in order: `instanceof ctor`, `Symbol.hasInstance`, then constructor-name\n * comparison. The constructor-name fallback handles cross-realm cases where `instanceof` fails.\n *\n * @typeParam T - The expected instance type.\n * @param value - The value to test.\n * @param type - The constructor name to compare against when `instanceof` is unavailable.\n * @param ctor - Optional constructor to use for `instanceof` and `Symbol.hasInstance` checks.\n * @returns `true` when `value` is an instance of the class described by `type`/`ctor`.\n */\nexport const isInstanceOf = <T>(\n value: unknown,\n type: string,\n ctor?: new (...args: any[]) => T\n): value is T => {\n // eslint-disable-next-line adk/use-is-instance-of -- this IS the implementation of isInstanceOf\n if ('undefined' !== typeof ctor && value instanceof ctor) return true\n /* istanbul ignore next 4 */\n if (\n 'undefined' !== typeof ctor &&\n typeof ctor[Symbol.hasInstance] === 'function' &&\n ctor[Symbol.hasInstance](value)\n )\n /* istanbul ignore next */\n return true\n // eslint-disable-next-line adk/prefer-is-object -- this guard is the building block isObject depends on (no circular usage)\n if ('object' === typeof value && null !== value) {\n const valueWithConstructor = value as { constructor?: Function }\n const constructorName = valueWithConstructor.constructor?.name\n return constructorName === type\n }\n return false\n}\n\nconst errorSchema = validator\n .any()\n .custom((value, helpers) => {\n if (isInstanceOf(value, 'Error', Error)) {\n return value\n }\n return helpers.error('any.invalid')\n })\n .required()\n\n/**\n * Returns `true` if `value` is an `Error` instance or satisfies the `Error` duck-type shape.\n *\n * @remarks\n * Returns `false` for `undefined` and `null` — the `Error` contract requires an actual instance.\n *\n * @param value - The value to test.\n * @returns `true` when `value` conforms to the `Error` shape.\n */\nexport const isError = (value: unknown): value is Error => {\n return passesSchema(errorSchema, value)\n}\n\n/**\n * Type guard to check if a value is a plain object (not null, not array)\n * @param value - The value to check\n * @returns True if the value is a plain object, false otherwise\n */\nexport const isObject = (value: unknown): value is { [key: string]: unknown } => {\n // eslint-disable-next-line adk/prefer-is-object -- this IS the implementation of isObject\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n","import { getEncoding } from 'js-tiktoken'\nimport { validator } from '@nhtio/validation'\nimport { isInstanceOf } from '../utils/guards'\nimport { LlamaTokenizer } from 'llama-tokenizer-js'\nimport { fromPreTrained as geminiFromPreTrained } from '@lenml/tokenizer-gemini'\nimport type { Tiktoken } from 'js-tiktoken'\n\n/**\n * The set of supported token encoding identifiers.\n *\n * @remarks\n * Each value maps to a specific estimation backend:\n * - `gpt2`, `r50k_base`, `p50k_base`, `p50k_edit`, `cl100k_base`, `o200k_base` — exact counts\n * via `js-tiktoken` (OpenAI / tiktoken-compatible models).\n * - `gemini` — exact counts via `@lenml/tokenizer-gemini`, which embeds Gemini's actual\n * SentencePiece vocabulary locally with no API call required.\n * - `llama2` — exact counts via `llama-tokenizer-js` (Llama 1 and 2). Llama 3+ uses a\n * different vocabulary and should use the `llama3` identifier once a suitable sync backend\n * is available.\n * - `claude` — heuristic approximation using Anthropic's published ~3.5 chars/token ratio.\n * No local tokenizer is available for Claude 3+ models; the Anthropic SDK's\n * `messages.countTokens()` API is the only exact path but requires a network call.\n *\n * When adding a new encoding, add a case to {@link Tokenizable.estimateTokens}.\n */\nexport const TokenEncoding = [\n 'gpt2',\n 'r50k_base',\n 'p50k_base',\n 'p50k_edit',\n 'cl100k_base',\n 'o200k_base',\n 'gemini',\n 'llama2',\n 'claude',\n] as const\n\n/**\n * Union of all recognised token encoding identifier strings.\n *\n * @remarks\n * Derived from {@link TokenEncoding} so the type and the runtime array stay in sync\n * automatically when new encodings are added.\n */\nexport type TokenEncoding = (typeof TokenEncoding)[number]\n\n/**\n * Backing schema for {@link Tokenizable.schema}.\n *\n * @remarks\n * Accepts a plain `string` or an existing {@link Tokenizable} instance. Strings pass through\n * unchanged; {@link Tokenizable} instances are accepted via {@link Tokenizable.isTokenizable}\n * to remain cross-realm safe.\n */\nconst stringOrTokenizableSchema = validator.alternatives(\n validator.string(),\n validator.custom((value, helpers) => {\n if (Tokenizable.isTokenizable(value)) {\n return value\n }\n return helpers.error('any.invalid')\n })\n)\n\n// Lazily-initialised singletons — tokenizers are expensive to load so we defer\n// until first use and reuse across all Tokenizable instances thereafter.\nlet geminiTokenizerInstance: ReturnType<typeof geminiFromPreTrained> | undefined\nlet llamaTokenizerInstance: InstanceType<typeof LlamaTokenizer> | undefined\n\nconst getGeminiTokenizer = () => {\n if (!geminiTokenizerInstance) {\n geminiTokenizerInstance = geminiFromPreTrained()\n }\n return geminiTokenizerInstance\n}\n\nconst getLlamaTokenizer = () => {\n if (!llamaTokenizerInstance) {\n llamaTokenizerInstance = new LlamaTokenizer()\n }\n return llamaTokenizerInstance\n}\n\n/**\n * A mutable string with a built-in token counter.\n *\n * @remarks\n * The wrapped string can be read via the standard coercion protocol and updated at any time via\n * {@link Tokenizable.set}. Token counts are computed lazily on first access per encoding and\n * cached until the value changes, avoiding redundant encoder invocations when the same content\n * is measured multiple times across a pipeline.\n *\n * Estimation is dispatched by encoding identifier — see {@link TokenEncoding} for the full list\n * of supported backends and their accuracy characteristics. Unrecognised encodings fall back to\n * a `ceil(length / 4)` character heuristic.\n *\n * The class implements the standard JS value-coercion protocol (`toString`, `valueOf`,\n * `toJSON`, `toLocaleString`, `Symbol.for('nodejs.util.inspect.custom')`) so instances behave\n * transparently as strings in most contexts.\n */\nexport class Tokenizable {\n /** The set of supported token-encoding identifiers, re-exposed as a static for convenience. */\n public static TokenEncoding = TokenEncoding\n\n /**\n * Validator schema that accepts a plain `string` or a {@link Tokenizable} instance.\n *\n * @remarks\n * Reusable fragment for any schema that wants to accept either form — for example,\n * `systemPrompt` and each item in `standingInstructions` in `turnContextSchema`.\n */\n public static schema = stringOrTokenizableSchema\n\n declare toJSON: () => string\n declare toString: () => string\n declare valueOf: () => string\n declare toLocaleString: () => string\n /** Replace the wrapped string value (and invalidate the cached token estimates). */\n declare set: (value: string) => void\n /** Estimate the token count of the wrapped string under the given {@link TokenEncoding}. */\n declare estimateTokens: (encoding: TokenEncoding) => number\n\n #value: string\n #cache: Map<TokenEncoding, number> = new Map()\n\n /**\n * @param value - The initial string value to wrap.\n */\n constructor(value: string) {\n this.#value = value\n\n const estimateTokensWithTiktoken = (encoding: TokenEncoding): number => {\n try {\n const enc: Tiktoken = getEncoding(encoding as any)\n return enc.encode(this.#value, []).length\n } catch {\n return Number.POSITIVE_INFINITY\n }\n }\n\n const estimateTokensWithGemini = (): number => {\n try {\n return getGeminiTokenizer().encode(this.#value).length\n } catch {\n return Number.POSITIVE_INFINITY\n }\n }\n\n const estimateTokensWithLlama2 = (): number => {\n try {\n return getLlamaTokenizer().encode(this.#value, false).length\n } catch {\n return Number.POSITIVE_INFINITY\n }\n }\n\n const estimateTokensWithClaudeHeuristic = (): number => {\n try {\n return Math.ceil(this.#value.length / 3.5)\n } catch {\n return Number.POSITIVE_INFINITY\n }\n }\n\n Object.defineProperties(this, {\n toJSON: {\n value: () => this.#value,\n enumerable: false,\n configurable: false,\n writable: false,\n },\n toString: {\n value: () => this.#value,\n enumerable: false,\n configurable: false,\n writable: false,\n },\n valueOf: {\n value: () => this.#value,\n enumerable: false,\n configurable: false,\n writable: false,\n },\n toLocaleString: {\n value: () => this.#value,\n enumerable: false,\n configurable: false,\n writable: false,\n },\n [Symbol.for('nodejs.util.inspect.custom')]: {\n value: () => this.#value,\n enumerable: false,\n configurable: false,\n writable: false,\n },\n set: {\n value: (next: string) => {\n this.#value = next\n this.#cache.clear()\n },\n enumerable: false,\n configurable: false,\n writable: false,\n },\n estimateTokens: {\n value: (encoding: TokenEncoding): number => {\n if (this.#cache.has(encoding)) {\n return this.#cache.get(encoding)!\n }\n\n let estimate: number\n switch (encoding) {\n case 'gpt2':\n case 'r50k_base':\n case 'p50k_base':\n case 'p50k_edit':\n case 'cl100k_base':\n case 'o200k_base':\n estimate = estimateTokensWithTiktoken(encoding)\n break\n case 'gemini':\n estimate = estimateTokensWithGemini()\n break\n case 'llama2':\n estimate = estimateTokensWithLlama2()\n break\n case 'claude':\n estimate = estimateTokensWithClaudeHeuristic()\n break\n }\n if (estimate === Number.POSITIVE_INFINITY) {\n estimate = Math.ceil(this.#value.length / 4)\n } else {\n this.#cache.set(encoding, estimate)\n }\n return estimate\n },\n enumerable: false,\n configurable: false,\n writable: false,\n },\n })\n }\n\n /**\n * Convenience overload for one-off token counting without managing a {@link Tokenizable} instance.\n *\n * @remarks\n * Creates a temporary instance and immediately discards it — no caching benefit. Use the\n * instance method when you need to count the same value under multiple encodings or when the\n * value may change over time.\n *\n * @param value - The string to count tokens for.\n * @param encoding - The encoding identifier to use for counting.\n * @returns The estimated number of tokens.\n */\n public static estimateTokens(value: string, encoding: TokenEncoding): number {\n const temp = new Tokenizable(value)\n return temp.estimateTokens(encoding)\n }\n\n /**\n * Returns `true` if `value` is a {@link Tokenizable} instance.\n *\n * @remarks\n * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety — `instanceof` would fail for instances\n * created in a different module copy or VM context.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link Tokenizable} instance.\n */\n public static isTokenizable(value: unknown): value is Tokenizable {\n return isInstanceOf(value, 'Tokenizable', Tokenizable)\n }\n}\n\n/**\n * Returns `true` if `value` is a {@link Tokenizable} instance.\n *\n * @remarks\n * Module-level convenience alias for {@link Tokenizable.isTokenizable}. Prefer this form when\n * you need a standalone type guard without importing the full class.\n *\n * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety — `instanceof` would fail for instances\n * created in a different module copy or VM context.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link Tokenizable} instance.\n */\nexport const isTokenizable = (value: unknown): value is Tokenizable => {\n return isInstanceOf(value, 'Tokenizable', Tokenizable)\n}\n","import { dset } from 'dset'\nimport { klona } from 'klona'\nimport { default as delve } from 'dlv'\nimport { isInstanceOf, isObject } from '../utils/guards'\nimport { E_INVALID_INITIAL_REGISTRY_VALUE } from '../exceptions/runtime'\n\n/**\n * A controlled-mutation key-value store with dot-path access and deep-clone isolation.\n *\n * @remarks\n * The registry enforces a safe read/write contract: callers never hold a live reference into\n * the internal store. Every value that enters (`set`) or leaves (`get`, `all`) is deep-cloned\n * via `klona`, so mutations to a retrieved value cannot affect stored state and vice versa.\n *\n * Keys are dot-delimited paths (e.g. `\"user.profile.name\"`), resolved via `dlv` for reads and\n * `dset` for writes; intermediate objects are created automatically on write.\n */\nexport class Registry {\n #store: Record<string, unknown>\n\n /**\n * @param initial - Optional plain object to seed the registry. Deep-cloned on construction.\n * @throws {@link @nhtio/adk!E_INVALID_INITIAL_REGISTRY_VALUE} when `initial` is defined but not a plain object.\n */\n constructor(initial?: Record<string, unknown>) {\n if ('undefined' !== typeof initial && !isObject(initial)) {\n throw new E_INVALID_INITIAL_REGISTRY_VALUE()\n }\n this.#store = initial ? klona(initial) : {}\n }\n\n /**\n * Returns `true` if `value` is a {@link Registry} instance.\n *\n * @remarks\n * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link Registry} instance.\n */\n public static isRegistry(value: unknown): value is Registry {\n return isInstanceOf(value, 'Registry', Registry)\n }\n\n /**\n * Retrieves the value at `key`, returning `defaultValue` if the path is absent.\n *\n * @remarks\n * The returned value is a deep clone — mutating it will not affect the stored state.\n *\n * @typeParam T - Expected type of the value at `key`.\n * @param key - Dot-delimited path into the store (e.g. `\"user.name\"`).\n * @param defaultValue - Fallback returned when the path resolves to `undefined`.\n * @returns A deep clone of the stored value cast to `T`, or `defaultValue` when the path is absent.\n */\n get<T = unknown>(key: string, defaultValue?: T): T {\n const cloned = klona(this.#store)\n const value = delve(cloned, key)\n return 'undefined' === typeof value ? (defaultValue as T) : (value as T)\n }\n\n /**\n * Sets the value at `key`, creating intermediate objects as needed.\n *\n * @remarks\n * The stored value is isolated from the caller — mutating `value` after this call will not\n * affect what is held in the registry.\n *\n * @param key - Dot-delimited path into the store (e.g. `\"user.name\"`).\n * @param value - Value to store at the path.\n */\n set(key: string, value: unknown): void {\n dset(this.#store, key, value)\n }\n\n /**\n * Returns `true` if the registry has a value at `key`, `false` otherwise.\n *\n * @remarks\n * A key resolving to `undefined` is treated as absent — same convention as {@link Registry.get}'s\n * `defaultValue` fallback. No clone is performed; this is a pure existence check.\n *\n * @param key - Dot-delimited path into the store (e.g. `\"user.name\"`).\n * @returns `true` when the path resolves to a value other than `undefined`.\n */\n has(key: string): boolean {\n return 'undefined' !== typeof delve(this.#store, key)\n }\n\n /**\n * Returns all leaf dot-paths present in the registry.\n *\n * @remarks\n * The store is deep-cloned before traversal. Plain objects are walked recursively with path\n * segments joined by dots; arrays, primitives, `null`, and class instances are treated as leaves.\n *\n * @returns A string array of dot-delimited paths to leaf values in the store.\n */\n keys(): string[] {\n const store = klona(this.#store)\n const keys: string[] = []\n\n const isPlainRecord = (value: unknown): value is Record<string, unknown> => {\n if (!isObject(value)) return false\n const prototype = Object.getPrototypeOf(value)\n return prototype === Object.prototype || prototype === null\n }\n\n const walk = (value: unknown, segments: string[]): void => {\n if (!isPlainRecord(value)) {\n if (segments.length > 0) keys.push(segments.join('.'))\n return\n }\n\n for (const [segment, child] of Object.entries(value)) {\n walk(child, [...segments, segment])\n }\n }\n\n walk(store, [])\n return keys\n }\n\n /**\n * Returns a deep clone of the entire store contents.\n *\n * @returns A plain object snapshot of all stored key-value pairs.\n */\n all(): Record<string, unknown> {\n return klona(this.#store)\n }\n}\n","/**\n * Canonical `JSON.stringify` that sorts object keys recursively so that semantically-equal\n * objects produce identical strings.\n *\n * @remarks\n * Used wherever the ADK derives a stable identity from a structured value — for example,\n * `Tool.executor` computing the `callId` for `ToolExecutionStart`/`End` events, and the\n * `reportToolCall` executor helper computing the `checksum` field on `TurnToolCallContent`.\n * Both code paths hash `canonicalStringify({ tool, args })` so that argument key order does not\n * affect the resulting identifier.\n *\n * Arrays are serialised in their declared order (order is meaningful for an array). Object keys\n * are sorted with `Array.prototype.sort()`'s default lexicographic comparator.\n *\n * @param value - The value to serialise.\n * @returns A canonical JSON string representation of `value`.\n */\nexport function canonicalStringify(value: unknown): string {\n if (value === null || typeof value !== 'object') return JSON.stringify(value)\n if (Array.isArray(value)) return '[' + value.map((v) => canonicalStringify(v)).join(',') + ']'\n const obj = value as Record<string, unknown>\n const keys = Object.keys(obj).sort()\n return '{' + keys.map((k) => JSON.stringify(k) + ':' + canonicalStringify(obj[k])).join(',') + '}'\n}\n","import { isInstanceOf } from '../utils/guards'\nimport { E_TOOL_ALREADY_REGISTERED } from '../exceptions/runtime'\nimport type { Tool } from './tool'\nimport type { DispatchContext } from '../contracts/dispatch_context'\n\n/**\n * Options accepted by {@link ToolRegistry.merge}.\n */\nexport interface MergeOptions {\n /**\n * What to do when two registries contain a tool with the same name AND neither tool's own\n * `onCollision` resolves the collision.\n *\n * @remarks\n * - `'throw'` (default): raise {@link @nhtio/adk!E_TOOL_ALREADY_REGISTERED} on the first unresolved\n * collision. Mirrors the default behaviour of {@link ToolRegistry.register} and surfaces\n * accidental name shadowing immediately.\n * - `'replace'`: the later registry's tool wins.\n * - `'keep'`: the earlier registry's tool wins; later occurrences are dropped.\n *\n * Per-tool {@link @nhtio/adk!Tool.onCollision} takes precedence: if the incoming tool declares\n * `'replace'` or `'keep'`, that policy wins regardless of this option. Only when the incoming\n * tool's policy is `'throw'` (the default) does this fallback apply.\n *\n * @defaultValue `'throw'`\n */\n onCollision?: 'throw' | 'replace' | 'keep'\n}\n\n/**\n * A mutable, turn-scoped collection of {@link @nhtio/adk!Tool} instances.\n *\n * @remarks\n * Each `TurnRunner.run()` call constructs a fresh `ToolRegistry` from the runner's configured\n * baseline tools, so middleware edits are isolated to the current turn and cannot bleed across\n * concurrent or subsequent turns.\n *\n * `Tool` instances are immutable, so `all()` returns a fresh array without deep-cloning.\n *\n * `register()` throws {@link @nhtio/adk!E_TOOL_ALREADY_REGISTERED} if a tool with the same name is already\n * present — pass `overwrite: true` to replace it explicitly.\n *\n * Tools can be **hidden** — registered and callable, but excluded from the default tool list\n * rendered to the model. This is useful for discovery patterns where an agent has a tool that\n * enumerates available tools, and the model picks one to call by name in a subsequent iteration.\n * Hidden state is a property of the registry, not the tool: the same tool can be visible in one\n * registry and hidden in another. See {@link hide}, {@link visible}, {@link hidden}.\n */\nexport class ToolRegistry {\n #tools: Map<string, Tool>\n #hidden: Set<string>\n\n /**\n * Returns `true` if `value` is a {@link ToolRegistry} instance.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link ToolRegistry} instance.\n */\n public static isToolRegistry(value: unknown): value is ToolRegistry {\n return isInstanceOf(value, 'ToolRegistry', ToolRegistry)\n }\n\n /**\n * @param tools - Optional initial tools. Insertion order is preserved. Duplicate names throw\n * {@link @nhtio/adk!E_TOOL_ALREADY_REGISTERED} — ensure each tool has a unique name.\n * @throws {@link @nhtio/adk!E_TOOL_ALREADY_REGISTERED} when two tools in `tools` share a name.\n */\n constructor(tools?: Tool[]) {\n this.#tools = new Map()\n this.#hidden = new Set()\n for (const tool of tools ?? []) {\n this.register(tool)\n }\n }\n\n /**\n * Adds a tool to the registry.\n *\n * @param tool - The tool to register.\n * @param overwrite - When `true`, silently replaces an existing tool with the same name.\n * Defaults to `false`.\n * @throws {@link @nhtio/adk!E_TOOL_ALREADY_REGISTERED} when a tool with the same name is already registered\n * and `overwrite` is not `true`.\n */\n register(tool: Tool, overwrite?: boolean): void {\n if (this.#tools.has(tool.name) && !overwrite) {\n throw new E_TOOL_ALREADY_REGISTERED()\n }\n this.#tools.set(tool.name, tool)\n }\n\n /**\n * Removes the tool with the given name from the registry.\n *\n * @remarks\n * Also removes the name from the hidden set if present. No-ops if no tool with that name is\n * registered.\n *\n * @param name - The name of the tool to remove.\n */\n unregister(name: string): void {\n this.#tools.delete(name)\n this.#hidden.delete(name)\n }\n\n /**\n * Returns the tool registered under `name`, or `undefined` if not present.\n *\n * @param name - The tool name to look up.\n */\n get(name: string): Tool | undefined {\n return this.#tools.get(name)\n }\n\n /**\n * Returns `true` if a tool with the given name is registered.\n *\n * @param name - The tool name to test.\n */\n has(name: string): boolean {\n return this.#tools.has(name)\n }\n\n /**\n * Returns a fresh array of all registered tools in insertion order.\n *\n * @remarks\n * Includes both visible and hidden tools. Use {@link visible} to get only non-hidden tools, or\n * {@link hidden} to get only hidden tools.\n *\n * Since {@link @nhtio/adk!Tool} instances are immutable, no deep-cloning is needed.\n */\n all(): Tool[] {\n return Array.from(this.#tools.values())\n }\n\n /**\n * Returns a fresh array of registered tools that are **not** hidden, in insertion order.\n *\n * @remarks\n * This is the accessor LLM batteries should use when building the tool list for the model.\n * Hidden tools are still callable (they resolve via {@link get}) but are excluded from the\n * rendered tool definitions.\n */\n visible(): Tool[] {\n return this.all().filter((t) => !this.#hidden.has(t.name))\n }\n\n /**\n * Returns a fresh array of registered tools that **are** hidden, in insertion order.\n *\n * @remarks\n * The converse of {@link visible}. Useful for discovery tools that enumerate all available\n * tools, and for propagating hidden state across {@link merge}.\n */\n hidden(): Tool[] {\n return this.all().filter((t) => this.#hidden.has(t.name))\n }\n\n /**\n * Marks one or more registered tools as hidden.\n *\n * @remarks\n * Hidden tools remain registered and callable via {@link get}, but are excluded from\n * {@link visible} (and therefore from the LLM tool list). No-ops for any name that is not\n * currently registered — the end result (the tool is not visible) matches the intent.\n *\n * @param names - One or more tool names to hide.\n */\n hide(...names: string[]): void {\n for (const name of names) {\n this.#hidden.add(name)\n }\n }\n\n /**\n * Unmarks one or more tools as hidden, making them visible again.\n *\n * @remarks\n * No-ops for any name that is not currently hidden.\n *\n * @param names - One or more tool names to unhide.\n */\n unhide(...names: string[]): void {\n for (const name of names) {\n this.#hidden.delete(name)\n }\n }\n\n /**\n * Replaces the entire hidden set with the given tool names.\n *\n * @remarks\n * Any previously hidden tool not in `names` becomes visible. Names that are not registered are\n * silently ignored — they are added to the set but have no effect until a tool with that name\n * is registered.\n *\n * @param names - The complete set of tool names to hide.\n */\n setHidden(...names: string[]): void {\n this.#hidden = new Set(names)\n }\n\n /**\n * Unhides every tool in the registry.\n */\n clearHidden(): void {\n this.#hidden.clear()\n }\n\n /**\n * Removes every tool whose {@link @nhtio/adk!Tool.ephemeral} flag is `true`.\n *\n * @remarks\n * Also removes pruned tool names from the hidden set. Synchronous and idempotent — calling it\n * twice in a row is a no-op the second time. The canonical caller is\n * {@link ToolRegistry.bindContext}, which schedules this method to run at\n * {@link @nhtio/adk!DispatchContext.ack}. Non-ephemeral tools are left untouched.\n */\n pruneEphemeral(): void {\n for (const [name, tool] of this.#tools) {\n if (tool.ephemeral) {\n this.#tools.delete(name)\n this.#hidden.delete(name)\n }\n }\n }\n\n /**\n * Binds this registry to a {@link @nhtio/adk!DispatchContext} so that {@link pruneEphemeral} runs\n * automatically when the context is acked.\n *\n * @remarks\n * The handler does NOT fire on {@link @nhtio/adk!DispatchContext.nack} — failed executor runs leave\n * any forged tools in place so the consumer can inspect what was registered when debugging the\n * failure. Subscriptions are short-lived and die with the context regardless.\n *\n * Forgetting this call after merging in `Subclass.forgeTools(ctx)` output means ephemeral tools\n * accumulate across executor invocations, and subsequent `forgeTools(ctx)` calls in later\n * iterations will see a stale `callId` enum that excludes new tool calls. The plan-documented\n * pattern is:\n *\n * ```ts\n * const executor: DispatchExecutorFn = async (ctx) => {\n * const forged = SpooledArtifact.forgeTools(ctx)\n * const merged = ToolRegistry.merge([main, forged])\n * main.bindContext(ctx)\n * const result = await llm.invoke({ tools: merged.all(), ... })\n * ctx.ack()\n * }\n * ```\n *\n * @param ctx - The execution context whose `ack` event should trigger pruning.\n * @returns An unsubscribe function — calling it before `ctx.ack()` prevents pruning. Rarely\n * useful outside of tests.\n *\n * @see {@link @nhtio/adk!SpooledArtifact.forgeTools}\n * @see {@link @nhtio/adk!DispatchContext.onAck}\n */\n bindContext(ctx: DispatchContext): () => void {\n return ctx.onAck(() => this.pruneEphemeral())\n }\n\n /**\n * Combines multiple {@link ToolRegistry} instances into a fresh registry without mutating any\n * input.\n *\n * @remarks\n * Iteration is left-to-right across `registries` and then in each registry's insertion order.\n * Collisions are resolved by consulting the **incoming** tool's {@link @nhtio/adk!Tool.onCollision} first:\n *\n * - `'replace'` (per-tool): the incoming tool wins, replacing the existing entry.\n * - `'keep'` (per-tool): the existing entry wins; the incoming tool is dropped.\n * - `'throw'` (per-tool, the default): fall back to the merge-level `options.onCollision`.\n *\n * The merge-level `options.onCollision` defaults to `'throw'`, which mirrors {@link register}.\n *\n * The result is a brand-new registry; no input is mutated and no event subscription is\n * propagated. Each `Tool`'s `ephemeral` flag carries through unchanged — the flag lives on the\n * tool, not the registry, so `bindContext(ctx)` on the merged registry will prune the forged\n * tools as expected.\n *\n * Hidden state is also propagated: a tool that is hidden in any source registry remains hidden\n * in the merged result, provided it survives collision resolution.\n *\n * @param registries - Registries to merge, in priority order (left-to-right insertion).\n * @param options - Merge-level collision policy. Defaults to `{ onCollision: 'throw' }`.\n * @returns A fresh {@link ToolRegistry} containing the resolved union of all inputs.\n * @throws {@link @nhtio/adk!E_TOOL_ALREADY_REGISTERED} when the resolved collision policy is `'throw'`\n * and a collision occurs.\n */\n static merge(registries: ToolRegistry[], options?: MergeOptions): ToolRegistry {\n const policy = options?.onCollision ?? 'throw'\n const merged = new ToolRegistry()\n for (const registry of registries) {\n for (const tool of registry.all()) {\n const existing = merged.get(tool.name)\n if (!existing) {\n merged.register(tool)\n continue\n }\n const incomingPolicy = tool.onCollision\n if (incomingPolicy === 'replace') {\n merged.register(tool, true)\n continue\n }\n if (incomingPolicy === 'keep') {\n continue\n }\n // Incoming policy is 'throw' — fall back to the merge-level option.\n if (policy === 'replace') {\n merged.register(tool, true)\n continue\n }\n if (policy === 'keep') {\n continue\n }\n throw new E_TOOL_ALREADY_REGISTERED()\n }\n // Propagate hidden state: any tool that was hidden in a source registry stays hidden\n // in the merged result, as long as it survived collision resolution.\n for (const tool of registry.hidden()) {\n if (merged.has(tool.name)) {\n merged.hide(tool.name)\n }\n }\n }\n return merged\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Ble4zEEl.js");
|
|
2
|
-
const require_exceptions = require("./exceptions-
|
|
3
|
-
const require_runtime = require("./runtime-
|
|
2
|
+
const require_exceptions = require("./exceptions-BRXrUKiW.js");
|
|
3
|
+
const require_runtime = require("./runtime-DslE1aBw.js");
|
|
4
4
|
let js_tiktoken = require("js-tiktoken");
|
|
5
5
|
let _nhtio_validation = require("@nhtio/validation");
|
|
6
6
|
let llama_tokenizer_js = require("llama-tokenizer-js");
|
|
@@ -127,6 +127,7 @@ var getLlamaTokenizer = () => {
|
|
|
127
127
|
* transparently as strings in most contexts.
|
|
128
128
|
*/
|
|
129
129
|
var Tokenizable = class Tokenizable {
|
|
130
|
+
/** The set of supported token-encoding identifiers, re-exposed as a static for convenience. */
|
|
130
131
|
static TokenEncoding = TokenEncoding;
|
|
131
132
|
/**
|
|
132
133
|
* Validator schema that accepts a plain `string` or a {@link Tokenizable} instance.
|
|
@@ -725,4 +726,4 @@ Object.defineProperty(exports, "isObject", {
|
|
|
725
726
|
}
|
|
726
727
|
});
|
|
727
728
|
|
|
728
|
-
//# sourceMappingURL=tool_registry-
|
|
729
|
+
//# sourceMappingURL=tool_registry-CKJPze3j.js.map
|