@nhtio/adk 1.20260604.0 → 1.20260607.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 +261 -0
- package/adk-mcp.mjs +1 -1
- package/batteries/embeddings/openai/adapter.cjs +1 -1
- package/batteries/embeddings/openai/adapter.mjs +1 -1
- package/batteries/embeddings/webllm/adapter.cjs +1 -1
- package/batteries/embeddings/webllm/adapter.mjs +1 -1
- package/batteries/index.d.ts +1 -0
- package/batteries/llm/openai_chat_completions/adapter.cjs +6 -6
- package/batteries/llm/openai_chat_completions/adapter.cjs.map +1 -1
- package/batteries/llm/openai_chat_completions/adapter.mjs +6 -6
- package/batteries/llm/openai_chat_completions/adapter.mjs.map +1 -1
- package/batteries/llm/openai_chat_completions/helpers.cjs +2 -2
- package/batteries/llm/openai_chat_completions/helpers.mjs +2 -2
- 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/webllm_chat_completions/adapter.cjs +6 -6
- package/batteries/llm/webllm_chat_completions/adapter.cjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/adapter.mjs +6 -6
- package/batteries/llm/webllm_chat_completions/adapter.mjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/validation.cjs +2 -2
- package/batteries/llm/webllm_chat_completions/validation.cjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/validation.mjs +2 -2
- package/batteries/llm/webllm_chat_completions/validation.mjs.map +1 -1
- package/batteries/storage/flydrive.cjs +1 -1
- package/batteries/storage/flydrive.mjs +2 -2
- package/batteries/storage/in_memory.cjs +1 -1
- package/batteries/storage/in_memory.mjs +1 -1
- package/batteries/storage/opfs.cjs +1 -1
- package/batteries/storage/opfs.mjs +1 -1
- package/batteries/tools/color.cjs +2 -2
- package/batteries/tools/color.mjs +2 -2
- package/batteries/tools/comparison.cjs +3 -3
- package/batteries/tools/comparison.mjs +3 -3
- package/batteries/tools/data_structure.cjs +3 -3
- package/batteries/tools/data_structure.mjs +3 -3
- package/batteries/tools/datetime_extended.cjs +2 -2
- package/batteries/tools/datetime_extended.mjs +2 -2
- package/batteries/tools/datetime_math.cjs +2 -2
- package/batteries/tools/datetime_math.mjs +2 -2
- package/batteries/tools/encoding.cjs +3 -3
- package/batteries/tools/encoding.mjs +3 -3
- package/batteries/tools/formatting.cjs +3 -3
- package/batteries/tools/formatting.mjs +3 -3
- package/batteries/tools/geo_basics.cjs +2 -2
- package/batteries/tools/geo_basics.mjs +2 -2
- package/batteries/tools/math/index.d.ts +16 -5
- package/batteries/tools/math.cjs +340 -22
- package/batteries/tools/math.cjs.map +1 -1
- package/batteries/tools/math.mjs +338 -21
- 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 +4 -4
- package/batteries/tools/parsing.mjs +4 -4
- package/batteries/tools/retrievables.cjs +4 -4
- package/batteries/tools/retrievables.mjs +4 -4
- package/batteries/tools/standing_instructions.cjs +4 -4
- package/batteries/tools/standing_instructions.mjs +4 -4
- package/batteries/tools/statistics.cjs +4 -4
- package/batteries/tools/statistics.mjs +4 -4
- package/batteries/tools/string_processing.cjs +3 -3
- package/batteries/tools/string_processing.mjs +3 -3
- package/batteries/tools/structured_data.cjs +3 -3
- package/batteries/tools/structured_data.mjs +3 -3
- package/batteries/tools/text_analysis.cjs +3 -3
- package/batteries/tools/text_analysis.mjs +3 -3
- package/batteries/tools/text_comparison.cjs +2 -2
- package/batteries/tools/text_comparison.mjs +2 -2
- package/batteries/tools/time.cjs +2 -2
- package/batteries/tools/time.mjs +2 -2
- package/batteries/tools/unit_conversion.cjs +2 -2
- package/batteries/tools/unit_conversion.mjs +2 -2
- package/batteries/vector/arangodb/index.d.ts +38 -0
- package/batteries/vector/arangodb.cjs +257 -0
- package/batteries/vector/arangodb.cjs.map +1 -0
- package/batteries/vector/arangodb.mjs +255 -0
- package/batteries/vector/arangodb.mjs.map +1 -0
- package/batteries/vector/builder.cjs +297 -0
- package/batteries/vector/builder.cjs.map +1 -0
- package/batteries/vector/builder.d.ts +87 -0
- package/batteries/vector/builder.mjs +294 -0
- package/batteries/vector/builder.mjs.map +1 -0
- package/batteries/vector/chroma/index.d.ts +32 -0
- package/batteries/vector/chroma.cjs +305 -0
- package/batteries/vector/chroma.cjs.map +1 -0
- package/batteries/vector/chroma.mjs +302 -0
- package/batteries/vector/chroma.mjs.map +1 -0
- package/batteries/vector/clickhouse/index.d.ts +39 -0
- package/batteries/vector/clickhouse.cjs +246 -0
- package/batteries/vector/clickhouse.cjs.map +1 -0
- package/batteries/vector/clickhouse.mjs +244 -0
- package/batteries/vector/clickhouse.mjs.map +1 -0
- package/batteries/vector/cloudflare/index.d.ts +43 -0
- package/batteries/vector/cloudflare.cjs +397 -0
- package/batteries/vector/cloudflare.cjs.map +1 -0
- package/batteries/vector/cloudflare.mjs +395 -0
- package/batteries/vector/cloudflare.mjs.map +1 -0
- package/batteries/vector/conformance/index.d.ts +15 -0
- package/batteries/vector/conformance.cjs +209 -0
- package/batteries/vector/conformance.cjs.map +1 -0
- package/batteries/vector/conformance.mjs +205 -0
- package/batteries/vector/conformance.mjs.map +1 -0
- package/batteries/vector/contract.cjs +42 -0
- package/batteries/vector/contract.cjs.map +1 -0
- package/batteries/vector/contract.d.ts +39 -0
- package/batteries/vector/contract.mjs +40 -0
- package/batteries/vector/contract.mjs.map +1 -0
- package/batteries/vector/couchbase/index.d.ts +49 -0
- package/batteries/vector/couchbase.cjs +401 -0
- package/batteries/vector/couchbase.cjs.map +1 -0
- package/batteries/vector/couchbase.mjs +399 -0
- package/batteries/vector/couchbase.mjs.map +1 -0
- package/batteries/vector/duckdb/index.d.ts +33 -0
- package/batteries/vector/duckdb.cjs +218 -0
- package/batteries/vector/duckdb.cjs.map +1 -0
- package/batteries/vector/duckdb.mjs +216 -0
- package/batteries/vector/duckdb.mjs.map +1 -0
- package/batteries/vector/elasticsearch/index.d.ts +43 -0
- package/batteries/vector/elasticsearch.cjs +306 -0
- package/batteries/vector/elasticsearch.cjs.map +1 -0
- package/batteries/vector/elasticsearch.mjs +303 -0
- package/batteries/vector/elasticsearch.mjs.map +1 -0
- package/batteries/vector/exceptions.cjs +126 -0
- package/batteries/vector/exceptions.cjs.map +1 -0
- package/batteries/vector/exceptions.d.ts +142 -0
- package/batteries/vector/exceptions.mjs +107 -0
- package/batteries/vector/exceptions.mjs.map +1 -0
- package/batteries/vector/factory.cjs +28 -0
- package/batteries/vector/factory.cjs.map +1 -0
- package/batteries/vector/factory.d.ts +38 -0
- package/batteries/vector/factory.mjs +25 -0
- package/batteries/vector/factory.mjs.map +1 -0
- package/batteries/vector/filters.cjs +107 -0
- package/batteries/vector/filters.cjs.map +1 -0
- package/batteries/vector/filters.d.ts +34 -0
- package/batteries/vector/filters.mjs +99 -0
- package/batteries/vector/filters.mjs.map +1 -0
- package/batteries/vector/helpers.cjs +23 -0
- package/batteries/vector/helpers.cjs.map +1 -0
- package/batteries/vector/helpers.d.ts +12 -0
- package/batteries/vector/helpers.mjs +17 -0
- package/batteries/vector/helpers.mjs.map +1 -0
- package/batteries/vector/hnswlib/index.d.ts +35 -0
- package/batteries/vector/hnswlib.cjs +237 -0
- package/batteries/vector/hnswlib.cjs.map +1 -0
- package/batteries/vector/hnswlib.mjs +235 -0
- package/batteries/vector/hnswlib.mjs.map +1 -0
- package/batteries/vector/in_memory/index.d.ts +23 -0
- package/batteries/vector/in_memory.cjs +178 -0
- package/batteries/vector/in_memory.cjs.map +1 -0
- package/batteries/vector/in_memory.mjs +176 -0
- package/batteries/vector/in_memory.mjs.map +1 -0
- package/batteries/vector/index.d.ts +18 -0
- package/batteries/vector/lancedb/index.d.ts +34 -0
- package/batteries/vector/lancedb.cjs +224 -0
- package/batteries/vector/lancedb.cjs.map +1 -0
- package/batteries/vector/lancedb.mjs +222 -0
- package/batteries/vector/lancedb.mjs.map +1 -0
- package/batteries/vector/mariadb/index.d.ts +39 -0
- package/batteries/vector/mariadb.cjs +228 -0
- package/batteries/vector/mariadb.cjs.map +1 -0
- package/batteries/vector/mariadb.mjs +226 -0
- package/batteries/vector/mariadb.mjs.map +1 -0
- package/batteries/vector/meilisearch/index.d.ts +36 -0
- package/batteries/vector/meilisearch.cjs +242 -0
- package/batteries/vector/meilisearch.cjs.map +1 -0
- package/batteries/vector/meilisearch.mjs +240 -0
- package/batteries/vector/meilisearch.mjs.map +1 -0
- package/batteries/vector/migrate.cjs +54 -0
- package/batteries/vector/migrate.cjs.map +1 -0
- package/batteries/vector/migrate.d.ts +30 -0
- package/batteries/vector/migrate.mjs +52 -0
- package/batteries/vector/migrate.mjs.map +1 -0
- package/batteries/vector/milvus/index.d.ts +35 -0
- package/batteries/vector/milvus.cjs +357 -0
- package/batteries/vector/milvus.cjs.map +1 -0
- package/batteries/vector/milvus.mjs +354 -0
- package/batteries/vector/milvus.mjs.map +1 -0
- package/batteries/vector/mongodb/index.d.ts +46 -0
- package/batteries/vector/mongodb.cjs +270 -0
- package/batteries/vector/mongodb.cjs.map +1 -0
- package/batteries/vector/mongodb.mjs +268 -0
- package/batteries/vector/mongodb.mjs.map +1 -0
- package/batteries/vector/neo4j/index.d.ts +38 -0
- package/batteries/vector/neo4j.cjs +231 -0
- package/batteries/vector/neo4j.cjs.map +1 -0
- package/batteries/vector/neo4j.mjs +229 -0
- package/batteries/vector/neo4j.mjs.map +1 -0
- package/batteries/vector/opensearch/index.d.ts +46 -0
- package/batteries/vector/opensearch.cjs +316 -0
- package/batteries/vector/opensearch.cjs.map +1 -0
- package/batteries/vector/opensearch.mjs +313 -0
- package/batteries/vector/opensearch.mjs.map +1 -0
- package/batteries/vector/oracle23ai/index.d.ts +45 -0
- package/batteries/vector/oracle23ai.cjs +340 -0
- package/batteries/vector/oracle23ai.cjs.map +1 -0
- package/batteries/vector/oracle23ai.mjs +338 -0
- package/batteries/vector/oracle23ai.mjs.map +1 -0
- package/batteries/vector/orama/index.d.ts +23 -0
- package/batteries/vector/orama.cjs +272 -0
- package/batteries/vector/orama.cjs.map +1 -0
- package/batteries/vector/orama.mjs +270 -0
- package/batteries/vector/orama.mjs.map +1 -0
- package/batteries/vector/pgvector/index.d.ts +43 -0
- package/batteries/vector/pgvector.cjs +411 -0
- package/batteries/vector/pgvector.cjs.map +1 -0
- package/batteries/vector/pgvector.mjs +408 -0
- package/batteries/vector/pgvector.mjs.map +1 -0
- package/batteries/vector/pinecone/index.d.ts +38 -0
- package/batteries/vector/pinecone.cjs +415 -0
- package/batteries/vector/pinecone.cjs.map +1 -0
- package/batteries/vector/pinecone.mjs +412 -0
- package/batteries/vector/pinecone.mjs.map +1 -0
- package/batteries/vector/plan.cjs +2 -0
- package/batteries/vector/plan.d.ts +65 -0
- package/batteries/vector/plan.mjs +0 -0
- package/batteries/vector/qdrant/index.d.ts +34 -0
- package/batteries/vector/qdrant.cjs +286 -0
- package/batteries/vector/qdrant.cjs.map +1 -0
- package/batteries/vector/qdrant.mjs +284 -0
- package/batteries/vector/qdrant.mjs.map +1 -0
- package/batteries/vector/redis/index.d.ts +44 -0
- package/batteries/vector/redis.cjs +391 -0
- package/batteries/vector/redis.cjs.map +1 -0
- package/batteries/vector/redis.mjs +388 -0
- package/batteries/vector/redis.mjs.map +1 -0
- package/batteries/vector/retrievable.cjs +69 -0
- package/batteries/vector/retrievable.cjs.map +1 -0
- package/batteries/vector/retrievable.mjs +67 -0
- package/batteries/vector/retrievable.mjs.map +1 -0
- package/batteries/vector/retrievable_glue.d.ts +24 -0
- package/batteries/vector/s3vectors/index.d.ts +52 -0
- package/batteries/vector/s3vectors.cjs +438 -0
- package/batteries/vector/s3vectors.cjs.map +1 -0
- package/batteries/vector/s3vectors.mjs +436 -0
- package/batteries/vector/s3vectors.mjs.map +1 -0
- package/batteries/vector/schema.cjs +96 -0
- package/batteries/vector/schema.cjs.map +1 -0
- package/batteries/vector/schema.d.ts +40 -0
- package/batteries/vector/schema.mjs +93 -0
- package/batteries/vector/schema.mjs.map +1 -0
- package/batteries/vector/solr/index.d.ts +36 -0
- package/batteries/vector/solr.cjs +230 -0
- package/batteries/vector/solr.cjs.map +1 -0
- package/batteries/vector/solr.mjs +228 -0
- package/batteries/vector/solr.mjs.map +1 -0
- package/batteries/vector/sqlite_vec/index.d.ts +30 -0
- package/batteries/vector/sqlite_vec.cjs +318 -0
- package/batteries/vector/sqlite_vec.cjs.map +1 -0
- package/batteries/vector/sqlite_vec.mjs +316 -0
- package/batteries/vector/sqlite_vec.mjs.map +1 -0
- package/batteries/vector/surrealdb/index.d.ts +37 -0
- package/batteries/vector/surrealdb.cjs +230 -0
- package/batteries/vector/surrealdb.cjs.map +1 -0
- package/batteries/vector/surrealdb.mjs +228 -0
- package/batteries/vector/surrealdb.mjs.map +1 -0
- package/batteries/vector/types.cjs +2 -0
- package/batteries/vector/types.d.ts +100 -0
- package/batteries/vector/types.mjs +0 -0
- package/batteries/vector/typesense/index.d.ts +38 -0
- package/batteries/vector/typesense.cjs +272 -0
- package/batteries/vector/typesense.cjs.map +1 -0
- package/batteries/vector/typesense.mjs +270 -0
- package/batteries/vector/typesense.mjs.map +1 -0
- package/batteries/vector/validation.cjs +90 -0
- package/batteries/vector/validation.cjs.map +1 -0
- package/batteries/vector/validation.d.ts +18 -0
- package/batteries/vector/validation.mjs +83 -0
- package/batteries/vector/validation.mjs.map +1 -0
- package/batteries/vector/vector_store_constructor.cjs +56 -0
- package/batteries/vector/vector_store_constructor.cjs.map +1 -0
- package/batteries/vector/vector_store_constructor.d.ts +30 -0
- package/batteries/vector/vector_store_constructor.mjs +53 -0
- package/batteries/vector/vector_store_constructor.mjs.map +1 -0
- package/batteries/vector/vespa/index.d.ts +39 -0
- package/batteries/vector/vespa.cjs +423 -0
- package/batteries/vector/vespa.cjs.map +1 -0
- package/batteries/vector/vespa.mjs +421 -0
- package/batteries/vector/vespa.mjs.map +1 -0
- package/batteries/vector/weaviate/index.d.ts +57 -0
- package/batteries/vector/weaviate.cjs +325 -0
- package/batteries/vector/weaviate.cjs.map +1 -0
- package/batteries/vector/weaviate.mjs +322 -0
- package/batteries/vector/weaviate.mjs.map +1 -0
- package/batteries/vector.cjs +63 -0
- package/batteries/vector.mjs +14 -0
- package/batteries.cjs +62 -0
- package/batteries.mjs +15 -1
- package/{chunk-kRvK8_k2.mjs → chunk-Bpcn9VDT.mjs} +5 -1
- package/{common-lMrnzoyn.mjs → common-BT0nfCi9.mjs} +8 -8
- package/{common-lMrnzoyn.mjs.map → common-BT0nfCi9.mjs.map} +1 -1
- package/{common-D_e5zYsG.js → common-Cj8TaQ9U.js} +8 -8
- package/{common-D_e5zYsG.js.map → common-Cj8TaQ9U.js.map} +1 -1
- package/common.cjs +7 -7
- package/common.mjs +7 -7
- package/{dispatch_runner-CpuyATj1.js → dispatch_runner-BHBNupqp.js} +2 -2
- package/dispatch_runner-BHBNupqp.js.map +1 -0
- package/{dispatch_runner-CDF3X0nv.mjs → dispatch_runner-DPcS7Y_M.mjs} +2 -2
- package/dispatch_runner-DPcS7Y_M.mjs.map +1 -0
- package/dispatch_runner.cjs +1 -1
- package/dispatch_runner.mjs +1 -1
- package/forge.cjs +4 -4
- package/forge.mjs +4 -4
- package/guards.cjs +8 -8
- package/guards.mjs +8 -8
- package/index.cjs +12 -12
- package/index.mjs +12 -12
- package/lib/classes/tool_registry.d.ts +70 -4
- package/mcp/adk-docs-corpus.json +1 -1
- package/package.json +424 -88
- package/skills/adk-assembly/SKILL.md +2 -2
- package/{spooled_artifact-B8gIIn9h.js → spooled_artifact-BTq6Nzfy.js} +4 -4
- package/spooled_artifact-BTq6Nzfy.js.map +1 -0
- package/{spooled_artifact-CWoKUDEm.mjs → spooled_artifact-CHoZgWwI.mjs} +4 -4
- package/spooled_artifact-CHoZgWwI.mjs.map +1 -0
- package/spooled_artifact.cjs +2 -2
- package/spooled_artifact.mjs +2 -2
- package/{spooled_markdown_artifact-DQX0RCdI.js → spooled_markdown_artifact-CALSDxIx.js} +3 -3
- package/{spooled_markdown_artifact-DQX0RCdI.js.map → spooled_markdown_artifact-CALSDxIx.js.map} +1 -1
- package/{spooled_markdown_artifact-CNle4jXN.mjs → spooled_markdown_artifact-Ci5UL7l4.mjs} +3 -3
- package/{spooled_markdown_artifact-CNle4jXN.mjs.map → spooled_markdown_artifact-Ci5UL7l4.mjs.map} +1 -1
- package/src/types/evaluatex.d.ts +31 -0
- package/{thought-BD6AkkOr.js → thought-BbwhJ1wb.js} +4 -4
- package/thought-BbwhJ1wb.js.map +1 -0
- package/{thought-B_P8LiB6.mjs → thought-D34QQZZ9.mjs} +4 -4
- package/thought-D34QQZZ9.mjs.map +1 -0
- package/{tool-CRZSUcdP.mjs → tool-CMhaDRNd.mjs} +3 -3
- package/tool-CMhaDRNd.mjs.map +1 -0
- package/{tool-CX9vNHAw.js → tool-CVyZkFC7.js} +3 -3
- package/tool-CVyZkFC7.js.map +1 -0
- package/{tool_call-BUeMuCc6.mjs → tool_call-CV5qVNlb.mjs} +3 -3
- package/{tool_call-BUeMuCc6.mjs.map → tool_call-CV5qVNlb.mjs.map} +1 -1
- package/{tool_call--7ti-frB.js → tool_call-Db68hB7y.js} +3 -3
- package/{tool_call--7ti-frB.js.map → tool_call-Db68hB7y.js.map} +1 -1
- package/{tool_registry-BGHg6KTq.mjs → tool_registry-D1pSSlsd.mjs} +109 -22
- package/tool_registry-D1pSSlsd.mjs.map +1 -0
- package/{tool_registry-CtCQ4Xoz.js → tool_registry-DYUYqXvo.js} +109 -22
- package/tool_registry-DYUYqXvo.js.map +1 -0
- package/{turn_runner-BJTtAORU.js → turn_runner-DqWHNP80.js} +5 -5
- package/turn_runner-DqWHNP80.js.map +1 -0
- package/{turn_runner-C02LZHjt.mjs → turn_runner-fg1Wc3dK.mjs} +5 -5
- package/turn_runner-fg1Wc3dK.mjs.map +1 -0
- package/turn_runner.cjs +1 -1
- package/turn_runner.mjs +1 -1
- package/dispatch_runner-CDF3X0nv.mjs.map +0 -1
- package/dispatch_runner-CpuyATj1.js.map +0 -1
- package/spooled_artifact-B8gIIn9h.js.map +0 -1
- package/spooled_artifact-CWoKUDEm.mjs.map +0 -1
- package/thought-BD6AkkOr.js.map +0 -1
- package/thought-B_P8LiB6.mjs.map +0 -1
- package/tool-CRZSUcdP.mjs.map +0 -1
- package/tool-CX9vNHAw.js.map +0 -1
- package/tool_registry-BGHg6KTq.mjs.map +0 -1
- package/tool_registry-CtCQ4Xoz.js.map +0 -1
- package/turn_runner-BJTtAORU.js.map +0 -1
- package/turn_runner-C02LZHjt.mjs.map +0 -1
|
@@ -5,7 +5,7 @@ license: MIT
|
|
|
5
5
|
compatibility: "Requires TypeScript/JavaScript project using @nhtio/adk; examples assume Node 20+ or compatible browser/runtime."
|
|
6
6
|
metadata:
|
|
7
7
|
package: "@nhtio/adk"
|
|
8
|
-
version: "1.
|
|
8
|
+
version: "1.20260607.0"
|
|
9
9
|
author: "Jak Giveon <jak@nht.io>"
|
|
10
10
|
copyright: "© 2025-present New Horizon Technology LTD"
|
|
11
11
|
---
|
|
@@ -17,7 +17,7 @@ Use this skill to help users build or review an `@nhtio/adk` assembly: the appli
|
|
|
17
17
|
## Package Metadata
|
|
18
18
|
|
|
19
19
|
- Package: `@nhtio/adk`
|
|
20
|
-
- Version: `1.
|
|
20
|
+
- Version: `1.20260607.0`
|
|
21
21
|
- License: MIT
|
|
22
22
|
- Author: Jak Giveon <jak@nht.io>
|
|
23
23
|
- Copyright: © 2025-present New Horizon Technology LTD
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
require("./chunk-Ble4zEEl.js");
|
|
2
2
|
const require_exceptions = require("./exceptions-CitH5wZI.js");
|
|
3
|
-
const require_tool_registry = require("./tool_registry-
|
|
3
|
+
const require_tool_registry = require("./tool_registry-DYUYqXvo.js");
|
|
4
4
|
const require_runtime = require("./runtime-MFFcJrRv.js");
|
|
5
|
-
const require_tool = require("./tool-
|
|
5
|
+
const require_tool = require("./tool-CVyZkFC7.js");
|
|
6
6
|
let _nhtio_validation = require("@nhtio/validation");
|
|
7
7
|
//#region src/lib/classes/artifact_tool.ts
|
|
8
8
|
/**
|
|
@@ -104,7 +104,7 @@ var ArtifactTool = class ArtifactTool extends require_tool.Tool {
|
|
|
104
104
|
* and `lineCount` present as callable properties. Arity is not enforced — implementations may add
|
|
105
105
|
* optional parameters beyond the contract.
|
|
106
106
|
*/
|
|
107
|
-
var spoolReaderSchema = _nhtio_validation.validator.any().custom((value, helpers) => {
|
|
107
|
+
var spoolReaderSchema = _nhtio_validation.validator.any().required().custom((value, helpers) => {
|
|
108
108
|
if (value !== null && value !== void 0 && typeof value.line === "function" && typeof value.byteLength === "function" && typeof value.lineCount === "function" && typeof value.readAll === "function") return value;
|
|
109
109
|
return helpers.error("any.invalid");
|
|
110
110
|
});
|
|
@@ -565,4 +565,4 @@ Object.defineProperty(exports, "implementsSpoolReader", {
|
|
|
565
565
|
}
|
|
566
566
|
});
|
|
567
567
|
|
|
568
|
-
//# sourceMappingURL=spooled_artifact-
|
|
568
|
+
//# sourceMappingURL=spooled_artifact-BTq6Nzfy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spooled_artifact-BTq6Nzfy.js","names":["#reader"],"sources":["../src/lib/classes/artifact_tool.ts","../src/lib/contracts/spool_reader.ts","../src/lib/classes/spooled_artifact.ts"],"sourcesContent":["import { Tool } from './tool'\nimport { validator } from '@nhtio/validation'\nimport { isInstanceOf } from '../utils/guards'\nimport { E_INVALID_INITIAL_TOOL_VALUE } from '../exceptions/runtime'\nimport { validateOrThrow, ValidationException } from '../utils/validation'\nimport type { Registry } from './registry'\nimport type { Schema } from '@nhtio/validation'\nimport type { Tokenizable } from './tokenizable'\nimport type { DispatchContext } from '../contracts/dispatch_context'\n\n/**\n * The execution function for an {@link ArtifactTool}.\n *\n * @remarks\n * Identical to the base tool handler except the return type is narrowed to\n * `string | Tokenizable | Promise<string | Tokenizable>`. Forged artifact-query tools emit\n * model-visible strings — the ADK wraps a bare-string return into a {@link @nhtio/adk!Tokenizable}\n * at the result-wrapping site so downstream code can rely on\n * `ToolCall.results instanceof Tokenizable` for every `ArtifactTool` invocation.\n */\nexport type ArtifactToolHandler = (\n args: unknown,\n ctx: DispatchContext,\n meta: Registry\n) => string | Tokenizable | Promise<string | Tokenizable>\n\n/**\n * Plain input object supplied to {@link ArtifactTool} at construction time.\n *\n * @remarks\n * Mirrors the base `RawTool` except `artifactConstructor` is forbidden — an `ArtifactTool`\n * emits a {@link @nhtio/adk!Tokenizable} directly into `ToolCall.results` and explicitly opts out of\n * `SpooledArtifact` wrapping. The forbidden field is enforced by {@link ArtifactTool.schema}\n * at construction time.\n */\nexport interface RawArtifactTool {\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. */\n inputSchema: Schema\n /** Execution function. Returns a string or {@link @nhtio/adk!Tokenizable}; the ADK wraps a bare string into a `Tokenizable` at the result-wrapping site. */\n handler: ArtifactToolHandler\n /** Optional arbitrary metadata for this tool. Defaults to `{}`. */\n meta?: Record<string, unknown>\n /**\n * When `true`, marks this tool as owned by a specific {@link @nhtio/adk!DispatchContext}.\n *\n * @remarks\n * `ArtifactTool` instances produced by `SpooledArtifact.forgeTools(ctx)` set this to `true`\n * so that `ToolRegistry.pruneEphemeral()` drops them at ctx-completion.\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 * Forged artifact-query tools default to `false` because their results are derived from\n * spooled artifact bodies — which may themselves be untrusted upstream tool output. The\n * trust signal does not promote handle-query results above the trust tier of the underlying\n * artifact.\n *\n * @defaultValue `false`\n */\n trusted?: boolean\n /**\n * Self-declared merge collision policy honoured by `ToolRegistry.merge`.\n *\n * @remarks\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 RawArtifactTool}.\n *\n * @remarks\n * Mirrors the base tool schema but explicitly forbids `artifactConstructor` — the entire\n * point of `ArtifactTool` is to opt out of `SpooledArtifact` wrapping.\n */\nconst rawArtifactToolSchema = validator.object<RawArtifactTool & { artifactConstructor?: never }>({\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 // 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 artifactConstructor: validator.any().forbidden(),\n})\n\n/**\n * A {@link @nhtio/adk!Tool} subclass whose handler return value is wrapped directly in a\n * {@link @nhtio/adk!Tokenizable} (not a {@link @nhtio/adk!SpooledArtifact}) when it\n * lands on `ToolCall.results`.\n *\n * @remarks\n * `ArtifactTool` is the canonical producer for **forged artifact-query tools** — the tools\n * `SpooledArtifact.forgeTools(ctx)` emits so the model can `head`, `tail`, `grep`, `json_get`,\n * `md_headings` (etc.) an artifact that is already in `ctx.turnToolCalls`.\n *\n * The difference from {@link @nhtio/adk!Tool} is structural, not stylistic:\n *\n * - A normal `Tool`'s handler returns bytes the ADK wraps in a fresh `SpooledArtifact`.\n * The artifact lands in `ToolCall.results`, joins `ctx.turnToolCalls`, and is itself a\n * first-class queryable artifact in the turn.\n * - An `ArtifactTool`'s handler returns a string that is **already the model-visible answer**\n * to a query against an existing artifact. The ADK wraps it in a `Tokenizable` rather\n * than a `SpooledArtifact`; nothing new is queryable on its own. Subsequent\n * `forgeTools(ctx)` calls exclude `ToolCall`s produced by an `ArtifactTool` from the\n * `callId` enum (via the `ToolCall.fromArtifactTool` marker) — this is the structural fix\n * that breaks the otherwise-recursive grep-on-the-grep-result loop.\n *\n * Consumers who want to build their own artifact-query tools (e.g. for a domain-specific\n * spooled subclass not shipped by the ADK) should extend or instantiate this class.\n */\nexport class ArtifactTool extends Tool {\n /**\n * Validator schema that accepts a {@link RawArtifactTool} object.\n *\n * @remarks\n * Differs from {@link @nhtio/adk!Tool.schema} by forbidding `artifactConstructor` — wrapping is\n * exactly the thing this class opts out of. Typed identically to {@link @nhtio/adk!Tool.schema} so the\n * subclass relationship `class ArtifactTool extends Tool` remains structurally sound; the\n * runtime validation rules still differ as declared by `rawArtifactToolSchema`.\n */\n public static schema = rawArtifactToolSchema as unknown as typeof Tool.schema\n\n /**\n * Returns `true` if `value` is an {@link ArtifactTool} 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 an {@link ArtifactTool} instance.\n */\n public static isArtifactTool(value: unknown): value is ArtifactTool {\n return isInstanceOf(value, 'ArtifactTool', ArtifactTool)\n }\n\n /**\n * @param raw - Raw tool input validated against {@link ArtifactTool.schema}.\n *\n * @throws {@link @nhtio/adk!E_INVALID_INITIAL_TOOL_VALUE} when `raw` does not satisfy\n * {@link ArtifactTool.schema} (most commonly, when `artifactConstructor` is supplied — it is\n * explicitly forbidden on this class) or when the base {@link @nhtio/adk!Tool} constructor rejects the\n * input for any reason.\n */\n constructor(raw: RawArtifactTool) {\n // Enforce the forbidden `artifactConstructor` field up-front so the error reports against\n // ArtifactTool's contract, not the base Tool's. The base Tool constructor re-validates\n // against its own schema and stores the resolved fields.\n try {\n validateOrThrow(rawArtifactToolSchema, raw, true)\n } catch (err) {\n if (isInstanceOf(err, 'ValidationException', ValidationException)) {\n throw new E_INVALID_INITIAL_TOOL_VALUE({ cause: err })\n }\n throw err\n }\n super(raw as never)\n }\n}\n","import { validator } from '@nhtio/validation'\nimport { passesSchema } from '../utils/validation'\n\n/**\n * Backing store contract for a {@link @nhtio/adk!SpooledArtifact}.\n *\n * @remarks\n * Implementations may read from memory, a file handle, a network stream, or any other byte\n * source. The interface is intentionally minimal — the artifact layer handles all higher-level\n * operations (`head`, `tail`, `grep`, etc.) by composing calls to these three primitives.\n *\n * Line indexing is 0-based. Implementations must return `undefined` from {@link SpoolReader.line}\n * when the index is out of range rather than throwing.\n *\n * All three methods may be synchronous or asynchronous to accommodate both in-memory and I/O-\n * backed implementations without forcing unnecessary promise overhead on simple cases.\n */\nexport interface SpoolReader {\n /**\n * Returns the line at the given 0-based index, or `undefined` when out of range.\n *\n * @param index - 0-based line index.\n * @returns The raw line string (without trailing newline), or `undefined`.\n */\n line(index: number): string | undefined | Promise<string | undefined>\n\n /**\n * Returns the total number of bytes in the underlying data.\n *\n * @remarks\n * Used for reporting and token-estimation purposes. Byte length is distinct from character\n * length for multi-byte encodings.\n *\n * @returns The byte length of the underlying data.\n */\n byteLength(): number | Promise<number>\n\n /**\n * Returns the total number of lines in the underlying data.\n *\n * @remarks\n * Required so consumers know when to stop iterating; the line count must remain stable for the\n * lifetime of the reader.\n *\n * @returns The total line count.\n */\n lineCount(): number | Promise<number>\n\n /**\n * Returns the full underlying content as a single decoded string, byte-faithful to the source.\n *\n * @remarks\n * Unlike {@link SpoolReader.line}, this method preserves trailing newlines and any non-`\\n`\n * line terminators (e.g. `\\r\\n`) present in the original bytes. It is the primitive that\n * powers `SpooledArtifact.asString()` — the round-trip-faithful alternative to assembling\n * the artifact body from per-line reads.\n *\n * Implementations should make this O(n) in the size of the underlying data and may cache the\n * result if the read source is durable. Streaming implementations may choose not to cache.\n *\n * @returns The full underlying content as a single string.\n */\n readAll(): string | Promise<string>\n}\n\n/**\n * Validator schema used to validate a {@link SpoolReader} value.\n *\n * @remarks\n * Because `SpoolReader` is a structural interface with no associated constructor, validation is\n * duck-typed: the value must be an object, class instance, or function with `line`, `byteLength`,\n * and `lineCount` present as callable properties. Arity is not enforced — implementations may add\n * optional parameters beyond the contract.\n */\nexport const spoolReaderSchema = validator\n .any()\n .required()\n .custom((value, helpers) => {\n if (\n value !== null &&\n value !== undefined &&\n typeof (value as any).line === 'function' &&\n typeof (value as any).byteLength === 'function' &&\n typeof (value as any).lineCount === 'function' &&\n typeof (value as any).readAll === 'function'\n ) {\n return value as SpoolReader\n }\n return helpers.error('any.invalid')\n })\n\n/**\n * Returns `true` if `value` implements the {@link SpoolReader} interface.\n *\n * @remarks\n * Duck-typed: checks that `value` is non-null with `line`, `byteLength`, `lineCount`, and\n * `readAll` as callable functions. Does not use `instanceof` — there is no `SpoolReader`\n * constructor.\n *\n * @param value - The value to test.\n * @returns `true` when `value` conforms to the {@link SpoolReader} interface.\n */\nexport const implementsSpoolReader = (value: unknown): value is SpoolReader => {\n return passesSchema(spoolReaderSchema, value)\n}\n","import { validator } from '@nhtio/validation'\nimport { isInstanceOf } from '../utils/guards'\nimport { ArtifactTool } from './artifact_tool'\nimport { ToolRegistry } from './tool_registry'\nimport { Tokenizable, TokenEncoding } from './tokenizable'\nimport { E_NOT_A_SPOOL_READER } from '../exceptions/runtime'\nimport { implementsSpoolReader } from '../contracts/spool_reader'\nimport type { ObjectSchema } from '@nhtio/validation'\nimport type { SpoolReader } from '../contracts/spool_reader'\nimport type { DispatchContext } from '../contracts/dispatch_context'\n\n/**\n * Constructor signature for {@link SpooledArtifact} and any subclass.\n *\n * @remarks\n * Used by {@link @nhtio/adk!Tool} to declare the artifact subclass the consumer should use when wrapping\n * the handler's serialised output. The variadic rest parameter accommodates subclass-specific\n * constructor arguments (e.g. `SpooledJsonArtifact(reader, format?)`).\n *\n * @typeParam A - The {@link SpooledArtifact} subtype the constructor produces.\n */\nexport type SpooledArtifactConstructor<A extends SpooledArtifact = SpooledArtifact> = new (\n reader: SpoolReader,\n ...rest: any[]\n) => A\n\n/**\n * Metadata table entry for one of the artifact's existing query methods, used by\n * {@link SpooledArtifact.forgeTools} to surface that method as an {@link @nhtio/adk!ArtifactTool}.\n *\n * @remarks\n * This is a metadata shape, not a general method → tool pipeline. `forgeTools` knows how to\n * marshal arguments for a fixed, closed set of method names (the base seven on\n * {@link SpooledArtifact} and the JSON/Markdown methods on the bundled subclasses); a\n * descriptor is the place to attach a tool name, description, args schema, and optional\n * serializer to one of those methods. Adding a descriptor for a method whose name is not\n * in that closed set will produce a tool whose handler invokes the method with no arguments.\n *\n * For new methods that require custom argument marshalling, branching, multi-step logic,\n * cross-artifact joins, or any other behaviour beyond \"call this existing method,\" override\n * {@link SpooledArtifact.forgeTools} and mint the {@link @nhtio/adk!ArtifactTool} directly — do not try\n * to express it through a descriptor.\n *\n * Zero-arg methods are the exception: a descriptor with no `argsSchema` (or one that adds\n * only `callId`-adjacent fields you don't consume) works for any method that takes no\n * arguments, regardless of name.\n */\nexport interface ToolMethodDescriptor {\n /** Absolute tool name as exposed to the LLM (e.g. `'artifact_head'`). */\n name: string\n /** Method to invoke on the resolved artifact instance (e.g. `'head'`, `'json_get'`). */\n method: string\n /** Human-readable description passed to the model. Should mention \"in this turn\" so the model understands the artifact's lifecycle scope. */\n description: string\n /** Schema for the method's own args, NOT including `callId`. `forgeTools()` injects `callId`. */\n argsSchema?: ObjectSchema\n /** Optional formatter for non-string return values. Defaults: string → as-is; string[] → newline-join; number → `String(n)`; otherwise `JSON.stringify(value, null, 2)`. */\n serialise?: (result: unknown) => string\n}\n\nconst noArgsSchema = validator.object<Record<string, never>>({})\n\n/**\n * Default serialiser for {@link @nhtio/adk!ArtifactTool} handler return values when a descriptor does not\n * provide its own. Exported for reuse by subclass `forgeTools` overrides.\n *\n * @param result - The artifact-method return value.\n * @returns A string suitable for inclusion in an LLM tool-call response.\n */\nexport const defaultSerialise = (result: unknown): string => {\n if (result === undefined) return '(undefined)'\n if (result === null) return 'null'\n if (typeof result === 'string') return result\n if (Array.isArray(result) && result.every((r) => typeof r === 'string')) {\n if (result.length === 0) return '(empty list)'\n return (result as string[]).join('\\n')\n }\n if (typeof result === 'number') return String(result)\n return JSON.stringify(result, null, 2)\n}\n\nconst baseToolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n {\n name: 'artifact_head',\n method: 'head',\n description:\n 'Return the first n lines of a spooled artifact produced earlier in this turn. Takes a callId selecting which artifact to inspect.',\n argsSchema: validator.object({\n n: validator.number().integer().min(1).default(10).description('Number of lines to return.'),\n }),\n },\n {\n name: 'artifact_tail',\n method: 'tail',\n description:\n 'Return the last n lines of a spooled artifact produced earlier in this turn. Takes a callId selecting which artifact to inspect.',\n argsSchema: validator.object({\n n: validator.number().integer().min(1).default(10).description('Number of lines to return.'),\n }),\n },\n {\n name: 'artifact_grep',\n method: 'grep',\n description:\n 'Return all lines matching a regular expression pattern from a spooled artifact produced earlier in this turn.',\n argsSchema: validator.object({\n pattern: validator\n .string()\n .required()\n .description('Regular expression pattern, applied via JavaScript RegExp.'),\n flags: validator\n .string()\n .pattern(/^[imsu]*$/)\n .optional()\n .description(\n \"Optional RegExp flags. Allowed: 'i' (case-insensitive), 'm' (multiline), 's' (dotAll), 'u' (unicode). 'g' and 'y' are disallowed because per-line matching is stateless.\"\n ),\n }),\n },\n {\n name: 'artifact_cat',\n method: 'cat',\n description:\n 'Return lines from a spooled artifact produced earlier in this turn, optionally bounded to a range.',\n argsSchema: validator.object({\n start: validator.number().integer().min(0).optional().description('Start line (inclusive).'),\n end: validator.number().integer().min(0).optional().description('End line (exclusive).'),\n }),\n },\n {\n name: 'artifact_byte_length',\n method: 'byteLength',\n description:\n 'Return the total byte length of a spooled artifact produced earlier in this turn.',\n argsSchema: noArgsSchema,\n },\n {\n name: 'artifact_line_count',\n method: 'lineCount',\n description: 'Return the total line count of a spooled artifact produced earlier in this turn.',\n argsSchema: noArgsSchema,\n },\n {\n name: 'artifact_estimate_tokens',\n method: 'estimateTokens',\n description:\n 'Estimate the total token count of a spooled artifact produced earlier in this turn under a named encoding.',\n argsSchema: validator.object({\n encoding: validator\n .string()\n .valid(...TokenEncoding)\n .required()\n .description('Token encoding identifier.'),\n }),\n },\n])\n\n/**\n * A lazy, line-oriented view over an arbitrary backing store.\n *\n * @remarks\n * All I/O methods are async to remain compatible with both in-memory and streaming\n * {@link @nhtio/adk!SpoolReader} implementations. Token estimation delegates to\n * {@link @nhtio/adk!Tokenizable.estimateTokens} — the same backends used elsewhere in the ADK.\n *\n * The class is read-only by design: mutation of the underlying data is the responsibility of the\n * producer that created the {@link @nhtio/adk!SpoolReader}, not the consumer reading from this artifact.\n */\nexport class SpooledArtifact {\n /**\n * The set of artifact-query methods this class surfaces via {@link SpooledArtifact.forgeTools}.\n *\n * @remarks\n * The base set covers the generic line-oriented operations every artifact supports:\n * `artifact_head`, `artifact_tail`, `artifact_grep`, `artifact_cat`, `artifact_byte_length`,\n * `artifact_line_count`, `artifact_estimate_tokens`. Each `toolMethods` array lists **only**\n * its own class's descriptors — subclasses do not concatenate inherited descriptors. The\n * subclass instead overrides {@link SpooledArtifact.forgeTools} to merge the base registry\n * (produced by `SpooledArtifact.forgeTools(ctx)`) with its own — see\n * {@link @nhtio/adk!SpooledJsonArtifact.forgeTools} and {@link @nhtio/adk!SpooledMarkdownArtifact.forgeTools} for\n * the canonical shape and the pattern downstream consumers should follow when building\n * their own `SpooledArtifact` subclasses.\n *\n * Tool names are absolute (not subclass-prefixed). Forged tools carry\n * `Tool.onCollision = 'replace'` so merging multiple subclasses' `forgeTools()` outputs is\n * silent — every same-named tool dispatches the same method on whatever artifact the\n * `callId` resolves to, so the overlap is behaviourally interchangeable.\n *\n * Frozen at module load.\n */\n public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = baseToolMethods\n\n #reader: SpoolReader\n\n /**\n * @param reader - The backing store to read from.\n * @throws {@link @nhtio/adk!E_NOT_A_SPOOL_READER} when `reader` does not implement {@link @nhtio/adk!SpoolReader}.\n */\n constructor(reader: SpoolReader) {\n if (!implementsSpoolReader(reader)) {\n throw new E_NOT_A_SPOOL_READER()\n }\n this.#reader = reader\n }\n\n /**\n * Returns the line at the given 0-based index, or `undefined` when out of range.\n *\n * @remarks\n * Protected so subclasses can scan the backing store line-by-line without allocating\n * intermediate arrays. Delegates directly to the {@link @nhtio/adk!SpoolReader}.\n *\n * @param index - 0-based line index.\n * @returns The raw line string, or `undefined` when out of range.\n */\n protected async line(index: number): Promise<string | undefined> {\n return this.#reader.line(index)\n }\n\n /**\n * Returns `true` if `value` is a {@link SpooledArtifact} instance (including any subclass).\n *\n * @remarks\n * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard: `instanceof` first, then\n * `Symbol.hasInstance`, then a `constructor.name` fallback. Subclass instances (e.g.\n * {@link @nhtio/adk!SpooledJsonArtifact}) satisfy this guard because `instanceof` walks the prototype\n * chain. The fallbacks handle the dual-module-copy case where two distinct `SpooledArtifact`\n * classes coexist in the same realm (e.g. one bundled into a downstream library, one in the\n * consumer's `node_modules`).\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link SpooledArtifact} instance.\n */\n public static isSpooledArtifact(value: unknown): value is SpooledArtifact {\n return isInstanceOf(value, 'SpooledArtifact', SpooledArtifact)\n }\n\n /**\n * Returns `true` if `value` is a constructor function whose prototype chain includes\n * {@link SpooledArtifact} (including `SpooledArtifact` itself).\n *\n * @remarks\n * Used by {@link @nhtio/adk!Tool} to validate the optional `artifactConstructor` field. Performs an\n * `instanceof`-based check on the prototype chain; falls back to a duck-type test that looks\n * for the canonical SpooledArtifact instance methods on `value.prototype` for cross-realm\n * safety (constructors passed from a different module copy or VM context).\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a constructor for `SpooledArtifact` or a subclass.\n */\n public static isSpooledArtifactConstructor(\n value: unknown\n ): value is SpooledArtifactConstructor<SpooledArtifact> {\n if (typeof value !== 'function') return false\n if (value === SpooledArtifact) return true\n const proto = (value as { prototype?: unknown }).prototype\n if (proto === undefined || proto === null) return false\n if (isInstanceOf(proto, 'SpooledArtifact', SpooledArtifact)) return true\n // Cross-realm duck-type fallback: prototype carries the canonical SpooledArtifact methods\n const methods = ['head', 'tail', 'grep', 'cat', 'byteLength', 'lineCount', 'estimateTokens']\n return methods.every((m) => typeof (proto as Record<string, unknown>)[m] === 'function')\n }\n\n /**\n * Returns the first `n` lines of the artifact.\n *\n * @remarks\n * If the artifact contains fewer than `n` lines, all available lines are returned. Matches the\n * behaviour of POSIX `head -n`.\n *\n * @param n - Number of lines to return. Defaults to 10.\n * @returns Array of line strings, without trailing newlines.\n */\n async head(n: number = 10): Promise<string[]> {\n const count = await this.#reader.lineCount()\n const limit = Math.min(n, count)\n const lines: string[] = []\n for (let i = 0; i < limit; i++) {\n const line = await this.#reader.line(i)\n if (line !== undefined) {\n lines.push(line)\n }\n }\n return lines\n }\n\n /**\n * Returns the last `n` lines of the artifact.\n *\n * @remarks\n * If the artifact contains fewer than `n` lines, all available lines are returned. Matches the\n * behaviour of POSIX `tail -n`.\n *\n * @param n - Number of lines to return. Defaults to 10.\n * @returns Array of line strings, without trailing newlines.\n */\n async tail(n: number = 10): Promise<string[]> {\n const count = await this.#reader.lineCount()\n const start = Math.max(0, count - n)\n const lines: string[] = []\n for (let i = start; i < count; i++) {\n const line = await this.#reader.line(i)\n if (line !== undefined) {\n lines.push(line)\n }\n }\n return lines\n }\n\n /**\n * Returns all lines that match `pattern`.\n *\n * @remarks\n * Behaves like POSIX `grep`: each line is tested against the pattern and included in the result\n * when it matches. The pattern is applied as a JavaScript `RegExp`; flags (e.g. case-\n * insensitivity) should be encoded in the expression itself.\n *\n * Stateful flags (`g`, `y`) on the supplied `RegExp` would normally cause `pattern.test()` to\n * advance `lastIndex` across calls, producing skipped matches and order-dependent results. To\n * keep the per-line semantics stateless, `grep` resets `pattern.lastIndex` to `0` before each\n * line test. The forged `artifact_grep` tool also rejects `g` and `y` flags up-front at schema\n * validation time.\n *\n * @param pattern - The regular expression to test each line against.\n * @returns Array of matching line strings, in order.\n */\n async grep(pattern: RegExp): Promise<string[]> {\n const count = await this.#reader.lineCount()\n const matches: string[] = []\n for (let i = 0; i < count; i++) {\n const line = await this.#reader.line(i)\n if (line !== undefined) {\n pattern.lastIndex = 0\n if (pattern.test(line)) {\n matches.push(line)\n }\n }\n }\n return matches\n }\n\n /**\n * Returns lines from the artifact, optionally bounded to a range.\n *\n * @remarks\n * Without arguments, returns all lines — equivalent to POSIX `cat`. With `start` and/or `end`,\n * behaves like `Array.prototype.slice`: `start` defaults to `0`, `end` defaults to the total\n * line count, and only lines in `[start, end)` are fetched from the backing store. For large\n * artifacts, prefer a bounded range or {@link SpooledArtifact.head} / {@link SpooledArtifact.tail}.\n *\n * @param start - 0-based start line index (inclusive). Defaults to `0`.\n * @param end - 0-based end line index (exclusive). Defaults to `lineCount()`.\n * @returns Array of line strings in the requested range.\n */\n async cat(start?: number, end?: number): Promise<string[]> {\n const count = await this.#reader.lineCount()\n const from = Math.max(0, start ?? 0)\n const to = Math.min(count, end ?? count)\n const lines: string[] = []\n for (let i = from; i < to; i++) {\n const line = await this.#reader.line(i)\n if (line !== undefined) {\n lines.push(line)\n }\n }\n return lines\n }\n\n /**\n * Returns the total byte length of the underlying data.\n *\n * @returns The byte length as reported by the {@link @nhtio/adk!SpoolReader}.\n */\n async byteLength(): Promise<number> {\n return this.#reader.byteLength()\n }\n\n /**\n * Returns the total number of lines in the artifact.\n *\n * @returns The line count as reported by the {@link @nhtio/adk!SpoolReader}.\n */\n async lineCount(): Promise<number> {\n return this.#reader.lineCount()\n }\n\n /**\n * Estimates the total token count of the artifact under `encoding`.\n *\n * @remarks\n * Reads the full byte-faithful content via {@link SpooledArtifact.asString} (which delegates to\n * {@link @nhtio/adk!SpoolReader.readAll}) and delegates to {@link @nhtio/adk!Tokenizable.estimateTokens}. The estimate\n * therefore reflects the actual source bytes — including trailing newlines and non-`\\n` line\n * terminators that the line-based {@link SpooledArtifact.cat} view would otherwise discard or\n * misrepresent.\n *\n * @param encoding - The encoding identifier to use for counting.\n * @returns The estimated number of tokens.\n */\n async estimateTokens(encoding: TokenEncoding): Promise<number> {\n const content = await this.#reader.readAll()\n return Tokenizable.estimateTokens(content, encoding)\n }\n\n /**\n * Returns the full artifact body as a single byte-faithful string.\n *\n * @remarks\n * Round-trip faithful to whatever bytes the {@link @nhtio/adk!SpoolReader} was constructed over —\n * preserves trailing newlines and non-`\\n` line terminators that {@link SpooledArtifact.cat}\n * discards via its line-based view. This is the canonical primitive for \"inline the artifact\n * content directly into a message\" use cases.\n *\n * `asString()` and the static `forgeTools(ctx)` factory on each subclass are independent\n * alternatives — a consumer chooses per turn whether to inline the body in a message\n * (`await tc.results.asString()`) or hand the model query tools\n * (`SpooledArtifact.forgeTools(ctx)`). Neither calls the other; either works with neither.\n *\n * @returns The full content as a single string.\n */\n async asString(): Promise<string> {\n return this.#reader.readAll()\n }\n\n /**\n * Forges a fresh {@link @nhtio/adk!ToolRegistry} of ephemeral {@link @nhtio/adk!ArtifactTool} instances that let the\n * LLM query artifacts already present in `ctx.turnToolCalls`.\n *\n * @remarks\n * Standard subclass extension pattern — each class owns only its own `toolMethods` and its\n * own `forgeTools`. The base `SpooledArtifact.forgeTools(ctx)` narrows the `callId` enum to\n * any `tc.results instanceof SpooledArtifact` (so subclass instances are included — that's\n * the whole point of inheritance) and dispatches the seven base methods (`head`, `tail`,\n * `grep`, `cat`, `byteLength`, `lineCount`, `estimateTokens`) on the resolved artifact.\n * Subclasses override `forgeTools` to call this static first and then register their own\n * tools on the returned registry — see {@link @nhtio/adk!SpooledJsonArtifact.forgeTools} and\n * {@link @nhtio/adk!SpooledMarkdownArtifact.forgeTools} for the canonical shape. There is no\n * `requiresSubclass` field, no helper indirection, and no `this`-based class narrowing —\n * just plain `instanceof ThisClass` at each subclass's own filter site.\n *\n * For each descriptor in this class's `toolMethods`, the factory:\n *\n * 1. Walks `ctx.turnToolCalls` to find `ToolCall`s whose `results instanceof SpooledArtifact`.\n * `ToolCall`s flagged `fromArtifactTool === true` are excluded — they carry a\n * {@link @nhtio/adk!Tokenizable}, not a `SpooledArtifact`, and including them would let the model\n * `artifact_grep` on a previous `artifact_grep` result (an infinite-recursion hazard with\n * no semantic value).\n * 2. Returns an empty registry if no compatible callIds are found — no point shipping tools\n * whose `callId` enum is empty.\n * 3. Otherwise mints an {@link @nhtio/adk!ArtifactTool} with `ephemeral: true` and `onCollision: 'replace'`\n * so multiple `Subclass.forgeTools(ctx)` outputs merge silently. The tool's `inputSchema`\n * includes a required `callId` field with `.valid(...compatibleIds)`, plus the descriptor's\n * own `argsSchema` fields.\n *\n * The handler resolves the artifact via `[...ctx.turnToolCalls].find(t => t.id === callId)`,\n * dispatches the descriptor's method, and serialises the return value (string → as-is;\n * string[] → newline-join; number → `String(n)`; otherwise `JSON.stringify(value, null, 2)`;\n * `descriptor.serialise` overrides the defaults). `grep` is special-cased: the handler\n * constructs `new RegExp(pattern, flags ?? '')` before invoking the artifact's `grep` method.\n *\n * The returned registry must be merged into the consumer's main registry and the main\n * registry must be bound to `ctx` via {@link @nhtio/adk!ToolRegistry.bindContext}:\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() // ← ephemeral cleanup fires here\n * }\n * ```\n *\n * @warning You **must** call `registry.bindContext(ctx)` on the registry hosting these tools,\n * or ephemeral cleanup will not run and the `callId` enum in subsequent executor calls will\n * be stale (excluding new tool calls produced in the meantime).\n *\n * @param ctx - The execution context whose `turnToolCalls` snapshot defines the `callId` enum.\n * @returns A fresh `ToolRegistry`. Empty when `turnToolCalls` contains no compatible artifacts.\n *\n * @see {@link @nhtio/adk!ToolRegistry.bindContext}\n * @see {@link @nhtio/adk!ToolRegistry.merge}\n * @see {@link @nhtio/adk!DispatchContext.onAck}\n */\n public static forgeTools(ctx: DispatchContext): ToolRegistry {\n const requires: SpooledArtifactConstructor = SpooledArtifact\n const calls = [...ctx.turnToolCalls]\n const compatibleIds = calls\n .filter((tc) => !tc.fromArtifactTool && isInstanceOf(tc.results, requires.name, requires))\n .map((tc) => tc.id)\n if (compatibleIds.length === 0) return new ToolRegistry([])\n\n const tools: ArtifactTool[] = []\n for (const descriptor of this.toolMethods) {\n const callIdSchema = validator\n .string()\n .valid(...compatibleIds)\n .required()\n .description('ToolCall id of the artifact to query.')\n\n const argsSchema = (descriptor.argsSchema ?? noArgsSchema).append({\n callId: callIdSchema,\n })\n\n const serialise = descriptor.serialise ?? defaultSerialise\n\n const tool = new ArtifactTool({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: argsSchema,\n ephemeral: true,\n onCollision: 'replace',\n handler: async (rawArgs, ctxInner) => {\n const args = rawArgs as Record<string, unknown> & { callId: string }\n const tc = [...ctxInner.turnToolCalls].find((t) => t.id === args.callId)\n if (!tc) {\n return `Error: no tool call with id ${args.callId} in this turn`\n }\n const artifact = tc.results\n if (!isInstanceOf(artifact, requires.name, requires)) {\n return `Error: tool call ${args.callId} results are not a ${requires.name} instance`\n }\n const methodArgs: unknown[] = []\n if (descriptor.method === 'grep') {\n const pattern = args.pattern as string\n const flags = (args.flags as string | undefined) ?? ''\n methodArgs.push(new RegExp(pattern, flags))\n } else if (descriptor.method === 'head' || descriptor.method === 'tail') {\n methodArgs.push((args.n as number | undefined) ?? 10)\n } else if (descriptor.method === 'cat') {\n methodArgs.push(args.start as number | undefined, args.end as number | undefined)\n } else if (descriptor.method === 'estimateTokens') {\n methodArgs.push(args.encoding as TokenEncoding)\n }\n const fn = (artifact as unknown as Record<string, (...a: unknown[]) => unknown>)[\n descriptor.method\n ]\n if (typeof fn !== 'function') {\n return `Error: artifact has no method ${descriptor.method}`\n }\n const result = await Promise.resolve(fn.apply(artifact, methodArgs))\n return serialise(result)\n },\n })\n tools.push(tool)\n }\n return new ToolRegistry(tools)\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as validateOrThrow, i as passesSchema, n as ValidationException } from "./exceptions-BeWH2FwP.mjs";
|
|
2
|
-
import { a as Tokenizable, i as TokenEncoding, s as isInstanceOf, t as ToolRegistry } from "./tool_registry-
|
|
2
|
+
import { a as Tokenizable, i as TokenEncoding, s as isInstanceOf, t as ToolRegistry } from "./tool_registry-D1pSSlsd.mjs";
|
|
3
3
|
import { C as E_NOT_A_SPOOL_READER, d as E_INVALID_INITIAL_TOOL_VALUE } from "./runtime-j92CNi5z.mjs";
|
|
4
|
-
import { t as Tool } from "./tool-
|
|
4
|
+
import { t as Tool } from "./tool-CMhaDRNd.mjs";
|
|
5
5
|
import { validator } from "@nhtio/validation";
|
|
6
6
|
//#region src/lib/classes/artifact_tool.ts
|
|
7
7
|
/**
|
|
@@ -103,7 +103,7 @@ var ArtifactTool = class ArtifactTool extends Tool {
|
|
|
103
103
|
* and `lineCount` present as callable properties. Arity is not enforced — implementations may add
|
|
104
104
|
* optional parameters beyond the contract.
|
|
105
105
|
*/
|
|
106
|
-
var spoolReaderSchema = validator.any().custom((value, helpers) => {
|
|
106
|
+
var spoolReaderSchema = validator.any().required().custom((value, helpers) => {
|
|
107
107
|
if (value !== null && value !== void 0 && typeof value.line === "function" && typeof value.byteLength === "function" && typeof value.lineCount === "function" && typeof value.readAll === "function") return value;
|
|
108
108
|
return helpers.error("any.invalid");
|
|
109
109
|
});
|
|
@@ -541,4 +541,4 @@ var SpooledArtifact = class SpooledArtifact {
|
|
|
541
541
|
//#endregion
|
|
542
542
|
export { ArtifactTool as i, defaultSerialise as n, implementsSpoolReader as r, SpooledArtifact as t };
|
|
543
543
|
|
|
544
|
-
//# sourceMappingURL=spooled_artifact-
|
|
544
|
+
//# sourceMappingURL=spooled_artifact-CHoZgWwI.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spooled_artifact-CHoZgWwI.mjs","names":["#reader"],"sources":["../src/lib/classes/artifact_tool.ts","../src/lib/contracts/spool_reader.ts","../src/lib/classes/spooled_artifact.ts"],"sourcesContent":["import { Tool } from './tool'\nimport { validator } from '@nhtio/validation'\nimport { isInstanceOf } from '../utils/guards'\nimport { E_INVALID_INITIAL_TOOL_VALUE } from '../exceptions/runtime'\nimport { validateOrThrow, ValidationException } from '../utils/validation'\nimport type { Registry } from './registry'\nimport type { Schema } from '@nhtio/validation'\nimport type { Tokenizable } from './tokenizable'\nimport type { DispatchContext } from '../contracts/dispatch_context'\n\n/**\n * The execution function for an {@link ArtifactTool}.\n *\n * @remarks\n * Identical to the base tool handler except the return type is narrowed to\n * `string | Tokenizable | Promise<string | Tokenizable>`. Forged artifact-query tools emit\n * model-visible strings — the ADK wraps a bare-string return into a {@link @nhtio/adk!Tokenizable}\n * at the result-wrapping site so downstream code can rely on\n * `ToolCall.results instanceof Tokenizable` for every `ArtifactTool` invocation.\n */\nexport type ArtifactToolHandler = (\n args: unknown,\n ctx: DispatchContext,\n meta: Registry\n) => string | Tokenizable | Promise<string | Tokenizable>\n\n/**\n * Plain input object supplied to {@link ArtifactTool} at construction time.\n *\n * @remarks\n * Mirrors the base `RawTool` except `artifactConstructor` is forbidden — an `ArtifactTool`\n * emits a {@link @nhtio/adk!Tokenizable} directly into `ToolCall.results` and explicitly opts out of\n * `SpooledArtifact` wrapping. The forbidden field is enforced by {@link ArtifactTool.schema}\n * at construction time.\n */\nexport interface RawArtifactTool {\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. */\n inputSchema: Schema\n /** Execution function. Returns a string or {@link @nhtio/adk!Tokenizable}; the ADK wraps a bare string into a `Tokenizable` at the result-wrapping site. */\n handler: ArtifactToolHandler\n /** Optional arbitrary metadata for this tool. Defaults to `{}`. */\n meta?: Record<string, unknown>\n /**\n * When `true`, marks this tool as owned by a specific {@link @nhtio/adk!DispatchContext}.\n *\n * @remarks\n * `ArtifactTool` instances produced by `SpooledArtifact.forgeTools(ctx)` set this to `true`\n * so that `ToolRegistry.pruneEphemeral()` drops them at ctx-completion.\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 * Forged artifact-query tools default to `false` because their results are derived from\n * spooled artifact bodies — which may themselves be untrusted upstream tool output. The\n * trust signal does not promote handle-query results above the trust tier of the underlying\n * artifact.\n *\n * @defaultValue `false`\n */\n trusted?: boolean\n /**\n * Self-declared merge collision policy honoured by `ToolRegistry.merge`.\n *\n * @remarks\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 RawArtifactTool}.\n *\n * @remarks\n * Mirrors the base tool schema but explicitly forbids `artifactConstructor` — the entire\n * point of `ArtifactTool` is to opt out of `SpooledArtifact` wrapping.\n */\nconst rawArtifactToolSchema = validator.object<RawArtifactTool & { artifactConstructor?: never }>({\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 // 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 artifactConstructor: validator.any().forbidden(),\n})\n\n/**\n * A {@link @nhtio/adk!Tool} subclass whose handler return value is wrapped directly in a\n * {@link @nhtio/adk!Tokenizable} (not a {@link @nhtio/adk!SpooledArtifact}) when it\n * lands on `ToolCall.results`.\n *\n * @remarks\n * `ArtifactTool` is the canonical producer for **forged artifact-query tools** — the tools\n * `SpooledArtifact.forgeTools(ctx)` emits so the model can `head`, `tail`, `grep`, `json_get`,\n * `md_headings` (etc.) an artifact that is already in `ctx.turnToolCalls`.\n *\n * The difference from {@link @nhtio/adk!Tool} is structural, not stylistic:\n *\n * - A normal `Tool`'s handler returns bytes the ADK wraps in a fresh `SpooledArtifact`.\n * The artifact lands in `ToolCall.results`, joins `ctx.turnToolCalls`, and is itself a\n * first-class queryable artifact in the turn.\n * - An `ArtifactTool`'s handler returns a string that is **already the model-visible answer**\n * to a query against an existing artifact. The ADK wraps it in a `Tokenizable` rather\n * than a `SpooledArtifact`; nothing new is queryable on its own. Subsequent\n * `forgeTools(ctx)` calls exclude `ToolCall`s produced by an `ArtifactTool` from the\n * `callId` enum (via the `ToolCall.fromArtifactTool` marker) — this is the structural fix\n * that breaks the otherwise-recursive grep-on-the-grep-result loop.\n *\n * Consumers who want to build their own artifact-query tools (e.g. for a domain-specific\n * spooled subclass not shipped by the ADK) should extend or instantiate this class.\n */\nexport class ArtifactTool extends Tool {\n /**\n * Validator schema that accepts a {@link RawArtifactTool} object.\n *\n * @remarks\n * Differs from {@link @nhtio/adk!Tool.schema} by forbidding `artifactConstructor` — wrapping is\n * exactly the thing this class opts out of. Typed identically to {@link @nhtio/adk!Tool.schema} so the\n * subclass relationship `class ArtifactTool extends Tool` remains structurally sound; the\n * runtime validation rules still differ as declared by `rawArtifactToolSchema`.\n */\n public static schema = rawArtifactToolSchema as unknown as typeof Tool.schema\n\n /**\n * Returns `true` if `value` is an {@link ArtifactTool} 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 an {@link ArtifactTool} instance.\n */\n public static isArtifactTool(value: unknown): value is ArtifactTool {\n return isInstanceOf(value, 'ArtifactTool', ArtifactTool)\n }\n\n /**\n * @param raw - Raw tool input validated against {@link ArtifactTool.schema}.\n *\n * @throws {@link @nhtio/adk!E_INVALID_INITIAL_TOOL_VALUE} when `raw` does not satisfy\n * {@link ArtifactTool.schema} (most commonly, when `artifactConstructor` is supplied — it is\n * explicitly forbidden on this class) or when the base {@link @nhtio/adk!Tool} constructor rejects the\n * input for any reason.\n */\n constructor(raw: RawArtifactTool) {\n // Enforce the forbidden `artifactConstructor` field up-front so the error reports against\n // ArtifactTool's contract, not the base Tool's. The base Tool constructor re-validates\n // against its own schema and stores the resolved fields.\n try {\n validateOrThrow(rawArtifactToolSchema, raw, true)\n } catch (err) {\n if (isInstanceOf(err, 'ValidationException', ValidationException)) {\n throw new E_INVALID_INITIAL_TOOL_VALUE({ cause: err })\n }\n throw err\n }\n super(raw as never)\n }\n}\n","import { validator } from '@nhtio/validation'\nimport { passesSchema } from '../utils/validation'\n\n/**\n * Backing store contract for a {@link @nhtio/adk!SpooledArtifact}.\n *\n * @remarks\n * Implementations may read from memory, a file handle, a network stream, or any other byte\n * source. The interface is intentionally minimal — the artifact layer handles all higher-level\n * operations (`head`, `tail`, `grep`, etc.) by composing calls to these three primitives.\n *\n * Line indexing is 0-based. Implementations must return `undefined` from {@link SpoolReader.line}\n * when the index is out of range rather than throwing.\n *\n * All three methods may be synchronous or asynchronous to accommodate both in-memory and I/O-\n * backed implementations without forcing unnecessary promise overhead on simple cases.\n */\nexport interface SpoolReader {\n /**\n * Returns the line at the given 0-based index, or `undefined` when out of range.\n *\n * @param index - 0-based line index.\n * @returns The raw line string (without trailing newline), or `undefined`.\n */\n line(index: number): string | undefined | Promise<string | undefined>\n\n /**\n * Returns the total number of bytes in the underlying data.\n *\n * @remarks\n * Used for reporting and token-estimation purposes. Byte length is distinct from character\n * length for multi-byte encodings.\n *\n * @returns The byte length of the underlying data.\n */\n byteLength(): number | Promise<number>\n\n /**\n * Returns the total number of lines in the underlying data.\n *\n * @remarks\n * Required so consumers know when to stop iterating; the line count must remain stable for the\n * lifetime of the reader.\n *\n * @returns The total line count.\n */\n lineCount(): number | Promise<number>\n\n /**\n * Returns the full underlying content as a single decoded string, byte-faithful to the source.\n *\n * @remarks\n * Unlike {@link SpoolReader.line}, this method preserves trailing newlines and any non-`\\n`\n * line terminators (e.g. `\\r\\n`) present in the original bytes. It is the primitive that\n * powers `SpooledArtifact.asString()` — the round-trip-faithful alternative to assembling\n * the artifact body from per-line reads.\n *\n * Implementations should make this O(n) in the size of the underlying data and may cache the\n * result if the read source is durable. Streaming implementations may choose not to cache.\n *\n * @returns The full underlying content as a single string.\n */\n readAll(): string | Promise<string>\n}\n\n/**\n * Validator schema used to validate a {@link SpoolReader} value.\n *\n * @remarks\n * Because `SpoolReader` is a structural interface with no associated constructor, validation is\n * duck-typed: the value must be an object, class instance, or function with `line`, `byteLength`,\n * and `lineCount` present as callable properties. Arity is not enforced — implementations may add\n * optional parameters beyond the contract.\n */\nexport const spoolReaderSchema = validator\n .any()\n .required()\n .custom((value, helpers) => {\n if (\n value !== null &&\n value !== undefined &&\n typeof (value as any).line === 'function' &&\n typeof (value as any).byteLength === 'function' &&\n typeof (value as any).lineCount === 'function' &&\n typeof (value as any).readAll === 'function'\n ) {\n return value as SpoolReader\n }\n return helpers.error('any.invalid')\n })\n\n/**\n * Returns `true` if `value` implements the {@link SpoolReader} interface.\n *\n * @remarks\n * Duck-typed: checks that `value` is non-null with `line`, `byteLength`, `lineCount`, and\n * `readAll` as callable functions. Does not use `instanceof` — there is no `SpoolReader`\n * constructor.\n *\n * @param value - The value to test.\n * @returns `true` when `value` conforms to the {@link SpoolReader} interface.\n */\nexport const implementsSpoolReader = (value: unknown): value is SpoolReader => {\n return passesSchema(spoolReaderSchema, value)\n}\n","import { validator } from '@nhtio/validation'\nimport { isInstanceOf } from '../utils/guards'\nimport { ArtifactTool } from './artifact_tool'\nimport { ToolRegistry } from './tool_registry'\nimport { Tokenizable, TokenEncoding } from './tokenizable'\nimport { E_NOT_A_SPOOL_READER } from '../exceptions/runtime'\nimport { implementsSpoolReader } from '../contracts/spool_reader'\nimport type { ObjectSchema } from '@nhtio/validation'\nimport type { SpoolReader } from '../contracts/spool_reader'\nimport type { DispatchContext } from '../contracts/dispatch_context'\n\n/**\n * Constructor signature for {@link SpooledArtifact} and any subclass.\n *\n * @remarks\n * Used by {@link @nhtio/adk!Tool} to declare the artifact subclass the consumer should use when wrapping\n * the handler's serialised output. The variadic rest parameter accommodates subclass-specific\n * constructor arguments (e.g. `SpooledJsonArtifact(reader, format?)`).\n *\n * @typeParam A - The {@link SpooledArtifact} subtype the constructor produces.\n */\nexport type SpooledArtifactConstructor<A extends SpooledArtifact = SpooledArtifact> = new (\n reader: SpoolReader,\n ...rest: any[]\n) => A\n\n/**\n * Metadata table entry for one of the artifact's existing query methods, used by\n * {@link SpooledArtifact.forgeTools} to surface that method as an {@link @nhtio/adk!ArtifactTool}.\n *\n * @remarks\n * This is a metadata shape, not a general method → tool pipeline. `forgeTools` knows how to\n * marshal arguments for a fixed, closed set of method names (the base seven on\n * {@link SpooledArtifact} and the JSON/Markdown methods on the bundled subclasses); a\n * descriptor is the place to attach a tool name, description, args schema, and optional\n * serializer to one of those methods. Adding a descriptor for a method whose name is not\n * in that closed set will produce a tool whose handler invokes the method with no arguments.\n *\n * For new methods that require custom argument marshalling, branching, multi-step logic,\n * cross-artifact joins, or any other behaviour beyond \"call this existing method,\" override\n * {@link SpooledArtifact.forgeTools} and mint the {@link @nhtio/adk!ArtifactTool} directly — do not try\n * to express it through a descriptor.\n *\n * Zero-arg methods are the exception: a descriptor with no `argsSchema` (or one that adds\n * only `callId`-adjacent fields you don't consume) works for any method that takes no\n * arguments, regardless of name.\n */\nexport interface ToolMethodDescriptor {\n /** Absolute tool name as exposed to the LLM (e.g. `'artifact_head'`). */\n name: string\n /** Method to invoke on the resolved artifact instance (e.g. `'head'`, `'json_get'`). */\n method: string\n /** Human-readable description passed to the model. Should mention \"in this turn\" so the model understands the artifact's lifecycle scope. */\n description: string\n /** Schema for the method's own args, NOT including `callId`. `forgeTools()` injects `callId`. */\n argsSchema?: ObjectSchema\n /** Optional formatter for non-string return values. Defaults: string → as-is; string[] → newline-join; number → `String(n)`; otherwise `JSON.stringify(value, null, 2)`. */\n serialise?: (result: unknown) => string\n}\n\nconst noArgsSchema = validator.object<Record<string, never>>({})\n\n/**\n * Default serialiser for {@link @nhtio/adk!ArtifactTool} handler return values when a descriptor does not\n * provide its own. Exported for reuse by subclass `forgeTools` overrides.\n *\n * @param result - The artifact-method return value.\n * @returns A string suitable for inclusion in an LLM tool-call response.\n */\nexport const defaultSerialise = (result: unknown): string => {\n if (result === undefined) return '(undefined)'\n if (result === null) return 'null'\n if (typeof result === 'string') return result\n if (Array.isArray(result) && result.every((r) => typeof r === 'string')) {\n if (result.length === 0) return '(empty list)'\n return (result as string[]).join('\\n')\n }\n if (typeof result === 'number') return String(result)\n return JSON.stringify(result, null, 2)\n}\n\nconst baseToolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n {\n name: 'artifact_head',\n method: 'head',\n description:\n 'Return the first n lines of a spooled artifact produced earlier in this turn. Takes a callId selecting which artifact to inspect.',\n argsSchema: validator.object({\n n: validator.number().integer().min(1).default(10).description('Number of lines to return.'),\n }),\n },\n {\n name: 'artifact_tail',\n method: 'tail',\n description:\n 'Return the last n lines of a spooled artifact produced earlier in this turn. Takes a callId selecting which artifact to inspect.',\n argsSchema: validator.object({\n n: validator.number().integer().min(1).default(10).description('Number of lines to return.'),\n }),\n },\n {\n name: 'artifact_grep',\n method: 'grep',\n description:\n 'Return all lines matching a regular expression pattern from a spooled artifact produced earlier in this turn.',\n argsSchema: validator.object({\n pattern: validator\n .string()\n .required()\n .description('Regular expression pattern, applied via JavaScript RegExp.'),\n flags: validator\n .string()\n .pattern(/^[imsu]*$/)\n .optional()\n .description(\n \"Optional RegExp flags. Allowed: 'i' (case-insensitive), 'm' (multiline), 's' (dotAll), 'u' (unicode). 'g' and 'y' are disallowed because per-line matching is stateless.\"\n ),\n }),\n },\n {\n name: 'artifact_cat',\n method: 'cat',\n description:\n 'Return lines from a spooled artifact produced earlier in this turn, optionally bounded to a range.',\n argsSchema: validator.object({\n start: validator.number().integer().min(0).optional().description('Start line (inclusive).'),\n end: validator.number().integer().min(0).optional().description('End line (exclusive).'),\n }),\n },\n {\n name: 'artifact_byte_length',\n method: 'byteLength',\n description:\n 'Return the total byte length of a spooled artifact produced earlier in this turn.',\n argsSchema: noArgsSchema,\n },\n {\n name: 'artifact_line_count',\n method: 'lineCount',\n description: 'Return the total line count of a spooled artifact produced earlier in this turn.',\n argsSchema: noArgsSchema,\n },\n {\n name: 'artifact_estimate_tokens',\n method: 'estimateTokens',\n description:\n 'Estimate the total token count of a spooled artifact produced earlier in this turn under a named encoding.',\n argsSchema: validator.object({\n encoding: validator\n .string()\n .valid(...TokenEncoding)\n .required()\n .description('Token encoding identifier.'),\n }),\n },\n])\n\n/**\n * A lazy, line-oriented view over an arbitrary backing store.\n *\n * @remarks\n * All I/O methods are async to remain compatible with both in-memory and streaming\n * {@link @nhtio/adk!SpoolReader} implementations. Token estimation delegates to\n * {@link @nhtio/adk!Tokenizable.estimateTokens} — the same backends used elsewhere in the ADK.\n *\n * The class is read-only by design: mutation of the underlying data is the responsibility of the\n * producer that created the {@link @nhtio/adk!SpoolReader}, not the consumer reading from this artifact.\n */\nexport class SpooledArtifact {\n /**\n * The set of artifact-query methods this class surfaces via {@link SpooledArtifact.forgeTools}.\n *\n * @remarks\n * The base set covers the generic line-oriented operations every artifact supports:\n * `artifact_head`, `artifact_tail`, `artifact_grep`, `artifact_cat`, `artifact_byte_length`,\n * `artifact_line_count`, `artifact_estimate_tokens`. Each `toolMethods` array lists **only**\n * its own class's descriptors — subclasses do not concatenate inherited descriptors. The\n * subclass instead overrides {@link SpooledArtifact.forgeTools} to merge the base registry\n * (produced by `SpooledArtifact.forgeTools(ctx)`) with its own — see\n * {@link @nhtio/adk!SpooledJsonArtifact.forgeTools} and {@link @nhtio/adk!SpooledMarkdownArtifact.forgeTools} for\n * the canonical shape and the pattern downstream consumers should follow when building\n * their own `SpooledArtifact` subclasses.\n *\n * Tool names are absolute (not subclass-prefixed). Forged tools carry\n * `Tool.onCollision = 'replace'` so merging multiple subclasses' `forgeTools()` outputs is\n * silent — every same-named tool dispatches the same method on whatever artifact the\n * `callId` resolves to, so the overlap is behaviourally interchangeable.\n *\n * Frozen at module load.\n */\n public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = baseToolMethods\n\n #reader: SpoolReader\n\n /**\n * @param reader - The backing store to read from.\n * @throws {@link @nhtio/adk!E_NOT_A_SPOOL_READER} when `reader` does not implement {@link @nhtio/adk!SpoolReader}.\n */\n constructor(reader: SpoolReader) {\n if (!implementsSpoolReader(reader)) {\n throw new E_NOT_A_SPOOL_READER()\n }\n this.#reader = reader\n }\n\n /**\n * Returns the line at the given 0-based index, or `undefined` when out of range.\n *\n * @remarks\n * Protected so subclasses can scan the backing store line-by-line without allocating\n * intermediate arrays. Delegates directly to the {@link @nhtio/adk!SpoolReader}.\n *\n * @param index - 0-based line index.\n * @returns The raw line string, or `undefined` when out of range.\n */\n protected async line(index: number): Promise<string | undefined> {\n return this.#reader.line(index)\n }\n\n /**\n * Returns `true` if `value` is a {@link SpooledArtifact} instance (including any subclass).\n *\n * @remarks\n * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard: `instanceof` first, then\n * `Symbol.hasInstance`, then a `constructor.name` fallback. Subclass instances (e.g.\n * {@link @nhtio/adk!SpooledJsonArtifact}) satisfy this guard because `instanceof` walks the prototype\n * chain. The fallbacks handle the dual-module-copy case where two distinct `SpooledArtifact`\n * classes coexist in the same realm (e.g. one bundled into a downstream library, one in the\n * consumer's `node_modules`).\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link SpooledArtifact} instance.\n */\n public static isSpooledArtifact(value: unknown): value is SpooledArtifact {\n return isInstanceOf(value, 'SpooledArtifact', SpooledArtifact)\n }\n\n /**\n * Returns `true` if `value` is a constructor function whose prototype chain includes\n * {@link SpooledArtifact} (including `SpooledArtifact` itself).\n *\n * @remarks\n * Used by {@link @nhtio/adk!Tool} to validate the optional `artifactConstructor` field. Performs an\n * `instanceof`-based check on the prototype chain; falls back to a duck-type test that looks\n * for the canonical SpooledArtifact instance methods on `value.prototype` for cross-realm\n * safety (constructors passed from a different module copy or VM context).\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a constructor for `SpooledArtifact` or a subclass.\n */\n public static isSpooledArtifactConstructor(\n value: unknown\n ): value is SpooledArtifactConstructor<SpooledArtifact> {\n if (typeof value !== 'function') return false\n if (value === SpooledArtifact) return true\n const proto = (value as { prototype?: unknown }).prototype\n if (proto === undefined || proto === null) return false\n if (isInstanceOf(proto, 'SpooledArtifact', SpooledArtifact)) return true\n // Cross-realm duck-type fallback: prototype carries the canonical SpooledArtifact methods\n const methods = ['head', 'tail', 'grep', 'cat', 'byteLength', 'lineCount', 'estimateTokens']\n return methods.every((m) => typeof (proto as Record<string, unknown>)[m] === 'function')\n }\n\n /**\n * Returns the first `n` lines of the artifact.\n *\n * @remarks\n * If the artifact contains fewer than `n` lines, all available lines are returned. Matches the\n * behaviour of POSIX `head -n`.\n *\n * @param n - Number of lines to return. Defaults to 10.\n * @returns Array of line strings, without trailing newlines.\n */\n async head(n: number = 10): Promise<string[]> {\n const count = await this.#reader.lineCount()\n const limit = Math.min(n, count)\n const lines: string[] = []\n for (let i = 0; i < limit; i++) {\n const line = await this.#reader.line(i)\n if (line !== undefined) {\n lines.push(line)\n }\n }\n return lines\n }\n\n /**\n * Returns the last `n` lines of the artifact.\n *\n * @remarks\n * If the artifact contains fewer than `n` lines, all available lines are returned. Matches the\n * behaviour of POSIX `tail -n`.\n *\n * @param n - Number of lines to return. Defaults to 10.\n * @returns Array of line strings, without trailing newlines.\n */\n async tail(n: number = 10): Promise<string[]> {\n const count = await this.#reader.lineCount()\n const start = Math.max(0, count - n)\n const lines: string[] = []\n for (let i = start; i < count; i++) {\n const line = await this.#reader.line(i)\n if (line !== undefined) {\n lines.push(line)\n }\n }\n return lines\n }\n\n /**\n * Returns all lines that match `pattern`.\n *\n * @remarks\n * Behaves like POSIX `grep`: each line is tested against the pattern and included in the result\n * when it matches. The pattern is applied as a JavaScript `RegExp`; flags (e.g. case-\n * insensitivity) should be encoded in the expression itself.\n *\n * Stateful flags (`g`, `y`) on the supplied `RegExp` would normally cause `pattern.test()` to\n * advance `lastIndex` across calls, producing skipped matches and order-dependent results. To\n * keep the per-line semantics stateless, `grep` resets `pattern.lastIndex` to `0` before each\n * line test. The forged `artifact_grep` tool also rejects `g` and `y` flags up-front at schema\n * validation time.\n *\n * @param pattern - The regular expression to test each line against.\n * @returns Array of matching line strings, in order.\n */\n async grep(pattern: RegExp): Promise<string[]> {\n const count = await this.#reader.lineCount()\n const matches: string[] = []\n for (let i = 0; i < count; i++) {\n const line = await this.#reader.line(i)\n if (line !== undefined) {\n pattern.lastIndex = 0\n if (pattern.test(line)) {\n matches.push(line)\n }\n }\n }\n return matches\n }\n\n /**\n * Returns lines from the artifact, optionally bounded to a range.\n *\n * @remarks\n * Without arguments, returns all lines — equivalent to POSIX `cat`. With `start` and/or `end`,\n * behaves like `Array.prototype.slice`: `start` defaults to `0`, `end` defaults to the total\n * line count, and only lines in `[start, end)` are fetched from the backing store. For large\n * artifacts, prefer a bounded range or {@link SpooledArtifact.head} / {@link SpooledArtifact.tail}.\n *\n * @param start - 0-based start line index (inclusive). Defaults to `0`.\n * @param end - 0-based end line index (exclusive). Defaults to `lineCount()`.\n * @returns Array of line strings in the requested range.\n */\n async cat(start?: number, end?: number): Promise<string[]> {\n const count = await this.#reader.lineCount()\n const from = Math.max(0, start ?? 0)\n const to = Math.min(count, end ?? count)\n const lines: string[] = []\n for (let i = from; i < to; i++) {\n const line = await this.#reader.line(i)\n if (line !== undefined) {\n lines.push(line)\n }\n }\n return lines\n }\n\n /**\n * Returns the total byte length of the underlying data.\n *\n * @returns The byte length as reported by the {@link @nhtio/adk!SpoolReader}.\n */\n async byteLength(): Promise<number> {\n return this.#reader.byteLength()\n }\n\n /**\n * Returns the total number of lines in the artifact.\n *\n * @returns The line count as reported by the {@link @nhtio/adk!SpoolReader}.\n */\n async lineCount(): Promise<number> {\n return this.#reader.lineCount()\n }\n\n /**\n * Estimates the total token count of the artifact under `encoding`.\n *\n * @remarks\n * Reads the full byte-faithful content via {@link SpooledArtifact.asString} (which delegates to\n * {@link @nhtio/adk!SpoolReader.readAll}) and delegates to {@link @nhtio/adk!Tokenizable.estimateTokens}. The estimate\n * therefore reflects the actual source bytes — including trailing newlines and non-`\\n` line\n * terminators that the line-based {@link SpooledArtifact.cat} view would otherwise discard or\n * misrepresent.\n *\n * @param encoding - The encoding identifier to use for counting.\n * @returns The estimated number of tokens.\n */\n async estimateTokens(encoding: TokenEncoding): Promise<number> {\n const content = await this.#reader.readAll()\n return Tokenizable.estimateTokens(content, encoding)\n }\n\n /**\n * Returns the full artifact body as a single byte-faithful string.\n *\n * @remarks\n * Round-trip faithful to whatever bytes the {@link @nhtio/adk!SpoolReader} was constructed over —\n * preserves trailing newlines and non-`\\n` line terminators that {@link SpooledArtifact.cat}\n * discards via its line-based view. This is the canonical primitive for \"inline the artifact\n * content directly into a message\" use cases.\n *\n * `asString()` and the static `forgeTools(ctx)` factory on each subclass are independent\n * alternatives — a consumer chooses per turn whether to inline the body in a message\n * (`await tc.results.asString()`) or hand the model query tools\n * (`SpooledArtifact.forgeTools(ctx)`). Neither calls the other; either works with neither.\n *\n * @returns The full content as a single string.\n */\n async asString(): Promise<string> {\n return this.#reader.readAll()\n }\n\n /**\n * Forges a fresh {@link @nhtio/adk!ToolRegistry} of ephemeral {@link @nhtio/adk!ArtifactTool} instances that let the\n * LLM query artifacts already present in `ctx.turnToolCalls`.\n *\n * @remarks\n * Standard subclass extension pattern — each class owns only its own `toolMethods` and its\n * own `forgeTools`. The base `SpooledArtifact.forgeTools(ctx)` narrows the `callId` enum to\n * any `tc.results instanceof SpooledArtifact` (so subclass instances are included — that's\n * the whole point of inheritance) and dispatches the seven base methods (`head`, `tail`,\n * `grep`, `cat`, `byteLength`, `lineCount`, `estimateTokens`) on the resolved artifact.\n * Subclasses override `forgeTools` to call this static first and then register their own\n * tools on the returned registry — see {@link @nhtio/adk!SpooledJsonArtifact.forgeTools} and\n * {@link @nhtio/adk!SpooledMarkdownArtifact.forgeTools} for the canonical shape. There is no\n * `requiresSubclass` field, no helper indirection, and no `this`-based class narrowing —\n * just plain `instanceof ThisClass` at each subclass's own filter site.\n *\n * For each descriptor in this class's `toolMethods`, the factory:\n *\n * 1. Walks `ctx.turnToolCalls` to find `ToolCall`s whose `results instanceof SpooledArtifact`.\n * `ToolCall`s flagged `fromArtifactTool === true` are excluded — they carry a\n * {@link @nhtio/adk!Tokenizable}, not a `SpooledArtifact`, and including them would let the model\n * `artifact_grep` on a previous `artifact_grep` result (an infinite-recursion hazard with\n * no semantic value).\n * 2. Returns an empty registry if no compatible callIds are found — no point shipping tools\n * whose `callId` enum is empty.\n * 3. Otherwise mints an {@link @nhtio/adk!ArtifactTool} with `ephemeral: true` and `onCollision: 'replace'`\n * so multiple `Subclass.forgeTools(ctx)` outputs merge silently. The tool's `inputSchema`\n * includes a required `callId` field with `.valid(...compatibleIds)`, plus the descriptor's\n * own `argsSchema` fields.\n *\n * The handler resolves the artifact via `[...ctx.turnToolCalls].find(t => t.id === callId)`,\n * dispatches the descriptor's method, and serialises the return value (string → as-is;\n * string[] → newline-join; number → `String(n)`; otherwise `JSON.stringify(value, null, 2)`;\n * `descriptor.serialise` overrides the defaults). `grep` is special-cased: the handler\n * constructs `new RegExp(pattern, flags ?? '')` before invoking the artifact's `grep` method.\n *\n * The returned registry must be merged into the consumer's main registry and the main\n * registry must be bound to `ctx` via {@link @nhtio/adk!ToolRegistry.bindContext}:\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() // ← ephemeral cleanup fires here\n * }\n * ```\n *\n * @warning You **must** call `registry.bindContext(ctx)` on the registry hosting these tools,\n * or ephemeral cleanup will not run and the `callId` enum in subsequent executor calls will\n * be stale (excluding new tool calls produced in the meantime).\n *\n * @param ctx - The execution context whose `turnToolCalls` snapshot defines the `callId` enum.\n * @returns A fresh `ToolRegistry`. Empty when `turnToolCalls` contains no compatible artifacts.\n *\n * @see {@link @nhtio/adk!ToolRegistry.bindContext}\n * @see {@link @nhtio/adk!ToolRegistry.merge}\n * @see {@link @nhtio/adk!DispatchContext.onAck}\n */\n public static forgeTools(ctx: DispatchContext): ToolRegistry {\n const requires: SpooledArtifactConstructor = SpooledArtifact\n const calls = [...ctx.turnToolCalls]\n const compatibleIds = calls\n .filter((tc) => !tc.fromArtifactTool && isInstanceOf(tc.results, requires.name, requires))\n .map((tc) => tc.id)\n if (compatibleIds.length === 0) return new ToolRegistry([])\n\n const tools: ArtifactTool[] = []\n for (const descriptor of this.toolMethods) {\n const callIdSchema = validator\n .string()\n .valid(...compatibleIds)\n .required()\n .description('ToolCall id of the artifact to query.')\n\n const argsSchema = (descriptor.argsSchema ?? noArgsSchema).append({\n callId: callIdSchema,\n })\n\n const serialise = descriptor.serialise ?? defaultSerialise\n\n const tool = new ArtifactTool({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: argsSchema,\n ephemeral: true,\n onCollision: 'replace',\n handler: async (rawArgs, ctxInner) => {\n const args = rawArgs as Record<string, unknown> & { callId: string }\n const tc = [...ctxInner.turnToolCalls].find((t) => t.id === args.callId)\n if (!tc) {\n return `Error: no tool call with id ${args.callId} in this turn`\n }\n const artifact = tc.results\n if (!isInstanceOf(artifact, requires.name, requires)) {\n return `Error: tool call ${args.callId} results are not a ${requires.name} instance`\n }\n const methodArgs: unknown[] = []\n if (descriptor.method === 'grep') {\n const pattern = args.pattern as string\n const flags = (args.flags as string | undefined) ?? ''\n methodArgs.push(new RegExp(pattern, flags))\n } else if (descriptor.method === 'head' || descriptor.method === 'tail') {\n methodArgs.push((args.n as number | undefined) ?? 10)\n } else if (descriptor.method === 'cat') {\n methodArgs.push(args.start as number | undefined, args.end as number | undefined)\n } else if (descriptor.method === 'estimateTokens') {\n methodArgs.push(args.encoding as TokenEncoding)\n }\n const fn = (artifact as unknown as Record<string, (...a: unknown[]) => unknown>)[\n descriptor.method\n ]\n if (typeof fn !== 'function') {\n return `Error: artifact has no method ${descriptor.method}`\n }\n const result = await Promise.resolve(fn.apply(artifact, methodArgs))\n return serialise(result)\n },\n })\n tools.push(tool)\n }\n return new ToolRegistry(tools)\n }\n}\n"],"mappings":"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"}
|
package/spooled_artifact.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
require("./chunk-Ble4zEEl.js");
|
|
3
|
-
const require_spooled_artifact = require("./spooled_artifact-
|
|
4
|
-
const require_spooled_markdown_artifact = require("./spooled_markdown_artifact-
|
|
3
|
+
const require_spooled_artifact = require("./spooled_artifact-BTq6Nzfy.js");
|
|
4
|
+
const require_spooled_markdown_artifact = require("./spooled_markdown_artifact-CALSDxIx.js");
|
|
5
5
|
exports.SpooledArtifact = require_spooled_artifact.SpooledArtifact;
|
|
6
6
|
exports.SpooledJsonArtifact = require_spooled_markdown_artifact.SpooledJsonArtifact;
|
|
7
7
|
exports.SpooledMarkdownArtifact = require_spooled_markdown_artifact.SpooledMarkdownArtifact;
|
package/spooled_artifact.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { r as implementsSpoolReader, t as SpooledArtifact } from "./spooled_artifact-
|
|
2
|
-
import { n as SpooledJsonArtifact, t as SpooledMarkdownArtifact } from "./spooled_markdown_artifact-
|
|
1
|
+
import { r as implementsSpoolReader, t as SpooledArtifact } from "./spooled_artifact-CHoZgWwI.mjs";
|
|
2
|
+
import { n as SpooledJsonArtifact, t as SpooledMarkdownArtifact } from "./spooled_markdown_artifact-Ci5UL7l4.mjs";
|
|
3
3
|
export { SpooledArtifact, SpooledJsonArtifact, SpooledMarkdownArtifact, implementsSpoolReader };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Ble4zEEl.js");
|
|
2
|
-
const require_tool_registry = require("./tool_registry-
|
|
3
|
-
const require_spooled_artifact = require("./spooled_artifact-
|
|
2
|
+
const require_tool_registry = require("./tool_registry-DYUYqXvo.js");
|
|
3
|
+
const require_spooled_artifact = require("./spooled_artifact-BTq6Nzfy.js");
|
|
4
4
|
let _nhtio_validation = require("@nhtio/validation");
|
|
5
5
|
let json5 = require("json5");
|
|
6
6
|
json5 = require_chunk.__toESM(json5);
|
|
@@ -783,4 +783,4 @@ Object.defineProperty(exports, "SpooledMarkdownArtifact", {
|
|
|
783
783
|
}
|
|
784
784
|
});
|
|
785
785
|
|
|
786
|
-
//# sourceMappingURL=spooled_markdown_artifact-
|
|
786
|
+
//# sourceMappingURL=spooled_markdown_artifact-CALSDxIx.js.map
|
package/{spooled_markdown_artifact-DQX0RCdI.js.map → spooled_markdown_artifact-CALSDxIx.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spooled_markdown_artifact-DQX0RCdI.js","names":["#format","#resolveFormat","#resolveRecords","#parsed","#resolveIndex","#index","#frontmatter"],"sources":["../src/lib/classes/spooled_json_artifact.ts","../src/lib/classes/spooled_markdown_artifact.ts"],"sourcesContent":["import { default as JSON5 } from 'json5'\nimport { JSONPath } from 'jsonpath-plus'\nimport { validator } from '@nhtio/validation'\nimport { ArtifactTool } from './artifact_tool'\nimport { ToolRegistry } from './tool_registry'\nimport { isInstanceOf, isObject } from '../utils/guards'\nimport { SpooledArtifact, defaultSerialise } from './spooled_artifact'\nimport type { SpoolReader } from '../contracts/spool_reader'\nimport type { ToolMethodDescriptor } from './spooled_artifact'\nimport type { DispatchContext } from '../contracts/dispatch_context'\n\n/**\n * The set of JSON-derived formats that {@link SpooledJsonArtifact} can handle.\n *\n * @remarks\n * - `json` — a single JSON value spanning the entire artifact (strict RFC 8259).\n * - `json5` — a single JSON5 value spanning the entire artifact; permits comments, trailing\n * commas, unquoted keys, and other relaxed syntax via the `json5` package.\n * - `jsonl` — newline-delimited JSON; each non-empty line is an independent JSON value.\n * - `ndjson` — alias for `jsonl`; both names are accepted and behave identically.\n */\nexport type JsonArtifactFormat = 'json' | 'json5' | 'jsonl' | 'ndjson'\n\n/**\n * Detects the {@link JsonArtifactFormat} of a raw string.\n *\n * @remarks\n * Detection strategy (in order):\n * 1. If the content parses as strict JSON → `json`.\n * 2. If every non-empty line parses as strict JSON → `jsonl`.\n * 3. If the content parses as JSON5 → `json5`.\n * 4. Otherwise throws.\n *\n * Strict JSON is tried before JSON5 so that well-formed JSON files are not unnecessarily\n * classified as JSON5.\n *\n * @param content - The full artifact text to inspect.\n * @returns The inferred format.\n * @throws `Error` when the content cannot be classified as any supported JSON format.\n */\nfunction inferFormat(content: string): JsonArtifactFormat {\n const trimmed = content.trim()\n\n // 1. Try strict JSON\n try {\n JSON.parse(trimmed)\n return 'json'\n } catch {\n // fall through\n }\n\n // 2. Try JSONL (every non-empty line is valid JSON)\n const nonEmptyLines = trimmed.split('\\n').filter((l) => l.trim().length > 0)\n if (\n nonEmptyLines.length > 0 &&\n nonEmptyLines.every((l) => {\n try {\n JSON.parse(l)\n return true\n } catch {\n return false\n }\n })\n ) {\n return 'jsonl'\n }\n\n // 3. Try JSON5\n try {\n JSON5.parse(trimmed)\n return 'json5'\n } catch {\n // fall through\n }\n\n throw new Error('Unable to infer JSON format: content is not valid JSON, JSONL, NDJSON, or JSON5')\n}\n\n/**\n * A {@link @nhtio/adk!SpooledArtifact} specialisation that adds JSON-aware read operations.\n *\n * @typeParam T - The expected shape of each parsed record. Defaults to `unknown`.\n *\n * @remarks\n * Construct with an optional `format` hint. When omitted the format is auto-detected on first\n * access by reading the full artifact and running {@link inferFormat}. Once detected (or\n * provided), the format is cached for the lifetime of the instance.\n *\n * All JSON methods are async, consistent with {@link @nhtio/adk!SpooledArtifact}.\n *\n * Path-based methods (`json_get`, `json_filter`, `json_pluck`) use\n * [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath) expressions. Full JSONPath syntax\n * is supported, including recursive descent (`..`), filter expressions (`[?(@.age > 18)]`),\n * and union selectors.\n */\nexport class SpooledJsonArtifact<T = unknown> extends SpooledArtifact {\n #format: JsonArtifactFormat | undefined\n #parsed: T[] | undefined\n\n /**\n * @param reader - The backing store to read from.\n * @param format - Optional format hint. When omitted, the format is inferred on first access.\n */\n constructor(reader: SpoolReader, format?: JsonArtifactFormat) {\n super(reader)\n this.#format = format\n }\n\n /**\n * Returns `true` if `value` is a {@link SpooledJsonArtifact} instance.\n *\n * @remarks\n * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard: `instanceof` first, then\n * `Symbol.hasInstance`, then a `constructor.name` fallback. Matches the pattern used by every\n * other class guard in the ADK; safe against the dual-module-copy case where two distinct\n * `SpooledJsonArtifact` classes coexist in the same realm.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link SpooledJsonArtifact} instance.\n */\n public static isSpooledJsonArtifact(value: unknown): value is SpooledJsonArtifact {\n return isInstanceOf(value, 'SpooledJsonArtifact', SpooledJsonArtifact)\n }\n\n /**\n * The JSON-specific artifact-query descriptors this class adds on top of the base set.\n *\n * @remarks\n * Lists `artifact_json_type`, `artifact_json_keys`, `artifact_json_length`,\n * `artifact_json_get`, `artifact_json_filter`, `artifact_json_slice`, `artifact_json_pluck`.\n * The base seven descriptors (`artifact_head`, etc.) are NOT included here — they are\n * forged separately by {@link SpooledJsonArtifact.forgeTools}, which calls\n * `SpooledArtifact.forgeTools(ctx)` to produce the base-narrowed tools and then registers\n * its own JSON tools on the result. Downstream consumers building custom subclasses\n * should follow the same pattern: own only your own descriptors; override `forgeTools` to\n * compose with the base output.\n */\n public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n {\n name: 'artifact_json_type',\n method: 'json_type',\n description:\n 'Return the JSON format (json | json5 | jsonl | ndjson) of a JSON artifact produced earlier in this turn.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_json_keys',\n method: 'json_keys',\n description: 'Return the top-level keys of a JSON artifact produced earlier in this turn.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_json_length',\n method: 'json_length',\n description:\n 'Return the record count of a JSON artifact produced earlier in this turn (1 for json/json5; line count for jsonl/ndjson).',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_json_get',\n method: 'json_get',\n description:\n 'Evaluate a JSONPath expression against a JSON artifact produced earlier in this turn.',\n argsSchema: validator.object({\n path: validator.string().required().description(\"JSONPath expression, e.g. '$.user.name'.\"),\n }),\n },\n {\n name: 'artifact_json_filter',\n method: 'json_filter',\n description:\n 'Return records of a JSON artifact (produced earlier in this turn) matched by a JSONPath filter.',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description(\"JSONPath filter expression, e.g. '$[?(@.age>18)]'.\"),\n }),\n },\n {\n name: 'artifact_json_slice',\n method: 'json_slice',\n description:\n 'Return a slice of records by index range from a JSON artifact produced earlier in this turn.',\n argsSchema: validator.object({\n start: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start index (inclusive).'),\n end: validator.number().integer().min(0).optional().description('End index (exclusive).'),\n }),\n },\n {\n name: 'artifact_json_pluck',\n method: 'json_pluck',\n description:\n 'Return all values matched by a JSONPath expression across every record of a JSON artifact produced earlier in this turn.',\n argsSchema: validator.object({\n path: validator.string().required().description(\"JSONPath expression, e.g. '$..name'.\"),\n }),\n },\n ])\n\n /**\n * Forges base-class tools plus JSON-specific tools narrowed to {@link SpooledJsonArtifact}.\n *\n * @remarks\n * Standard subclass extension pattern: call `SpooledArtifact.forgeTools(ctx)` to produce\n * the base seven `artifact_*` tools narrowed to any `SpooledArtifact` in the turn, then\n * register one `ArtifactTool` per JSON-specific descriptor narrowed to JSON artifacts.\n * Downstream consumers building their own subclasses should follow the same shape.\n */\n public static override forgeTools(ctx: DispatchContext): ToolRegistry {\n const registry = SpooledArtifact.forgeTools(ctx)\n const requires = SpooledJsonArtifact\n const compatibleIds = [...ctx.turnToolCalls]\n .filter((tc) => !tc.fromArtifactTool && isInstanceOf(tc.results, requires.name, requires))\n .map((tc) => tc.id)\n if (compatibleIds.length === 0) return registry\n\n for (const descriptor of this.toolMethods) {\n const callIdSchema = validator\n .string()\n .valid(...compatibleIds)\n .required()\n .description('ToolCall id of the artifact to query.')\n\n const argsSchema = (\n descriptor.argsSchema ?? validator.object<Record<string, never>>({})\n ).append({\n callId: callIdSchema,\n })\n\n const tool = new ArtifactTool({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: argsSchema,\n ephemeral: true,\n onCollision: 'replace',\n handler: async (rawArgs, ctxInner) => {\n const args = rawArgs as Record<string, unknown> & { callId: string }\n const tc = [...ctxInner.turnToolCalls].find((t) => t.id === args.callId)\n if (!tc) {\n return `Error: no tool call with id ${args.callId} in this turn`\n }\n const artifact = tc.results\n if (!isInstanceOf(artifact, requires.name, requires)) {\n return `Error: tool call ${args.callId} results are not a ${requires.name} instance`\n }\n const methodArgs: unknown[] = []\n if (\n descriptor.method === 'json_get' ||\n descriptor.method === 'json_filter' ||\n descriptor.method === 'json_pluck'\n ) {\n methodArgs.push(args.path as string)\n } else if (descriptor.method === 'json_slice') {\n methodArgs.push(args.start as number | undefined, args.end as number | undefined)\n }\n const fn = (artifact as unknown as Record<string, (...a: unknown[]) => unknown>)[\n descriptor.method\n ]\n if (typeof fn !== 'function') {\n return `Error: artifact has no method ${descriptor.method}`\n }\n const result = await Promise.resolve(fn.apply(artifact, methodArgs))\n const serialise = descriptor.serialise ?? defaultSerialise\n return serialise(result)\n },\n })\n registry.register(tool)\n }\n return registry\n }\n\n /**\n * Resolves and caches the detected or provided format.\n */\n async #resolveFormat(): Promise<JsonArtifactFormat> {\n if (this.#format !== undefined) {\n return this.#format\n }\n const lines = await this.cat()\n this.#format = inferFormat(lines.join('\\n'))\n return this.#format\n }\n\n /**\n * Parses and caches all records from the artifact.\n *\n * @remarks\n * For `json`/`json5` format: returns a single-element array containing the parsed root value.\n * For `jsonl`/`ndjson` format: returns one element per non-empty line.\n */\n async #resolveRecords(): Promise<T[]> {\n if (this.#parsed !== undefined) {\n return this.#parsed\n }\n const format = await this.#resolveFormat()\n const lines = await this.cat()\n if (format === 'json') {\n this.#parsed = [JSON.parse(lines.join('\\n')) as T]\n } else if (format === 'json5') {\n this.#parsed = [JSON5.parse(lines.join('\\n')) as T]\n } else {\n // jsonl / ndjson\n this.#parsed = lines.filter((l) => l.trim().length > 0).map((l) => JSON.parse(l) as T)\n }\n return this.#parsed\n }\n\n /**\n * Returns the detected or provided format for this artifact.\n *\n * @returns One of `'json'`, `'json5'`, `'jsonl'`, or `'ndjson'`.\n */\n async json_type(): Promise<JsonArtifactFormat> {\n return this.#resolveFormat()\n }\n\n /**\n * Returns the top-level keys of the parsed content.\n *\n * @remarks\n * - For `json`/`json5`: returns the keys of the root object, or `undefined` when the root is\n * not a plain object (e.g. an array or scalar).\n * - For `jsonl`/`ndjson`: returns the union of keys across all records that are plain objects.\n * Duplicate keys are deduplicated.\n *\n * @returns Array of key strings, or `undefined` when no object keys are present.\n */\n async json_keys(): Promise<string[] | undefined> {\n const records = await this.#resolveRecords()\n const format = await this.#resolveFormat()\n if (format === 'json' || format === 'json5') {\n const root = records[0]\n if (isObject(root)) {\n return Object.keys(root as object)\n }\n return undefined\n }\n const keySet = new Set<string>()\n for (const record of records) {\n if (isObject(record)) {\n for (const key of Object.keys(record as object)) {\n keySet.add(key)\n }\n }\n }\n return keySet.size > 0 ? Array.from(keySet) : undefined\n }\n\n /**\n * Returns the total number of records in the artifact.\n *\n * @remarks\n * - For `json`/`json5`: always `1` (the entire artifact is a single value).\n * - For `jsonl`/`ndjson`: the number of non-empty lines.\n *\n * @returns The record count.\n */\n async json_length(): Promise<number> {\n const records = await this.#resolveRecords()\n return records.length\n }\n\n /**\n * Evaluates a JSONPath expression against the parsed content.\n *\n * @remarks\n * Uses [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath). Full JSONPath syntax is\n * supported: recursive descent (`$..*`), filter expressions (`$[?(@.age > 18)]`), union\n * selectors, and more.\n *\n * - For `json`/`json5`: evaluates the expression against the root value.\n * - For `jsonl`/`ndjson`: evaluates the expression against each record and returns a flat\n * array of all matches across all records.\n *\n * @param path - A JSONPath expression (e.g. `'$.user.address.city'`, `'$..name'`).\n * @returns Array of matched values. Empty array when no matches are found.\n */\n async json_get(path: string): Promise<unknown[]> {\n const records = await this.#resolveRecords()\n const format = await this.#resolveFormat()\n if (format === 'json' || format === 'json5') {\n return JSONPath({ path, json: records[0] as object })\n }\n return records.flatMap((r) => JSONPath({ path, json: r as object }))\n }\n\n /**\n * Returns a slice of the parsed records by index range.\n *\n * @remarks\n * For `json`/`json5`: always returns `[root]` — the artifact is a single record so slicing is\n * not meaningful. For `jsonl`/`ndjson`: behaves like `Array.prototype.slice`.\n *\n * @param start - Start index (inclusive). Defaults to `0`.\n * @param end - End index (exclusive). Defaults to the record count.\n * @returns Array of sliced records.\n */\n async json_slice(start?: number, end?: number): Promise<T[]> {\n const records = await this.#resolveRecords()\n const format = await this.#resolveFormat()\n if (format === 'json' || format === 'json5') {\n return records\n }\n return records.slice(start, end)\n }\n\n /**\n * Returns records matched by a JSONPath filter expression.\n *\n * @remarks\n * Evaluates `path` against each record and returns those for which the expression produces at\n * least one match. For `json`/`json5`, evaluates against the root value and returns it in an\n * array if matched.\n *\n * @param path - A JSONPath expression (e.g. `'$[?(@.status === \"active\")]'`).\n * @returns Array of matching records.\n */\n async json_filter(path: string): Promise<T[]> {\n const records = await this.#resolveRecords()\n return records.filter((r) => {\n const matches = JSONPath({ path, json: r as object })\n return Array.isArray(matches) && matches.length > 0\n })\n }\n\n /**\n * Returns all values matched by a JSONPath expression across every record.\n *\n * @remarks\n * Convenience over {@link SpooledJsonArtifact.json_get} with an identical signature — use\n * whichever name better communicates intent at the call site. `json_pluck` reads well for\n * extracting a single field column; `json_get` reads well for structured queries.\n *\n * @param path - A JSONPath expression (e.g. `'$..name'`).\n * @returns Array of matched values.\n */\n async json_pluck(path: string): Promise<unknown[]> {\n return this.json_get(path)\n }\n}\n","import { remark } from 'remark'\nimport { visit } from 'unist-util-visit'\nimport { load as yamlLoad } from 'js-yaml'\nimport { validator } from '@nhtio/validation'\nimport { isInstanceOf } from '../utils/guards'\nimport { ArtifactTool } from './artifact_tool'\nimport { ToolRegistry } from './tool_registry'\nimport { default as remarkGfm } from 'remark-gfm'\nimport { toString as mdastToString } from 'mdast-util-to-string'\nimport { default as remarkFrontmatter } from 'remark-frontmatter'\nimport { SpooledArtifact, defaultSerialise } from './spooled_artifact'\nimport type { Root, Link, Image } from 'mdast'\nimport type { SpoolReader } from '../contracts/spool_reader'\nimport type { ToolMethodDescriptor } from './spooled_artifact'\nimport type { DispatchContext } from '../contracts/dispatch_context'\n\n/**\n * A single heading entry in the document's structural index.\n *\n * @remarks\n * `startLine` is the 0-based line of the heading itself. `endLine` is the 0-based index of the\n * last line belonging to this section (inclusive) — the line immediately before the next heading\n * of equal or lesser depth, or the last line of the document.\n */\nexport interface MarkdownHeadingEntry {\n /** ATX heading depth: 1 (`#`) through 6 (`######`). */\n depth: 1 | 2 | 3 | 4 | 5 | 6\n /** The heading text with the leading `#` prefix stripped and trimmed. */\n text: string\n /** 0-based line index of the heading line itself. */\n startLine: number\n /** 0-based line index of the last line in this section (inclusive). */\n endLine: number\n}\n\n/**\n * A single fenced code block entry in the document's structural index.\n */\nexport interface MarkdownCodeEntry {\n /** The language identifier immediately after the opening fence, or `null` when absent. */\n lang: string | null\n /** 0-based line index of the opening fence line. */\n startLine: number\n /** 0-based line index of the closing fence line. */\n endLine: number\n}\n\ninterface MarkdownIndex {\n headings: MarkdownHeadingEntry[]\n codeBlocks: MarkdownCodeEntry[]\n}\n\n/**\n * A section of a markdown document as returned by {@link SpooledMarkdownArtifact.md_sections}.\n *\n * @remarks\n * Contains only line-range metadata — no content is fetched until the caller explicitly\n * requests it via `cat(bodyStartLine, bodyEndLine + 1)`.\n */\nexport interface MarkdownSection {\n depth: 1 | 2 | 3 | 4 | 5 | 6\n /** The heading text. */\n heading: string\n /** 0-based line of the heading itself. */\n headingLine: number\n /** 0-based line of the first body line (heading line + 1). */\n bodyStartLine: number\n /** 0-based line of the last body line (inclusive). */\n bodyEndLine: number\n}\n\n/**\n * Returns a configured remark processor with frontmatter and GFM support.\n */\nfunction processor() {\n return remark().use(remarkFrontmatter).use(remarkGfm)\n}\n\n/**\n * Parses a heading line (e.g. `## My Heading`) and returns `{ depth, text }`, or `null` when\n * the line is not an ATX heading.\n */\nfunction parseHeadingLine(line: string): { depth: 1 | 2 | 3 | 4 | 5 | 6; text: string } | null {\n const match = /^(#{1,6})\\s+(.*)$/.exec(line)\n if (!match) return null\n const depth = match[1].length as 1 | 2 | 3 | 4 | 5 | 6\n return { depth, text: match[2].trim() }\n}\n\n/**\n * Returns the length of a fence marker at the start of `line` (3+), or `0` if the line is not\n * a fence opener/closer. Handles both backtick (` ``` `) and tilde (`~~~`) fences.\n */\nfunction fenceLength(line: string): number {\n const trimmed = line.trimStart()\n const match = /^(`{3,}|~{3,})/.exec(trimmed)\n return match ? match[1].length : 0\n}\n\n/**\n * Extracts the language identifier from a fence opener line (e.g. ` ```ts ` → `'ts'`), or\n * `null` when none is present.\n */\nfunction fenceLang(line: string): string | null {\n const trimmed = line.trimStart()\n const match = /^(?:`{3,}|~{3,})(\\S+)/.exec(trimmed)\n return match ? match[1] : null\n}\n\n/**\n * A {@link @nhtio/adk!SpooledArtifact} specialisation that adds markdown-aware structural queries.\n *\n * @remarks\n * Designed for large markdown documents where loading the full content into memory is\n * impractical. The structural index (heading positions, code block positions) is built by a\n * single line-by-line scan of the {@link @nhtio/adk!SpoolReader} without retaining any content. Only the\n * tiny metadata index and the parsed frontmatter object are cached.\n *\n * Content retrieval is always bounded — use `cat(start, end)` or the `startLine`/`endLine`\n * parameters on inline methods to fetch only the lines you need.\n *\n * Inline methods (`md_links`, `md_images`, `md_text`, `md_ast`) accept optional line-range\n * arguments. Without a range they read the full document — documented trade-off, caller\n * responsibility to bound the range for large documents.\n *\n * The processor always applies `remark-gfm` (tables, task lists, strikethrough, autolinks)\n * in addition to standard CommonMark and YAML frontmatter.\n */\nexport class SpooledMarkdownArtifact extends SpooledArtifact {\n #index: MarkdownIndex | undefined\n #frontmatter: Record<string, unknown> | null | undefined\n\n /**\n * @param reader - The backing store to read from.\n */\n constructor(reader: SpoolReader) {\n super(reader)\n }\n\n /**\n * Returns `true` if `value` is a {@link SpooledMarkdownArtifact} instance.\n *\n * @remarks\n * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard: `instanceof` first, then\n * `Symbol.hasInstance`, then a `constructor.name` fallback. Matches the pattern used by every\n * other class guard in the ADK; safe against the dual-module-copy case where two distinct\n * `SpooledMarkdownArtifact` classes coexist in the same realm.\n */\n public static isSpooledMarkdownArtifact(value: unknown): value is SpooledMarkdownArtifact {\n return isInstanceOf(value, 'SpooledMarkdownArtifact', SpooledMarkdownArtifact)\n }\n\n /**\n * The markdown-specific artifact-query descriptors this class adds on top of the base set.\n *\n * @remarks\n * Lists `artifact_md_frontmatter`, `artifact_md_headings`, `artifact_md_code_blocks`,\n * `artifact_md_sections`, `artifact_md_links`, `artifact_md_images`, `artifact_md_text`,\n * `artifact_md_ast`. The base seven descriptors (`artifact_head`, etc.) are NOT included\n * here — they are forged separately by {@link SpooledMarkdownArtifact.forgeTools}, which\n * calls `SpooledArtifact.forgeTools(ctx)` to produce the base-narrowed tools and then\n * registers its own markdown tools on the result. Downstream consumers building custom\n * subclasses should follow the same pattern: own only your own descriptors; override\n * `forgeTools` to compose with the base output.\n */\n public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n {\n name: 'artifact_md_frontmatter',\n method: 'md_frontmatter',\n description:\n 'Return parsed YAML frontmatter (or undefined) from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_md_headings',\n method: 'md_headings',\n description:\n 'Return all headings, optionally filtered by depth, from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n depth: validator\n .number()\n .integer()\n .min(1)\n .max(6)\n .optional()\n .description('ATX heading depth (1-6).'),\n }),\n },\n {\n name: 'artifact_md_code_blocks',\n method: 'md_code_blocks',\n description:\n 'Return all fenced code block entries, optionally filtered by language, from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n lang: validator\n .string()\n .optional()\n .description('Language identifier. Pass empty string to match blocks with no lang.'),\n }),\n },\n {\n name: 'artifact_md_sections',\n method: 'md_sections',\n description:\n 'Return document sections (line-range metadata only) from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n depth: validator\n .number()\n .integer()\n .min(1)\n .max(6)\n .optional()\n .description('ATX heading depth (1-6).'),\n }),\n },\n {\n name: 'artifact_md_links',\n method: 'md_links',\n description:\n 'Return all inline and reference links within the given line range from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n startLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start line (inclusive).'),\n endLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('End line (exclusive).'),\n }),\n },\n {\n name: 'artifact_md_images',\n method: 'md_images',\n description:\n 'Return all images within the given line range from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n startLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start line (inclusive).'),\n endLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('End line (exclusive).'),\n }),\n },\n {\n name: 'artifact_md_text',\n method: 'md_text',\n description:\n 'Return plain text with markup stripped, for the given line range, from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n startLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start line (inclusive).'),\n endLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('End line (exclusive).'),\n }),\n },\n {\n name: 'artifact_md_ast',\n method: 'md_ast',\n description:\n 'Return the full MDAST Root for the specified line range from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n startLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start line (inclusive).'),\n endLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('End line (exclusive).'),\n }),\n },\n ])\n\n /**\n * Forges base-class tools plus markdown-specific tools narrowed to\n * {@link SpooledMarkdownArtifact}.\n *\n * @remarks\n * Standard subclass extension pattern: call `SpooledArtifact.forgeTools(ctx)` to produce\n * the base seven `artifact_*` tools narrowed to any `SpooledArtifact` in the turn, then\n * register one `ArtifactTool` per markdown-specific descriptor narrowed to markdown\n * artifacts. Downstream consumers building their own subclasses should follow the same\n * shape.\n */\n public static override forgeTools(ctx: DispatchContext): ToolRegistry {\n const registry = SpooledArtifact.forgeTools(ctx)\n const requires = SpooledMarkdownArtifact\n const compatibleIds = [...ctx.turnToolCalls]\n .filter((tc) => !tc.fromArtifactTool && isInstanceOf(tc.results, requires.name, requires))\n .map((tc) => tc.id)\n if (compatibleIds.length === 0) return registry\n\n for (const descriptor of this.toolMethods) {\n const callIdSchema = validator\n .string()\n .valid(...compatibleIds)\n .required()\n .description('ToolCall id of the artifact to query.')\n\n const argsSchema = (\n descriptor.argsSchema ?? validator.object<Record<string, never>>({})\n ).append({\n callId: callIdSchema,\n })\n\n const tool = new ArtifactTool({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: argsSchema,\n ephemeral: true,\n onCollision: 'replace',\n handler: async (rawArgs, ctxInner) => {\n const args = rawArgs as Record<string, unknown> & { callId: string }\n const tc = [...ctxInner.turnToolCalls].find((t) => t.id === args.callId)\n if (!tc) {\n return `Error: no tool call with id ${args.callId} in this turn`\n }\n const artifact = tc.results\n if (!isInstanceOf(artifact, requires.name, requires)) {\n return `Error: tool call ${args.callId} results are not a ${requires.name} instance`\n }\n const methodArgs: unknown[] = []\n if (descriptor.method === 'md_headings' || descriptor.method === 'md_sections') {\n methodArgs.push(args.depth as number | undefined)\n } else if (descriptor.method === 'md_code_blocks') {\n methodArgs.push(args.lang as string | undefined)\n } else if (\n descriptor.method === 'md_links' ||\n descriptor.method === 'md_images' ||\n descriptor.method === 'md_text' ||\n descriptor.method === 'md_ast'\n ) {\n methodArgs.push(\n args.startLine as number | undefined,\n args.endLine as number | undefined\n )\n }\n const fn = (artifact as unknown as Record<string, (...a: unknown[]) => unknown>)[\n descriptor.method\n ]\n if (typeof fn !== 'function') {\n return `Error: artifact has no method ${descriptor.method}`\n }\n const result = await Promise.resolve(fn.apply(artifact, methodArgs))\n const serialise = descriptor.serialise ?? defaultSerialise\n return serialise(result)\n },\n })\n registry.register(tool)\n }\n return registry\n }\n\n /**\n * Builds the structural index in a single top-to-bottom pass, retaining only metadata.\n */\n async #resolveIndex(): Promise<MarkdownIndex> {\n if (this.#index !== undefined) return this.#index\n\n const count = await this.lineCount()\n const headingsRaw: Array<{ depth: 1 | 2 | 3 | 4 | 5 | 6; text: string; startLine: number }> = []\n const codeBlocks: MarkdownCodeEntry[] = []\n\n let inFrontmatter = false\n let frontmatterClosed = false\n let inCodeBlock = false\n let openFenceLen = 0\n let openFenceStartLine = 0\n let openFenceLang: string | null = null\n\n for (let i = 0; i < count; i++) {\n const rawLine = await this.line(i)\n const l = rawLine ?? ''\n\n // Handle frontmatter block at the top of the document\n if (i === 0 && l.trim() === '---') {\n inFrontmatter = true\n continue\n }\n if (inFrontmatter) {\n if (l.trim() === '---') {\n inFrontmatter = false\n frontmatterClosed = true\n }\n continue\n }\n if (!frontmatterClosed && i === 0) {\n // No frontmatter — treat as normal document from the start\n }\n\n // Handle fenced code blocks\n const fLen = fenceLength(l)\n if (!inCodeBlock && fLen >= 3) {\n inCodeBlock = true\n openFenceLen = fLen\n openFenceStartLine = i\n openFenceLang = fenceLang(l)\n continue\n }\n if (inCodeBlock) {\n // A closing fence must use the same fence character (` or ~) and be at least as long.\n if (fLen >= openFenceLen) {\n const openLine = (await this.line(openFenceStartLine)) ?? ''\n const openChar = openLine.trimStart()[0]\n const closeChar = l.trimStart()[0]\n if (closeChar === openChar) {\n codeBlocks.push({ lang: openFenceLang, startLine: openFenceStartLine, endLine: i })\n inCodeBlock = false\n openFenceLen = 0\n }\n }\n continue\n }\n\n // Detect ATX headings (not inside code blocks, not in frontmatter)\n const heading = parseHeadingLine(l)\n if (heading) {\n headingsRaw.push({ ...heading, startLine: i })\n }\n }\n\n // Unclosed code block — record it anyway\n if (inCodeBlock) {\n codeBlocks.push({ lang: openFenceLang, startLine: openFenceStartLine, endLine: count - 1 })\n }\n\n // Post-process heading endLine values\n const headings: MarkdownHeadingEntry[] = headingsRaw.map((h, idx) => {\n const nextBoundary = headingsRaw.slice(idx + 1).find((n) => n.depth <= h.depth)\n const endLine = nextBoundary ? nextBoundary.startLine - 1 : count - 1\n return { ...h, endLine }\n })\n\n this.#index = { headings, codeBlocks }\n return this.#index\n }\n\n // ── Frontmatter ───────────────────────────────────────────────────────────\n\n /**\n * Returns the parsed YAML frontmatter, or `undefined` when no frontmatter block is present.\n *\n * @remarks\n * Short-circuits after reading the frontmatter block — never reads the document body. Caches\n * the result so subsequent calls are free. The result is `undefined` (not an empty object)\n * when no frontmatter is found, distinguishing \"no frontmatter\" from \"empty frontmatter\".\n */\n async md_frontmatter(): Promise<Record<string, unknown> | undefined> {\n if (this.#frontmatter !== undefined) return this.#frontmatter ?? undefined\n\n const firstLine = await this.line(0)\n if (firstLine?.trim() !== '---') {\n this.#frontmatter = null\n return undefined\n }\n\n const maxScan = Math.min(await this.lineCount(), 200)\n const yamlLines: string[] = []\n let closed = false\n for (let i = 1; i < maxScan; i++) {\n const l = await this.line(i)\n if (l?.trim() === '---') {\n closed = true\n break\n }\n yamlLines.push(l ?? '')\n }\n\n if (!closed) {\n this.#frontmatter = null\n return undefined\n }\n\n this.#frontmatter = yamlLoad(yamlLines.join('\\n')) as Record<string, unknown>\n return this.#frontmatter\n }\n\n // ── Structural index queries ──────────────────────────────────────────────\n\n /**\n * Returns all headings in document order, optionally filtered by depth.\n *\n * @remarks\n * Uses the cached structural index — no content is fetched from the {@link @nhtio/adk!SpoolReader}.\n *\n * @param depth - When provided, only headings at this ATX depth (1–6) are returned.\n */\n async md_headings(depth?: 1 | 2 | 3 | 4 | 5 | 6): Promise<MarkdownHeadingEntry[]> {\n const index = await this.#resolveIndex()\n if (depth === undefined) return index.headings.slice()\n return index.headings.filter((h) => h.depth === depth)\n }\n\n /**\n * Returns all fenced code block entries, optionally filtered by language identifier.\n *\n * @remarks\n * Returns line-range metadata only — no content is fetched. Use `cat(entry.startLine + 1,\n * entry.endLine)` to retrieve the code body (excluding fence lines).\n *\n * @param lang - When provided, only blocks with this exact lang identifier are returned.\n * Pass an empty string to match blocks with no lang identifier.\n */\n async md_code_blocks(lang?: string): Promise<MarkdownCodeEntry[]> {\n const index = await this.#resolveIndex()\n if (lang === undefined) return index.codeBlocks.slice()\n const target = lang === '' ? null : lang\n return index.codeBlocks.filter((b) => b.lang === target)\n }\n\n /**\n * Returns document sections derived from the structural index.\n *\n * @remarks\n * Returns only line-range metadata — body content is never fetched. To retrieve the body of a\n * section, call `cat(section.bodyStartLine, section.bodyEndLine + 1)`.\n *\n * When `depth` is provided, only sections introduced by a heading at that depth are returned;\n * deeper headings become part of the body.\n *\n * @param depth - When provided, only sections at this ATX depth (1–6) are returned.\n */\n async md_sections(depth?: 1 | 2 | 3 | 4 | 5 | 6): Promise<MarkdownSection[]> {\n const index = await this.#resolveIndex()\n const headings =\n depth !== undefined ? index.headings.filter((h) => h.depth === depth) : index.headings\n return headings.map((h) => ({\n depth: h.depth,\n heading: h.text,\n headingLine: h.startLine,\n bodyStartLine: h.startLine + 1,\n bodyEndLine: h.endLine,\n }))\n }\n\n // ── Inline queries (bounded) ──────────────────────────────────────────────\n\n /**\n * Returns the full MDAST Root for the specified line range.\n *\n * @remarks\n * Without a range, reads the full document — for large documents, use\n * {@link SpooledMarkdownArtifact.md_sections} to locate sections and pass\n * bounded line ranges here.\n *\n * @param startLine - 0-based start line (inclusive). Defaults to `0`.\n * @param endLine - 0-based end line (exclusive). Defaults to `lineCount()`.\n */\n async md_ast(startLine?: number, endLine?: number): Promise<Root> {\n const lines = await this.cat(startLine, endLine)\n return processor().parse(lines.join('\\n')) as Root\n }\n\n /**\n * Returns all inline and reference links in the specified line range.\n *\n * @param startLine - 0-based start line (inclusive). Defaults to `0`.\n * @param endLine - 0-based end line (exclusive). Defaults to `lineCount()`.\n */\n async md_links(\n startLine?: number,\n endLine?: number\n ): Promise<Array<{ text: string; url: string; title?: string }>> {\n const lines = await this.cat(startLine, endLine)\n const ast = processor().parse(lines.join('\\n'))\n const results: Array<{ text: string; url: string; title?: string }> = []\n visit(ast, 'link', (node: Link) => {\n results.push({\n text: mdastToString(node),\n url: node.url,\n title: node.title ?? undefined,\n })\n })\n return results\n }\n\n /**\n * Returns all images in the specified line range.\n *\n * @param startLine - 0-based start line (inclusive). Defaults to `0`.\n * @param endLine - 0-based end line (exclusive). Defaults to `lineCount()`.\n */\n async md_images(\n startLine?: number,\n endLine?: number\n ): Promise<Array<{ alt: string; url: string; title?: string }>> {\n const lines = await this.cat(startLine, endLine)\n const ast = processor().parse(lines.join('\\n'))\n const results: Array<{ alt: string; url: string; title?: string }> = []\n visit(ast, 'image', (node: Image) => {\n results.push({\n alt: node.alt ?? '',\n url: node.url,\n title: node.title ?? undefined,\n })\n })\n return results\n }\n\n /**\n * Returns all document text with markup stripped, for the specified line range.\n *\n * @remarks\n * Uses `mdast-util-to-string` to extract plain text from the AST — code, link text, and\n * alt text are included; markdown syntax is removed.\n *\n * @param startLine - 0-based start line (inclusive). Defaults to `0`.\n * @param endLine - 0-based end line (exclusive). Defaults to `lineCount()`.\n */\n async md_text(startLine?: number, endLine?: number): Promise<string> {\n const lines = await this.cat(startLine, endLine)\n const ast = processor().parse(lines.join('\\n'))\n return mdastToString(ast)\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"spooled_markdown_artifact-CALSDxIx.js","names":["#format","#resolveFormat","#resolveRecords","#parsed","#resolveIndex","#index","#frontmatter"],"sources":["../src/lib/classes/spooled_json_artifact.ts","../src/lib/classes/spooled_markdown_artifact.ts"],"sourcesContent":["import { default as JSON5 } from 'json5'\nimport { JSONPath } from 'jsonpath-plus'\nimport { validator } from '@nhtio/validation'\nimport { ArtifactTool } from './artifact_tool'\nimport { ToolRegistry } from './tool_registry'\nimport { isInstanceOf, isObject } from '../utils/guards'\nimport { SpooledArtifact, defaultSerialise } from './spooled_artifact'\nimport type { SpoolReader } from '../contracts/spool_reader'\nimport type { ToolMethodDescriptor } from './spooled_artifact'\nimport type { DispatchContext } from '../contracts/dispatch_context'\n\n/**\n * The set of JSON-derived formats that {@link SpooledJsonArtifact} can handle.\n *\n * @remarks\n * - `json` — a single JSON value spanning the entire artifact (strict RFC 8259).\n * - `json5` — a single JSON5 value spanning the entire artifact; permits comments, trailing\n * commas, unquoted keys, and other relaxed syntax via the `json5` package.\n * - `jsonl` — newline-delimited JSON; each non-empty line is an independent JSON value.\n * - `ndjson` — alias for `jsonl`; both names are accepted and behave identically.\n */\nexport type JsonArtifactFormat = 'json' | 'json5' | 'jsonl' | 'ndjson'\n\n/**\n * Detects the {@link JsonArtifactFormat} of a raw string.\n *\n * @remarks\n * Detection strategy (in order):\n * 1. If the content parses as strict JSON → `json`.\n * 2. If every non-empty line parses as strict JSON → `jsonl`.\n * 3. If the content parses as JSON5 → `json5`.\n * 4. Otherwise throws.\n *\n * Strict JSON is tried before JSON5 so that well-formed JSON files are not unnecessarily\n * classified as JSON5.\n *\n * @param content - The full artifact text to inspect.\n * @returns The inferred format.\n * @throws `Error` when the content cannot be classified as any supported JSON format.\n */\nfunction inferFormat(content: string): JsonArtifactFormat {\n const trimmed = content.trim()\n\n // 1. Try strict JSON\n try {\n JSON.parse(trimmed)\n return 'json'\n } catch {\n // fall through\n }\n\n // 2. Try JSONL (every non-empty line is valid JSON)\n const nonEmptyLines = trimmed.split('\\n').filter((l) => l.trim().length > 0)\n if (\n nonEmptyLines.length > 0 &&\n nonEmptyLines.every((l) => {\n try {\n JSON.parse(l)\n return true\n } catch {\n return false\n }\n })\n ) {\n return 'jsonl'\n }\n\n // 3. Try JSON5\n try {\n JSON5.parse(trimmed)\n return 'json5'\n } catch {\n // fall through\n }\n\n throw new Error('Unable to infer JSON format: content is not valid JSON, JSONL, NDJSON, or JSON5')\n}\n\n/**\n * A {@link @nhtio/adk!SpooledArtifact} specialisation that adds JSON-aware read operations.\n *\n * @typeParam T - The expected shape of each parsed record. Defaults to `unknown`.\n *\n * @remarks\n * Construct with an optional `format` hint. When omitted the format is auto-detected on first\n * access by reading the full artifact and running {@link inferFormat}. Once detected (or\n * provided), the format is cached for the lifetime of the instance.\n *\n * All JSON methods are async, consistent with {@link @nhtio/adk!SpooledArtifact}.\n *\n * Path-based methods (`json_get`, `json_filter`, `json_pluck`) use\n * [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath) expressions. Full JSONPath syntax\n * is supported, including recursive descent (`..`), filter expressions (`[?(@.age > 18)]`),\n * and union selectors.\n */\nexport class SpooledJsonArtifact<T = unknown> extends SpooledArtifact {\n #format: JsonArtifactFormat | undefined\n #parsed: T[] | undefined\n\n /**\n * @param reader - The backing store to read from.\n * @param format - Optional format hint. When omitted, the format is inferred on first access.\n */\n constructor(reader: SpoolReader, format?: JsonArtifactFormat) {\n super(reader)\n this.#format = format\n }\n\n /**\n * Returns `true` if `value` is a {@link SpooledJsonArtifact} instance.\n *\n * @remarks\n * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard: `instanceof` first, then\n * `Symbol.hasInstance`, then a `constructor.name` fallback. Matches the pattern used by every\n * other class guard in the ADK; safe against the dual-module-copy case where two distinct\n * `SpooledJsonArtifact` classes coexist in the same realm.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link SpooledJsonArtifact} instance.\n */\n public static isSpooledJsonArtifact(value: unknown): value is SpooledJsonArtifact {\n return isInstanceOf(value, 'SpooledJsonArtifact', SpooledJsonArtifact)\n }\n\n /**\n * The JSON-specific artifact-query descriptors this class adds on top of the base set.\n *\n * @remarks\n * Lists `artifact_json_type`, `artifact_json_keys`, `artifact_json_length`,\n * `artifact_json_get`, `artifact_json_filter`, `artifact_json_slice`, `artifact_json_pluck`.\n * The base seven descriptors (`artifact_head`, etc.) are NOT included here — they are\n * forged separately by {@link SpooledJsonArtifact.forgeTools}, which calls\n * `SpooledArtifact.forgeTools(ctx)` to produce the base-narrowed tools and then registers\n * its own JSON tools on the result. Downstream consumers building custom subclasses\n * should follow the same pattern: own only your own descriptors; override `forgeTools` to\n * compose with the base output.\n */\n public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n {\n name: 'artifact_json_type',\n method: 'json_type',\n description:\n 'Return the JSON format (json | json5 | jsonl | ndjson) of a JSON artifact produced earlier in this turn.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_json_keys',\n method: 'json_keys',\n description: 'Return the top-level keys of a JSON artifact produced earlier in this turn.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_json_length',\n method: 'json_length',\n description:\n 'Return the record count of a JSON artifact produced earlier in this turn (1 for json/json5; line count for jsonl/ndjson).',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_json_get',\n method: 'json_get',\n description:\n 'Evaluate a JSONPath expression against a JSON artifact produced earlier in this turn.',\n argsSchema: validator.object({\n path: validator.string().required().description(\"JSONPath expression, e.g. '$.user.name'.\"),\n }),\n },\n {\n name: 'artifact_json_filter',\n method: 'json_filter',\n description:\n 'Return records of a JSON artifact (produced earlier in this turn) matched by a JSONPath filter.',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description(\"JSONPath filter expression, e.g. '$[?(@.age>18)]'.\"),\n }),\n },\n {\n name: 'artifact_json_slice',\n method: 'json_slice',\n description:\n 'Return a slice of records by index range from a JSON artifact produced earlier in this turn.',\n argsSchema: validator.object({\n start: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start index (inclusive).'),\n end: validator.number().integer().min(0).optional().description('End index (exclusive).'),\n }),\n },\n {\n name: 'artifact_json_pluck',\n method: 'json_pluck',\n description:\n 'Return all values matched by a JSONPath expression across every record of a JSON artifact produced earlier in this turn.',\n argsSchema: validator.object({\n path: validator.string().required().description(\"JSONPath expression, e.g. '$..name'.\"),\n }),\n },\n ])\n\n /**\n * Forges base-class tools plus JSON-specific tools narrowed to {@link SpooledJsonArtifact}.\n *\n * @remarks\n * Standard subclass extension pattern: call `SpooledArtifact.forgeTools(ctx)` to produce\n * the base seven `artifact_*` tools narrowed to any `SpooledArtifact` in the turn, then\n * register one `ArtifactTool` per JSON-specific descriptor narrowed to JSON artifacts.\n * Downstream consumers building their own subclasses should follow the same shape.\n */\n public static override forgeTools(ctx: DispatchContext): ToolRegistry {\n const registry = SpooledArtifact.forgeTools(ctx)\n const requires = SpooledJsonArtifact\n const compatibleIds = [...ctx.turnToolCalls]\n .filter((tc) => !tc.fromArtifactTool && isInstanceOf(tc.results, requires.name, requires))\n .map((tc) => tc.id)\n if (compatibleIds.length === 0) return registry\n\n for (const descriptor of this.toolMethods) {\n const callIdSchema = validator\n .string()\n .valid(...compatibleIds)\n .required()\n .description('ToolCall id of the artifact to query.')\n\n const argsSchema = (\n descriptor.argsSchema ?? validator.object<Record<string, never>>({})\n ).append({\n callId: callIdSchema,\n })\n\n const tool = new ArtifactTool({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: argsSchema,\n ephemeral: true,\n onCollision: 'replace',\n handler: async (rawArgs, ctxInner) => {\n const args = rawArgs as Record<string, unknown> & { callId: string }\n const tc = [...ctxInner.turnToolCalls].find((t) => t.id === args.callId)\n if (!tc) {\n return `Error: no tool call with id ${args.callId} in this turn`\n }\n const artifact = tc.results\n if (!isInstanceOf(artifact, requires.name, requires)) {\n return `Error: tool call ${args.callId} results are not a ${requires.name} instance`\n }\n const methodArgs: unknown[] = []\n if (\n descriptor.method === 'json_get' ||\n descriptor.method === 'json_filter' ||\n descriptor.method === 'json_pluck'\n ) {\n methodArgs.push(args.path as string)\n } else if (descriptor.method === 'json_slice') {\n methodArgs.push(args.start as number | undefined, args.end as number | undefined)\n }\n const fn = (artifact as unknown as Record<string, (...a: unknown[]) => unknown>)[\n descriptor.method\n ]\n if (typeof fn !== 'function') {\n return `Error: artifact has no method ${descriptor.method}`\n }\n const result = await Promise.resolve(fn.apply(artifact, methodArgs))\n const serialise = descriptor.serialise ?? defaultSerialise\n return serialise(result)\n },\n })\n registry.register(tool)\n }\n return registry\n }\n\n /**\n * Resolves and caches the detected or provided format.\n */\n async #resolveFormat(): Promise<JsonArtifactFormat> {\n if (this.#format !== undefined) {\n return this.#format\n }\n const lines = await this.cat()\n this.#format = inferFormat(lines.join('\\n'))\n return this.#format\n }\n\n /**\n * Parses and caches all records from the artifact.\n *\n * @remarks\n * For `json`/`json5` format: returns a single-element array containing the parsed root value.\n * For `jsonl`/`ndjson` format: returns one element per non-empty line.\n */\n async #resolveRecords(): Promise<T[]> {\n if (this.#parsed !== undefined) {\n return this.#parsed\n }\n const format = await this.#resolveFormat()\n const lines = await this.cat()\n if (format === 'json') {\n this.#parsed = [JSON.parse(lines.join('\\n')) as T]\n } else if (format === 'json5') {\n this.#parsed = [JSON5.parse(lines.join('\\n')) as T]\n } else {\n // jsonl / ndjson\n this.#parsed = lines.filter((l) => l.trim().length > 0).map((l) => JSON.parse(l) as T)\n }\n return this.#parsed\n }\n\n /**\n * Returns the detected or provided format for this artifact.\n *\n * @returns One of `'json'`, `'json5'`, `'jsonl'`, or `'ndjson'`.\n */\n async json_type(): Promise<JsonArtifactFormat> {\n return this.#resolveFormat()\n }\n\n /**\n * Returns the top-level keys of the parsed content.\n *\n * @remarks\n * - For `json`/`json5`: returns the keys of the root object, or `undefined` when the root is\n * not a plain object (e.g. an array or scalar).\n * - For `jsonl`/`ndjson`: returns the union of keys across all records that are plain objects.\n * Duplicate keys are deduplicated.\n *\n * @returns Array of key strings, or `undefined` when no object keys are present.\n */\n async json_keys(): Promise<string[] | undefined> {\n const records = await this.#resolveRecords()\n const format = await this.#resolveFormat()\n if (format === 'json' || format === 'json5') {\n const root = records[0]\n if (isObject(root)) {\n return Object.keys(root as object)\n }\n return undefined\n }\n const keySet = new Set<string>()\n for (const record of records) {\n if (isObject(record)) {\n for (const key of Object.keys(record as object)) {\n keySet.add(key)\n }\n }\n }\n return keySet.size > 0 ? Array.from(keySet) : undefined\n }\n\n /**\n * Returns the total number of records in the artifact.\n *\n * @remarks\n * - For `json`/`json5`: always `1` (the entire artifact is a single value).\n * - For `jsonl`/`ndjson`: the number of non-empty lines.\n *\n * @returns The record count.\n */\n async json_length(): Promise<number> {\n const records = await this.#resolveRecords()\n return records.length\n }\n\n /**\n * Evaluates a JSONPath expression against the parsed content.\n *\n * @remarks\n * Uses [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath). Full JSONPath syntax is\n * supported: recursive descent (`$..*`), filter expressions (`$[?(@.age > 18)]`), union\n * selectors, and more.\n *\n * - For `json`/`json5`: evaluates the expression against the root value.\n * - For `jsonl`/`ndjson`: evaluates the expression against each record and returns a flat\n * array of all matches across all records.\n *\n * @param path - A JSONPath expression (e.g. `'$.user.address.city'`, `'$..name'`).\n * @returns Array of matched values. Empty array when no matches are found.\n */\n async json_get(path: string): Promise<unknown[]> {\n const records = await this.#resolveRecords()\n const format = await this.#resolveFormat()\n if (format === 'json' || format === 'json5') {\n return JSONPath({ path, json: records[0] as object })\n }\n return records.flatMap((r) => JSONPath({ path, json: r as object }))\n }\n\n /**\n * Returns a slice of the parsed records by index range.\n *\n * @remarks\n * For `json`/`json5`: always returns `[root]` — the artifact is a single record so slicing is\n * not meaningful. For `jsonl`/`ndjson`: behaves like `Array.prototype.slice`.\n *\n * @param start - Start index (inclusive). Defaults to `0`.\n * @param end - End index (exclusive). Defaults to the record count.\n * @returns Array of sliced records.\n */\n async json_slice(start?: number, end?: number): Promise<T[]> {\n const records = await this.#resolveRecords()\n const format = await this.#resolveFormat()\n if (format === 'json' || format === 'json5') {\n return records\n }\n return records.slice(start, end)\n }\n\n /**\n * Returns records matched by a JSONPath filter expression.\n *\n * @remarks\n * Evaluates `path` against each record and returns those for which the expression produces at\n * least one match. For `json`/`json5`, evaluates against the root value and returns it in an\n * array if matched.\n *\n * @param path - A JSONPath expression (e.g. `'$[?(@.status === \"active\")]'`).\n * @returns Array of matching records.\n */\n async json_filter(path: string): Promise<T[]> {\n const records = await this.#resolveRecords()\n return records.filter((r) => {\n const matches = JSONPath({ path, json: r as object })\n return Array.isArray(matches) && matches.length > 0\n })\n }\n\n /**\n * Returns all values matched by a JSONPath expression across every record.\n *\n * @remarks\n * Convenience over {@link SpooledJsonArtifact.json_get} with an identical signature — use\n * whichever name better communicates intent at the call site. `json_pluck` reads well for\n * extracting a single field column; `json_get` reads well for structured queries.\n *\n * @param path - A JSONPath expression (e.g. `'$..name'`).\n * @returns Array of matched values.\n */\n async json_pluck(path: string): Promise<unknown[]> {\n return this.json_get(path)\n }\n}\n","import { remark } from 'remark'\nimport { visit } from 'unist-util-visit'\nimport { load as yamlLoad } from 'js-yaml'\nimport { validator } from '@nhtio/validation'\nimport { isInstanceOf } from '../utils/guards'\nimport { ArtifactTool } from './artifact_tool'\nimport { ToolRegistry } from './tool_registry'\nimport { default as remarkGfm } from 'remark-gfm'\nimport { toString as mdastToString } from 'mdast-util-to-string'\nimport { default as remarkFrontmatter } from 'remark-frontmatter'\nimport { SpooledArtifact, defaultSerialise } from './spooled_artifact'\nimport type { Root, Link, Image } from 'mdast'\nimport type { SpoolReader } from '../contracts/spool_reader'\nimport type { ToolMethodDescriptor } from './spooled_artifact'\nimport type { DispatchContext } from '../contracts/dispatch_context'\n\n/**\n * A single heading entry in the document's structural index.\n *\n * @remarks\n * `startLine` is the 0-based line of the heading itself. `endLine` is the 0-based index of the\n * last line belonging to this section (inclusive) — the line immediately before the next heading\n * of equal or lesser depth, or the last line of the document.\n */\nexport interface MarkdownHeadingEntry {\n /** ATX heading depth: 1 (`#`) through 6 (`######`). */\n depth: 1 | 2 | 3 | 4 | 5 | 6\n /** The heading text with the leading `#` prefix stripped and trimmed. */\n text: string\n /** 0-based line index of the heading line itself. */\n startLine: number\n /** 0-based line index of the last line in this section (inclusive). */\n endLine: number\n}\n\n/**\n * A single fenced code block entry in the document's structural index.\n */\nexport interface MarkdownCodeEntry {\n /** The language identifier immediately after the opening fence, or `null` when absent. */\n lang: string | null\n /** 0-based line index of the opening fence line. */\n startLine: number\n /** 0-based line index of the closing fence line. */\n endLine: number\n}\n\ninterface MarkdownIndex {\n headings: MarkdownHeadingEntry[]\n codeBlocks: MarkdownCodeEntry[]\n}\n\n/**\n * A section of a markdown document as returned by {@link SpooledMarkdownArtifact.md_sections}.\n *\n * @remarks\n * Contains only line-range metadata — no content is fetched until the caller explicitly\n * requests it via `cat(bodyStartLine, bodyEndLine + 1)`.\n */\nexport interface MarkdownSection {\n depth: 1 | 2 | 3 | 4 | 5 | 6\n /** The heading text. */\n heading: string\n /** 0-based line of the heading itself. */\n headingLine: number\n /** 0-based line of the first body line (heading line + 1). */\n bodyStartLine: number\n /** 0-based line of the last body line (inclusive). */\n bodyEndLine: number\n}\n\n/**\n * Returns a configured remark processor with frontmatter and GFM support.\n */\nfunction processor() {\n return remark().use(remarkFrontmatter).use(remarkGfm)\n}\n\n/**\n * Parses a heading line (e.g. `## My Heading`) and returns `{ depth, text }`, or `null` when\n * the line is not an ATX heading.\n */\nfunction parseHeadingLine(line: string): { depth: 1 | 2 | 3 | 4 | 5 | 6; text: string } | null {\n const match = /^(#{1,6})\\s+(.*)$/.exec(line)\n if (!match) return null\n const depth = match[1].length as 1 | 2 | 3 | 4 | 5 | 6\n return { depth, text: match[2].trim() }\n}\n\n/**\n * Returns the length of a fence marker at the start of `line` (3+), or `0` if the line is not\n * a fence opener/closer. Handles both backtick (` ``` `) and tilde (`~~~`) fences.\n */\nfunction fenceLength(line: string): number {\n const trimmed = line.trimStart()\n const match = /^(`{3,}|~{3,})/.exec(trimmed)\n return match ? match[1].length : 0\n}\n\n/**\n * Extracts the language identifier from a fence opener line (e.g. ` ```ts ` → `'ts'`), or\n * `null` when none is present.\n */\nfunction fenceLang(line: string): string | null {\n const trimmed = line.trimStart()\n const match = /^(?:`{3,}|~{3,})(\\S+)/.exec(trimmed)\n return match ? match[1] : null\n}\n\n/**\n * A {@link @nhtio/adk!SpooledArtifact} specialisation that adds markdown-aware structural queries.\n *\n * @remarks\n * Designed for large markdown documents where loading the full content into memory is\n * impractical. The structural index (heading positions, code block positions) is built by a\n * single line-by-line scan of the {@link @nhtio/adk!SpoolReader} without retaining any content. Only the\n * tiny metadata index and the parsed frontmatter object are cached.\n *\n * Content retrieval is always bounded — use `cat(start, end)` or the `startLine`/`endLine`\n * parameters on inline methods to fetch only the lines you need.\n *\n * Inline methods (`md_links`, `md_images`, `md_text`, `md_ast`) accept optional line-range\n * arguments. Without a range they read the full document — documented trade-off, caller\n * responsibility to bound the range for large documents.\n *\n * The processor always applies `remark-gfm` (tables, task lists, strikethrough, autolinks)\n * in addition to standard CommonMark and YAML frontmatter.\n */\nexport class SpooledMarkdownArtifact extends SpooledArtifact {\n #index: MarkdownIndex | undefined\n #frontmatter: Record<string, unknown> | null | undefined\n\n /**\n * @param reader - The backing store to read from.\n */\n constructor(reader: SpoolReader) {\n super(reader)\n }\n\n /**\n * Returns `true` if `value` is a {@link SpooledMarkdownArtifact} instance.\n *\n * @remarks\n * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard: `instanceof` first, then\n * `Symbol.hasInstance`, then a `constructor.name` fallback. Matches the pattern used by every\n * other class guard in the ADK; safe against the dual-module-copy case where two distinct\n * `SpooledMarkdownArtifact` classes coexist in the same realm.\n */\n public static isSpooledMarkdownArtifact(value: unknown): value is SpooledMarkdownArtifact {\n return isInstanceOf(value, 'SpooledMarkdownArtifact', SpooledMarkdownArtifact)\n }\n\n /**\n * The markdown-specific artifact-query descriptors this class adds on top of the base set.\n *\n * @remarks\n * Lists `artifact_md_frontmatter`, `artifact_md_headings`, `artifact_md_code_blocks`,\n * `artifact_md_sections`, `artifact_md_links`, `artifact_md_images`, `artifact_md_text`,\n * `artifact_md_ast`. The base seven descriptors (`artifact_head`, etc.) are NOT included\n * here — they are forged separately by {@link SpooledMarkdownArtifact.forgeTools}, which\n * calls `SpooledArtifact.forgeTools(ctx)` to produce the base-narrowed tools and then\n * registers its own markdown tools on the result. Downstream consumers building custom\n * subclasses should follow the same pattern: own only your own descriptors; override\n * `forgeTools` to compose with the base output.\n */\n public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n {\n name: 'artifact_md_frontmatter',\n method: 'md_frontmatter',\n description:\n 'Return parsed YAML frontmatter (or undefined) from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_md_headings',\n method: 'md_headings',\n description:\n 'Return all headings, optionally filtered by depth, from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n depth: validator\n .number()\n .integer()\n .min(1)\n .max(6)\n .optional()\n .description('ATX heading depth (1-6).'),\n }),\n },\n {\n name: 'artifact_md_code_blocks',\n method: 'md_code_blocks',\n description:\n 'Return all fenced code block entries, optionally filtered by language, from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n lang: validator\n .string()\n .optional()\n .description('Language identifier. Pass empty string to match blocks with no lang.'),\n }),\n },\n {\n name: 'artifact_md_sections',\n method: 'md_sections',\n description:\n 'Return document sections (line-range metadata only) from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n depth: validator\n .number()\n .integer()\n .min(1)\n .max(6)\n .optional()\n .description('ATX heading depth (1-6).'),\n }),\n },\n {\n name: 'artifact_md_links',\n method: 'md_links',\n description:\n 'Return all inline and reference links within the given line range from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n startLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start line (inclusive).'),\n endLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('End line (exclusive).'),\n }),\n },\n {\n name: 'artifact_md_images',\n method: 'md_images',\n description:\n 'Return all images within the given line range from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n startLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start line (inclusive).'),\n endLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('End line (exclusive).'),\n }),\n },\n {\n name: 'artifact_md_text',\n method: 'md_text',\n description:\n 'Return plain text with markup stripped, for the given line range, from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n startLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start line (inclusive).'),\n endLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('End line (exclusive).'),\n }),\n },\n {\n name: 'artifact_md_ast',\n method: 'md_ast',\n description:\n 'Return the full MDAST Root for the specified line range from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n startLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start line (inclusive).'),\n endLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('End line (exclusive).'),\n }),\n },\n ])\n\n /**\n * Forges base-class tools plus markdown-specific tools narrowed to\n * {@link SpooledMarkdownArtifact}.\n *\n * @remarks\n * Standard subclass extension pattern: call `SpooledArtifact.forgeTools(ctx)` to produce\n * the base seven `artifact_*` tools narrowed to any `SpooledArtifact` in the turn, then\n * register one `ArtifactTool` per markdown-specific descriptor narrowed to markdown\n * artifacts. Downstream consumers building their own subclasses should follow the same\n * shape.\n */\n public static override forgeTools(ctx: DispatchContext): ToolRegistry {\n const registry = SpooledArtifact.forgeTools(ctx)\n const requires = SpooledMarkdownArtifact\n const compatibleIds = [...ctx.turnToolCalls]\n .filter((tc) => !tc.fromArtifactTool && isInstanceOf(tc.results, requires.name, requires))\n .map((tc) => tc.id)\n if (compatibleIds.length === 0) return registry\n\n for (const descriptor of this.toolMethods) {\n const callIdSchema = validator\n .string()\n .valid(...compatibleIds)\n .required()\n .description('ToolCall id of the artifact to query.')\n\n const argsSchema = (\n descriptor.argsSchema ?? validator.object<Record<string, never>>({})\n ).append({\n callId: callIdSchema,\n })\n\n const tool = new ArtifactTool({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: argsSchema,\n ephemeral: true,\n onCollision: 'replace',\n handler: async (rawArgs, ctxInner) => {\n const args = rawArgs as Record<string, unknown> & { callId: string }\n const tc = [...ctxInner.turnToolCalls].find((t) => t.id === args.callId)\n if (!tc) {\n return `Error: no tool call with id ${args.callId} in this turn`\n }\n const artifact = tc.results\n if (!isInstanceOf(artifact, requires.name, requires)) {\n return `Error: tool call ${args.callId} results are not a ${requires.name} instance`\n }\n const methodArgs: unknown[] = []\n if (descriptor.method === 'md_headings' || descriptor.method === 'md_sections') {\n methodArgs.push(args.depth as number | undefined)\n } else if (descriptor.method === 'md_code_blocks') {\n methodArgs.push(args.lang as string | undefined)\n } else if (\n descriptor.method === 'md_links' ||\n descriptor.method === 'md_images' ||\n descriptor.method === 'md_text' ||\n descriptor.method === 'md_ast'\n ) {\n methodArgs.push(\n args.startLine as number | undefined,\n args.endLine as number | undefined\n )\n }\n const fn = (artifact as unknown as Record<string, (...a: unknown[]) => unknown>)[\n descriptor.method\n ]\n if (typeof fn !== 'function') {\n return `Error: artifact has no method ${descriptor.method}`\n }\n const result = await Promise.resolve(fn.apply(artifact, methodArgs))\n const serialise = descriptor.serialise ?? defaultSerialise\n return serialise(result)\n },\n })\n registry.register(tool)\n }\n return registry\n }\n\n /**\n * Builds the structural index in a single top-to-bottom pass, retaining only metadata.\n */\n async #resolveIndex(): Promise<MarkdownIndex> {\n if (this.#index !== undefined) return this.#index\n\n const count = await this.lineCount()\n const headingsRaw: Array<{ depth: 1 | 2 | 3 | 4 | 5 | 6; text: string; startLine: number }> = []\n const codeBlocks: MarkdownCodeEntry[] = []\n\n let inFrontmatter = false\n let frontmatterClosed = false\n let inCodeBlock = false\n let openFenceLen = 0\n let openFenceStartLine = 0\n let openFenceLang: string | null = null\n\n for (let i = 0; i < count; i++) {\n const rawLine = await this.line(i)\n const l = rawLine ?? ''\n\n // Handle frontmatter block at the top of the document\n if (i === 0 && l.trim() === '---') {\n inFrontmatter = true\n continue\n }\n if (inFrontmatter) {\n if (l.trim() === '---') {\n inFrontmatter = false\n frontmatterClosed = true\n }\n continue\n }\n if (!frontmatterClosed && i === 0) {\n // No frontmatter — treat as normal document from the start\n }\n\n // Handle fenced code blocks\n const fLen = fenceLength(l)\n if (!inCodeBlock && fLen >= 3) {\n inCodeBlock = true\n openFenceLen = fLen\n openFenceStartLine = i\n openFenceLang = fenceLang(l)\n continue\n }\n if (inCodeBlock) {\n // A closing fence must use the same fence character (` or ~) and be at least as long.\n if (fLen >= openFenceLen) {\n const openLine = (await this.line(openFenceStartLine)) ?? ''\n const openChar = openLine.trimStart()[0]\n const closeChar = l.trimStart()[0]\n if (closeChar === openChar) {\n codeBlocks.push({ lang: openFenceLang, startLine: openFenceStartLine, endLine: i })\n inCodeBlock = false\n openFenceLen = 0\n }\n }\n continue\n }\n\n // Detect ATX headings (not inside code blocks, not in frontmatter)\n const heading = parseHeadingLine(l)\n if (heading) {\n headingsRaw.push({ ...heading, startLine: i })\n }\n }\n\n // Unclosed code block — record it anyway\n if (inCodeBlock) {\n codeBlocks.push({ lang: openFenceLang, startLine: openFenceStartLine, endLine: count - 1 })\n }\n\n // Post-process heading endLine values\n const headings: MarkdownHeadingEntry[] = headingsRaw.map((h, idx) => {\n const nextBoundary = headingsRaw.slice(idx + 1).find((n) => n.depth <= h.depth)\n const endLine = nextBoundary ? nextBoundary.startLine - 1 : count - 1\n return { ...h, endLine }\n })\n\n this.#index = { headings, codeBlocks }\n return this.#index\n }\n\n // ── Frontmatter ───────────────────────────────────────────────────────────\n\n /**\n * Returns the parsed YAML frontmatter, or `undefined` when no frontmatter block is present.\n *\n * @remarks\n * Short-circuits after reading the frontmatter block — never reads the document body. Caches\n * the result so subsequent calls are free. The result is `undefined` (not an empty object)\n * when no frontmatter is found, distinguishing \"no frontmatter\" from \"empty frontmatter\".\n */\n async md_frontmatter(): Promise<Record<string, unknown> | undefined> {\n if (this.#frontmatter !== undefined) return this.#frontmatter ?? undefined\n\n const firstLine = await this.line(0)\n if (firstLine?.trim() !== '---') {\n this.#frontmatter = null\n return undefined\n }\n\n const maxScan = Math.min(await this.lineCount(), 200)\n const yamlLines: string[] = []\n let closed = false\n for (let i = 1; i < maxScan; i++) {\n const l = await this.line(i)\n if (l?.trim() === '---') {\n closed = true\n break\n }\n yamlLines.push(l ?? '')\n }\n\n if (!closed) {\n this.#frontmatter = null\n return undefined\n }\n\n this.#frontmatter = yamlLoad(yamlLines.join('\\n')) as Record<string, unknown>\n return this.#frontmatter\n }\n\n // ── Structural index queries ──────────────────────────────────────────────\n\n /**\n * Returns all headings in document order, optionally filtered by depth.\n *\n * @remarks\n * Uses the cached structural index — no content is fetched from the {@link @nhtio/adk!SpoolReader}.\n *\n * @param depth - When provided, only headings at this ATX depth (1–6) are returned.\n */\n async md_headings(depth?: 1 | 2 | 3 | 4 | 5 | 6): Promise<MarkdownHeadingEntry[]> {\n const index = await this.#resolveIndex()\n if (depth === undefined) return index.headings.slice()\n return index.headings.filter((h) => h.depth === depth)\n }\n\n /**\n * Returns all fenced code block entries, optionally filtered by language identifier.\n *\n * @remarks\n * Returns line-range metadata only — no content is fetched. Use `cat(entry.startLine + 1,\n * entry.endLine)` to retrieve the code body (excluding fence lines).\n *\n * @param lang - When provided, only blocks with this exact lang identifier are returned.\n * Pass an empty string to match blocks with no lang identifier.\n */\n async md_code_blocks(lang?: string): Promise<MarkdownCodeEntry[]> {\n const index = await this.#resolveIndex()\n if (lang === undefined) return index.codeBlocks.slice()\n const target = lang === '' ? null : lang\n return index.codeBlocks.filter((b) => b.lang === target)\n }\n\n /**\n * Returns document sections derived from the structural index.\n *\n * @remarks\n * Returns only line-range metadata — body content is never fetched. To retrieve the body of a\n * section, call `cat(section.bodyStartLine, section.bodyEndLine + 1)`.\n *\n * When `depth` is provided, only sections introduced by a heading at that depth are returned;\n * deeper headings become part of the body.\n *\n * @param depth - When provided, only sections at this ATX depth (1–6) are returned.\n */\n async md_sections(depth?: 1 | 2 | 3 | 4 | 5 | 6): Promise<MarkdownSection[]> {\n const index = await this.#resolveIndex()\n const headings =\n depth !== undefined ? index.headings.filter((h) => h.depth === depth) : index.headings\n return headings.map((h) => ({\n depth: h.depth,\n heading: h.text,\n headingLine: h.startLine,\n bodyStartLine: h.startLine + 1,\n bodyEndLine: h.endLine,\n }))\n }\n\n // ── Inline queries (bounded) ──────────────────────────────────────────────\n\n /**\n * Returns the full MDAST Root for the specified line range.\n *\n * @remarks\n * Without a range, reads the full document — for large documents, use\n * {@link SpooledMarkdownArtifact.md_sections} to locate sections and pass\n * bounded line ranges here.\n *\n * @param startLine - 0-based start line (inclusive). Defaults to `0`.\n * @param endLine - 0-based end line (exclusive). Defaults to `lineCount()`.\n */\n async md_ast(startLine?: number, endLine?: number): Promise<Root> {\n const lines = await this.cat(startLine, endLine)\n return processor().parse(lines.join('\\n')) as Root\n }\n\n /**\n * Returns all inline and reference links in the specified line range.\n *\n * @param startLine - 0-based start line (inclusive). Defaults to `0`.\n * @param endLine - 0-based end line (exclusive). Defaults to `lineCount()`.\n */\n async md_links(\n startLine?: number,\n endLine?: number\n ): Promise<Array<{ text: string; url: string; title?: string }>> {\n const lines = await this.cat(startLine, endLine)\n const ast = processor().parse(lines.join('\\n'))\n const results: Array<{ text: string; url: string; title?: string }> = []\n visit(ast, 'link', (node: Link) => {\n results.push({\n text: mdastToString(node),\n url: node.url,\n title: node.title ?? undefined,\n })\n })\n return results\n }\n\n /**\n * Returns all images in the specified line range.\n *\n * @param startLine - 0-based start line (inclusive). Defaults to `0`.\n * @param endLine - 0-based end line (exclusive). Defaults to `lineCount()`.\n */\n async md_images(\n startLine?: number,\n endLine?: number\n ): Promise<Array<{ alt: string; url: string; title?: string }>> {\n const lines = await this.cat(startLine, endLine)\n const ast = processor().parse(lines.join('\\n'))\n const results: Array<{ alt: string; url: string; title?: string }> = []\n visit(ast, 'image', (node: Image) => {\n results.push({\n alt: node.alt ?? '',\n url: node.url,\n title: node.title ?? undefined,\n })\n })\n return results\n }\n\n /**\n * Returns all document text with markup stripped, for the specified line range.\n *\n * @remarks\n * Uses `mdast-util-to-string` to extract plain text from the AST — code, link text, and\n * alt text are included; markdown syntax is removed.\n *\n * @param startLine - 0-based start line (inclusive). Defaults to `0`.\n * @param endLine - 0-based end line (exclusive). Defaults to `lineCount()`.\n */\n async md_text(startLine?: number, endLine?: number): Promise<string> {\n const lines = await this.cat(startLine, endLine)\n const ast = processor().parse(lines.join('\\n'))\n return mdastToString(ast)\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as isObject, s as isInstanceOf } from "./tool_registry-
|
|
2
|
-
import { i as ArtifactTool, n as defaultSerialise, t as SpooledArtifact } from "./spooled_artifact-
|
|
1
|
+
import { c as isObject, s as isInstanceOf } from "./tool_registry-D1pSSlsd.mjs";
|
|
2
|
+
import { i as ArtifactTool, n as defaultSerialise, t as SpooledArtifact } from "./spooled_artifact-CHoZgWwI.mjs";
|
|
3
3
|
import { validator } from "@nhtio/validation";
|
|
4
4
|
import JSON5 from "json5";
|
|
5
5
|
import { JSONPath } from "jsonpath-plus";
|
|
@@ -768,4 +768,4 @@ var SpooledMarkdownArtifact = class SpooledMarkdownArtifact extends SpooledArtif
|
|
|
768
768
|
//#endregion
|
|
769
769
|
export { SpooledJsonArtifact as n, SpooledMarkdownArtifact as t };
|
|
770
770
|
|
|
771
|
-
//# sourceMappingURL=spooled_markdown_artifact-
|
|
771
|
+
//# sourceMappingURL=spooled_markdown_artifact-Ci5UL7l4.mjs.map
|