@nhtio/adk 1.20260607.2 → 1.20260609.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (501) hide show
  1. package/CHANGELOG.md +185 -0
  2. package/batteries/embeddings/openai/adapter.cjs +1 -1
  3. package/batteries/embeddings/openai/adapter.mjs +1 -1
  4. package/batteries/embeddings/openai/exceptions.cjs +1 -1
  5. package/batteries/embeddings/openai/exceptions.mjs +1 -1
  6. package/batteries/embeddings/openai/types.d.ts +7 -0
  7. package/batteries/embeddings/webllm/adapter.cjs +1 -1
  8. package/batteries/embeddings/webllm/adapter.mjs +1 -1
  9. package/batteries/embeddings/webllm/exceptions.cjs +1 -1
  10. package/batteries/embeddings/webllm/exceptions.mjs +1 -1
  11. package/batteries/llm/chat_common/helpers.d.ts +165 -0
  12. package/batteries/llm/chat_common/types.d.ts +309 -0
  13. package/batteries/llm/index.d.ts +5 -0
  14. package/batteries/llm/ollama/adapter.cjs +736 -0
  15. package/batteries/llm/ollama/adapter.cjs.map +1 -0
  16. package/batteries/llm/ollama/adapter.d.ts +64 -0
  17. package/batteries/llm/ollama/adapter.mjs +734 -0
  18. package/batteries/llm/ollama/adapter.mjs.map +1 -0
  19. package/batteries/llm/ollama/exceptions.cjs +105 -0
  20. package/batteries/llm/ollama/exceptions.cjs.map +1 -0
  21. package/batteries/llm/ollama/exceptions.d.ts +112 -0
  22. package/batteries/llm/ollama/exceptions.mjs +96 -0
  23. package/batteries/llm/ollama/exceptions.mjs.map +1 -0
  24. package/batteries/llm/ollama/helpers.cjs +487 -0
  25. package/batteries/llm/ollama/helpers.cjs.map +1 -0
  26. package/batteries/llm/ollama/helpers.d.ts +158 -0
  27. package/batteries/llm/ollama/helpers.mjs +450 -0
  28. package/batteries/llm/ollama/helpers.mjs.map +1 -0
  29. package/batteries/llm/ollama/index.d.ts +29 -0
  30. package/batteries/llm/ollama/types.cjs +2 -0
  31. package/batteries/llm/ollama/types.d.ts +334 -0
  32. package/batteries/llm/ollama/types.mjs +0 -0
  33. package/batteries/llm/ollama/validation.cjs +130 -0
  34. package/batteries/llm/ollama/validation.cjs.map +1 -0
  35. package/batteries/llm/ollama/validation.d.ts +31 -0
  36. package/batteries/llm/ollama/validation.mjs +127 -0
  37. package/batteries/llm/ollama/validation.mjs.map +1 -0
  38. package/batteries/llm/ollama.cjs +54 -0
  39. package/batteries/llm/ollama.mjs +6 -0
  40. package/batteries/llm/openai_chat_completions/adapter.cjs +36 -19
  41. package/batteries/llm/openai_chat_completions/adapter.cjs.map +1 -1
  42. package/batteries/llm/openai_chat_completions/adapter.mjs +23 -6
  43. package/batteries/llm/openai_chat_completions/adapter.mjs.map +1 -1
  44. package/batteries/llm/openai_chat_completions/exceptions.cjs +1 -1
  45. package/batteries/llm/openai_chat_completions/exceptions.mjs +1 -1
  46. package/batteries/llm/openai_chat_completions/helpers.cjs +80 -320
  47. package/batteries/llm/openai_chat_completions/helpers.cjs.map +1 -1
  48. package/batteries/llm/openai_chat_completions/helpers.d.ts +68 -144
  49. package/batteries/llm/openai_chat_completions/helpers.mjs +40 -280
  50. package/batteries/llm/openai_chat_completions/helpers.mjs.map +1 -1
  51. package/batteries/llm/openai_chat_completions/types.d.ts +273 -181
  52. package/batteries/llm/openai_chat_completions/validation.cjs +2 -2
  53. package/batteries/llm/openai_chat_completions/validation.cjs.map +1 -1
  54. package/batteries/llm/openai_chat_completions/validation.mjs +2 -2
  55. package/batteries/llm/openai_chat_completions/validation.mjs.map +1 -1
  56. package/batteries/llm/openai_chat_completions.cjs +29 -28
  57. package/batteries/llm/openai_chat_completions.mjs +2 -1
  58. package/batteries/llm/webllm_chat_completions/adapter.cjs +38 -19
  59. package/batteries/llm/webllm_chat_completions/adapter.cjs.map +1 -1
  60. package/batteries/llm/webllm_chat_completions/adapter.d.ts +18 -0
  61. package/batteries/llm/webllm_chat_completions/adapter.mjs +25 -6
  62. package/batteries/llm/webllm_chat_completions/adapter.mjs.map +1 -1
  63. package/batteries/llm/webllm_chat_completions/exceptions.cjs +1 -1
  64. package/batteries/llm/webllm_chat_completions/exceptions.mjs +1 -1
  65. package/batteries/llm/webllm_chat_completions/helpers.cjs +29 -28
  66. package/batteries/llm/webllm_chat_completions/helpers.mjs +2 -1
  67. package/batteries/llm/webllm_chat_completions/types.d.ts +21 -0
  68. package/batteries/llm/webllm_chat_completions/validation.cjs +13 -1
  69. package/batteries/llm/webllm_chat_completions/validation.cjs.map +1 -1
  70. package/batteries/llm/webllm_chat_completions/validation.d.ts +12 -0
  71. package/batteries/llm/webllm_chat_completions/validation.mjs +13 -1
  72. package/batteries/llm/webllm_chat_completions/validation.mjs.map +1 -1
  73. package/batteries/llm/webllm_chat_completions.cjs +29 -28
  74. package/batteries/llm/webllm_chat_completions.mjs +2 -1
  75. package/batteries/llm.cjs +44 -28
  76. package/batteries/llm.mjs +9 -4
  77. package/batteries/storage/flydrive.cjs +1 -1
  78. package/batteries/storage/flydrive.mjs +1 -1
  79. package/batteries/storage/in_memory/index.d.ts +1 -1
  80. package/batteries/storage/in_memory.cjs +2 -2
  81. package/batteries/storage/in_memory.cjs.map +1 -1
  82. package/batteries/storage/in_memory.mjs +2 -2
  83. package/batteries/storage/in_memory.mjs.map +1 -1
  84. package/batteries/storage/opfs/index.d.ts +19 -0
  85. package/batteries/storage/opfs.cjs +1 -1
  86. package/batteries/storage/opfs.cjs.map +1 -1
  87. package/batteries/storage/opfs.mjs +1 -1
  88. package/batteries/storage/opfs.mjs.map +1 -1
  89. package/batteries/tools/color.cjs +3 -2
  90. package/batteries/tools/color.cjs.map +1 -1
  91. package/batteries/tools/color.mjs +3 -2
  92. package/batteries/tools/color.mjs.map +1 -1
  93. package/batteries/tools/comparison.cjs +4 -3
  94. package/batteries/tools/comparison.cjs.map +1 -1
  95. package/batteries/tools/comparison.mjs +4 -3
  96. package/batteries/tools/comparison.mjs.map +1 -1
  97. package/batteries/tools/data_structure.cjs +30 -10
  98. package/batteries/tools/data_structure.cjs.map +1 -1
  99. package/batteries/tools/data_structure.mjs +30 -10
  100. package/batteries/tools/data_structure.mjs.map +1 -1
  101. package/batteries/tools/datetime_extended.cjs +5 -10
  102. package/batteries/tools/datetime_extended.cjs.map +1 -1
  103. package/batteries/tools/datetime_extended.mjs +5 -10
  104. package/batteries/tools/datetime_extended.mjs.map +1 -1
  105. package/batteries/tools/datetime_math.cjs +2 -2
  106. package/batteries/tools/datetime_math.mjs +2 -2
  107. package/batteries/tools/encoding.cjs +13 -4
  108. package/batteries/tools/encoding.cjs.map +1 -1
  109. package/batteries/tools/encoding.mjs +13 -4
  110. package/batteries/tools/encoding.mjs.map +1 -1
  111. package/batteries/tools/formatting.cjs +4 -4
  112. package/batteries/tools/formatting.cjs.map +1 -1
  113. package/batteries/tools/formatting.mjs +4 -4
  114. package/batteries/tools/formatting.mjs.map +1 -1
  115. package/batteries/tools/geo_basics.cjs +2 -2
  116. package/batteries/tools/geo_basics.mjs +2 -2
  117. package/batteries/tools/index.d.ts +1 -0
  118. package/batteries/tools/math.cjs +10 -8
  119. package/batteries/tools/math.cjs.map +1 -1
  120. package/batteries/tools/math.mjs +10 -8
  121. package/batteries/tools/math.mjs.map +1 -1
  122. package/batteries/tools/memory.cjs +5 -5
  123. package/batteries/tools/memory.mjs +5 -5
  124. package/batteries/tools/parsing.cjs +9 -5
  125. package/batteries/tools/parsing.cjs.map +1 -1
  126. package/batteries/tools/parsing.mjs +9 -5
  127. package/batteries/tools/parsing.mjs.map +1 -1
  128. package/batteries/tools/retrievables.cjs +4 -4
  129. package/batteries/tools/retrievables.mjs +4 -4
  130. package/batteries/tools/searxng/exceptions.d.ts +21 -0
  131. package/batteries/tools/searxng/index.d.ts +150 -0
  132. package/batteries/tools/searxng.cjs +5 -0
  133. package/batteries/tools/searxng.mjs +2 -0
  134. package/batteries/tools/standing_instructions.cjs +4 -4
  135. package/batteries/tools/standing_instructions.mjs +4 -4
  136. package/batteries/tools/statistics.cjs +54 -43
  137. package/batteries/tools/statistics.cjs.map +1 -1
  138. package/batteries/tools/statistics.mjs +54 -43
  139. package/batteries/tools/statistics.mjs.map +1 -1
  140. package/batteries/tools/string_processing.cjs +5 -5
  141. package/batteries/tools/string_processing.cjs.map +1 -1
  142. package/batteries/tools/string_processing.mjs +5 -5
  143. package/batteries/tools/string_processing.mjs.map +1 -1
  144. package/batteries/tools/structured_data.cjs +8 -13
  145. package/batteries/tools/structured_data.cjs.map +1 -1
  146. package/batteries/tools/structured_data.mjs +8 -13
  147. package/batteries/tools/structured_data.mjs.map +1 -1
  148. package/batteries/tools/text_analysis.cjs +3 -3
  149. package/batteries/tools/text_analysis.mjs +3 -3
  150. package/batteries/tools/text_comparison.cjs +2 -2
  151. package/batteries/tools/text_comparison.mjs +2 -2
  152. package/batteries/tools/time.cjs +2 -2
  153. package/batteries/tools/time.mjs +2 -2
  154. package/batteries/tools/unit_conversion.cjs +10 -8
  155. package/batteries/tools/unit_conversion.cjs.map +1 -1
  156. package/batteries/tools/unit_conversion.mjs +10 -8
  157. package/batteries/tools/unit_conversion.mjs.map +1 -1
  158. package/batteries/tools.cjs +3 -0
  159. package/batteries/tools.mjs +2 -1
  160. package/batteries/vector/arangodb/index.d.ts +2 -0
  161. package/batteries/vector/arangodb.cjs +2 -1
  162. package/batteries/vector/arangodb.cjs.map +1 -1
  163. package/batteries/vector/arangodb.mjs +2 -1
  164. package/batteries/vector/arangodb.mjs.map +1 -1
  165. package/batteries/vector/builder.cjs +31 -0
  166. package/batteries/vector/builder.cjs.map +1 -1
  167. package/batteries/vector/builder.d.ts +58 -0
  168. package/batteries/vector/builder.mjs +31 -0
  169. package/batteries/vector/builder.mjs.map +1 -1
  170. package/batteries/vector/chroma/index.d.ts +4 -0
  171. package/batteries/vector/chroma.cjs +3 -0
  172. package/batteries/vector/chroma.cjs.map +1 -1
  173. package/batteries/vector/chroma.mjs +3 -0
  174. package/batteries/vector/chroma.mjs.map +1 -1
  175. package/batteries/vector/clickhouse/index.d.ts +2 -0
  176. package/batteries/vector/clickhouse.cjs +2 -1
  177. package/batteries/vector/clickhouse.cjs.map +1 -1
  178. package/batteries/vector/clickhouse.mjs +2 -1
  179. package/batteries/vector/clickhouse.mjs.map +1 -1
  180. package/batteries/vector/cloudflare/index.d.ts +2 -0
  181. package/batteries/vector/cloudflare.cjs +2 -1
  182. package/batteries/vector/cloudflare.cjs.map +1 -1
  183. package/batteries/vector/cloudflare.mjs +2 -1
  184. package/batteries/vector/cloudflare.mjs.map +1 -1
  185. package/batteries/vector/conformance/index.d.ts +22 -0
  186. package/batteries/vector/conformance.cjs +22 -0
  187. package/batteries/vector/conformance.cjs.map +1 -1
  188. package/batteries/vector/conformance.mjs +22 -0
  189. package/batteries/vector/conformance.mjs.map +1 -1
  190. package/batteries/vector/contract.cjs +22 -0
  191. package/batteries/vector/contract.cjs.map +1 -1
  192. package/batteries/vector/contract.d.ts +51 -0
  193. package/batteries/vector/contract.mjs +22 -0
  194. package/batteries/vector/contract.mjs.map +1 -1
  195. package/batteries/vector/couchbase/index.d.ts +2 -0
  196. package/batteries/vector/couchbase.cjs +2 -1
  197. package/batteries/vector/couchbase.cjs.map +1 -1
  198. package/batteries/vector/couchbase.mjs +2 -1
  199. package/batteries/vector/couchbase.mjs.map +1 -1
  200. package/batteries/vector/duckdb/index.d.ts +2 -0
  201. package/batteries/vector/duckdb.cjs +2 -1
  202. package/batteries/vector/duckdb.cjs.map +1 -1
  203. package/batteries/vector/duckdb.mjs +2 -1
  204. package/batteries/vector/duckdb.mjs.map +1 -1
  205. package/batteries/vector/elasticsearch/index.d.ts +2 -0
  206. package/batteries/vector/elasticsearch.cjs +2 -1
  207. package/batteries/vector/elasticsearch.cjs.map +1 -1
  208. package/batteries/vector/elasticsearch.mjs +2 -1
  209. package/batteries/vector/elasticsearch.mjs.map +1 -1
  210. package/batteries/vector/exceptions.cjs +1 -1
  211. package/batteries/vector/exceptions.mjs +1 -1
  212. package/batteries/vector/factory.cjs +6 -0
  213. package/batteries/vector/factory.cjs.map +1 -1
  214. package/batteries/vector/factory.d.ts +14 -0
  215. package/batteries/vector/factory.mjs +6 -0
  216. package/batteries/vector/factory.mjs.map +1 -1
  217. package/batteries/vector/filters.cjs +22 -1
  218. package/batteries/vector/filters.cjs.map +1 -1
  219. package/batteries/vector/filters.d.ts +38 -0
  220. package/batteries/vector/filters.mjs +22 -1
  221. package/batteries/vector/filters.mjs.map +1 -1
  222. package/batteries/vector/helpers.cjs +13 -0
  223. package/batteries/vector/helpers.cjs.map +1 -1
  224. package/batteries/vector/helpers.d.ts +14 -0
  225. package/batteries/vector/helpers.mjs +13 -0
  226. package/batteries/vector/helpers.mjs.map +1 -1
  227. package/batteries/vector/hnswlib/index.d.ts +2 -0
  228. package/batteries/vector/hnswlib.cjs +2 -1
  229. package/batteries/vector/hnswlib.cjs.map +1 -1
  230. package/batteries/vector/hnswlib.mjs +2 -1
  231. package/batteries/vector/hnswlib.mjs.map +1 -1
  232. package/batteries/vector/in_memory/index.d.ts +1 -0
  233. package/batteries/vector/in_memory.cjs +1 -0
  234. package/batteries/vector/in_memory.cjs.map +1 -1
  235. package/batteries/vector/in_memory.mjs +1 -0
  236. package/batteries/vector/in_memory.mjs.map +1 -1
  237. package/batteries/vector/lancedb/index.d.ts +2 -0
  238. package/batteries/vector/lancedb.cjs +2 -1
  239. package/batteries/vector/lancedb.cjs.map +1 -1
  240. package/batteries/vector/lancedb.mjs +2 -1
  241. package/batteries/vector/lancedb.mjs.map +1 -1
  242. package/batteries/vector/mariadb/index.d.ts +2 -0
  243. package/batteries/vector/mariadb.cjs +2 -1
  244. package/batteries/vector/mariadb.cjs.map +1 -1
  245. package/batteries/vector/mariadb.mjs +2 -1
  246. package/batteries/vector/mariadb.mjs.map +1 -1
  247. package/batteries/vector/meilisearch/index.d.ts +2 -0
  248. package/batteries/vector/meilisearch.cjs +2 -1
  249. package/batteries/vector/meilisearch.cjs.map +1 -1
  250. package/batteries/vector/meilisearch.mjs +2 -1
  251. package/batteries/vector/meilisearch.mjs.map +1 -1
  252. package/batteries/vector/migrate.cjs +18 -1
  253. package/batteries/vector/migrate.cjs.map +1 -1
  254. package/batteries/vector/migrate.d.ts +31 -0
  255. package/batteries/vector/migrate.mjs +18 -1
  256. package/batteries/vector/migrate.mjs.map +1 -1
  257. package/batteries/vector/milvus/index.d.ts +5 -0
  258. package/batteries/vector/milvus.cjs +4 -0
  259. package/batteries/vector/milvus.cjs.map +1 -1
  260. package/batteries/vector/milvus.mjs +4 -0
  261. package/batteries/vector/milvus.mjs.map +1 -1
  262. package/batteries/vector/mongodb/index.d.ts +2 -0
  263. package/batteries/vector/mongodb.cjs +2 -1
  264. package/batteries/vector/mongodb.cjs.map +1 -1
  265. package/batteries/vector/mongodb.mjs +2 -1
  266. package/batteries/vector/mongodb.mjs.map +1 -1
  267. package/batteries/vector/neo4j/index.d.ts +2 -0
  268. package/batteries/vector/neo4j.cjs +2 -1
  269. package/batteries/vector/neo4j.cjs.map +1 -1
  270. package/batteries/vector/neo4j.mjs +2 -1
  271. package/batteries/vector/neo4j.mjs.map +1 -1
  272. package/batteries/vector/opensearch/index.d.ts +2 -0
  273. package/batteries/vector/opensearch.cjs +2 -1
  274. package/batteries/vector/opensearch.cjs.map +1 -1
  275. package/batteries/vector/opensearch.mjs +2 -1
  276. package/batteries/vector/opensearch.mjs.map +1 -1
  277. package/batteries/vector/oracle23ai/index.d.ts +2 -0
  278. package/batteries/vector/oracle23ai.cjs +2 -1
  279. package/batteries/vector/oracle23ai.cjs.map +1 -1
  280. package/batteries/vector/oracle23ai.mjs +2 -1
  281. package/batteries/vector/oracle23ai.mjs.map +1 -1
  282. package/batteries/vector/orama/index.d.ts +1 -0
  283. package/batteries/vector/orama.cjs +1 -0
  284. package/batteries/vector/orama.cjs.map +1 -1
  285. package/batteries/vector/orama.mjs +1 -0
  286. package/batteries/vector/orama.mjs.map +1 -1
  287. package/batteries/vector/pgvector/index.d.ts +9 -2
  288. package/batteries/vector/pgvector.cjs +4 -0
  289. package/batteries/vector/pgvector.cjs.map +1 -1
  290. package/batteries/vector/pgvector.mjs +4 -0
  291. package/batteries/vector/pgvector.mjs.map +1 -1
  292. package/batteries/vector/pinecone/index.d.ts +5 -0
  293. package/batteries/vector/pinecone.cjs +3 -1
  294. package/batteries/vector/pinecone.cjs.map +1 -1
  295. package/batteries/vector/pinecone.mjs +3 -1
  296. package/batteries/vector/pinecone.mjs.map +1 -1
  297. package/batteries/vector/plan.d.ts +27 -0
  298. package/batteries/vector/qdrant/index.d.ts +5 -0
  299. package/batteries/vector/qdrant.cjs +4 -0
  300. package/batteries/vector/qdrant.cjs.map +1 -1
  301. package/batteries/vector/qdrant.mjs +4 -0
  302. package/batteries/vector/qdrant.mjs.map +1 -1
  303. package/batteries/vector/redis/index.d.ts +2 -0
  304. package/batteries/vector/redis.cjs +2 -1
  305. package/batteries/vector/redis.cjs.map +1 -1
  306. package/batteries/vector/redis.mjs +2 -1
  307. package/batteries/vector/redis.mjs.map +1 -1
  308. package/batteries/vector/retrievable.cjs +9 -1
  309. package/batteries/vector/retrievable.cjs.map +1 -1
  310. package/batteries/vector/retrievable.mjs +9 -1
  311. package/batteries/vector/retrievable.mjs.map +1 -1
  312. package/batteries/vector/retrievable_glue.d.ts +21 -0
  313. package/batteries/vector/s3vectors/index.d.ts +2 -0
  314. package/batteries/vector/s3vectors.cjs +2 -1
  315. package/batteries/vector/s3vectors.cjs.map +1 -1
  316. package/batteries/vector/s3vectors.mjs +2 -1
  317. package/batteries/vector/s3vectors.mjs.map +1 -1
  318. package/batteries/vector/schema.cjs +28 -0
  319. package/batteries/vector/schema.cjs.map +1 -1
  320. package/batteries/vector/schema.d.ts +39 -0
  321. package/batteries/vector/schema.mjs +28 -0
  322. package/batteries/vector/schema.mjs.map +1 -1
  323. package/batteries/vector/solr/index.d.ts +2 -0
  324. package/batteries/vector/solr.cjs +2 -1
  325. package/batteries/vector/solr.cjs.map +1 -1
  326. package/batteries/vector/solr.mjs +2 -1
  327. package/batteries/vector/solr.mjs.map +1 -1
  328. package/batteries/vector/sqlite_vec/index.d.ts +6 -3
  329. package/batteries/vector/sqlite_vec.cjs +2 -0
  330. package/batteries/vector/sqlite_vec.cjs.map +1 -1
  331. package/batteries/vector/sqlite_vec.mjs +2 -0
  332. package/batteries/vector/sqlite_vec.mjs.map +1 -1
  333. package/batteries/vector/surrealdb/index.d.ts +2 -0
  334. package/batteries/vector/surrealdb.cjs +2 -1
  335. package/batteries/vector/surrealdb.cjs.map +1 -1
  336. package/batteries/vector/surrealdb.mjs +2 -1
  337. package/batteries/vector/surrealdb.mjs.map +1 -1
  338. package/batteries/vector/types.d.ts +27 -0
  339. package/batteries/vector/typesense/index.d.ts +2 -0
  340. package/batteries/vector/typesense.cjs +2 -1
  341. package/batteries/vector/typesense.cjs.map +1 -1
  342. package/batteries/vector/typesense.mjs +2 -1
  343. package/batteries/vector/typesense.mjs.map +1 -1
  344. package/batteries/vector/validation.cjs +14 -0
  345. package/batteries/vector/validation.cjs.map +1 -1
  346. package/batteries/vector/validation.d.ts +14 -0
  347. package/batteries/vector/validation.mjs +14 -0
  348. package/batteries/vector/validation.mjs.map +1 -1
  349. package/batteries/vector/vector_store_constructor.cjs +1 -1
  350. package/batteries/vector/vector_store_constructor.cjs.map +1 -1
  351. package/batteries/vector/vector_store_constructor.d.ts +1 -1
  352. package/batteries/vector/vector_store_constructor.mjs +1 -1
  353. package/batteries/vector/vector_store_constructor.mjs.map +1 -1
  354. package/batteries/vector/vespa/index.d.ts +2 -0
  355. package/batteries/vector/vespa.cjs +2 -1
  356. package/batteries/vector/vespa.cjs.map +1 -1
  357. package/batteries/vector/vespa.mjs +2 -1
  358. package/batteries/vector/vespa.mjs.map +1 -1
  359. package/batteries/vector/weaviate/index.d.ts +2 -0
  360. package/batteries/vector/weaviate.cjs +2 -1
  361. package/batteries/vector/weaviate.cjs.map +1 -1
  362. package/batteries/vector/weaviate.mjs +2 -1
  363. package/batteries/vector/weaviate.mjs.map +1 -1
  364. package/batteries.cjs +46 -28
  365. package/batteries.mjs +10 -5
  366. package/{common-BT0nfCi9.mjs → common-DYDUi99O.mjs} +9 -9
  367. package/common-DYDUi99O.mjs.map +1 -0
  368. package/{common-Cj8TaQ9U.js → common-DZl3ADJs.js} +9 -9
  369. package/common-DZl3ADJs.js.map +1 -0
  370. package/common.cjs +7 -7
  371. package/common.d.ts +1 -1
  372. package/common.mjs +7 -7
  373. package/{dispatch_runner-DPcS7Y_M.mjs → dispatch_runner--ZhdDWRZ.mjs} +27 -5
  374. package/{dispatch_runner-DPcS7Y_M.mjs.map → dispatch_runner--ZhdDWRZ.mjs.map} +1 -1
  375. package/{dispatch_runner-BHBNupqp.js → dispatch_runner-nHDKkxye.js} +27 -5
  376. package/{dispatch_runner-BHBNupqp.js.map → dispatch_runner-nHDKkxye.js.map} +1 -1
  377. package/dispatch_runner.cjs +1 -1
  378. package/dispatch_runner.d.ts +1 -1
  379. package/dispatch_runner.mjs +1 -1
  380. package/eslint/rules/artifact_tool_forbids_artifact_constructor.cjs +1 -0
  381. package/eslint/rules/artifact_tool_forbids_artifact_constructor.cjs.map +1 -1
  382. package/eslint/rules/artifact_tool_forbids_artifact_constructor.d.ts +1 -0
  383. package/eslint/rules/artifact_tool_forbids_artifact_constructor.mjs +1 -0
  384. package/eslint/rules/artifact_tool_forbids_artifact_constructor.mjs.map +1 -1
  385. package/eslint/rules/no_model_in_tool_handler.cjs +1 -0
  386. package/eslint/rules/no_model_in_tool_handler.cjs.map +1 -1
  387. package/eslint/rules/no_model_in_tool_handler.d.ts +1 -0
  388. package/eslint/rules/no_model_in_tool_handler.mjs +1 -0
  389. package/eslint/rules/no_model_in_tool_handler.mjs.map +1 -1
  390. package/eslint/rules/require_validator_any_required.cjs +1 -0
  391. package/eslint/rules/require_validator_any_required.cjs.map +1 -1
  392. package/eslint/rules/require_validator_any_required.d.ts +1 -0
  393. package/eslint/rules/require_validator_any_required.mjs +1 -0
  394. package/eslint/rules/require_validator_any_required.mjs.map +1 -1
  395. package/eslint/rules/thought_payload_requires_replay_tag.cjs +1 -0
  396. package/eslint/rules/thought_payload_requires_replay_tag.cjs.map +1 -1
  397. package/eslint/rules/thought_payload_requires_replay_tag.d.ts +1 -0
  398. package/eslint/rules/thought_payload_requires_replay_tag.mjs +1 -0
  399. package/eslint/rules/thought_payload_requires_replay_tag.mjs.map +1 -1
  400. package/eslint/rules/token_encoding_requires_context_window.cjs +1 -0
  401. package/eslint/rules/token_encoding_requires_context_window.cjs.map +1 -1
  402. package/eslint/rules/token_encoding_requires_context_window.d.ts +1 -0
  403. package/eslint/rules/token_encoding_requires_context_window.mjs +1 -0
  404. package/eslint/rules/token_encoding_requires_context_window.mjs.map +1 -1
  405. package/eslint.cjs +1 -1
  406. package/eslint.mjs +1 -1
  407. package/{exceptions-BeWH2FwP.mjs → exceptions-BDhN0Xzr.mjs} +3 -2
  408. package/exceptions-BDhN0Xzr.mjs.map +1 -0
  409. package/{exceptions-CitH5wZI.js → exceptions-BRXrUKiW.js} +3 -2
  410. package/exceptions-BRXrUKiW.js.map +1 -0
  411. package/exceptions.cjs +2 -2
  412. package/exceptions.mjs +2 -2
  413. package/factories.cjs +1 -1
  414. package/factories.mjs +1 -1
  415. package/forge.cjs +4 -4
  416. package/forge.d.ts +1 -1
  417. package/forge.mjs +4 -4
  418. package/guards.cjs +9 -9
  419. package/guards.mjs +9 -9
  420. package/helpers-DSTFxTiC.js +497 -0
  421. package/helpers-DSTFxTiC.js.map +1 -0
  422. package/helpers-xhrQbMAG.mjs +306 -0
  423. package/helpers-xhrQbMAG.mjs.map +1 -0
  424. package/index.cjs +13 -13
  425. package/index.mjs +13 -13
  426. package/lib/classes/base_exception.d.ts +1 -0
  427. package/lib/classes/media.d.ts +10 -0
  428. package/lib/classes/retrievable.d.ts +1 -1
  429. package/lib/classes/spooled_json_artifact.d.ts +1 -1
  430. package/lib/classes/spooled_markdown_artifact.d.ts +1 -0
  431. package/lib/classes/tokenizable.d.ts +3 -0
  432. package/lib/classes/tool.d.ts +8 -0
  433. package/lib/classes/turn_gate.d.ts +6 -0
  434. package/lib/dispatch_runner.d.ts +4 -32
  435. package/lib/helpers/bignum.cjs +82 -0
  436. package/lib/helpers/bignum.cjs.map +1 -0
  437. package/lib/helpers/bignum.d.ts +52 -0
  438. package/lib/helpers/bignum.mjs +74 -0
  439. package/lib/helpers/bignum.mjs.map +1 -0
  440. package/lib/turn_runner.d.ts +1 -1
  441. package/lib/types/dispatch_runner.d.ts +83 -0
  442. package/lib/utils/exceptions.d.ts +1 -1
  443. package/lib/utils/retry.cjs.map +1 -1
  444. package/lib/utils/retry.d.ts +2 -0
  445. package/lib/utils/retry.mjs.map +1 -1
  446. package/mcp/adk-docs-corpus.json +1 -1
  447. package/package.json +264 -224
  448. package/{runtime-j92CNi5z.mjs → runtime-Bz5zA8wc.mjs} +2 -2
  449. package/{runtime-j92CNi5z.mjs.map → runtime-Bz5zA8wc.mjs.map} +1 -1
  450. package/{runtime-MFFcJrRv.js → runtime-DslE1aBw.js} +2 -2
  451. package/{runtime-MFFcJrRv.js.map → runtime-DslE1aBw.js.map} +1 -1
  452. package/searxng-Bkrwhwhw.js +269 -0
  453. package/searxng-Bkrwhwhw.js.map +1 -0
  454. package/searxng-CyA-nEu5.mjs +257 -0
  455. package/searxng-CyA-nEu5.mjs.map +1 -0
  456. package/skills/adk-assembly/SKILL.md +2 -2
  457. package/{spooled_artifact-CHoZgWwI.mjs → spooled_artifact-7eePq7JA.mjs} +5 -5
  458. package/{spooled_artifact-CHoZgWwI.mjs.map → spooled_artifact-7eePq7JA.mjs.map} +1 -1
  459. package/{spooled_artifact-BTq6Nzfy.js → spooled_artifact-DX8LLyUX.js} +5 -5
  460. package/{spooled_artifact-BTq6Nzfy.js.map → spooled_artifact-DX8LLyUX.js.map} +1 -1
  461. package/spooled_artifact.cjs +2 -2
  462. package/spooled_artifact.mjs +2 -2
  463. package/{spooled_markdown_artifact-CALSDxIx.js → spooled_markdown_artifact-ClX72lek.js} +4 -4
  464. package/spooled_markdown_artifact-ClX72lek.js.map +1 -0
  465. package/{spooled_markdown_artifact-Ci5UL7l4.mjs → spooled_markdown_artifact-wkrBF3oX.mjs} +4 -4
  466. package/spooled_markdown_artifact-wkrBF3oX.mjs.map +1 -0
  467. package/{thought-D34QQZZ9.mjs → thought-B_vxAiKU.mjs} +5 -5
  468. package/{thought-D34QQZZ9.mjs.map → thought-B_vxAiKU.mjs.map} +1 -1
  469. package/{thought-BbwhJ1wb.js → thought-DLwpF7MI.js} +5 -5
  470. package/{thought-BbwhJ1wb.js.map → thought-DLwpF7MI.js.map} +1 -1
  471. package/{tool-CVyZkFC7.js → tool-D5WGVIcI.js} +4 -4
  472. package/{tool-CVyZkFC7.js.map → tool-D5WGVIcI.js.map} +1 -1
  473. package/{tool-CMhaDRNd.mjs → tool-wMYMVl60.mjs} +4 -4
  474. package/{tool-CMhaDRNd.mjs.map → tool-wMYMVl60.mjs.map} +1 -1
  475. package/{tool_call-CV5qVNlb.mjs → tool_call-B4-_-vjG.mjs} +5 -5
  476. package/tool_call-B4-_-vjG.mjs.map +1 -0
  477. package/{tool_call-Db68hB7y.js → tool_call-DixVlW40.js} +5 -5
  478. package/tool_call-DixVlW40.js.map +1 -0
  479. package/{tool_registry-D1pSSlsd.mjs → tool_registry-791Vrjtf.mjs} +4 -3
  480. package/tool_registry-791Vrjtf.mjs.map +1 -0
  481. package/{tool_registry-DYUYqXvo.js → tool_registry-CKJPze3j.js} +4 -3
  482. package/tool_registry-CKJPze3j.js.map +1 -0
  483. package/{turn_runner-DqWHNP80.js → turn_runner-HXImLGIn.js} +7 -7
  484. package/turn_runner-HXImLGIn.js.map +1 -0
  485. package/{turn_runner-fg1Wc3dK.mjs → turn_runner-ZyYO-Kti.mjs} +7 -7
  486. package/turn_runner-ZyYO-Kti.mjs.map +1 -0
  487. package/turn_runner.cjs +1 -1
  488. package/turn_runner.mjs +1 -1
  489. package/types.d.ts +1 -1
  490. package/common-BT0nfCi9.mjs.map +0 -1
  491. package/common-Cj8TaQ9U.js.map +0 -1
  492. package/exceptions-BeWH2FwP.mjs.map +0 -1
  493. package/exceptions-CitH5wZI.js.map +0 -1
  494. package/spooled_markdown_artifact-CALSDxIx.js.map +0 -1
  495. package/spooled_markdown_artifact-Ci5UL7l4.mjs.map +0 -1
  496. package/tool_call-CV5qVNlb.mjs.map +0 -1
  497. package/tool_call-Db68hB7y.js.map +0 -1
  498. package/tool_registry-D1pSSlsd.mjs.map +0 -1
  499. package/tool_registry-DYUYqXvo.js.map +0 -1
  500. package/turn_runner-DqWHNP80.js.map +0 -1
  501. package/turn_runner-fg1Wc3dK.mjs.map +0 -1
@@ -1,8 +1,9 @@
1
- import { o as isError } from "../../tool_registry-D1pSSlsd.mjs";
2
- import { t as Tool } from "../../tool-CMhaDRNd.mjs";
3
- import "../../common-BT0nfCi9.mjs";
4
- import { n as SpooledJsonArtifact } from "../../spooled_markdown_artifact-Ci5UL7l4.mjs";
1
+ import { o as isError } from "../../tool_registry-791Vrjtf.mjs";
2
+ import { t as Tool } from "../../tool-wMYMVl60.mjs";
3
+ import "../../common-DYDUi99O.mjs";
4
+ import { n as SpooledJsonArtifact } from "../../spooled_markdown_artifact-wkrBF3oX.mjs";
5
5
  import "../../guards.mjs";
6
+ import { bigMean, bigSum, bigToNumber, formatBig } from "../../lib/helpers/bignum.mjs";
6
7
  import { validator } from "@nhtio/validation";
7
8
  import { equalIntervalBreaks, interquartileRange, max, mean, median, min, mode, quantile, sampleCorrelation, standardDeviation, sum, variance, zScore } from "simple-statistics";
8
9
  //#region src/batteries/tools/statistics/index.ts
@@ -15,18 +16,24 @@ import { equalIntervalBreaks, interquartileRange, max, mean, median, min, mode,
15
16
  * Pre-constructed bundled tools for the `statistics` category. Import individually, the whole
16
17
  * category, or import every tool via `@nhtio/adk/batteries`.
17
18
  */
19
+ /**
20
+ * Normalise the `numbers`/`x`/`y` input to a `number[]`.
21
+ *
22
+ * @remarks
23
+ * The input schema is `validator.array().items(validator.number())`, which already rejects
24
+ * `NaN`, `±Infinity`, and magnitudes `> Number.MAX_SAFE_INTEGER` before the handler runs — so by
25
+ * the time a value reaches here it is a finite, in-range float64. This guard only enforces
26
+ * non-emptiness (and defensively re-checks the array shape). It deliberately NO LONGER silently
27
+ * drops non-finite entries: those can't arrive through the typed schema, and a silent filter hid
28
+ * real input errors.
29
+ */
18
30
  function parseNumbers(input) {
19
- let arr = input;
20
- if (typeof input === "string") try {
21
- arr = JSON.parse(input);
22
- } catch {
23
- return { error: "Invalid JSON — expected an array of numbers." };
24
- }
25
- if (!Array.isArray(arr)) return { error: "Input must be a JSON array of numbers." };
26
- const nums = arr.filter((v) => typeof v === "number" && Number.isFinite(v));
27
- if (nums.length === 0) return { error: "No finite numbers found in the array." };
28
- return nums;
31
+ if (!Array.isArray(input)) return { error: "Input must be an array of numbers." };
32
+ if (input.length === 0) return { error: "Array must contain at least one number." };
33
+ return input;
29
34
  }
35
+ /** Shared `precision` schema fragment (significant digits for numeric output, default 8). */
36
+ var precisionField = validator.number().default(8).description(`Significant digits for numeric output (default: 8).`);
30
37
  /**
31
38
  * Compute descriptive statistics for a JSON array of numbers.
32
39
  *
@@ -38,25 +45,29 @@ function parseNumbers(input) {
38
45
  var statsDescribeTool = new Tool({
39
46
  name: "stats_describe",
40
47
  description: "Compute descriptive statistics for a numeric array: count, sum, min, max, range, mean, median, mode, variance, standard deviation, quartiles (Q1–Q3), IQR, and key percentiles.",
41
- inputSchema: validator.object({ numbers: validator.string().required().description("JSON array of numbers") }),
48
+ inputSchema: validator.object({
49
+ numbers: validator.array().items(validator.number()).required().description("Array of numbers"),
50
+ precision: precisionField
51
+ }),
42
52
  artifactConstructor: () => SpooledJsonArtifact,
43
53
  handler: async (args) => {
44
- const { numbers } = args;
54
+ const { numbers, precision } = args;
45
55
  const nums = parseNumbers(numbers);
46
56
  if ("error" in nums) return `Error: ${nums.error}`;
47
57
  const sorted = [...nums].sort((a, b) => a - b);
48
58
  const modeVal = mode(nums);
59
+ const fmt = (n) => formatBig(n, precision);
49
60
  return JSON.stringify({
50
61
  count: nums.length,
51
- sum: Number.parseFloat(sum(nums).toPrecision(12)),
62
+ sum: formatBig(bigSum(nums), precision),
52
63
  min: min(nums),
53
64
  max: max(nums),
54
65
  range: max(nums) - min(nums),
55
- mean: Number.parseFloat(mean(nums).toPrecision(10)),
66
+ mean: formatBig(bigMean(nums), precision),
56
67
  median: median(nums),
57
68
  mode: modeVal,
58
- variance: Number.parseFloat(variance(nums).toPrecision(8)),
59
- std_dev: Number.parseFloat(standardDeviation(nums).toPrecision(8)),
69
+ variance: fmt(variance(nums)),
70
+ std_dev: fmt(standardDeviation(nums)),
60
71
  q1: quantile(sorted, .25),
61
72
  q2: quantile(sorted, .5),
62
73
  q3: quantile(sorted, .75),
@@ -79,8 +90,8 @@ var statsCorrelateTool = new Tool({
79
90
  name: "stats_correlate",
80
91
  description: "Compute the Pearson correlation coefficient between two numeric arrays. Returns the r value (-1 to 1), r², and a plain-English interpretation.",
81
92
  inputSchema: validator.object({
82
- x: validator.string().required().description("JSON array of numbers (first variable)"),
83
- y: validator.string().required().description("JSON array of numbers (second variable, same length as x)")
93
+ x: validator.array().items(validator.number()).required().description("Array of numbers (first variable)"),
94
+ y: validator.array().items(validator.number()).required().description("Array of numbers (second variable, same length as x)")
84
95
  }),
85
96
  handler: async (args) => {
86
97
  const { x: rawX, y: rawY } = args;
@@ -90,6 +101,7 @@ var statsCorrelateTool = new Tool({
90
101
  if ("error" in y) return `Error in y: ${y.error}`;
91
102
  if (x.length !== y.length) return `Error: Arrays must be the same length (x: ${x.length}, y: ${y.length}).`;
92
103
  if (x.length < 2) return "Error: At least 2 data points required.";
104
+ if (standardDeviation(x) === 0 || standardDeviation(y) === 0) return "Correlation is undefined: at least one variable is constant (zero variance), so Pearson r cannot be computed.";
93
105
  try {
94
106
  const r = sampleCorrelation(x, y);
95
107
  const absR = Math.abs(r);
@@ -114,47 +126,45 @@ var statsTransformTool = new Tool({
114
126
  name: "stats_transform",
115
127
  description: "Transform a numeric array: normalize (min-max or z-score), compute running totals, rolling averages, percent change between consecutive values, rank each value, or detect outliers.",
116
128
  inputSchema: validator.object({
117
- numbers: validator.string().required().description("JSON array of numbers"),
129
+ numbers: validator.array().items(validator.number()).required().description("Array of numbers"),
118
130
  operation: validator.string().valid("normalize_min_max", "normalize_z_score", "normalize_percent_of_sum", "running_total", "rolling_avg", "pct_change", "rank", "outliers_iqr", "outliers_zscore").required().description("Transformation to apply"),
119
131
  window: validator.number().default(3).description("For rolling_avg: window size (default: 3)"),
120
- threshold: validator.number().default(3).description("For outliers_zscore: z-score threshold (default: 3.0)")
132
+ threshold: validator.number().default(3).description("For outliers_zscore: z-score threshold (default: 3.0)"),
133
+ precision: precisionField
121
134
  }),
122
135
  handler: async (args) => {
123
- const { numbers, operation, window, threshold } = args;
136
+ const { numbers, operation, window, threshold, precision } = args;
124
137
  const nums = parseNumbers(numbers);
125
138
  if ("error" in nums) return `Error: ${nums.error}`;
139
+ const round = (n) => Number.parseFloat(formatBig(n, precision));
126
140
  switch (operation) {
127
141
  case "normalize_min_max": {
128
142
  const lo = min(nums);
129
143
  const hi = max(nums);
130
144
  if (lo === hi) return JSON.stringify(nums.map(() => 0));
131
- return JSON.stringify(nums.map((v) => Number.parseFloat(((v - lo) / (hi - lo)).toFixed(8))));
145
+ return JSON.stringify(nums.map((v) => round((v - lo) / (hi - lo))));
132
146
  }
133
147
  case "normalize_z_score": {
134
148
  const m = mean(nums);
135
149
  const sd = standardDeviation(nums);
136
150
  if (sd === 0) return JSON.stringify(nums.map(() => 0));
137
- return JSON.stringify(nums.map((v) => Number.parseFloat(zScore(v, m, sd).toFixed(8))));
151
+ return JSON.stringify(nums.map((v) => round(zScore(v, m, sd))));
138
152
  }
139
153
  case "normalize_percent_of_sum": {
140
154
  const total = sum(nums);
141
155
  if (total === 0) return JSON.stringify(nums.map(() => 0));
142
- return JSON.stringify(nums.map((v) => Number.parseFloat((v / total * 100).toFixed(4))));
143
- }
144
- case "running_total": {
145
- const totals = [];
146
- let acc = 0;
147
- for (const v of nums) {
148
- acc += v;
149
- totals.push(Number.parseFloat(acc.toPrecision(12)));
150
- }
151
- return JSON.stringify(totals);
156
+ return JSON.stringify(nums.map((v) => round(v / total * 100)));
152
157
  }
158
+ case "running_total": return JSON.stringify(nums.map((_, i) => {
159
+ const big = bigSum(nums.slice(0, i + 1));
160
+ const asNum = bigToNumber(big);
161
+ if (Number.isFinite(asNum) && Math.abs(asNum) <= Number.MAX_SAFE_INTEGER) return round(asNum);
162
+ return formatBig(big, precision);
163
+ }));
153
164
  case "rolling_avg": {
154
165
  const w = Math.max(1, Math.floor(window));
155
166
  return JSON.stringify(nums.map((_, i) => {
156
- const slice = nums.slice(Math.max(0, i - w + 1), i + 1);
157
- return Number.parseFloat(mean(slice).toPrecision(8));
167
+ return round(mean(nums.slice(Math.max(0, i - w + 1), i + 1)));
158
168
  }));
159
169
  }
160
170
  case "pct_change": {
@@ -208,11 +218,12 @@ var statsHistogramTool = new Tool({
208
218
  name: "stats_histogram",
209
219
  description: "Bin a numeric array into equal-width histogram buckets and display counts.",
210
220
  inputSchema: validator.object({
211
- numbers: validator.string().required().description("JSON array of numbers"),
212
- bins: validator.number().default(10).description("Number of bins (default: 10, max: 100)")
221
+ numbers: validator.array().items(validator.number()).required().description("Array of numbers"),
222
+ bins: validator.number().default(10).description("Number of bins (default: 10, max: 100)"),
223
+ precision: precisionField
213
224
  }),
214
225
  handler: async (args) => {
215
- const { numbers, bins } = args;
226
+ const { numbers, bins, precision } = args;
216
227
  const nums = parseNumbers(numbers);
217
228
  if ("error" in nums) return `Error: ${nums.error}`;
218
229
  const binCount = Math.max(2, Math.min(100, Math.floor(bins)));
@@ -233,7 +244,7 @@ var statsHistogramTool = new Tool({
233
244
  const count = nums.filter((v) => isLast ? v >= breaks[i] && v <= breaks[i + 1] : v >= breaks[i] && v < breaks[i + 1]).length;
234
245
  const pct = (count / nums.length * 100).toFixed(1);
235
246
  const bar = "█".repeat(maxCount > 0 ? Math.round(count / maxCount * 20) : 0);
236
- const range = `[${breaks[i].toPrecision(4)}, ${breaks[i + 1].toPrecision(4)}${isLast ? "]" : ")"}`;
247
+ const range = `[${formatBig(breaks[i], precision)}, ${formatBig(breaks[i + 1], precision)}${isLast ? "]" : ")"}`;
237
248
  rows.push(`${range.padEnd(22)} ${String(count).padStart(4)} (${pct.padStart(5)}%) ${bar}`);
238
249
  }
239
250
  return rows.join("\n");
@@ -1 +1 @@
1
- {"version":3,"file":"statistics.mjs","names":[],"sources":["../../../src/batteries/tools/statistics/index.ts"],"sourcesContent":["/**\n * Pre-constructed tools for descriptive statistics, correlation, quantiles, and numeric summaries.\n *\n * @module @nhtio/adk/batteries/tools/statistics\n *\n * @remarks\n * Pre-constructed bundled tools for the `statistics` category. Import individually, the whole\n * category, or import every tool via `@nhtio/adk/batteries`.\n */\n\nimport { isError } from '@nhtio/adk/guards'\nimport { validator } from '@nhtio/validation'\nimport { Tool, SpooledJsonArtifact } from '@nhtio/adk/common'\nimport {\n equalIntervalBreaks,\n interquartileRange,\n max,\n mean,\n median,\n min,\n mode,\n quantile,\n sampleCorrelation,\n standardDeviation,\n sum,\n variance,\n zScore,\n} from 'simple-statistics'\n\nfunction parseNumbers(input: unknown): number[] | { error: string } {\n let arr: unknown = input\n if (typeof input === 'string') {\n try {\n arr = JSON.parse(input)\n } catch {\n return { error: 'Invalid JSON — expected an array of numbers.' }\n }\n }\n if (!Array.isArray(arr)) return { error: 'Input must be a JSON array of numbers.' }\n const nums = (arr as unknown[]).filter(\n (v): v is number => typeof v === 'number' && Number.isFinite(v)\n )\n if (nums.length === 0) return { error: 'No finite numbers found in the array.' }\n return nums\n}\n\n/**\n * Compute descriptive statistics for a JSON array of numbers.\n *\n * @remarks\n * Returns count, sum, min/max/range, mean, median, mode, variance, standard deviation,\n * quartiles (Q1/Q2/Q3), IQR, and key percentiles (P10/P90/P95/P99) as a pretty-printed JSON\n * object. Non-numeric and non-finite entries are silently filtered.\n */\nexport const statsDescribeTool = new Tool({\n name: 'stats_describe',\n description:\n 'Compute descriptive statistics for a numeric array: count, sum, min, max, range, mean, median, mode, variance, standard deviation, quartiles (Q1–Q3), IQR, and key percentiles.',\n inputSchema: validator.object({\n numbers: validator.string().required().description('JSON array of numbers'),\n }),\n artifactConstructor: () => SpooledJsonArtifact,\n handler: async (args) => {\n const { numbers } = args as { numbers: string }\n const nums = parseNumbers(numbers)\n if ('error' in nums) return `Error: ${nums.error}`\n\n const sorted = [...nums].sort((a, b) => a - b)\n const modeVal = mode(nums)\n\n return JSON.stringify(\n {\n count: nums.length,\n sum: Number.parseFloat(sum(nums).toPrecision(12)),\n min: min(nums),\n max: max(nums),\n range: max(nums) - min(nums),\n mean: Number.parseFloat(mean(nums).toPrecision(10)),\n median: median(nums),\n mode: modeVal,\n variance: Number.parseFloat(variance(nums).toPrecision(8)),\n std_dev: Number.parseFloat(standardDeviation(nums).toPrecision(8)),\n q1: quantile(sorted, 0.25),\n q2: quantile(sorted, 0.5),\n q3: quantile(sorted, 0.75),\n iqr: interquartileRange(nums),\n p10: quantile(sorted, 0.1),\n p90: quantile(sorted, 0.9),\n p95: quantile(sorted, 0.95),\n p99: quantile(sorted, 0.99),\n },\n null,\n 2\n )\n },\n})\n\n/**\n * Compute the Pearson correlation coefficient between two numeric arrays.\n *\n * @remarks\n * Returns `r`, `r²` (as a percentage of explained variance), and a plain-English interpretation\n * of strength and direction. Arrays must be the same length and contain at least two points.\n */\nexport const statsCorrelateTool = new Tool({\n name: 'stats_correlate',\n description:\n 'Compute the Pearson correlation coefficient between two numeric arrays. Returns the r value (-1 to 1), r², and a plain-English interpretation.',\n inputSchema: validator.object({\n x: validator.string().required().description('JSON array of numbers (first variable)'),\n y: validator\n .string()\n .required()\n .description('JSON array of numbers (second variable, same length as x)'),\n }),\n handler: async (args) => {\n const { x: rawX, y: rawY } = args as { x: string; y: string }\n const x = parseNumbers(rawX)\n if ('error' in x) return `Error in x: ${x.error}`\n const y = parseNumbers(rawY)\n if ('error' in y) return `Error in y: ${y.error}`\n\n if (x.length !== y.length)\n return `Error: Arrays must be the same length (x: ${x.length}, y: ${y.length}).`\n if (x.length < 2) return 'Error: At least 2 data points required.'\n\n try {\n const r = sampleCorrelation(x, y)\n const absR = Math.abs(r)\n const direction = r > 0 ? 'positive' : r < 0 ? 'negative' : 'no'\n const strength =\n absR >= 0.9\n ? 'very strong'\n : absR >= 0.7\n ? 'strong'\n : absR >= 0.5\n ? 'moderate'\n : absR >= 0.3\n ? 'weak'\n : 'very weak / negligible'\n return `r = ${r.toFixed(6)}\\nr² = ${(r * r * 100).toFixed(2)}% (explained variance)\\nInterpretation: ${strength} ${direction} correlation`\n } catch (err) {\n return `Error: ${isError(err) ? err.message : String(err)}`\n }\n },\n})\n\n/**\n * Transform a numeric array — normalise, smooth, rank, or detect outliers.\n *\n * @remarks\n * Supported operations: `normalize_min_max`, `normalize_z_score`, `normalize_percent_of_sum`,\n * `running_total`, `rolling_avg`, `pct_change`, `rank`, `outliers_iqr`, `outliers_zscore`. Most\n * operations return a JSON array of transformed values; outlier operations return a\n * human-readable report.\n */\nexport const statsTransformTool = new Tool({\n name: 'stats_transform',\n description:\n 'Transform a numeric array: normalize (min-max or z-score), compute running totals, rolling averages, percent change between consecutive values, rank each value, or detect outliers.',\n inputSchema: validator.object({\n numbers: validator.string().required().description('JSON array of numbers'),\n operation: validator\n .string()\n .valid(\n 'normalize_min_max',\n 'normalize_z_score',\n 'normalize_percent_of_sum',\n 'running_total',\n 'rolling_avg',\n 'pct_change',\n 'rank',\n 'outliers_iqr',\n 'outliers_zscore'\n )\n .required()\n .description('Transformation to apply'),\n window: validator.number().default(3).description('For rolling_avg: window size (default: 3)'),\n threshold: validator\n .number()\n .default(3.0)\n .description('For outliers_zscore: z-score threshold (default: 3.0)'),\n }),\n handler: async (args) => {\n const { numbers, operation, window, threshold } = args as {\n numbers: string\n operation: string\n window: number\n threshold: number\n }\n const nums = parseNumbers(numbers)\n if ('error' in nums) return `Error: ${nums.error}`\n\n switch (operation) {\n case 'normalize_min_max': {\n const lo = min(nums)\n const hi = max(nums)\n if (lo === hi) return JSON.stringify(nums.map(() => 0))\n return JSON.stringify(nums.map((v) => Number.parseFloat(((v - lo) / (hi - lo)).toFixed(8))))\n }\n\n case 'normalize_z_score': {\n const m = mean(nums)\n const sd = standardDeviation(nums)\n if (sd === 0) return JSON.stringify(nums.map(() => 0))\n return JSON.stringify(nums.map((v) => Number.parseFloat(zScore(v, m, sd).toFixed(8))))\n }\n\n case 'normalize_percent_of_sum': {\n const total = sum(nums)\n if (total === 0) return JSON.stringify(nums.map(() => 0))\n return JSON.stringify(nums.map((v) => Number.parseFloat(((v / total) * 100).toFixed(4))))\n }\n\n case 'running_total': {\n const totals: number[] = []\n let acc = 0\n for (const v of nums) {\n acc += v\n totals.push(Number.parseFloat(acc.toPrecision(12)))\n }\n return JSON.stringify(totals)\n }\n\n case 'rolling_avg': {\n const w = Math.max(1, Math.floor(window))\n return JSON.stringify(\n nums.map((_, i) => {\n const slice = nums.slice(Math.max(0, i - w + 1), i + 1)\n return Number.parseFloat(mean(slice).toPrecision(8))\n })\n )\n }\n\n case 'pct_change': {\n const changes: (number | null)[] = [null]\n for (let i = 1; i < nums.length; i++) {\n if (nums[i - 1] === 0) {\n changes.push(null)\n } else {\n changes.push(\n Number.parseFloat(\n (((nums[i] - nums[i - 1]) / Math.abs(nums[i - 1])) * 100).toFixed(4)\n )\n )\n }\n }\n return JSON.stringify(changes)\n }\n\n case 'rank': {\n const sorted = [...nums].sort((a, b) => a - b)\n return JSON.stringify(nums.map((v) => sorted.indexOf(v) + 1))\n }\n\n case 'outliers_iqr': {\n const sorted = [...nums].sort((a, b) => a - b)\n const q1 = quantile(sorted, 0.25)\n const q3 = quantile(sorted, 0.75)\n const iqr = q3 - q1\n const lo = q1 - 1.5 * iqr\n const hi = q3 + 1.5 * iqr\n const outliers = nums\n .map((v, i) => ({ index: i, value: v }))\n .filter(({ value }) => value < lo || value > hi)\n if (outliers.length === 0) return 'No outliers detected (IQR method).'\n return `${outliers.length} outlier(s) detected:\\n${outliers.map((o) => ` [${o.index}] = ${o.value}`).join('\\n')}`\n }\n\n case 'outliers_zscore': {\n const m = mean(nums)\n const sd = standardDeviation(nums)\n const outliers = nums\n .map((v, i) => ({ index: i, value: v, z: sd === 0 ? 0 : Math.abs(zScore(v, m, sd)) }))\n .filter((o) => o.z > threshold)\n if (outliers.length === 0) return `No outliers detected (|z| > ${threshold}).`\n return `${outliers.length} outlier(s) detected (|z| > ${threshold}):\\n${outliers.map((o) => ` [${o.index}] = ${o.value} (z = ${o.z.toFixed(3)})`).join('\\n')}`\n }\n\n default:\n return `Error: Unknown operation \"${operation}\".`\n }\n },\n})\n\n/**\n * Bin a numeric array into equal-width histogram buckets.\n *\n * @remarks\n * Output is a text histogram showing each bin's range, count, percentage of total, and a bar\n * chart. The last bin is inclusive on both ends; preceding bins are half-open. `bins` is clamped\n * to `[2, 100]`.\n */\nexport const statsHistogramTool = new Tool({\n name: 'stats_histogram',\n description: 'Bin a numeric array into equal-width histogram buckets and display counts.',\n inputSchema: validator.object({\n numbers: validator.string().required().description('JSON array of numbers'),\n bins: validator.number().default(10).description('Number of bins (default: 10, max: 100)'),\n }),\n handler: async (args) => {\n const { numbers, bins } = args as { numbers: string; bins: number }\n const nums = parseNumbers(numbers)\n if ('error' in nums) return `Error: ${nums.error}`\n\n const binCount = Math.max(2, Math.min(100, Math.floor(bins)))\n\n try {\n const breaks = equalIntervalBreaks(nums, binCount)\n const rows: string[] = []\n const maxCount = (() => {\n let m = 0\n for (let i = 0; i < breaks.length - 1; i++) {\n const isLast = i === breaks.length - 2\n const count = nums.filter((v) =>\n isLast ? v >= breaks[i] && v <= breaks[i + 1] : v >= breaks[i] && v < breaks[i + 1]\n ).length\n if (count > m) m = count\n }\n return m\n })()\n\n for (let i = 0; i < breaks.length - 1; i++) {\n const isLast = i === breaks.length - 2\n const count = nums.filter((v) =>\n isLast ? v >= breaks[i] && v <= breaks[i + 1] : v >= breaks[i] && v < breaks[i + 1]\n ).length\n const pct = ((count / nums.length) * 100).toFixed(1)\n const bar = '█'.repeat(maxCount > 0 ? Math.round((count / maxCount) * 20) : 0)\n const range = `[${breaks[i].toPrecision(4)}, ${breaks[i + 1].toPrecision(4)}${isLast ? ']' : ')'}`\n rows.push(`${range.padEnd(22)} ${String(count).padStart(4)} (${pct.padStart(5)}%) ${bar}`)\n }\n\n return rows.join('\\n')\n } catch (err) {\n return `Error: ${isError(err) ? err.message : String(err)}`\n }\n },\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"statistics.mjs","names":[],"sources":["../../../src/batteries/tools/statistics/index.ts"],"sourcesContent":["/**\n * Pre-constructed tools for descriptive statistics, correlation, quantiles, and numeric summaries.\n *\n * @module @nhtio/adk/batteries/tools/statistics\n *\n * @remarks\n * Pre-constructed bundled tools for the `statistics` category. Import individually, the whole\n * category, or import every tool via `@nhtio/adk/batteries`.\n */\n\nimport { isError } from '@nhtio/adk/guards'\nimport { validator } from '@nhtio/validation'\nimport { Tool, SpooledJsonArtifact } from '@nhtio/adk/common'\nimport {\n bigSum,\n bigMean,\n formatBig,\n bigToNumber,\n DEFAULT_PRECISION,\n} from '@nhtio/adk/lib/helpers/bignum'\nimport {\n equalIntervalBreaks,\n interquartileRange,\n max,\n mean,\n median,\n min,\n mode,\n quantile,\n sampleCorrelation,\n standardDeviation,\n sum,\n variance,\n zScore,\n} from 'simple-statistics'\n\n/**\n * Normalise the `numbers`/`x`/`y` input to a `number[]`.\n *\n * @remarks\n * The input schema is `validator.array().items(validator.number())`, which already rejects\n * `NaN`, `±Infinity`, and magnitudes `> Number.MAX_SAFE_INTEGER` before the handler runs — so by\n * the time a value reaches here it is a finite, in-range float64. This guard only enforces\n * non-emptiness (and defensively re-checks the array shape). It deliberately NO LONGER silently\n * drops non-finite entries: those can't arrive through the typed schema, and a silent filter hid\n * real input errors.\n */\nfunction parseNumbers(input: unknown): number[] | { error: string } {\n if (!Array.isArray(input)) return { error: 'Input must be an array of numbers.' }\n if (input.length === 0) return { error: 'Array must contain at least one number.' }\n return input as number[]\n}\n\n/** Shared `precision` schema fragment (significant digits for numeric output, default 8). */\nconst precisionField = validator\n .number()\n .default(DEFAULT_PRECISION)\n .description(`Significant digits for numeric output (default: ${DEFAULT_PRECISION}).`)\n\n/**\n * Compute descriptive statistics for a JSON array of numbers.\n *\n * @remarks\n * Returns count, sum, min/max/range, mean, median, mode, variance, standard deviation,\n * quartiles (Q1/Q2/Q3), IQR, and key percentiles (P10/P90/P95/P99) as a pretty-printed JSON\n * object. Non-numeric and non-finite entries are silently filtered.\n */\nexport const statsDescribeTool = new Tool({\n name: 'stats_describe',\n description:\n 'Compute descriptive statistics for a numeric array: count, sum, min, max, range, mean, median, mode, variance, standard deviation, quartiles (Q1–Q3), IQR, and key percentiles.',\n inputSchema: validator.object({\n numbers: validator.array().items(validator.number()).required().description('Array of numbers'),\n precision: precisionField,\n }),\n artifactConstructor: () => SpooledJsonArtifact,\n handler: async (args) => {\n const { numbers, precision } = args as { numbers: number[]; precision: number }\n const nums = parseNumbers(numbers)\n if ('error' in nums) return `Error: ${nums.error}`\n\n const sorted = [...nums].sort((a, b) => a - b)\n const modeVal = mode(nums)\n // Computed aggregates (sum/mean/variance/std_dev) are emitted as `precision`-significant-digit\n // STRINGS via BigNumber: this is lossless (no toPrecision round-trip) and overflow-safe (a sum\n // exceeding float64 stays exact, e.g. 2e308 instead of Infinity). Order statistics\n // (min/max/median/quartiles/range) are always input elements or midpoints — in-range by\n // construction — so they remain numbers.\n const fmt = (n: number): string => formatBig(n, precision)\n\n return JSON.stringify(\n {\n count: nums.length,\n sum: formatBig(bigSum(nums), precision),\n min: min(nums),\n max: max(nums),\n range: max(nums) - min(nums),\n mean: formatBig(bigMean(nums), precision),\n median: median(nums),\n mode: modeVal,\n variance: fmt(variance(nums)),\n std_dev: fmt(standardDeviation(nums)),\n q1: quantile(sorted, 0.25),\n q2: quantile(sorted, 0.5),\n q3: quantile(sorted, 0.75),\n iqr: interquartileRange(nums),\n p10: quantile(sorted, 0.1),\n p90: quantile(sorted, 0.9),\n p95: quantile(sorted, 0.95),\n p99: quantile(sorted, 0.99),\n },\n null,\n 2\n )\n },\n})\n\n/**\n * Compute the Pearson correlation coefficient between two numeric arrays.\n *\n * @remarks\n * Returns `r`, `r²` (as a percentage of explained variance), and a plain-English interpretation\n * of strength and direction. Arrays must be the same length and contain at least two points.\n */\nexport const statsCorrelateTool = new Tool({\n name: 'stats_correlate',\n description:\n 'Compute the Pearson correlation coefficient between two numeric arrays. Returns the r value (-1 to 1), r², and a plain-English interpretation.',\n inputSchema: validator.object({\n x: validator\n .array()\n .items(validator.number())\n .required()\n .description('Array of numbers (first variable)'),\n y: validator\n .array()\n .items(validator.number())\n .required()\n .description('Array of numbers (second variable, same length as x)'),\n }),\n handler: async (args) => {\n const { x: rawX, y: rawY } = args as { x: number[]; y: number[] }\n const x = parseNumbers(rawX)\n if ('error' in x) return `Error in x: ${x.error}`\n const y = parseNumbers(rawY)\n if ('error' in y) return `Error in y: ${y.error}`\n\n if (x.length !== y.length)\n return `Error: Arrays must be the same length (x: ${x.length}, y: ${y.length}).`\n if (x.length < 2) return 'Error: At least 2 data points required.'\n\n // Pearson r is undefined when either variable has zero variance (constant) — the formula\n // divides by a standard deviation of 0. Report that explicitly instead of emitting `r = NaN`,\n // which reads like a real (negligible) correlation.\n if (standardDeviation(x) === 0 || standardDeviation(y) === 0) {\n return 'Correlation is undefined: at least one variable is constant (zero variance), so Pearson r cannot be computed.'\n }\n\n try {\n const r = sampleCorrelation(x, y)\n const absR = Math.abs(r)\n const direction = r > 0 ? 'positive' : r < 0 ? 'negative' : 'no'\n const strength =\n absR >= 0.9\n ? 'very strong'\n : absR >= 0.7\n ? 'strong'\n : absR >= 0.5\n ? 'moderate'\n : absR >= 0.3\n ? 'weak'\n : 'very weak / negligible'\n return `r = ${r.toFixed(6)}\\nr² = ${(r * r * 100).toFixed(2)}% (explained variance)\\nInterpretation: ${strength} ${direction} correlation`\n } catch (err) {\n return `Error: ${isError(err) ? err.message : String(err)}`\n }\n },\n})\n\n/**\n * Transform a numeric array — normalise, smooth, rank, or detect outliers.\n *\n * @remarks\n * Supported operations: `normalize_min_max`, `normalize_z_score`, `normalize_percent_of_sum`,\n * `running_total`, `rolling_avg`, `pct_change`, `rank`, `outliers_iqr`, `outliers_zscore`. Most\n * operations return a JSON array of transformed values; outlier operations return a\n * human-readable report.\n */\nexport const statsTransformTool = new Tool({\n name: 'stats_transform',\n description:\n 'Transform a numeric array: normalize (min-max or z-score), compute running totals, rolling averages, percent change between consecutive values, rank each value, or detect outliers.',\n inputSchema: validator.object({\n numbers: validator.array().items(validator.number()).required().description('Array of numbers'),\n operation: validator\n .string()\n .valid(\n 'normalize_min_max',\n 'normalize_z_score',\n 'normalize_percent_of_sum',\n 'running_total',\n 'rolling_avg',\n 'pct_change',\n 'rank',\n 'outliers_iqr',\n 'outliers_zscore'\n )\n .required()\n .description('Transformation to apply'),\n window: validator.number().default(3).description('For rolling_avg: window size (default: 3)'),\n threshold: validator\n .number()\n .default(3.0)\n .description('For outliers_zscore: z-score threshold (default: 3.0)'),\n precision: precisionField,\n }),\n handler: async (args) => {\n const { numbers, operation, window, threshold, precision } = args as {\n numbers: number[]\n operation: string\n window: number\n threshold: number\n precision: number\n }\n const nums = parseNumbers(numbers)\n if ('error' in nums) return `Error: ${nums.error}`\n\n // Round a float to `precision` significant digits without the toPrecision/parse noise.\n const round = (n: number): number => Number.parseFloat(formatBig(n, precision))\n\n switch (operation) {\n case 'normalize_min_max': {\n const lo = min(nums)\n const hi = max(nums)\n if (lo === hi) return JSON.stringify(nums.map(() => 0))\n return JSON.stringify(nums.map((v) => round((v - lo) / (hi - lo))))\n }\n\n case 'normalize_z_score': {\n const m = mean(nums)\n const sd = standardDeviation(nums)\n if (sd === 0) return JSON.stringify(nums.map(() => 0))\n return JSON.stringify(nums.map((v) => round(zScore(v, m, sd))))\n }\n\n case 'normalize_percent_of_sum': {\n const total = sum(nums)\n if (total === 0) return JSON.stringify(nums.map(() => 0))\n return JSON.stringify(nums.map((v) => round((v / total) * 100)))\n }\n\n case 'running_total': {\n // Each prefix sum is computed exactly via BigNumber (so a cumulative total exceeding\n // float64 stays exact instead of overflowing to Infinity). Each entry is a plain number\n // when it fits float64 (the common case), or a precise string when it would otherwise\n // overflow to Infinity → JSON null.\n return JSON.stringify(\n nums.map((_, i) => {\n const big = bigSum(nums.slice(0, i + 1))\n const asNum = bigToNumber(big)\n // Number only when exactly representable; otherwise the exact string (covers both\n // overflow and the silent-rounding gap above 2^53).\n if (Number.isFinite(asNum) && Math.abs(asNum) <= Number.MAX_SAFE_INTEGER) {\n return round(asNum)\n }\n return formatBig(big, precision)\n })\n )\n }\n\n case 'rolling_avg': {\n const w = Math.max(1, Math.floor(window))\n return JSON.stringify(\n nums.map((_, i) => {\n const slice = nums.slice(Math.max(0, i - w + 1), i + 1)\n return round(mean(slice))\n })\n )\n }\n\n case 'pct_change': {\n const changes: (number | null)[] = [null]\n for (let i = 1; i < nums.length; i++) {\n if (nums[i - 1] === 0) {\n changes.push(null)\n } else {\n changes.push(\n Number.parseFloat(\n (((nums[i] - nums[i - 1]) / Math.abs(nums[i - 1])) * 100).toFixed(4)\n )\n )\n }\n }\n return JSON.stringify(changes)\n }\n\n case 'rank': {\n const sorted = [...nums].sort((a, b) => a - b)\n return JSON.stringify(nums.map((v) => sorted.indexOf(v) + 1))\n }\n\n case 'outliers_iqr': {\n const sorted = [...nums].sort((a, b) => a - b)\n const q1 = quantile(sorted, 0.25)\n const q3 = quantile(sorted, 0.75)\n const iqr = q3 - q1\n const lo = q1 - 1.5 * iqr\n const hi = q3 + 1.5 * iqr\n const outliers = nums\n .map((v, i) => ({ index: i, value: v }))\n .filter(({ value }) => value < lo || value > hi)\n if (outliers.length === 0) return 'No outliers detected (IQR method).'\n return `${outliers.length} outlier(s) detected:\\n${outliers.map((o) => ` [${o.index}] = ${o.value}`).join('\\n')}`\n }\n\n case 'outliers_zscore': {\n const m = mean(nums)\n const sd = standardDeviation(nums)\n const outliers = nums\n .map((v, i) => ({ index: i, value: v, z: sd === 0 ? 0 : Math.abs(zScore(v, m, sd)) }))\n .filter((o) => o.z > threshold)\n if (outliers.length === 0) return `No outliers detected (|z| > ${threshold}).`\n return `${outliers.length} outlier(s) detected (|z| > ${threshold}):\\n${outliers.map((o) => ` [${o.index}] = ${o.value} (z = ${o.z.toFixed(3)})`).join('\\n')}`\n }\n\n default:\n return `Error: Unknown operation \"${operation}\".`\n }\n },\n})\n\n/**\n * Bin a numeric array into equal-width histogram buckets.\n *\n * @remarks\n * Output is a text histogram showing each bin's range, count, percentage of total, and a bar\n * chart. The last bin is inclusive on both ends; preceding bins are half-open. `bins` is clamped\n * to `[2, 100]`.\n */\nexport const statsHistogramTool = new Tool({\n name: 'stats_histogram',\n description: 'Bin a numeric array into equal-width histogram buckets and display counts.',\n inputSchema: validator.object({\n numbers: validator.array().items(validator.number()).required().description('Array of numbers'),\n bins: validator.number().default(10).description('Number of bins (default: 10, max: 100)'),\n precision: precisionField,\n }),\n handler: async (args) => {\n const { numbers, bins, precision } = args as {\n numbers: number[]\n bins: number\n precision: number\n }\n const nums = parseNumbers(numbers)\n if ('error' in nums) return `Error: ${nums.error}`\n\n const binCount = Math.max(2, Math.min(100, Math.floor(bins)))\n\n try {\n const breaks = equalIntervalBreaks(nums, binCount)\n const rows: string[] = []\n const maxCount = (() => {\n let m = 0\n for (let i = 0; i < breaks.length - 1; i++) {\n const isLast = i === breaks.length - 2\n const count = nums.filter((v) =>\n isLast ? v >= breaks[i] && v <= breaks[i + 1] : v >= breaks[i] && v < breaks[i + 1]\n ).length\n if (count > m) m = count\n }\n return m\n })()\n\n for (let i = 0; i < breaks.length - 1; i++) {\n const isLast = i === breaks.length - 2\n const count = nums.filter((v) =>\n isLast ? v >= breaks[i] && v <= breaks[i + 1] : v >= breaks[i] && v < breaks[i + 1]\n ).length\n const pct = ((count / nums.length) * 100).toFixed(1)\n const bar = '█'.repeat(maxCount > 0 ? Math.round((count / maxCount) * 20) : 0)\n const range = `[${formatBig(breaks[i], precision)}, ${formatBig(breaks[i + 1], precision)}${isLast ? ']' : ')'}`\n rows.push(`${range.padEnd(22)} ${String(count).padStart(4)} (${pct.padStart(5)}%) ${bar}`)\n }\n\n return rows.join('\\n')\n } catch (err) {\n return `Error: ${isError(err) ? err.message : String(err)}`\n }\n },\n})\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("../../chunk-Ble4zEEl.js");
3
- const require_tool_registry = require("../../tool_registry-DYUYqXvo.js");
4
- const require_tool = require("../../tool-CVyZkFC7.js");
5
- require("../../common-Cj8TaQ9U.js");
3
+ const require_tool_registry = require("../../tool_registry-CKJPze3j.js");
4
+ const require_tool = require("../../tool-D5WGVIcI.js");
5
+ require("../../common-DZl3ADJs.js");
6
6
  require("../../guards.cjs");
7
7
  let _nhtio_validation = require("@nhtio/validation");
8
8
  let case_anything = require("case-anything");
@@ -33,8 +33,8 @@ function applyStringOp(text, op) {
33
33
  case "trim_start": return text.trimStart();
34
34
  case "trim_end": return text.trimEnd();
35
35
  case "normalize_whitespace": return text.replace(/\s+/g, " ").trim();
36
- case "reverse": return text.split("").reverse().join("");
37
- case "slug": return text.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
36
+ case "reverse": return [...text].reverse().join("");
37
+ case "slug": return text.toLowerCase().replace(/\u00df/g, "ss").replace(/\u00e6/g, "ae").replace(/\u0153/g, "oe").replace(/\u00f8/g, "o").replace(/\u0111/g, "d").replace(/\u0142/g, "l").replace(/\u00fe/g, "th").normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
38
38
  case "strip_html": return text.replace(/<[^>]*>/g, "");
39
39
  case "count_words": return text.trim() === "" ? 0 : text.trim().split(/\s+/).length;
40
40
  case "count_chars": return text.length;
@@ -1 +1 @@
1
- {"version":3,"file":"string_processing.cjs","names":[],"sources":["../../../src/batteries/tools/string_processing/index.ts"],"sourcesContent":["/**\n * Pre-constructed tools for casing, trimming, normalizing, and transforming strings.\n *\n * @module @nhtio/adk/batteries/tools/string_processing\n *\n * @remarks\n * Pre-constructed bundled tools for the `string_processing` category. Import individually, the whole\n * category, or import every tool via `@nhtio/adk/batteries`.\n */\n\nimport { Tool } from '@nhtio/adk/common'\nimport { isError } from '@nhtio/adk/guards'\nimport { validator } from '@nhtio/validation'\nimport { camelCase, capitalCase, kebabCase, pascalCase, snakeCase, trainCase } from 'case-anything'\n\ntype StringOp =\n | { op: 'uppercase' }\n | { op: 'lowercase' }\n | { op: 'titlecase' }\n | { op: 'sentence_case' }\n | { op: 'capitalize' }\n | { op: 'camel_case' }\n | { op: 'pascal_case' }\n | { op: 'snake_case' }\n | { op: 'kebab_case' }\n | { op: 'train_case' }\n | { op: 'constant_case' }\n | { op: 'trim' }\n | { op: 'trim_start' }\n | { op: 'trim_end' }\n | { op: 'normalize_whitespace' }\n | { op: 'reverse' }\n | { op: 'slug' }\n | { op: 'strip_html' }\n | { op: 'count_words' }\n | { op: 'count_chars' }\n | { op: 'count_lines' }\n | { op: 'repeat'; count: number }\n | { op: 'pad_start'; length: number; char?: string }\n | { op: 'pad_end'; length: number; char?: string }\n | { op: 'slice'; start: number; end?: number }\n | { op: 'truncate'; length: number; suffix?: string }\n | { op: 'replace'; from: string; to: string }\n | { op: 'replace_all'; from: string; to: string }\n | { op: 'regex_replace'; pattern: string; replacement: string; flags?: string }\n | { op: 'split'; delimiter: string }\n | { op: 'indent'; size?: number; char?: string }\n | { op: 'dedent' }\n\nfunction applyStringOp(text: string, op: StringOp): string | number | string[] {\n switch (op.op) {\n case 'uppercase':\n return text.toUpperCase()\n case 'lowercase':\n return text.toLowerCase()\n case 'capitalize':\n return text.charAt(0).toUpperCase() + text.slice(1)\n case 'titlecase':\n return capitalCase(text)\n case 'sentence_case':\n return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase()\n case 'camel_case':\n return camelCase(text)\n case 'pascal_case':\n return pascalCase(text)\n case 'snake_case':\n return snakeCase(text)\n case 'kebab_case':\n return kebabCase(text)\n case 'train_case':\n return trainCase(text)\n case 'constant_case':\n return snakeCase(text).toUpperCase()\n case 'trim':\n return text.trim()\n case 'trim_start':\n return text.trimStart()\n case 'trim_end':\n return text.trimEnd()\n case 'normalize_whitespace':\n return text.replace(/\\s+/g, ' ').trim()\n case 'reverse':\n return text.split('').reverse().join('')\n case 'slug':\n return text\n .toLowerCase()\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n case 'strip_html':\n return text.replace(/<[^>]*>/g, '')\n case 'count_words':\n return text.trim() === '' ? 0 : text.trim().split(/\\s+/).length\n case 'count_chars':\n return text.length\n case 'count_lines':\n return text === '' ? 0 : text.split('\\n').length\n case 'repeat':\n return text.repeat(Math.max(0, Math.min(100, Math.floor(op.count))))\n case 'pad_start':\n return text.padStart(op.length, op.char ?? ' ')\n case 'pad_end':\n return text.padEnd(op.length, op.char ?? ' ')\n case 'slice':\n return text.slice(op.start, op.end)\n case 'truncate': {\n const suffix = op.suffix ?? '…'\n if (text.length <= op.length) return text\n return text.slice(0, Math.max(0, op.length - suffix.length)) + suffix\n }\n case 'replace':\n return text.replace(op.from, op.to)\n case 'replace_all':\n return text.split(op.from).join(op.to)\n case 'regex_replace': {\n const flags = (op.flags ?? 'g').replace(/[^gimsuy]/g, '')\n let re: RegExp\n try {\n re = new RegExp(op.pattern, flags)\n } catch (e) {\n throw new Error(`Invalid regex: ${isError(e) ? e.message : String(e)}`)\n }\n return text.replace(re, op.replacement)\n }\n case 'split':\n return text.split(op.delimiter)\n case 'indent': {\n const size = op.size ?? 2\n const ch = op.char ?? ' '\n const pad = ch.repeat(size)\n return text\n .split('\\n')\n .map((l) => (l === '' ? l : pad + l))\n .join('\\n')\n }\n case 'dedent': {\n const lines = text.split('\\n')\n const nonEmpty = lines.filter((l) => l.trim() !== '')\n if (nonEmpty.length === 0) return text\n const minIndent = Math.min(...nonEmpty.map((l) => l.match(/^(\\s*)/)?.[1].length ?? 0))\n return lines.map((l) => l.slice(minIndent)).join('\\n')\n }\n default:\n throw new Error(`Unknown operation: ${(op as { op: string }).op}`)\n }\n}\n\n/**\n * Apply an ordered pipeline of string transformations.\n *\n * @remarks\n * Each operation reads the previous step's output. Most operations return strings; `count_*`\n * return numbers and `split` returns an array — once a non-string flows through, subsequent\n * operations report an error rather than coercing. The result is always serialised to a string\n * (arrays become JSON; numbers/booleans are stringified).\n */\nexport const stringTransformTool = new Tool({\n name: 'string_transform',\n description:\n 'Apply one or more string transformations in sequence. Supports case conversion (camelCase, snake_case, kebab-case, etc.), trimming, truncation, replacement, splitting, indentation, and more.',\n inputSchema: validator.object({\n text: validator.string().required().allow('').description('Input string to transform'),\n operations: validator\n .array()\n .items(validator.object().unknown(true))\n .required()\n .description('Ordered list of operations to apply. Each operation has an \"op\" field.'),\n }),\n handler: async (args) => {\n const { text, operations } = args as { text: string; operations: StringOp[] }\n let current: string | number | string[] = text\n\n for (const [i, op] of operations.entries()) {\n if (typeof current !== 'string') {\n return `Error: Operation ${i + 1} (\"${op.op}\") requires a string input, but the previous operation returned ${Array.isArray(current) ? 'an array' : typeof current}.`\n }\n try {\n current = applyStringOp(current, op)\n } catch (err) {\n return `Error in operation ${i + 1} (\"${op.op}\"): ${isError(err) ? err.message : String(err)}`\n }\n }\n\n if (Array.isArray(current)) return JSON.stringify(current)\n return String(current)\n },\n})\n\n/**\n * Extract all matches of a regular expression from a string.\n *\n * @remarks\n * The `g` flag is always enabled. `group` selects which capture group to return per match (0 =\n * full match). Output is at most 500 matches; if truncated, the suffix `(truncated at 500)` is\n * appended.\n */\nexport const stringExtractTool = new Tool({\n name: 'string_extract',\n description:\n 'Extract all matches of a regex pattern from text. Returns a JSON array of matched strings. Use capture groups to pull out specific parts.',\n inputSchema: validator.object({\n text: validator.string().required().allow('').description('Input text to search'),\n pattern: validator\n .string()\n .required()\n .description('Regular expression pattern (no surrounding slashes)'),\n flags: validator\n .string()\n .default('g')\n .description('Regex flags (default: \"g\"). \"g\" is always included.'),\n group: validator\n .number()\n .default(0)\n .description('Capture group index to return (0 = full match, 1 = first group). Default: 0.'),\n }),\n handler: async (args) => {\n const {\n text,\n pattern,\n flags: rawFlags,\n group,\n } = args as {\n text: string\n pattern: string\n flags: string\n group: number\n }\n const flags = rawFlags.replace(/[^gimsuy]/g, '')\n const flagsWithG = flags.includes('g') ? flags : flags + 'g'\n\n let regex: RegExp\n try {\n regex = new RegExp(pattern, flagsWithG)\n } catch (err) {\n return `Error: Invalid regex — ${isError(err) ? err.message : String(err)}`\n }\n\n const matches: string[] = []\n let match: RegExpExecArray | null\n const MAX_MATCHES = 500\n\n while ((match = regex.exec(text)) !== null && matches.length < MAX_MATCHES) {\n const value = match[group]\n if (value !== undefined) matches.push(value)\n if (match.index === regex.lastIndex) regex.lastIndex++\n }\n\n if (matches.length === 0) return 'No matches found.'\n const truncated = matches.length === MAX_MATCHES ? ' (truncated at 500)' : ''\n return JSON.stringify(matches) + truncated\n },\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"string_processing.cjs","names":[],"sources":["../../../src/batteries/tools/string_processing/index.ts"],"sourcesContent":["/**\n * Pre-constructed tools for casing, trimming, normalizing, and transforming strings.\n *\n * @module @nhtio/adk/batteries/tools/string_processing\n *\n * @remarks\n * Pre-constructed bundled tools for the `string_processing` category. Import individually, the whole\n * category, or import every tool via `@nhtio/adk/batteries`.\n */\n\nimport { Tool } from '@nhtio/adk/common'\nimport { isError } from '@nhtio/adk/guards'\nimport { validator } from '@nhtio/validation'\nimport { camelCase, capitalCase, kebabCase, pascalCase, snakeCase, trainCase } from 'case-anything'\n\ntype StringOp =\n | { op: 'uppercase' }\n | { op: 'lowercase' }\n | { op: 'titlecase' }\n | { op: 'sentence_case' }\n | { op: 'capitalize' }\n | { op: 'camel_case' }\n | { op: 'pascal_case' }\n | { op: 'snake_case' }\n | { op: 'kebab_case' }\n | { op: 'train_case' }\n | { op: 'constant_case' }\n | { op: 'trim' }\n | { op: 'trim_start' }\n | { op: 'trim_end' }\n | { op: 'normalize_whitespace' }\n | { op: 'reverse' }\n | { op: 'slug' }\n | { op: 'strip_html' }\n | { op: 'count_words' }\n | { op: 'count_chars' }\n | { op: 'count_lines' }\n | { op: 'repeat'; count: number }\n | { op: 'pad_start'; length: number; char?: string }\n | { op: 'pad_end'; length: number; char?: string }\n | { op: 'slice'; start: number; end?: number }\n | { op: 'truncate'; length: number; suffix?: string }\n | { op: 'replace'; from: string; to: string }\n | { op: 'replace_all'; from: string; to: string }\n | { op: 'regex_replace'; pattern: string; replacement: string; flags?: string }\n | { op: 'split'; delimiter: string }\n | { op: 'indent'; size?: number; char?: string }\n | { op: 'dedent' }\n\nfunction applyStringOp(text: string, op: StringOp): string | number | string[] {\n switch (op.op) {\n case 'uppercase':\n return text.toUpperCase()\n case 'lowercase':\n return text.toLowerCase()\n case 'capitalize':\n return text.charAt(0).toUpperCase() + text.slice(1)\n case 'titlecase':\n return capitalCase(text)\n case 'sentence_case':\n return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase()\n case 'camel_case':\n return camelCase(text)\n case 'pascal_case':\n return pascalCase(text)\n case 'snake_case':\n return snakeCase(text)\n case 'kebab_case':\n return kebabCase(text)\n case 'train_case':\n return trainCase(text)\n case 'constant_case':\n return snakeCase(text).toUpperCase()\n case 'trim':\n return text.trim()\n case 'trim_start':\n return text.trimStart()\n case 'trim_end':\n return text.trimEnd()\n case 'normalize_whitespace':\n return text.replace(/\\s+/g, ' ').trim()\n case 'reverse':\n // Iterate by code point ([...text]), not UTF-16 code unit, so astral characters / emoji\n // (surrogate pairs) are not split into broken halves. 'A\\ud83d\\udca5B' \\u2192 'B\\ud83d\\udca5A'.\n return [...text].reverse().join('')\n case 'slug':\n return (\n text\n .toLowerCase()\n // Transliterate common Latin-1 letters/ligatures that do NOT decompose under NFD, so they\n // survive the a-z0-9 filter instead of becoming hyphens (e.g. 'f\\u00f8tex' \\u2192 'fotex', not 'f-tex').\n .replace(/\\u00df/g, 'ss')\n .replace(/\\u00e6/g, 'ae')\n .replace(/\\u0153/g, 'oe')\n .replace(/\\u00f8/g, 'o')\n .replace(/\\u0111/g, 'd')\n .replace(/\\u0142/g, 'l')\n .replace(/\\u00fe/g, 'th')\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n )\n case 'strip_html':\n return text.replace(/<[^>]*>/g, '')\n case 'count_words':\n return text.trim() === '' ? 0 : text.trim().split(/\\s+/).length\n case 'count_chars':\n return text.length\n case 'count_lines':\n return text === '' ? 0 : text.split('\\n').length\n case 'repeat':\n return text.repeat(Math.max(0, Math.min(100, Math.floor(op.count))))\n case 'pad_start':\n return text.padStart(op.length, op.char ?? ' ')\n case 'pad_end':\n return text.padEnd(op.length, op.char ?? ' ')\n case 'slice':\n return text.slice(op.start, op.end)\n case 'truncate': {\n const suffix = op.suffix ?? '…'\n if (text.length <= op.length) return text\n return text.slice(0, Math.max(0, op.length - suffix.length)) + suffix\n }\n case 'replace':\n return text.replace(op.from, op.to)\n case 'replace_all':\n return text.split(op.from).join(op.to)\n case 'regex_replace': {\n const flags = (op.flags ?? 'g').replace(/[^gimsuy]/g, '')\n let re: RegExp\n try {\n re = new RegExp(op.pattern, flags)\n } catch (e) {\n throw new Error(`Invalid regex: ${isError(e) ? e.message : String(e)}`)\n }\n return text.replace(re, op.replacement)\n }\n case 'split':\n return text.split(op.delimiter)\n case 'indent': {\n const size = op.size ?? 2\n const ch = op.char ?? ' '\n const pad = ch.repeat(size)\n return text\n .split('\\n')\n .map((l) => (l === '' ? l : pad + l))\n .join('\\n')\n }\n case 'dedent': {\n const lines = text.split('\\n')\n const nonEmpty = lines.filter((l) => l.trim() !== '')\n if (nonEmpty.length === 0) return text\n const minIndent = Math.min(...nonEmpty.map((l) => l.match(/^(\\s*)/)?.[1].length ?? 0))\n return lines.map((l) => l.slice(minIndent)).join('\\n')\n }\n default:\n throw new Error(`Unknown operation: ${(op as { op: string }).op}`)\n }\n}\n\n/**\n * Apply an ordered pipeline of string transformations.\n *\n * @remarks\n * Each operation reads the previous step's output. Most operations return strings; `count_*`\n * return numbers and `split` returns an array — once a non-string flows through, subsequent\n * operations report an error rather than coercing. The result is always serialised to a string\n * (arrays become JSON; numbers/booleans are stringified).\n */\nexport const stringTransformTool = new Tool({\n name: 'string_transform',\n description:\n 'Apply one or more string transformations in sequence. Supports case conversion (camelCase, snake_case, kebab-case, etc.), trimming, truncation, replacement, splitting, indentation, and more.',\n inputSchema: validator.object({\n text: validator.string().required().allow('').description('Input string to transform'),\n operations: validator\n .array()\n .items(validator.object().unknown(true))\n .required()\n .description('Ordered list of operations to apply. Each operation has an \"op\" field.'),\n }),\n handler: async (args) => {\n const { text, operations } = args as { text: string; operations: StringOp[] }\n let current: string | number | string[] = text\n\n for (const [i, op] of operations.entries()) {\n if (typeof current !== 'string') {\n return `Error: Operation ${i + 1} (\"${op.op}\") requires a string input, but the previous operation returned ${Array.isArray(current) ? 'an array' : typeof current}.`\n }\n try {\n current = applyStringOp(current, op)\n } catch (err) {\n return `Error in operation ${i + 1} (\"${op.op}\"): ${isError(err) ? err.message : String(err)}`\n }\n }\n\n if (Array.isArray(current)) return JSON.stringify(current)\n return String(current)\n },\n})\n\n/**\n * Extract all matches of a regular expression from a string.\n *\n * @remarks\n * The `g` flag is always enabled. `group` selects which capture group to return per match (0 =\n * full match). Output is at most 500 matches; if truncated, the suffix `(truncated at 500)` is\n * appended.\n */\nexport const stringExtractTool = new Tool({\n name: 'string_extract',\n description:\n 'Extract all matches of a regex pattern from text. Returns a JSON array of matched strings. Use capture groups to pull out specific parts.',\n inputSchema: validator.object({\n text: validator.string().required().allow('').description('Input text to search'),\n pattern: validator\n .string()\n .required()\n .description('Regular expression pattern (no surrounding slashes)'),\n flags: validator\n .string()\n .default('g')\n .description('Regex flags (default: \"g\"). \"g\" is always included.'),\n group: validator\n .number()\n .default(0)\n .description('Capture group index to return (0 = full match, 1 = first group). Default: 0.'),\n }),\n handler: async (args) => {\n const {\n text,\n pattern,\n flags: rawFlags,\n group,\n } = args as {\n text: string\n pattern: string\n flags: string\n group: number\n }\n const flags = rawFlags.replace(/[^gimsuy]/g, '')\n const flagsWithG = flags.includes('g') ? flags : flags + 'g'\n\n let regex: RegExp\n try {\n regex = new RegExp(pattern, flagsWithG)\n } catch (err) {\n return `Error: Invalid regex — ${isError(err) ? err.message : String(err)}`\n }\n\n const matches: string[] = []\n let match: RegExpExecArray | null\n const MAX_MATCHES = 500\n\n while ((match = regex.exec(text)) !== null && matches.length < MAX_MATCHES) {\n const value = match[group]\n if (value !== undefined) matches.push(value)\n if (match.index === regex.lastIndex) regex.lastIndex++\n }\n\n if (matches.length === 0) return 'No matches found.'\n const truncated = matches.length === MAX_MATCHES ? ' (truncated at 500)' : ''\n return JSON.stringify(matches) + truncated\n },\n})\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { o as isError } from "../../tool_registry-D1pSSlsd.mjs";
2
- import { t as Tool } from "../../tool-CMhaDRNd.mjs";
3
- import "../../common-BT0nfCi9.mjs";
1
+ import { o as isError } from "../../tool_registry-791Vrjtf.mjs";
2
+ import { t as Tool } from "../../tool-wMYMVl60.mjs";
3
+ import "../../common-DYDUi99O.mjs";
4
4
  import "../../guards.mjs";
5
5
  import { validator } from "@nhtio/validation";
6
6
  import { camelCase, capitalCase, kebabCase, pascalCase, snakeCase, trainCase } from "case-anything";
@@ -31,8 +31,8 @@ function applyStringOp(text, op) {
31
31
  case "trim_start": return text.trimStart();
32
32
  case "trim_end": return text.trimEnd();
33
33
  case "normalize_whitespace": return text.replace(/\s+/g, " ").trim();
34
- case "reverse": return text.split("").reverse().join("");
35
- case "slug": return text.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
34
+ case "reverse": return [...text].reverse().join("");
35
+ case "slug": return text.toLowerCase().replace(/\u00df/g, "ss").replace(/\u00e6/g, "ae").replace(/\u0153/g, "oe").replace(/\u00f8/g, "o").replace(/\u0111/g, "d").replace(/\u0142/g, "l").replace(/\u00fe/g, "th").normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
36
36
  case "strip_html": return text.replace(/<[^>]*>/g, "");
37
37
  case "count_words": return text.trim() === "" ? 0 : text.trim().split(/\s+/).length;
38
38
  case "count_chars": return text.length;
@@ -1 +1 @@
1
- {"version":3,"file":"string_processing.mjs","names":[],"sources":["../../../src/batteries/tools/string_processing/index.ts"],"sourcesContent":["/**\n * Pre-constructed tools for casing, trimming, normalizing, and transforming strings.\n *\n * @module @nhtio/adk/batteries/tools/string_processing\n *\n * @remarks\n * Pre-constructed bundled tools for the `string_processing` category. Import individually, the whole\n * category, or import every tool via `@nhtio/adk/batteries`.\n */\n\nimport { Tool } from '@nhtio/adk/common'\nimport { isError } from '@nhtio/adk/guards'\nimport { validator } from '@nhtio/validation'\nimport { camelCase, capitalCase, kebabCase, pascalCase, snakeCase, trainCase } from 'case-anything'\n\ntype StringOp =\n | { op: 'uppercase' }\n | { op: 'lowercase' }\n | { op: 'titlecase' }\n | { op: 'sentence_case' }\n | { op: 'capitalize' }\n | { op: 'camel_case' }\n | { op: 'pascal_case' }\n | { op: 'snake_case' }\n | { op: 'kebab_case' }\n | { op: 'train_case' }\n | { op: 'constant_case' }\n | { op: 'trim' }\n | { op: 'trim_start' }\n | { op: 'trim_end' }\n | { op: 'normalize_whitespace' }\n | { op: 'reverse' }\n | { op: 'slug' }\n | { op: 'strip_html' }\n | { op: 'count_words' }\n | { op: 'count_chars' }\n | { op: 'count_lines' }\n | { op: 'repeat'; count: number }\n | { op: 'pad_start'; length: number; char?: string }\n | { op: 'pad_end'; length: number; char?: string }\n | { op: 'slice'; start: number; end?: number }\n | { op: 'truncate'; length: number; suffix?: string }\n | { op: 'replace'; from: string; to: string }\n | { op: 'replace_all'; from: string; to: string }\n | { op: 'regex_replace'; pattern: string; replacement: string; flags?: string }\n | { op: 'split'; delimiter: string }\n | { op: 'indent'; size?: number; char?: string }\n | { op: 'dedent' }\n\nfunction applyStringOp(text: string, op: StringOp): string | number | string[] {\n switch (op.op) {\n case 'uppercase':\n return text.toUpperCase()\n case 'lowercase':\n return text.toLowerCase()\n case 'capitalize':\n return text.charAt(0).toUpperCase() + text.slice(1)\n case 'titlecase':\n return capitalCase(text)\n case 'sentence_case':\n return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase()\n case 'camel_case':\n return camelCase(text)\n case 'pascal_case':\n return pascalCase(text)\n case 'snake_case':\n return snakeCase(text)\n case 'kebab_case':\n return kebabCase(text)\n case 'train_case':\n return trainCase(text)\n case 'constant_case':\n return snakeCase(text).toUpperCase()\n case 'trim':\n return text.trim()\n case 'trim_start':\n return text.trimStart()\n case 'trim_end':\n return text.trimEnd()\n case 'normalize_whitespace':\n return text.replace(/\\s+/g, ' ').trim()\n case 'reverse':\n return text.split('').reverse().join('')\n case 'slug':\n return text\n .toLowerCase()\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n case 'strip_html':\n return text.replace(/<[^>]*>/g, '')\n case 'count_words':\n return text.trim() === '' ? 0 : text.trim().split(/\\s+/).length\n case 'count_chars':\n return text.length\n case 'count_lines':\n return text === '' ? 0 : text.split('\\n').length\n case 'repeat':\n return text.repeat(Math.max(0, Math.min(100, Math.floor(op.count))))\n case 'pad_start':\n return text.padStart(op.length, op.char ?? ' ')\n case 'pad_end':\n return text.padEnd(op.length, op.char ?? ' ')\n case 'slice':\n return text.slice(op.start, op.end)\n case 'truncate': {\n const suffix = op.suffix ?? '…'\n if (text.length <= op.length) return text\n return text.slice(0, Math.max(0, op.length - suffix.length)) + suffix\n }\n case 'replace':\n return text.replace(op.from, op.to)\n case 'replace_all':\n return text.split(op.from).join(op.to)\n case 'regex_replace': {\n const flags = (op.flags ?? 'g').replace(/[^gimsuy]/g, '')\n let re: RegExp\n try {\n re = new RegExp(op.pattern, flags)\n } catch (e) {\n throw new Error(`Invalid regex: ${isError(e) ? e.message : String(e)}`)\n }\n return text.replace(re, op.replacement)\n }\n case 'split':\n return text.split(op.delimiter)\n case 'indent': {\n const size = op.size ?? 2\n const ch = op.char ?? ' '\n const pad = ch.repeat(size)\n return text\n .split('\\n')\n .map((l) => (l === '' ? l : pad + l))\n .join('\\n')\n }\n case 'dedent': {\n const lines = text.split('\\n')\n const nonEmpty = lines.filter((l) => l.trim() !== '')\n if (nonEmpty.length === 0) return text\n const minIndent = Math.min(...nonEmpty.map((l) => l.match(/^(\\s*)/)?.[1].length ?? 0))\n return lines.map((l) => l.slice(minIndent)).join('\\n')\n }\n default:\n throw new Error(`Unknown operation: ${(op as { op: string }).op}`)\n }\n}\n\n/**\n * Apply an ordered pipeline of string transformations.\n *\n * @remarks\n * Each operation reads the previous step's output. Most operations return strings; `count_*`\n * return numbers and `split` returns an array — once a non-string flows through, subsequent\n * operations report an error rather than coercing. The result is always serialised to a string\n * (arrays become JSON; numbers/booleans are stringified).\n */\nexport const stringTransformTool = new Tool({\n name: 'string_transform',\n description:\n 'Apply one or more string transformations in sequence. Supports case conversion (camelCase, snake_case, kebab-case, etc.), trimming, truncation, replacement, splitting, indentation, and more.',\n inputSchema: validator.object({\n text: validator.string().required().allow('').description('Input string to transform'),\n operations: validator\n .array()\n .items(validator.object().unknown(true))\n .required()\n .description('Ordered list of operations to apply. Each operation has an \"op\" field.'),\n }),\n handler: async (args) => {\n const { text, operations } = args as { text: string; operations: StringOp[] }\n let current: string | number | string[] = text\n\n for (const [i, op] of operations.entries()) {\n if (typeof current !== 'string') {\n return `Error: Operation ${i + 1} (\"${op.op}\") requires a string input, but the previous operation returned ${Array.isArray(current) ? 'an array' : typeof current}.`\n }\n try {\n current = applyStringOp(current, op)\n } catch (err) {\n return `Error in operation ${i + 1} (\"${op.op}\"): ${isError(err) ? err.message : String(err)}`\n }\n }\n\n if (Array.isArray(current)) return JSON.stringify(current)\n return String(current)\n },\n})\n\n/**\n * Extract all matches of a regular expression from a string.\n *\n * @remarks\n * The `g` flag is always enabled. `group` selects which capture group to return per match (0 =\n * full match). Output is at most 500 matches; if truncated, the suffix `(truncated at 500)` is\n * appended.\n */\nexport const stringExtractTool = new Tool({\n name: 'string_extract',\n description:\n 'Extract all matches of a regex pattern from text. Returns a JSON array of matched strings. Use capture groups to pull out specific parts.',\n inputSchema: validator.object({\n text: validator.string().required().allow('').description('Input text to search'),\n pattern: validator\n .string()\n .required()\n .description('Regular expression pattern (no surrounding slashes)'),\n flags: validator\n .string()\n .default('g')\n .description('Regex flags (default: \"g\"). \"g\" is always included.'),\n group: validator\n .number()\n .default(0)\n .description('Capture group index to return (0 = full match, 1 = first group). Default: 0.'),\n }),\n handler: async (args) => {\n const {\n text,\n pattern,\n flags: rawFlags,\n group,\n } = args as {\n text: string\n pattern: string\n flags: string\n group: number\n }\n const flags = rawFlags.replace(/[^gimsuy]/g, '')\n const flagsWithG = flags.includes('g') ? flags : flags + 'g'\n\n let regex: RegExp\n try {\n regex = new RegExp(pattern, flagsWithG)\n } catch (err) {\n return `Error: Invalid regex — ${isError(err) ? err.message : String(err)}`\n }\n\n const matches: string[] = []\n let match: RegExpExecArray | null\n const MAX_MATCHES = 500\n\n while ((match = regex.exec(text)) !== null && matches.length < MAX_MATCHES) {\n const value = match[group]\n if (value !== undefined) matches.push(value)\n if (match.index === regex.lastIndex) regex.lastIndex++\n }\n\n if (matches.length === 0) return 'No matches found.'\n const truncated = matches.length === MAX_MATCHES ? ' (truncated at 500)' : ''\n return JSON.stringify(matches) + truncated\n },\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"string_processing.mjs","names":[],"sources":["../../../src/batteries/tools/string_processing/index.ts"],"sourcesContent":["/**\n * Pre-constructed tools for casing, trimming, normalizing, and transforming strings.\n *\n * @module @nhtio/adk/batteries/tools/string_processing\n *\n * @remarks\n * Pre-constructed bundled tools for the `string_processing` category. Import individually, the whole\n * category, or import every tool via `@nhtio/adk/batteries`.\n */\n\nimport { Tool } from '@nhtio/adk/common'\nimport { isError } from '@nhtio/adk/guards'\nimport { validator } from '@nhtio/validation'\nimport { camelCase, capitalCase, kebabCase, pascalCase, snakeCase, trainCase } from 'case-anything'\n\ntype StringOp =\n | { op: 'uppercase' }\n | { op: 'lowercase' }\n | { op: 'titlecase' }\n | { op: 'sentence_case' }\n | { op: 'capitalize' }\n | { op: 'camel_case' }\n | { op: 'pascal_case' }\n | { op: 'snake_case' }\n | { op: 'kebab_case' }\n | { op: 'train_case' }\n | { op: 'constant_case' }\n | { op: 'trim' }\n | { op: 'trim_start' }\n | { op: 'trim_end' }\n | { op: 'normalize_whitespace' }\n | { op: 'reverse' }\n | { op: 'slug' }\n | { op: 'strip_html' }\n | { op: 'count_words' }\n | { op: 'count_chars' }\n | { op: 'count_lines' }\n | { op: 'repeat'; count: number }\n | { op: 'pad_start'; length: number; char?: string }\n | { op: 'pad_end'; length: number; char?: string }\n | { op: 'slice'; start: number; end?: number }\n | { op: 'truncate'; length: number; suffix?: string }\n | { op: 'replace'; from: string; to: string }\n | { op: 'replace_all'; from: string; to: string }\n | { op: 'regex_replace'; pattern: string; replacement: string; flags?: string }\n | { op: 'split'; delimiter: string }\n | { op: 'indent'; size?: number; char?: string }\n | { op: 'dedent' }\n\nfunction applyStringOp(text: string, op: StringOp): string | number | string[] {\n switch (op.op) {\n case 'uppercase':\n return text.toUpperCase()\n case 'lowercase':\n return text.toLowerCase()\n case 'capitalize':\n return text.charAt(0).toUpperCase() + text.slice(1)\n case 'titlecase':\n return capitalCase(text)\n case 'sentence_case':\n return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase()\n case 'camel_case':\n return camelCase(text)\n case 'pascal_case':\n return pascalCase(text)\n case 'snake_case':\n return snakeCase(text)\n case 'kebab_case':\n return kebabCase(text)\n case 'train_case':\n return trainCase(text)\n case 'constant_case':\n return snakeCase(text).toUpperCase()\n case 'trim':\n return text.trim()\n case 'trim_start':\n return text.trimStart()\n case 'trim_end':\n return text.trimEnd()\n case 'normalize_whitespace':\n return text.replace(/\\s+/g, ' ').trim()\n case 'reverse':\n // Iterate by code point ([...text]), not UTF-16 code unit, so astral characters / emoji\n // (surrogate pairs) are not split into broken halves. 'A\\ud83d\\udca5B' \\u2192 'B\\ud83d\\udca5A'.\n return [...text].reverse().join('')\n case 'slug':\n return (\n text\n .toLowerCase()\n // Transliterate common Latin-1 letters/ligatures that do NOT decompose under NFD, so they\n // survive the a-z0-9 filter instead of becoming hyphens (e.g. 'f\\u00f8tex' \\u2192 'fotex', not 'f-tex').\n .replace(/\\u00df/g, 'ss')\n .replace(/\\u00e6/g, 'ae')\n .replace(/\\u0153/g, 'oe')\n .replace(/\\u00f8/g, 'o')\n .replace(/\\u0111/g, 'd')\n .replace(/\\u0142/g, 'l')\n .replace(/\\u00fe/g, 'th')\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n )\n case 'strip_html':\n return text.replace(/<[^>]*>/g, '')\n case 'count_words':\n return text.trim() === '' ? 0 : text.trim().split(/\\s+/).length\n case 'count_chars':\n return text.length\n case 'count_lines':\n return text === '' ? 0 : text.split('\\n').length\n case 'repeat':\n return text.repeat(Math.max(0, Math.min(100, Math.floor(op.count))))\n case 'pad_start':\n return text.padStart(op.length, op.char ?? ' ')\n case 'pad_end':\n return text.padEnd(op.length, op.char ?? ' ')\n case 'slice':\n return text.slice(op.start, op.end)\n case 'truncate': {\n const suffix = op.suffix ?? '…'\n if (text.length <= op.length) return text\n return text.slice(0, Math.max(0, op.length - suffix.length)) + suffix\n }\n case 'replace':\n return text.replace(op.from, op.to)\n case 'replace_all':\n return text.split(op.from).join(op.to)\n case 'regex_replace': {\n const flags = (op.flags ?? 'g').replace(/[^gimsuy]/g, '')\n let re: RegExp\n try {\n re = new RegExp(op.pattern, flags)\n } catch (e) {\n throw new Error(`Invalid regex: ${isError(e) ? e.message : String(e)}`)\n }\n return text.replace(re, op.replacement)\n }\n case 'split':\n return text.split(op.delimiter)\n case 'indent': {\n const size = op.size ?? 2\n const ch = op.char ?? ' '\n const pad = ch.repeat(size)\n return text\n .split('\\n')\n .map((l) => (l === '' ? l : pad + l))\n .join('\\n')\n }\n case 'dedent': {\n const lines = text.split('\\n')\n const nonEmpty = lines.filter((l) => l.trim() !== '')\n if (nonEmpty.length === 0) return text\n const minIndent = Math.min(...nonEmpty.map((l) => l.match(/^(\\s*)/)?.[1].length ?? 0))\n return lines.map((l) => l.slice(minIndent)).join('\\n')\n }\n default:\n throw new Error(`Unknown operation: ${(op as { op: string }).op}`)\n }\n}\n\n/**\n * Apply an ordered pipeline of string transformations.\n *\n * @remarks\n * Each operation reads the previous step's output. Most operations return strings; `count_*`\n * return numbers and `split` returns an array — once a non-string flows through, subsequent\n * operations report an error rather than coercing. The result is always serialised to a string\n * (arrays become JSON; numbers/booleans are stringified).\n */\nexport const stringTransformTool = new Tool({\n name: 'string_transform',\n description:\n 'Apply one or more string transformations in sequence. Supports case conversion (camelCase, snake_case, kebab-case, etc.), trimming, truncation, replacement, splitting, indentation, and more.',\n inputSchema: validator.object({\n text: validator.string().required().allow('').description('Input string to transform'),\n operations: validator\n .array()\n .items(validator.object().unknown(true))\n .required()\n .description('Ordered list of operations to apply. Each operation has an \"op\" field.'),\n }),\n handler: async (args) => {\n const { text, operations } = args as { text: string; operations: StringOp[] }\n let current: string | number | string[] = text\n\n for (const [i, op] of operations.entries()) {\n if (typeof current !== 'string') {\n return `Error: Operation ${i + 1} (\"${op.op}\") requires a string input, but the previous operation returned ${Array.isArray(current) ? 'an array' : typeof current}.`\n }\n try {\n current = applyStringOp(current, op)\n } catch (err) {\n return `Error in operation ${i + 1} (\"${op.op}\"): ${isError(err) ? err.message : String(err)}`\n }\n }\n\n if (Array.isArray(current)) return JSON.stringify(current)\n return String(current)\n },\n})\n\n/**\n * Extract all matches of a regular expression from a string.\n *\n * @remarks\n * The `g` flag is always enabled. `group` selects which capture group to return per match (0 =\n * full match). Output is at most 500 matches; if truncated, the suffix `(truncated at 500)` is\n * appended.\n */\nexport const stringExtractTool = new Tool({\n name: 'string_extract',\n description:\n 'Extract all matches of a regex pattern from text. Returns a JSON array of matched strings. Use capture groups to pull out specific parts.',\n inputSchema: validator.object({\n text: validator.string().required().allow('').description('Input text to search'),\n pattern: validator\n .string()\n .required()\n .description('Regular expression pattern (no surrounding slashes)'),\n flags: validator\n .string()\n .default('g')\n .description('Regex flags (default: \"g\"). \"g\" is always included.'),\n group: validator\n .number()\n .default(0)\n .description('Capture group index to return (0 = full match, 1 = first group). Default: 0.'),\n }),\n handler: async (args) => {\n const {\n text,\n pattern,\n flags: rawFlags,\n group,\n } = args as {\n text: string\n pattern: string\n flags: string\n group: number\n }\n const flags = rawFlags.replace(/[^gimsuy]/g, '')\n const flagsWithG = flags.includes('g') ? flags : flags + 'g'\n\n let regex: RegExp\n try {\n regex = new RegExp(pattern, flagsWithG)\n } catch (err) {\n return `Error: Invalid regex — ${isError(err) ? err.message : String(err)}`\n }\n\n const matches: string[] = []\n let match: RegExpExecArray | null\n const MAX_MATCHES = 500\n\n while ((match = regex.exec(text)) !== null && matches.length < MAX_MATCHES) {\n const value = match[group]\n if (value !== undefined) matches.push(value)\n if (match.index === regex.lastIndex) regex.lastIndex++\n }\n\n if (matches.length === 0) return 'No matches found.'\n const truncated = matches.length === MAX_MATCHES ? ' (truncated at 500)' : ''\n return JSON.stringify(matches) + truncated\n },\n})\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("../../chunk-Ble4zEEl.js");
3
- const require_tool_registry = require("../../tool_registry-DYUYqXvo.js");
4
- const require_tool = require("../../tool-CVyZkFC7.js");
5
- require("../../common-Cj8TaQ9U.js");
3
+ const require_tool_registry = require("../../tool_registry-CKJPze3j.js");
4
+ const require_tool = require("../../tool-D5WGVIcI.js");
5
+ require("../../common-DZl3ADJs.js");
6
6
  require("../../guards.cjs");
7
7
  let _nhtio_validation = require("@nhtio/validation");
8
8
  //#region src/batteries/tools/structured_data/index.ts
@@ -51,29 +51,24 @@ var formatTableTool = new require_tool.Tool({
51
51
  }
52
52
  if (!Array.isArray(rows)) return "Error: Input must be a JSON array.";
53
53
  if (rows.length === 0) return "Empty array — no data to display.";
54
+ if (!explicitColumns && !require_tool_registry.isObject(rows[0])) return "Error: Cannot infer columns — the first row is not an object. Provide \"columns\", or pass an array of objects.";
54
55
  const columns = explicitColumns ?? Object.keys(rows[0]);
56
+ const cell = (row, col) => require_tool_registry.isObject(row) ? row[col] : void 0;
55
57
  if (format === "csv") {
56
58
  const lines = [columns.map(csvEscape).join(",")];
57
- for (const row of rows) {
58
- const obj = row;
59
- lines.push(columns.map((col) => csvEscape(obj[col])).join(","));
60
- }
59
+ for (const row of rows) lines.push(columns.map((col) => csvEscape(cell(row, col))).join(","));
61
60
  return lines.join("\n");
62
61
  }
63
62
  if (format === "tsv") {
64
63
  const lines = [columns.map(tsvEscape).join(" ")];
65
- for (const row of rows) {
66
- const obj = row;
67
- lines.push(columns.map((col) => tsvEscape(obj[col])).join(" "));
68
- }
64
+ for (const row of rows) lines.push(columns.map((col) => tsvEscape(cell(row, col))).join(" "));
69
65
  return lines.join("\n");
70
66
  }
71
67
  return [
72
68
  "| " + columns.map(mdEscape).join(" | ") + " |",
73
69
  "| " + columns.map(() => "---").join(" | ") + " |",
74
70
  ...rows.map((row) => {
75
- const obj = row;
76
- return "| " + columns.map((col) => mdEscape(obj[col])).join(" | ") + " |";
71
+ return "| " + columns.map((col) => mdEscape(cell(row, col))).join(" | ") + " |";
77
72
  })
78
73
  ].join("\n");
79
74
  }
@@ -1 +1 @@
1
- {"version":3,"file":"structured_data.cjs","names":[],"sources":["../../../src/batteries/tools/structured_data/index.ts"],"sourcesContent":["/**\n * Pre-constructed tools for transforming arrays and objects into tables and tabular text.\n *\n * @module @nhtio/adk/batteries/tools/structured_data\n *\n * @remarks\n * Pre-constructed bundled tools for the `structured_data` category. Import individually, the whole\n * category, or import every tool via `@nhtio/adk/batteries`.\n */\n\nimport { Tool } from '@nhtio/adk/common'\nimport { isError } from '@nhtio/adk/guards'\nimport { validator } from '@nhtio/validation'\n\nfunction csvEscape(value: unknown): string {\n const str = value === null || value === undefined ? '' : String(value)\n if (str.includes(',') || str.includes('\"') || str.includes('\\n') || str.includes('\\r')) {\n return '\"' + str.replace(/\"/g, '\"\"') + '\"'\n }\n return str\n}\n\nfunction tsvEscape(value: unknown): string {\n const str = value === null || value === undefined ? '' : String(value)\n return str.replace(/\\t/g, ' ').replace(/\\r?\\n/g, ' ')\n}\n\nfunction mdEscape(value: unknown): string {\n return String(value === null || value === undefined ? '' : value)\n .replace(/\\|/g, '\\\\|')\n .replace(/\\r?\\n/g, ' ')\n}\n\n/**\n * Convert a JSON array of objects into a formatted table.\n *\n * @remarks\n * Supports `markdown`, `csv`, and `tsv` output. Columns default to the keys of the first row;\n * supply `columns` to control which keys appear and in what order.\n */\nexport const formatTableTool = new Tool({\n name: 'format_table',\n description:\n 'Convert a JSON array of objects into a formatted table. Supports Markdown, CSV, and TSV output.',\n inputSchema: validator.object({\n data: validator.string().required().description('JSON array of objects as a string'),\n format: validator\n .string()\n .valid('markdown', 'csv', 'tsv')\n .required()\n .description('Output format'),\n columns: validator\n .array()\n .items(validator.string())\n .optional()\n .description(\n 'Column keys to include, in order. If omitted, all keys from the first row are used.'\n ),\n }),\n handler: async (args) => {\n const {\n data,\n format,\n columns: explicitColumns,\n } = args as {\n data: string\n format: 'markdown' | 'csv' | 'tsv'\n columns?: string[]\n }\n\n let rows: unknown[]\n try {\n rows = JSON.parse(data)\n } catch {\n return 'Error: Invalid JSON input.'\n }\n\n if (!Array.isArray(rows)) return 'Error: Input must be a JSON array.'\n if (rows.length === 0) return 'Empty array — no data to display.'\n\n const columns = explicitColumns ?? Object.keys(rows[0] as Record<string, unknown>)\n\n if (format === 'csv') {\n const lines = [columns.map(csvEscape).join(',')]\n for (const row of rows) {\n const obj = row as Record<string, unknown>\n lines.push(columns.map((col) => csvEscape(obj[col])).join(','))\n }\n return lines.join('\\n')\n }\n\n if (format === 'tsv') {\n const lines = [columns.map(tsvEscape).join('\\t')]\n for (const row of rows) {\n const obj = row as Record<string, unknown>\n lines.push(columns.map((col) => tsvEscape(obj[col])).join('\\t'))\n }\n return lines.join('\\n')\n }\n\n const header = '| ' + columns.map(mdEscape).join(' | ') + ' |'\n const separator = '| ' + columns.map(() => '---').join(' | ') + ' |'\n const dataRows = rows.map((row) => {\n const obj = row as Record<string, unknown>\n return '| ' + columns.map((col) => mdEscape(obj[col])).join(' | ') + ' |'\n })\n return [header, separator, ...dataRows].join('\\n')\n },\n})\n\n/**\n * Pretty-print or minify a JSON string.\n *\n * @remarks\n * Validates the input as JSON, then re-serialises it with the requested indentation. `indent` is\n * clamped to the range [0, 8]; `0` produces minified output.\n */\nexport const jsonFormatTool = new Tool({\n name: 'json_format',\n description: 'Pretty-print or minify a JSON string. Validates JSON and normalises whitespace.',\n inputSchema: validator.object({\n data: validator.string().required().description('JSON string to format'),\n indent: validator\n .number()\n .default(2)\n .description('Indentation spaces (0 = minify, default: 2). Max: 8.'),\n }),\n handler: async (args) => {\n const { data, indent } = args as { data: string; indent: number }\n try {\n const parsed = JSON.parse(data)\n return JSON.stringify(parsed, null, Math.max(0, Math.min(8, Math.floor(indent))))\n } catch (err) {\n return `Error: Invalid JSON — ${isError(err) ? err.message : String(err)}`\n }\n },\n})\n\nconst FORMAT_PATTERNS: Record<string, { pattern: RegExp; label: string }> = {\n email: {\n pattern: /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/,\n label: 'email address',\n },\n uuid: {\n pattern: /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,\n label: 'UUID (v1–v5)',\n },\n ipv4: {\n pattern: /^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$/,\n label: 'IPv4 address',\n },\n iso_date: {\n pattern: /^\\d{4}-\\d{2}-\\d{2}$/,\n label: 'ISO 8601 date (YYYY-MM-DD)',\n },\n iso_datetime: {\n pattern: /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2}(\\.\\d+)?)?(Z|[+-]\\d{2}:\\d{2})?$/,\n label: 'ISO 8601 datetime',\n },\n hex_color: {\n pattern: /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,\n label: 'CSS hex color',\n },\n phone_e164: {\n pattern: /^\\+[1-9]\\d{1,14}$/,\n label: 'E.164 phone number',\n },\n semver: {\n pattern: /^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z-.]+)?(\\+[0-9A-Za-z-.]+)?$/,\n label: 'Semantic Version (SemVer)',\n },\n integer: {\n pattern: /^-?\\d+$/,\n label: 'integer',\n },\n decimal: {\n pattern: /^-?\\d+(\\.\\d+)?$/,\n label: 'decimal number',\n },\n alphanumeric: {\n pattern: /^[a-zA-Z0-9]+$/,\n label: 'alphanumeric string',\n },\n slug: {\n pattern: /^[a-z0-9]+(-[a-z0-9]+)*$/,\n label: 'URL slug',\n },\n hex: {\n pattern: /^(0x)?[0-9a-fA-F]+$/,\n label: 'hexadecimal string',\n },\n base64: {\n pattern: /^[A-Za-z0-9+/]*={0,2}$/,\n label: 'base64-encoded string',\n },\n}\n\n/**\n * Check whether a string matches a known format.\n *\n * @remarks\n * Supported formats: `email`, `uuid` (v1–v5), `ipv4`, `iso_date`, `iso_datetime`, `hex_color`,\n * `phone_e164`, `semver`, `integer`, `decimal`, `alphanumeric`, `slug`, `hex`, `base64`.\n */\nexport const validateFormatTool = new Tool({\n name: 'validate_format',\n description:\n 'Check whether a string matches a known format (email, UUID, ISO date, hex colour, phone number, semver, slug, etc.).',\n inputSchema: validator.object({\n value: validator.string().required().description('The string to validate'),\n format: validator\n .string()\n .valid(...Object.keys(FORMAT_PATTERNS))\n .required()\n .description(\n `Format to validate against. One of: ${Object.keys(FORMAT_PATTERNS).join(', ')}`\n ),\n }),\n handler: async (args) => {\n const { value, format } = args as { value: string; format: string }\n const def = FORMAT_PATTERNS[format]\n if (!def) {\n return `Error: Unknown format \"${format}\". Supported: ${Object.keys(FORMAT_PATTERNS).join(', ')}`\n }\n const valid = def.pattern.test(value)\n return valid\n ? `Valid: \"${value}\" is a valid ${def.label}.`\n : `Invalid: \"${value}\" is not a valid ${def.label}.`\n },\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"structured_data.cjs","names":[],"sources":["../../../src/batteries/tools/structured_data/index.ts"],"sourcesContent":["/**\n * Pre-constructed tools for transforming arrays and objects into tables and tabular text.\n *\n * @module @nhtio/adk/batteries/tools/structured_data\n *\n * @remarks\n * Pre-constructed bundled tools for the `structured_data` category. Import individually, the whole\n * category, or import every tool via `@nhtio/adk/batteries`.\n */\n\nimport { Tool } from '@nhtio/adk/common'\nimport { validator } from '@nhtio/validation'\nimport { isError, isObject } from '@nhtio/adk/guards'\n\nfunction csvEscape(value: unknown): string {\n const str = value === null || value === undefined ? '' : String(value)\n if (str.includes(',') || str.includes('\"') || str.includes('\\n') || str.includes('\\r')) {\n return '\"' + str.replace(/\"/g, '\"\"') + '\"'\n }\n return str\n}\n\nfunction tsvEscape(value: unknown): string {\n const str = value === null || value === undefined ? '' : String(value)\n return str.replace(/\\t/g, ' ').replace(/\\r?\\n/g, ' ')\n}\n\nfunction mdEscape(value: unknown): string {\n return String(value === null || value === undefined ? '' : value)\n .replace(/\\|/g, '\\\\|')\n .replace(/\\r?\\n/g, ' ')\n}\n\n/**\n * Convert a JSON array of objects into a formatted table.\n *\n * @remarks\n * Supports `markdown`, `csv`, and `tsv` output. Columns default to the keys of the first row;\n * supply `columns` to control which keys appear and in what order.\n */\nexport const formatTableTool = new Tool({\n name: 'format_table',\n description:\n 'Convert a JSON array of objects into a formatted table. Supports Markdown, CSV, and TSV output.',\n inputSchema: validator.object({\n data: validator.string().required().description('JSON array of objects as a string'),\n format: validator\n .string()\n .valid('markdown', 'csv', 'tsv')\n .required()\n .description('Output format'),\n columns: validator\n .array()\n .items(validator.string())\n .optional()\n .description(\n 'Column keys to include, in order. If omitted, all keys from the first row are used.'\n ),\n }),\n handler: async (args) => {\n const {\n data,\n format,\n columns: explicitColumns,\n } = args as {\n data: string\n format: 'markdown' | 'csv' | 'tsv'\n columns?: string[]\n }\n\n let rows: unknown[]\n try {\n rows = JSON.parse(data)\n } catch {\n return 'Error: Invalid JSON input.'\n }\n\n if (!Array.isArray(rows)) return 'Error: Input must be a JSON array.'\n if (rows.length === 0) return 'Empty array — no data to display.'\n\n // Columns default to the first row's keys, but only an object row has keys. If columns aren't\n // given and the first row isn't an object, there's nothing to tabulate — error clearly rather\n // than throwing on `Object.keys(null)`.\n if (!explicitColumns && !isObject(rows[0])) {\n return 'Error: Cannot infer columns — the first row is not an object. Provide \"columns\", or pass an array of objects.'\n }\n const columns = explicitColumns ?? Object.keys(rows[0] as Record<string, unknown>)\n\n // Read a cell safely: a null/primitive row has no properties, so it yields empty cells rather\n // than throwing on `row[col]`.\n const cell = (row: unknown, col: string): unknown =>\n isObject(row) ? (row as Record<string, unknown>)[col] : undefined\n\n if (format === 'csv') {\n const lines = [columns.map(csvEscape).join(',')]\n for (const row of rows) {\n lines.push(columns.map((col) => csvEscape(cell(row, col))).join(','))\n }\n return lines.join('\\n')\n }\n\n if (format === 'tsv') {\n const lines = [columns.map(tsvEscape).join('\\t')]\n for (const row of rows) {\n lines.push(columns.map((col) => tsvEscape(cell(row, col))).join('\\t'))\n }\n return lines.join('\\n')\n }\n\n const header = '| ' + columns.map(mdEscape).join(' | ') + ' |'\n const separator = '| ' + columns.map(() => '---').join(' | ') + ' |'\n const dataRows = rows.map((row) => {\n return '| ' + columns.map((col) => mdEscape(cell(row, col))).join(' | ') + ' |'\n })\n return [header, separator, ...dataRows].join('\\n')\n },\n})\n\n/**\n * Pretty-print or minify a JSON string.\n *\n * @remarks\n * Validates the input as JSON, then re-serialises it with the requested indentation. `indent` is\n * clamped to the range [0, 8]; `0` produces minified output.\n */\nexport const jsonFormatTool = new Tool({\n name: 'json_format',\n description: 'Pretty-print or minify a JSON string. Validates JSON and normalises whitespace.',\n inputSchema: validator.object({\n data: validator.string().required().description('JSON string to format'),\n indent: validator\n .number()\n .default(2)\n .description('Indentation spaces (0 = minify, default: 2). Max: 8.'),\n }),\n handler: async (args) => {\n const { data, indent } = args as { data: string; indent: number }\n try {\n const parsed = JSON.parse(data)\n return JSON.stringify(parsed, null, Math.max(0, Math.min(8, Math.floor(indent))))\n } catch (err) {\n return `Error: Invalid JSON — ${isError(err) ? err.message : String(err)}`\n }\n },\n})\n\nconst FORMAT_PATTERNS: Record<string, { pattern: RegExp; label: string }> = {\n email: {\n pattern: /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/,\n label: 'email address',\n },\n uuid: {\n pattern: /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,\n label: 'UUID (v1–v5)',\n },\n ipv4: {\n pattern: /^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$/,\n label: 'IPv4 address',\n },\n iso_date: {\n pattern: /^\\d{4}-\\d{2}-\\d{2}$/,\n label: 'ISO 8601 date (YYYY-MM-DD)',\n },\n iso_datetime: {\n pattern: /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2}(\\.\\d+)?)?(Z|[+-]\\d{2}:\\d{2})?$/,\n label: 'ISO 8601 datetime',\n },\n hex_color: {\n pattern: /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,\n label: 'CSS hex color',\n },\n phone_e164: {\n pattern: /^\\+[1-9]\\d{1,14}$/,\n label: 'E.164 phone number',\n },\n semver: {\n pattern: /^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z-.]+)?(\\+[0-9A-Za-z-.]+)?$/,\n label: 'Semantic Version (SemVer)',\n },\n integer: {\n pattern: /^-?\\d+$/,\n label: 'integer',\n },\n decimal: {\n pattern: /^-?\\d+(\\.\\d+)?$/,\n label: 'decimal number',\n },\n alphanumeric: {\n pattern: /^[a-zA-Z0-9]+$/,\n label: 'alphanumeric string',\n },\n slug: {\n pattern: /^[a-z0-9]+(-[a-z0-9]+)*$/,\n label: 'URL slug',\n },\n hex: {\n pattern: /^(0x)?[0-9a-fA-F]+$/,\n label: 'hexadecimal string',\n },\n base64: {\n pattern: /^[A-Za-z0-9+/]*={0,2}$/,\n label: 'base64-encoded string',\n },\n}\n\n/**\n * Check whether a string matches a known format.\n *\n * @remarks\n * Supported formats: `email`, `uuid` (v1–v5), `ipv4`, `iso_date`, `iso_datetime`, `hex_color`,\n * `phone_e164`, `semver`, `integer`, `decimal`, `alphanumeric`, `slug`, `hex`, `base64`.\n */\nexport const validateFormatTool = new Tool({\n name: 'validate_format',\n description:\n 'Check whether a string matches a known format (email, UUID, ISO date, hex colour, phone number, semver, slug, etc.).',\n inputSchema: validator.object({\n value: validator.string().required().description('The string to validate'),\n format: validator\n .string()\n .valid(...Object.keys(FORMAT_PATTERNS))\n .required()\n .description(\n `Format to validate against. One of: ${Object.keys(FORMAT_PATTERNS).join(', ')}`\n ),\n }),\n handler: async (args) => {\n const { value, format } = args as { value: string; format: string }\n const def = FORMAT_PATTERNS[format]\n if (!def) {\n return `Error: Unknown format \"${format}\". Supported: ${Object.keys(FORMAT_PATTERNS).join(', ')}`\n }\n const valid = def.pattern.test(value)\n return valid\n ? `Valid: \"${value}\" is a valid ${def.label}.`\n : `Invalid: \"${value}\" is not a valid ${def.label}.`\n },\n})\n"],"mappings":"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"}