ai-functions 2.1.3 → 2.3.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 (277) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +55 -1
  3. package/README.md +38 -0
  4. package/dist/ai-promise.d.ts +3 -3
  5. package/dist/ai-promise.d.ts.map +1 -1
  6. package/dist/ai-promise.js +135 -64
  7. package/dist/ai-promise.js.map +1 -1
  8. package/dist/ai-schemas.d.ts +56 -0
  9. package/dist/ai-schemas.d.ts.map +1 -0
  10. package/dist/ai-schemas.js +53 -0
  11. package/dist/ai-schemas.js.map +1 -0
  12. package/dist/ai.d.ts +16 -242
  13. package/dist/ai.d.ts.map +1 -1
  14. package/dist/ai.js +51 -858
  15. package/dist/ai.js.map +1 -1
  16. package/dist/batch/anthropic.d.ts +6 -4
  17. package/dist/batch/anthropic.d.ts.map +1 -1
  18. package/dist/batch/anthropic.js +83 -145
  19. package/dist/batch/anthropic.js.map +1 -1
  20. package/dist/batch/bedrock.d.ts +8 -30
  21. package/dist/batch/bedrock.d.ts.map +1 -1
  22. package/dist/batch/bedrock.js +155 -338
  23. package/dist/batch/bedrock.js.map +1 -1
  24. package/dist/batch/cloudflare.d.ts +8 -20
  25. package/dist/batch/cloudflare.d.ts.map +1 -1
  26. package/dist/batch/cloudflare.js +68 -189
  27. package/dist/batch/cloudflare.js.map +1 -1
  28. package/dist/batch/google.d.ts +6 -20
  29. package/dist/batch/google.d.ts.map +1 -1
  30. package/dist/batch/google.js +70 -238
  31. package/dist/batch/google.js.map +1 -1
  32. package/dist/batch/index.d.ts +4 -1
  33. package/dist/batch/index.d.ts.map +1 -1
  34. package/dist/batch/index.js +4 -1
  35. package/dist/batch/index.js.map +1 -1
  36. package/dist/batch/memory.d.ts +1 -1
  37. package/dist/batch/memory.d.ts.map +1 -1
  38. package/dist/batch/memory.js +14 -10
  39. package/dist/batch/memory.js.map +1 -1
  40. package/dist/batch/openai.d.ts +11 -14
  41. package/dist/batch/openai.d.ts.map +1 -1
  42. package/dist/batch/openai.js +52 -156
  43. package/dist/batch/openai.js.map +1 -1
  44. package/dist/batch/provider.d.ts +111 -0
  45. package/dist/batch/provider.d.ts.map +1 -0
  46. package/dist/batch/provider.js +233 -0
  47. package/dist/batch/provider.js.map +1 -0
  48. package/dist/batch-map.d.ts.map +1 -1
  49. package/dist/batch-map.js +23 -17
  50. package/dist/batch-map.js.map +1 -1
  51. package/dist/batch-queue.d.ts +65 -0
  52. package/dist/batch-queue.d.ts.map +1 -1
  53. package/dist/batch-queue.js +169 -14
  54. package/dist/batch-queue.js.map +1 -1
  55. package/dist/budget.d.ts.map +1 -1
  56. package/dist/budget.js +27 -14
  57. package/dist/budget.js.map +1 -1
  58. package/dist/cache.d.ts +23 -0
  59. package/dist/cache.d.ts.map +1 -1
  60. package/dist/cache.js +36 -15
  61. package/dist/cache.js.map +1 -1
  62. package/dist/context.d.ts +26 -8
  63. package/dist/context.d.ts.map +1 -1
  64. package/dist/context.js +64 -62
  65. package/dist/context.js.map +1 -1
  66. package/dist/digital-objects-registry.d.ts +229 -0
  67. package/dist/digital-objects-registry.d.ts.map +1 -0
  68. package/dist/digital-objects-registry.js +617 -0
  69. package/dist/digital-objects-registry.js.map +1 -0
  70. package/dist/embeddings.d.ts +2 -2
  71. package/dist/embeddings.d.ts.map +1 -1
  72. package/dist/errors.d.ts +22 -0
  73. package/dist/errors.d.ts.map +1 -0
  74. package/dist/errors.js +35 -0
  75. package/dist/errors.js.map +1 -0
  76. package/dist/eval/runner.d.ts +8 -0
  77. package/dist/eval/runner.d.ts.map +1 -1
  78. package/dist/eval/runner.js +41 -35
  79. package/dist/eval/runner.js.map +1 -1
  80. package/dist/eval-log/in-memory.d.ts +34 -0
  81. package/dist/eval-log/in-memory.d.ts.map +1 -0
  82. package/dist/eval-log/in-memory.js +84 -0
  83. package/dist/eval-log/in-memory.js.map +1 -0
  84. package/dist/eval-log/index.d.ts +29 -0
  85. package/dist/eval-log/index.d.ts.map +1 -0
  86. package/dist/eval-log/index.js +39 -0
  87. package/dist/eval-log/index.js.map +1 -0
  88. package/dist/eval-log/types.d.ts +101 -0
  89. package/dist/eval-log/types.d.ts.map +1 -0
  90. package/dist/eval-log/types.js +16 -0
  91. package/dist/eval-log/types.js.map +1 -0
  92. package/dist/function-registry.d.ts +116 -0
  93. package/dist/function-registry.d.ts.map +1 -0
  94. package/dist/function-registry.js +546 -0
  95. package/dist/function-registry.js.map +1 -0
  96. package/dist/generate.d.ts +9 -3
  97. package/dist/generate.d.ts.map +1 -1
  98. package/dist/generate.js +18 -18
  99. package/dist/generate.js.map +1 -1
  100. package/dist/index.d.ts +18 -11
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/index.js +35 -18
  103. package/dist/index.js.map +1 -1
  104. package/dist/logger.d.ts +118 -0
  105. package/dist/logger.d.ts.map +1 -0
  106. package/dist/logger.js +187 -0
  107. package/dist/logger.js.map +1 -0
  108. package/dist/middleware/budget.d.ts +84 -0
  109. package/dist/middleware/budget.d.ts.map +1 -0
  110. package/dist/middleware/budget.js +110 -0
  111. package/dist/middleware/budget.js.map +1 -0
  112. package/dist/middleware/cache.d.ts +103 -0
  113. package/dist/middleware/cache.d.ts.map +1 -0
  114. package/dist/middleware/cache.js +228 -0
  115. package/dist/middleware/cache.js.map +1 -0
  116. package/dist/middleware/embed-cache.d.ts +99 -0
  117. package/dist/middleware/embed-cache.d.ts.map +1 -0
  118. package/dist/middleware/embed-cache.js +128 -0
  119. package/dist/middleware/embed-cache.js.map +1 -0
  120. package/dist/middleware/index.d.ts +11 -0
  121. package/dist/middleware/index.d.ts.map +1 -0
  122. package/dist/middleware/index.js +11 -0
  123. package/dist/middleware/index.js.map +1 -0
  124. package/dist/middleware/trace.d.ts +103 -0
  125. package/dist/middleware/trace.d.ts.map +1 -0
  126. package/dist/middleware/trace.js +176 -0
  127. package/dist/middleware/trace.js.map +1 -0
  128. package/dist/primitives.d.ts +120 -1
  129. package/dist/primitives.d.ts.map +1 -1
  130. package/dist/primitives.js +398 -26
  131. package/dist/primitives.js.map +1 -1
  132. package/dist/retry.d.ts +66 -1
  133. package/dist/retry.d.ts.map +1 -1
  134. package/dist/retry.js +115 -8
  135. package/dist/retry.js.map +1 -1
  136. package/dist/schema.js +2 -2
  137. package/dist/schema.js.map +1 -1
  138. package/dist/telemetry.d.ts +128 -0
  139. package/dist/telemetry.d.ts.map +1 -0
  140. package/dist/telemetry.js +285 -0
  141. package/dist/telemetry.js.map +1 -0
  142. package/dist/template.d.ts.map +1 -1
  143. package/dist/template.js +6 -1
  144. package/dist/template.js.map +1 -1
  145. package/dist/tool-orchestration.d.ts +66 -4
  146. package/dist/tool-orchestration.d.ts.map +1 -1
  147. package/dist/tool-orchestration.js +123 -23
  148. package/dist/tool-orchestration.js.map +1 -1
  149. package/dist/type-guards.d.ts +28 -0
  150. package/dist/type-guards.d.ts.map +1 -0
  151. package/dist/type-guards.js +29 -0
  152. package/dist/type-guards.js.map +1 -0
  153. package/dist/types.d.ts +135 -17
  154. package/dist/types.d.ts.map +1 -1
  155. package/dist/types.js +36 -1
  156. package/dist/types.js.map +1 -1
  157. package/dist/wrap-for-v3.d.ts +80 -0
  158. package/dist/wrap-for-v3.d.ts.map +1 -0
  159. package/dist/wrap-for-v3.js +89 -0
  160. package/dist/wrap-for-v3.js.map +1 -0
  161. package/examples/00-quickstart.ts +232 -0
  162. package/examples/01-rag-chatbot.ts +212 -0
  163. package/examples/02-multi-agent-research.ts +290 -0
  164. package/examples/03-email-classification.ts +379 -0
  165. package/examples/04-content-moderation.ts +400 -0
  166. package/examples/05-document-extraction.ts +455 -0
  167. package/examples/06-streaming-chat-nextjs.ts +437 -0
  168. package/examples/07-cloudflare-worker.ts +483 -0
  169. package/examples/08-batch-processing.ts +491 -0
  170. package/examples/09-budget-constrained.ts +527 -0
  171. package/examples/10-tool-orchestration.ts +565 -0
  172. package/examples/11-retry-resilience.ts +403 -0
  173. package/examples/12-caching-strategies.ts +422 -0
  174. package/examples/README.md +145 -0
  175. package/package.json +28 -25
  176. package/src/ai-promise.ts +226 -140
  177. package/src/ai-schemas.ts +122 -0
  178. package/src/ai.ts +69 -1176
  179. package/src/batch/anthropic.ts +96 -161
  180. package/src/batch/bedrock.ts +203 -454
  181. package/src/batch/cloudflare.ts +99 -282
  182. package/src/batch/google.ts +91 -297
  183. package/src/batch/index.ts +4 -1
  184. package/src/batch/memory.ts +15 -10
  185. package/src/batch/openai.ts +65 -193
  186. package/src/batch/provider.ts +336 -0
  187. package/src/batch-map.ts +29 -24
  188. package/src/batch-queue.ts +200 -11
  189. package/src/budget.ts +31 -18
  190. package/src/cache.ts +45 -17
  191. package/src/context.ts +106 -77
  192. package/src/digital-objects-registry.ts +750 -0
  193. package/src/errors.ts +37 -0
  194. package/src/eval/runner.ts +60 -36
  195. package/src/eval-log/in-memory.ts +90 -0
  196. package/src/eval-log/index.ts +46 -0
  197. package/src/eval-log/types.ts +110 -0
  198. package/src/function-registry.ts +671 -0
  199. package/src/generate.ts +33 -28
  200. package/src/index.ts +119 -21
  201. package/src/logger.ts +232 -0
  202. package/src/middleware/budget.ts +171 -0
  203. package/src/middleware/cache.ts +299 -0
  204. package/src/middleware/embed-cache.ts +195 -0
  205. package/src/middleware/index.ts +23 -0
  206. package/src/middleware/trace.ts +248 -0
  207. package/src/primitives.ts +589 -62
  208. package/src/retry.ts +144 -18
  209. package/src/schema.ts +8 -8
  210. package/src/telemetry.ts +403 -0
  211. package/src/template.ts +8 -4
  212. package/src/tool-orchestration.ts +213 -48
  213. package/src/type-guards.ts +31 -0
  214. package/src/types.ts +164 -25
  215. package/src/wrap-for-v3.ts +105 -0
  216. package/test/ai-promise.test.ts +1080 -0
  217. package/test/ai-proxy.test.ts +1 -1
  218. package/test/batch-autosubmit-errors.test.ts +49 -37
  219. package/test/batch-blog-posts.test.ts +87 -129
  220. package/test/core-functions.test.ts +183 -579
  221. package/test/decide.test.ts +154 -322
  222. package/test/define.test.ts +211 -8
  223. package/test/digital-objects-registry.test.ts +760 -0
  224. package/test/embedding-cache-middleware.test.ts +140 -0
  225. package/test/generate-core.test.ts +140 -229
  226. package/test/implicit-batch.test.ts +22 -65
  227. package/test/retry-policy-integration.test.ts +117 -0
  228. package/test/schema.test.ts +55 -19
  229. package/test/template.test.ts +1164 -0
  230. package/test/tool-orchestration.test.ts +270 -0
  231. package/test/wrap-for-v3.test.ts +612 -0
  232. package/vitest.config.js +6 -0
  233. package/vitest.config.ts +20 -0
  234. package/LICENSE +0 -21
  235. package/dist/rpc/auth.d.ts +0 -69
  236. package/dist/rpc/auth.d.ts.map +0 -1
  237. package/dist/rpc/auth.js +0 -136
  238. package/dist/rpc/auth.js.map +0 -1
  239. package/dist/rpc/client.d.ts +0 -62
  240. package/dist/rpc/client.d.ts.map +0 -1
  241. package/dist/rpc/client.js +0 -103
  242. package/dist/rpc/client.js.map +0 -1
  243. package/dist/rpc/deferred.d.ts +0 -60
  244. package/dist/rpc/deferred.d.ts.map +0 -1
  245. package/dist/rpc/deferred.js +0 -96
  246. package/dist/rpc/deferred.js.map +0 -1
  247. package/dist/rpc/index.d.ts +0 -22
  248. package/dist/rpc/index.d.ts.map +0 -1
  249. package/dist/rpc/index.js +0 -38
  250. package/dist/rpc/index.js.map +0 -1
  251. package/dist/rpc/local.d.ts +0 -42
  252. package/dist/rpc/local.d.ts.map +0 -1
  253. package/dist/rpc/local.js +0 -50
  254. package/dist/rpc/local.js.map +0 -1
  255. package/dist/rpc/server.d.ts +0 -165
  256. package/dist/rpc/server.d.ts.map +0 -1
  257. package/dist/rpc/server.js +0 -405
  258. package/dist/rpc/server.js.map +0 -1
  259. package/dist/rpc/session.d.ts +0 -32
  260. package/dist/rpc/session.d.ts.map +0 -1
  261. package/dist/rpc/session.js +0 -43
  262. package/dist/rpc/session.js.map +0 -1
  263. package/dist/rpc/transport.d.ts +0 -306
  264. package/dist/rpc/transport.d.ts.map +0 -1
  265. package/dist/rpc/transport.js +0 -731
  266. package/dist/rpc/transport.js.map +0 -1
  267. package/src/batch/anthropic.js +0 -256
  268. package/src/batch/bedrock.js +0 -584
  269. package/src/batch/cloudflare.js +0 -287
  270. package/src/batch/google.js +0 -359
  271. package/src/batch/index.js +0 -30
  272. package/src/batch/memory.js +0 -187
  273. package/src/batch/openai.js +0 -402
  274. package/src/eval/index.js +0 -7
  275. package/src/eval/models.js +0 -119
  276. package/src/eval/runner.js +0 -147
  277. package/test/schema.test.js +0 -96
@@ -768,3 +768,273 @@ describe('Token Usage Tracking', () => {
768
768
  expect(result.usage!.totalTokens).toBe(160)
769
769
  })
770
770
  })
771
+
772
+ // ============================================================================
773
+ // cachedTool Tests - Tool result caching with cleanup
774
+ // ============================================================================
775
+
776
+ import { cachedTool, type CachedTool } from '../src/tool-orchestration.js'
777
+
778
+ describe('cachedTool', () => {
779
+ describe('basic caching behavior', () => {
780
+ it('should cache tool results', async () => {
781
+ let executionCount = 0
782
+ const countingTool: Tool = {
783
+ name: 'counting',
784
+ description: 'Counts executions',
785
+ parameters: z.object({ key: z.string() }),
786
+ execute: async ({ key }) => {
787
+ executionCount++
788
+ return { key, count: executionCount }
789
+ },
790
+ }
791
+
792
+ const cached = cachedTool(countingTool, { ttl: 1000 })
793
+
794
+ // First call executes the tool
795
+ const result1 = await cached.execute({ key: 'test' })
796
+ expect(result1).toEqual({ key: 'test', count: 1 })
797
+
798
+ // Second call with same key returns cached result
799
+ const result2 = await cached.execute({ key: 'test' })
800
+ expect(result2).toEqual({ key: 'test', count: 1 })
801
+ expect(executionCount).toBe(1) // Only executed once
802
+
803
+ // Different key executes again
804
+ const result3 = await cached.execute({ key: 'other' })
805
+ expect(result3).toEqual({ key: 'other', count: 2 })
806
+ })
807
+
808
+ it('should expire cached entries after TTL', async () => {
809
+ vi.useFakeTimers()
810
+ let executionCount = 0
811
+ const countingTool: Tool = {
812
+ name: 'counting',
813
+ description: 'Counts executions',
814
+ parameters: z.object({ key: z.string() }),
815
+ execute: async ({ key }) => {
816
+ executionCount++
817
+ return { key, count: executionCount }
818
+ },
819
+ }
820
+
821
+ const cached = cachedTool(countingTool, { ttl: 100 })
822
+
823
+ // First call
824
+ await cached.execute({ key: 'test' })
825
+ expect(executionCount).toBe(1)
826
+
827
+ // After TTL expires
828
+ vi.advanceTimersByTime(150)
829
+
830
+ // Should execute again since cache expired
831
+ await cached.execute({ key: 'test' })
832
+ expect(executionCount).toBe(2)
833
+
834
+ vi.useRealTimers()
835
+ })
836
+ })
837
+
838
+ describe('cache cleanup', () => {
839
+ it('should periodically clean up expired entries', async () => {
840
+ vi.useFakeTimers()
841
+ let executionCount = 0
842
+ const countingTool: Tool = {
843
+ name: 'counting',
844
+ description: 'Counts executions',
845
+ parameters: z.object({ key: z.string() }),
846
+ execute: async ({ key }) => {
847
+ executionCount++
848
+ return { key, count: executionCount }
849
+ },
850
+ }
851
+
852
+ const cached = cachedTool(countingTool, {
853
+ ttl: 100,
854
+ cleanupIntervalMs: 50,
855
+ }) as CachedTool
856
+
857
+ // Execute to populate cache
858
+ await cached.execute({ key: 'entry1' })
859
+ await cached.execute({ key: 'entry2' })
860
+
861
+ expect(cached.cacheSize()).toBe(2)
862
+
863
+ // Wait for TTL to expire and cleanup to run
864
+ vi.advanceTimersByTime(150)
865
+
866
+ // Entries should be cleaned up automatically
867
+ expect(cached.cacheSize()).toBe(0)
868
+
869
+ // Cleanup timer
870
+ cached.destroy()
871
+ vi.useRealTimers()
872
+ })
873
+
874
+ it('should stop cleanup timer and clear cache when destroyed', async () => {
875
+ vi.useFakeTimers()
876
+ const countingTool: Tool = {
877
+ name: 'counting',
878
+ description: 'Counts executions',
879
+ parameters: z.object({ key: z.string() }),
880
+ execute: async ({ key }) => ({ key }),
881
+ }
882
+
883
+ const cached = cachedTool(countingTool, {
884
+ ttl: 100,
885
+ cleanupIntervalMs: 50,
886
+ }) as CachedTool
887
+
888
+ await cached.execute({ key: 'entry1' })
889
+ expect(cached.cacheSize()).toBe(1)
890
+
891
+ // Destroy stops cleanup timer and clears cache to prevent memory leaks
892
+ cached.destroy()
893
+
894
+ // Cache should be cleared immediately on destroy
895
+ expect(cached.cacheSize()).toBe(0)
896
+
897
+ // Advancing time should have no effect (timer is stopped)
898
+ vi.advanceTimersByTime(150)
899
+ expect(cached.cacheSize()).toBe(0)
900
+
901
+ vi.useRealTimers()
902
+ })
903
+
904
+ it('should clear all cache entries on clearCache()', async () => {
905
+ const countingTool: Tool = {
906
+ name: 'counting',
907
+ description: 'Counts executions',
908
+ parameters: z.object({ key: z.string() }),
909
+ execute: async ({ key }) => ({ key }),
910
+ }
911
+
912
+ const cached = cachedTool(countingTool, { ttl: 60000 }) as CachedTool
913
+
914
+ await cached.execute({ key: 'entry1' })
915
+ await cached.execute({ key: 'entry2' })
916
+ await cached.execute({ key: 'entry3' })
917
+
918
+ expect(cached.cacheSize()).toBe(3)
919
+
920
+ cached.clearCache()
921
+ expect(cached.cacheSize()).toBe(0)
922
+
923
+ cached.destroy()
924
+ })
925
+ })
926
+
927
+ describe('max cache size (LRU eviction)', () => {
928
+ it('should evict oldest entries when maxSize is reached', async () => {
929
+ vi.useFakeTimers()
930
+ let executionCount = 0
931
+ const countingTool: Tool = {
932
+ name: 'counting',
933
+ description: 'Counts executions',
934
+ parameters: z.object({ key: z.string() }),
935
+ execute: async ({ key }) => {
936
+ executionCount++
937
+ return { key, count: executionCount }
938
+ },
939
+ }
940
+
941
+ const cached = cachedTool(countingTool, {
942
+ ttl: 60000,
943
+ maxSize: 3,
944
+ }) as CachedTool
945
+
946
+ // Fill cache to max
947
+ await cached.execute({ key: 'a' })
948
+ vi.advanceTimersByTime(10)
949
+ await cached.execute({ key: 'b' })
950
+ vi.advanceTimersByTime(10)
951
+ await cached.execute({ key: 'c' })
952
+ vi.advanceTimersByTime(10)
953
+
954
+ expect(cached.cacheSize()).toBe(3)
955
+ expect(executionCount).toBe(3)
956
+
957
+ // Adding 4th entry should evict oldest ('a')
958
+ await cached.execute({ key: 'd' })
959
+ expect(cached.cacheSize()).toBe(3)
960
+
961
+ // Accessing 'a' should re-execute since it was evicted
962
+ await cached.execute({ key: 'a' })
963
+ expect(executionCount).toBe(5) // New execution
964
+
965
+ cached.destroy()
966
+ vi.useRealTimers()
967
+ })
968
+
969
+ it('should update LRU order on cache hit', async () => {
970
+ vi.useFakeTimers()
971
+ let executionCount = 0
972
+ const countingTool: Tool = {
973
+ name: 'counting',
974
+ description: 'Counts executions',
975
+ parameters: z.object({ key: z.string() }),
976
+ execute: async ({ key }) => {
977
+ executionCount++
978
+ return { key, count: executionCount }
979
+ },
980
+ }
981
+
982
+ const cached = cachedTool(countingTool, {
983
+ ttl: 60000,
984
+ maxSize: 3,
985
+ }) as CachedTool
986
+
987
+ // Fill cache: a, b, c (oldest to newest)
988
+ await cached.execute({ key: 'a' })
989
+ vi.advanceTimersByTime(10)
990
+ await cached.execute({ key: 'b' })
991
+ vi.advanceTimersByTime(10)
992
+ await cached.execute({ key: 'c' })
993
+ vi.advanceTimersByTime(10)
994
+
995
+ // Access 'a' to make it recently used
996
+ await cached.execute({ key: 'a' }) // Cache hit
997
+ vi.advanceTimersByTime(10)
998
+ expect(executionCount).toBe(3) // No new execution
999
+
1000
+ // Add 'd' - should evict 'b' (now oldest) not 'a'
1001
+ await cached.execute({ key: 'd' })
1002
+
1003
+ // 'b' was evicted, 'a' and 'c' remain
1004
+ await cached.execute({ key: 'b' }) // Should re-execute
1005
+ expect(executionCount).toBe(5)
1006
+
1007
+ await cached.execute({ key: 'a' }) // Still cached
1008
+ expect(executionCount).toBe(5)
1009
+
1010
+ cached.destroy()
1011
+ vi.useRealTimers()
1012
+ })
1013
+ })
1014
+
1015
+ describe('resource cleanup on tool destruction', () => {
1016
+ it('should clean up timers and memory when destroy is called', async () => {
1017
+ const tool: Tool = {
1018
+ name: 'test',
1019
+ description: 'Test tool',
1020
+ parameters: z.object({ key: z.string() }),
1021
+ execute: async ({ key }) => ({ key }),
1022
+ }
1023
+
1024
+ const cached = cachedTool(tool, {
1025
+ ttl: 1000,
1026
+ cleanupIntervalMs: 100,
1027
+ }) as CachedTool
1028
+
1029
+ await cached.execute({ key: 'test' })
1030
+ expect(cached.cacheSize()).toBe(1)
1031
+
1032
+ cached.destroy()
1033
+ expect(cached.cacheSize()).toBe(0)
1034
+
1035
+ // Should still work after destroy but without caching
1036
+ await cached.execute({ key: 'test2' })
1037
+ expect(cached.cacheSize()).toBe(0)
1038
+ })
1039
+ })
1040
+ })