@fgv/ts-extras 5.1.0-4 → 5.1.0-40

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 (368) hide show
  1. package/dist/index.browser.js +4 -2
  2. package/dist/index.browser.js.map +1 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/packlets/ai-assist/apiClient.js +886 -158
  5. package/dist/packlets/ai-assist/apiClient.js.map +1 -0
  6. package/dist/packlets/ai-assist/chatRequestBuilders.js +282 -0
  7. package/dist/packlets/ai-assist/chatRequestBuilders.js.map +1 -0
  8. package/dist/packlets/ai-assist/converters.js +47 -3
  9. package/dist/packlets/ai-assist/converters.js.map +1 -0
  10. package/dist/packlets/ai-assist/embeddingClient.js +345 -0
  11. package/dist/packlets/ai-assist/embeddingClient.js.map +1 -0
  12. package/dist/packlets/ai-assist/endpoint.js +78 -0
  13. package/dist/packlets/ai-assist/endpoint.js.map +1 -0
  14. package/dist/packlets/ai-assist/http.js +75 -0
  15. package/dist/packlets/ai-assist/http.js.map +1 -0
  16. package/dist/packlets/ai-assist/imageOptionsResolver.js +193 -0
  17. package/dist/packlets/ai-assist/imageOptionsResolver.js.map +1 -0
  18. package/dist/packlets/ai-assist/index.js +10 -4
  19. package/dist/packlets/ai-assist/index.js.map +1 -0
  20. package/dist/packlets/ai-assist/jsonCompletion.js +93 -0
  21. package/dist/packlets/ai-assist/jsonCompletion.js.map +1 -0
  22. package/dist/packlets/ai-assist/jsonResponse.js +149 -0
  23. package/dist/packlets/ai-assist/jsonResponse.js.map +1 -0
  24. package/dist/packlets/ai-assist/model.js +193 -9
  25. package/dist/packlets/ai-assist/model.js.map +1 -0
  26. package/dist/packlets/ai-assist/registry.js +314 -12
  27. package/dist/packlets/ai-assist/registry.js.map +1 -0
  28. package/dist/packlets/ai-assist/sseParser.js +123 -0
  29. package/dist/packlets/ai-assist/sseParser.js.map +1 -0
  30. package/dist/packlets/ai-assist/streamingAdapters/anthropic.js +368 -0
  31. package/dist/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -0
  32. package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +687 -0
  33. package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -0
  34. package/dist/packlets/ai-assist/streamingAdapters/common.js +187 -0
  35. package/dist/packlets/ai-assist/streamingAdapters/common.js.map +1 -0
  36. package/dist/packlets/ai-assist/streamingAdapters/gemini.js +204 -0
  37. package/dist/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -0
  38. package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js +170 -0
  39. package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -0
  40. package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js +386 -0
  41. package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -0
  42. package/dist/packlets/ai-assist/streamingAdapters/proxy.js +173 -0
  43. package/dist/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -0
  44. package/dist/packlets/ai-assist/streamingClient.js +140 -0
  45. package/dist/packlets/ai-assist/streamingClient.js.map +1 -0
  46. package/dist/packlets/ai-assist/thinkingOptionsResolver.js +288 -0
  47. package/dist/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -0
  48. package/dist/packlets/ai-assist/toolFormats.js +106 -10
  49. package/dist/packlets/ai-assist/toolFormats.js.map +1 -0
  50. package/dist/packlets/conversion/converters.js +35 -1
  51. package/dist/packlets/conversion/converters.js.map +1 -0
  52. package/dist/packlets/conversion/index.js.map +1 -0
  53. package/dist/packlets/crypto-utils/constants.js.map +1 -0
  54. package/dist/packlets/crypto-utils/converters.js +42 -4
  55. package/dist/packlets/crypto-utils/converters.js.map +1 -0
  56. package/dist/packlets/crypto-utils/directEncryptionProvider.js.map +1 -0
  57. package/dist/packlets/crypto-utils/encryptedFile.js.map +1 -0
  58. package/dist/packlets/crypto-utils/hpkeProvider.js +333 -0
  59. package/dist/packlets/crypto-utils/hpkeProvider.js.map +1 -0
  60. package/dist/packlets/crypto-utils/index.browser.js +10 -2
  61. package/dist/packlets/crypto-utils/index.browser.js.map +1 -0
  62. package/dist/packlets/crypto-utils/index.js +6 -0
  63. package/dist/packlets/crypto-utils/index.js.map +1 -0
  64. package/dist/packlets/crypto-utils/keyPairAlgorithmParams.js +71 -0
  65. package/dist/packlets/crypto-utils/keyPairAlgorithmParams.js.map +1 -0
  66. package/dist/packlets/crypto-utils/keystore/converters.js +103 -11
  67. package/dist/packlets/crypto-utils/keystore/converters.js.map +1 -0
  68. package/dist/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js +287 -0
  69. package/dist/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js.map +1 -0
  70. package/dist/packlets/crypto-utils/keystore/index.browser.js +36 -0
  71. package/dist/packlets/crypto-utils/keystore/index.browser.js.map +1 -0
  72. package/dist/packlets/crypto-utils/keystore/index.js +3 -0
  73. package/dist/packlets/crypto-utils/keystore/index.js.map +1 -0
  74. package/dist/packlets/crypto-utils/keystore/keyStore.js +633 -118
  75. package/dist/packlets/crypto-utils/keystore/keyStore.js.map +1 -0
  76. package/dist/packlets/crypto-utils/keystore/model.js +22 -1
  77. package/dist/packlets/crypto-utils/keystore/model.js.map +1 -0
  78. package/dist/packlets/crypto-utils/keystore/privateKeyStorage.js +21 -0
  79. package/dist/packlets/crypto-utils/keystore/privateKeyStorage.js.map +1 -0
  80. package/dist/packlets/crypto-utils/model.js +32 -0
  81. package/dist/packlets/crypto-utils/model.js.map +1 -0
  82. package/dist/packlets/crypto-utils/nodeCryptoProvider.js +270 -1
  83. package/dist/packlets/crypto-utils/nodeCryptoProvider.js.map +1 -0
  84. package/dist/packlets/crypto-utils/spkiHelpers.js +209 -0
  85. package/dist/packlets/crypto-utils/spkiHelpers.js.map +1 -0
  86. package/dist/packlets/csv/csvFileHelpers.js +0 -14
  87. package/dist/packlets/csv/csvFileHelpers.js.map +1 -0
  88. package/dist/packlets/csv/csvHelpers.js +14 -0
  89. package/dist/packlets/csv/csvHelpers.js.map +1 -0
  90. package/dist/packlets/csv/index.browser.js +1 -3
  91. package/dist/packlets/csv/index.browser.js.map +1 -0
  92. package/dist/packlets/csv/index.js.map +1 -0
  93. package/dist/packlets/experimental/extendedArray.js.map +1 -0
  94. package/dist/packlets/experimental/formatter.js.map +1 -0
  95. package/dist/packlets/experimental/index.js.map +1 -0
  96. package/dist/packlets/experimental/rangeOf.js.map +1 -0
  97. package/dist/packlets/hash/index.browser.js.map +1 -0
  98. package/dist/packlets/hash/index.js.map +1 -0
  99. package/dist/packlets/hash/index.node.js.map +1 -0
  100. package/dist/packlets/hash/md5Normalizer.browser.js.map +1 -0
  101. package/dist/packlets/hash/md5Normalizer.js.map +1 -0
  102. package/dist/packlets/mustache/index.js.map +1 -0
  103. package/dist/packlets/mustache/interfaces.js.map +1 -0
  104. package/dist/packlets/mustache/mustacheTemplate.js +42 -4
  105. package/dist/packlets/mustache/mustacheTemplate.js.map +1 -0
  106. package/dist/packlets/record-jar/index.browser.js +1 -3
  107. package/dist/packlets/record-jar/index.browser.js.map +1 -0
  108. package/dist/packlets/record-jar/index.js.map +1 -0
  109. package/dist/packlets/record-jar/recordJarFileHelpers.js +0 -18
  110. package/dist/packlets/record-jar/recordJarFileHelpers.js.map +1 -0
  111. package/dist/packlets/record-jar/recordJarHelpers.js +18 -0
  112. package/dist/packlets/record-jar/recordJarHelpers.js.map +1 -0
  113. package/dist/packlets/yaml/converters.js.map +1 -0
  114. package/dist/packlets/yaml/index.js +1 -0
  115. package/dist/packlets/yaml/index.js.map +1 -0
  116. package/dist/packlets/yaml/serializers.js +48 -0
  117. package/dist/packlets/yaml/serializers.js.map +1 -0
  118. package/dist/packlets/zip-file-tree/index.js.map +1 -0
  119. package/dist/packlets/zip-file-tree/zipFileTreeAccessors.js +2 -2
  120. package/dist/packlets/zip-file-tree/zipFileTreeAccessors.js.map +1 -0
  121. package/dist/packlets/zip-file-tree/zipFileTreeWriter.js.map +1 -0
  122. package/dist/ts-extras.d.ts +3880 -105
  123. package/dist/tsdoc-metadata.json +1 -1
  124. package/lib/index.browser.d.ts +4 -2
  125. package/lib/index.browser.d.ts.map +1 -0
  126. package/lib/index.browser.js +8 -3
  127. package/lib/index.browser.js.map +1 -0
  128. package/lib/index.d.ts.map +1 -0
  129. package/lib/index.js.map +1 -0
  130. package/lib/packlets/ai-assist/apiClient.d.ts +115 -32
  131. package/lib/packlets/ai-assist/apiClient.d.ts.map +1 -0
  132. package/lib/packlets/ai-assist/apiClient.js +888 -156
  133. package/lib/packlets/ai-assist/apiClient.js.map +1 -0
  134. package/lib/packlets/ai-assist/chatRequestBuilders.d.ts +149 -0
  135. package/lib/packlets/ai-assist/chatRequestBuilders.d.ts.map +1 -0
  136. package/lib/packlets/ai-assist/chatRequestBuilders.js +293 -0
  137. package/lib/packlets/ai-assist/chatRequestBuilders.js.map +1 -0
  138. package/lib/packlets/ai-assist/converters.d.ts +15 -1
  139. package/lib/packlets/ai-assist/converters.d.ts.map +1 -0
  140. package/lib/packlets/ai-assist/converters.js +47 -3
  141. package/lib/packlets/ai-assist/converters.js.map +1 -0
  142. package/lib/packlets/ai-assist/embeddingClient.d.ts +69 -0
  143. package/lib/packlets/ai-assist/embeddingClient.d.ts.map +1 -0
  144. package/lib/packlets/ai-assist/embeddingClient.js +349 -0
  145. package/lib/packlets/ai-assist/embeddingClient.js.map +1 -0
  146. package/lib/packlets/ai-assist/endpoint.d.ts +28 -0
  147. package/lib/packlets/ai-assist/endpoint.d.ts.map +1 -0
  148. package/lib/packlets/ai-assist/endpoint.js +82 -0
  149. package/lib/packlets/ai-assist/endpoint.js.map +1 -0
  150. package/lib/packlets/ai-assist/http.d.ts +24 -0
  151. package/lib/packlets/ai-assist/http.d.ts.map +1 -0
  152. package/lib/packlets/ai-assist/http.js +78 -0
  153. package/lib/packlets/ai-assist/http.js.map +1 -0
  154. package/lib/packlets/ai-assist/imageOptionsResolver.d.ts +66 -0
  155. package/lib/packlets/ai-assist/imageOptionsResolver.d.ts.map +1 -0
  156. package/lib/packlets/ai-assist/imageOptionsResolver.js +197 -0
  157. package/lib/packlets/ai-assist/imageOptionsResolver.js.map +1 -0
  158. package/lib/packlets/ai-assist/index.d.ts +10 -4
  159. package/lib/packlets/ai-assist/index.d.ts.map +1 -0
  160. package/lib/packlets/ai-assist/index.js +36 -1
  161. package/lib/packlets/ai-assist/index.js.map +1 -0
  162. package/lib/packlets/ai-assist/jsonCompletion.d.ts +93 -0
  163. package/lib/packlets/ai-assist/jsonCompletion.d.ts.map +1 -0
  164. package/lib/packlets/ai-assist/jsonCompletion.js +97 -0
  165. package/lib/packlets/ai-assist/jsonCompletion.js.map +1 -0
  166. package/lib/packlets/ai-assist/jsonResponse.d.ts +91 -0
  167. package/lib/packlets/ai-assist/jsonResponse.d.ts.map +1 -0
  168. package/lib/packlets/ai-assist/jsonResponse.js +154 -0
  169. package/lib/packlets/ai-assist/jsonResponse.js.map +1 -0
  170. package/lib/packlets/ai-assist/model.d.ts +1202 -12
  171. package/lib/packlets/ai-assist/model.d.ts.map +1 -0
  172. package/lib/packlets/ai-assist/model.js +198 -10
  173. package/lib/packlets/ai-assist/model.js.map +1 -0
  174. package/lib/packlets/ai-assist/registry.d.ts +56 -1
  175. package/lib/packlets/ai-assist/registry.d.ts.map +1 -0
  176. package/lib/packlets/ai-assist/registry.js +319 -13
  177. package/lib/packlets/ai-assist/registry.js.map +1 -0
  178. package/lib/packlets/ai-assist/sseParser.d.ts +45 -0
  179. package/lib/packlets/ai-assist/sseParser.d.ts.map +1 -0
  180. package/lib/packlets/ai-assist/sseParser.js +128 -0
  181. package/lib/packlets/ai-assist/sseParser.js.map +1 -0
  182. package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts +72 -0
  183. package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts.map +1 -0
  184. package/lib/packlets/ai-assist/streamingAdapters/anthropic.js +371 -0
  185. package/lib/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -0
  186. package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts +260 -0
  187. package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts.map +1 -0
  188. package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +694 -0
  189. package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -0
  190. package/lib/packlets/ai-assist/streamingAdapters/common.d.ts +154 -0
  191. package/lib/packlets/ai-assist/streamingAdapters/common.d.ts.map +1 -0
  192. package/lib/packlets/ai-assist/streamingAdapters/common.js +193 -0
  193. package/lib/packlets/ai-assist/streamingAdapters/common.js.map +1 -0
  194. package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts +43 -0
  195. package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts.map +1 -0
  196. package/lib/packlets/ai-assist/streamingAdapters/gemini.js +207 -0
  197. package/lib/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -0
  198. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts +19 -0
  199. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts.map +1 -0
  200. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js +173 -0
  201. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -0
  202. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts +33 -0
  203. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts.map +1 -0
  204. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js +389 -0
  205. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -0
  206. package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts +34 -0
  207. package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts.map +1 -0
  208. package/lib/packlets/ai-assist/streamingAdapters/proxy.js +176 -0
  209. package/lib/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -0
  210. package/lib/packlets/ai-assist/streamingClient.d.ts +50 -0
  211. package/lib/packlets/ai-assist/streamingClient.d.ts.map +1 -0
  212. package/lib/packlets/ai-assist/streamingClient.js +146 -0
  213. package/lib/packlets/ai-assist/streamingClient.js.map +1 -0
  214. package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts +87 -0
  215. package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts.map +1 -0
  216. package/lib/packlets/ai-assist/thinkingOptionsResolver.js +294 -0
  217. package/lib/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -0
  218. package/lib/packlets/ai-assist/toolFormats.d.ts +40 -9
  219. package/lib/packlets/ai-assist/toolFormats.d.ts.map +1 -0
  220. package/lib/packlets/ai-assist/toolFormats.js +107 -10
  221. package/lib/packlets/ai-assist/toolFormats.js.map +1 -0
  222. package/lib/packlets/conversion/converters.d.ts +8 -1
  223. package/lib/packlets/conversion/converters.d.ts.map +1 -0
  224. package/lib/packlets/conversion/converters.js +36 -2
  225. package/lib/packlets/conversion/converters.js.map +1 -0
  226. package/lib/packlets/conversion/index.d.ts.map +1 -0
  227. package/lib/packlets/conversion/index.js.map +1 -0
  228. package/lib/packlets/crypto-utils/constants.d.ts.map +1 -0
  229. package/lib/packlets/crypto-utils/constants.js.map +1 -0
  230. package/lib/packlets/crypto-utils/converters.d.ts +20 -1
  231. package/lib/packlets/crypto-utils/converters.d.ts.map +1 -0
  232. package/lib/packlets/crypto-utils/converters.js +43 -5
  233. package/lib/packlets/crypto-utils/converters.js.map +1 -0
  234. package/lib/packlets/crypto-utils/directEncryptionProvider.d.ts.map +1 -0
  235. package/lib/packlets/crypto-utils/directEncryptionProvider.js.map +1 -0
  236. package/lib/packlets/crypto-utils/encryptedFile.d.ts.map +1 -0
  237. package/lib/packlets/crypto-utils/encryptedFile.js.map +1 -0
  238. package/lib/packlets/crypto-utils/hpkeProvider.d.ts +142 -0
  239. package/lib/packlets/crypto-utils/hpkeProvider.d.ts.map +1 -0
  240. package/lib/packlets/crypto-utils/hpkeProvider.js +337 -0
  241. package/lib/packlets/crypto-utils/hpkeProvider.js.map +1 -0
  242. package/lib/packlets/crypto-utils/index.browser.d.ts +4 -1
  243. package/lib/packlets/crypto-utils/index.browser.d.ts.map +1 -0
  244. package/lib/packlets/crypto-utils/index.browser.js +21 -3
  245. package/lib/packlets/crypto-utils/index.browser.js.map +1 -0
  246. package/lib/packlets/crypto-utils/index.d.ts +3 -0
  247. package/lib/packlets/crypto-utils/index.d.ts.map +1 -0
  248. package/lib/packlets/crypto-utils/index.js +17 -1
  249. package/lib/packlets/crypto-utils/index.js.map +1 -0
  250. package/lib/packlets/crypto-utils/keyPairAlgorithmParams.d.ts +54 -0
  251. package/lib/packlets/crypto-utils/keyPairAlgorithmParams.d.ts.map +1 -0
  252. package/lib/packlets/crypto-utils/keyPairAlgorithmParams.js +74 -0
  253. package/lib/packlets/crypto-utils/keyPairAlgorithmParams.js.map +1 -0
  254. package/lib/packlets/crypto-utils/keystore/converters.d.ts +68 -6
  255. package/lib/packlets/crypto-utils/keystore/converters.d.ts.map +1 -0
  256. package/lib/packlets/crypto-utils/keystore/converters.js +101 -9
  257. package/lib/packlets/crypto-utils/keystore/converters.js.map +1 -0
  258. package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.d.ts +148 -0
  259. package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.d.ts.map +1 -0
  260. package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js +324 -0
  261. package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js.map +1 -0
  262. package/lib/packlets/crypto-utils/keystore/index.browser.d.ts +10 -0
  263. package/lib/packlets/crypto-utils/keystore/index.browser.d.ts.map +1 -0
  264. package/lib/packlets/crypto-utils/keystore/index.browser.js +76 -0
  265. package/lib/packlets/crypto-utils/keystore/index.browser.js.map +1 -0
  266. package/lib/packlets/crypto-utils/keystore/index.d.ts +2 -0
  267. package/lib/packlets/crypto-utils/keystore/index.d.ts.map +1 -0
  268. package/lib/packlets/crypto-utils/keystore/index.js +5 -1
  269. package/lib/packlets/crypto-utils/keystore/index.js.map +1 -0
  270. package/lib/packlets/crypto-utils/keystore/keyStore.d.ts +205 -13
  271. package/lib/packlets/crypto-utils/keystore/keyStore.d.ts.map +1 -0
  272. package/lib/packlets/crypto-utils/keystore/keyStore.js +639 -124
  273. package/lib/packlets/crypto-utils/keystore/keyStore.js.map +1 -0
  274. package/lib/packlets/crypto-utils/keystore/model.d.ts +275 -19
  275. package/lib/packlets/crypto-utils/keystore/model.d.ts.map +1 -0
  276. package/lib/packlets/crypto-utils/keystore/model.js +24 -2
  277. package/lib/packlets/crypto-utils/keystore/model.js.map +1 -0
  278. package/lib/packlets/crypto-utils/keystore/privateKeyStorage.d.ts +53 -0
  279. package/lib/packlets/crypto-utils/keystore/privateKeyStorage.d.ts.map +1 -0
  280. package/lib/packlets/crypto-utils/keystore/privateKeyStorage.js +22 -0
  281. package/lib/packlets/crypto-utils/keystore/privateKeyStorage.js.map +1 -0
  282. package/lib/packlets/crypto-utils/model.d.ts +348 -10
  283. package/lib/packlets/crypto-utils/model.d.ts.map +1 -0
  284. package/lib/packlets/crypto-utils/model.js +33 -1
  285. package/lib/packlets/crypto-utils/model.js.map +1 -0
  286. package/lib/packlets/crypto-utils/nodeCryptoProvider.d.ts +110 -2
  287. package/lib/packlets/crypto-utils/nodeCryptoProvider.d.ts.map +1 -0
  288. package/lib/packlets/crypto-utils/nodeCryptoProvider.js +269 -0
  289. package/lib/packlets/crypto-utils/nodeCryptoProvider.js.map +1 -0
  290. package/lib/packlets/crypto-utils/spkiHelpers.d.ts +110 -0
  291. package/lib/packlets/crypto-utils/spkiHelpers.d.ts.map +1 -0
  292. package/lib/packlets/crypto-utils/spkiHelpers.js +219 -0
  293. package/lib/packlets/crypto-utils/spkiHelpers.js.map +1 -0
  294. package/lib/packlets/csv/csvFileHelpers.d.ts +0 -10
  295. package/lib/packlets/csv/csvFileHelpers.d.ts.map +1 -0
  296. package/lib/packlets/csv/csvFileHelpers.js +0 -15
  297. package/lib/packlets/csv/csvFileHelpers.js.map +1 -0
  298. package/lib/packlets/csv/csvHelpers.d.ts +10 -0
  299. package/lib/packlets/csv/csvHelpers.d.ts.map +1 -0
  300. package/lib/packlets/csv/csvHelpers.js +15 -0
  301. package/lib/packlets/csv/csvHelpers.js.map +1 -0
  302. package/lib/packlets/csv/index.browser.d.ts +0 -1
  303. package/lib/packlets/csv/index.browser.d.ts.map +1 -0
  304. package/lib/packlets/csv/index.browser.js +1 -5
  305. package/lib/packlets/csv/index.browser.js.map +1 -0
  306. package/lib/packlets/csv/index.d.ts.map +1 -0
  307. package/lib/packlets/csv/index.js.map +1 -0
  308. package/lib/packlets/experimental/extendedArray.d.ts.map +1 -0
  309. package/lib/packlets/experimental/extendedArray.js.map +1 -0
  310. package/lib/packlets/experimental/formatter.d.ts.map +1 -0
  311. package/lib/packlets/experimental/formatter.js.map +1 -0
  312. package/lib/packlets/experimental/index.d.ts.map +1 -0
  313. package/lib/packlets/experimental/index.js.map +1 -0
  314. package/lib/packlets/experimental/rangeOf.d.ts.map +1 -0
  315. package/lib/packlets/experimental/rangeOf.js.map +1 -0
  316. package/lib/packlets/hash/index.browser.d.ts.map +1 -0
  317. package/lib/packlets/hash/index.browser.js.map +1 -0
  318. package/lib/packlets/hash/index.d.ts.map +1 -0
  319. package/lib/packlets/hash/index.js.map +1 -0
  320. package/lib/packlets/hash/index.node.d.ts.map +1 -0
  321. package/lib/packlets/hash/index.node.js.map +1 -0
  322. package/lib/packlets/hash/md5Normalizer.browser.d.ts.map +1 -0
  323. package/lib/packlets/hash/md5Normalizer.browser.js.map +1 -0
  324. package/lib/packlets/hash/md5Normalizer.d.ts.map +1 -0
  325. package/lib/packlets/hash/md5Normalizer.js.map +1 -0
  326. package/lib/packlets/mustache/index.d.ts +1 -1
  327. package/lib/packlets/mustache/index.d.ts.map +1 -0
  328. package/lib/packlets/mustache/index.js.map +1 -0
  329. package/lib/packlets/mustache/interfaces.d.ts +34 -0
  330. package/lib/packlets/mustache/interfaces.d.ts.map +1 -0
  331. package/lib/packlets/mustache/interfaces.js.map +1 -0
  332. package/lib/packlets/mustache/mustacheTemplate.d.ts +2 -0
  333. package/lib/packlets/mustache/mustacheTemplate.d.ts.map +1 -0
  334. package/lib/packlets/mustache/mustacheTemplate.js +42 -4
  335. package/lib/packlets/mustache/mustacheTemplate.js.map +1 -0
  336. package/lib/packlets/record-jar/index.browser.d.ts +0 -1
  337. package/lib/packlets/record-jar/index.browser.d.ts.map +1 -0
  338. package/lib/packlets/record-jar/index.browser.js +1 -5
  339. package/lib/packlets/record-jar/index.browser.js.map +1 -0
  340. package/lib/packlets/record-jar/index.d.ts.map +1 -0
  341. package/lib/packlets/record-jar/index.js.map +1 -0
  342. package/lib/packlets/record-jar/recordJarFileHelpers.d.ts +0 -11
  343. package/lib/packlets/record-jar/recordJarFileHelpers.d.ts.map +1 -0
  344. package/lib/packlets/record-jar/recordJarFileHelpers.js +0 -19
  345. package/lib/packlets/record-jar/recordJarFileHelpers.js.map +1 -0
  346. package/lib/packlets/record-jar/recordJarHelpers.d.ts +11 -0
  347. package/lib/packlets/record-jar/recordJarHelpers.d.ts.map +1 -0
  348. package/lib/packlets/record-jar/recordJarHelpers.js +19 -0
  349. package/lib/packlets/record-jar/recordJarHelpers.js.map +1 -0
  350. package/lib/packlets/yaml/converters.d.ts.map +1 -0
  351. package/lib/packlets/yaml/converters.js.map +1 -0
  352. package/lib/packlets/yaml/index.d.ts +1 -0
  353. package/lib/packlets/yaml/index.d.ts.map +1 -0
  354. package/lib/packlets/yaml/index.js +1 -0
  355. package/lib/packlets/yaml/index.js.map +1 -0
  356. package/lib/packlets/yaml/serializers.d.ts +45 -0
  357. package/lib/packlets/yaml/serializers.d.ts.map +1 -0
  358. package/lib/packlets/yaml/serializers.js +84 -0
  359. package/lib/packlets/yaml/serializers.js.map +1 -0
  360. package/lib/packlets/zip-file-tree/index.d.ts.map +1 -0
  361. package/lib/packlets/zip-file-tree/index.js.map +1 -0
  362. package/lib/packlets/zip-file-tree/zipFileTreeAccessors.d.ts +2 -2
  363. package/lib/packlets/zip-file-tree/zipFileTreeAccessors.d.ts.map +1 -0
  364. package/lib/packlets/zip-file-tree/zipFileTreeAccessors.js +2 -2
  365. package/lib/packlets/zip-file-tree/zipFileTreeAccessors.js.map +1 -0
  366. package/lib/packlets/zip-file-tree/zipFileTreeWriter.d.ts.map +1 -0
  367. package/lib/packlets/zip-file-tree/zipFileTreeWriter.js.map +1 -0
  368. package/package.json +20 -15
@@ -0,0 +1,288 @@
1
+ // Copyright (c) 2026 Erik Fortune
2
+ //
3
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ // of this software and associated documentation files (the "Software"), to deal
5
+ // in the Software without restriction, including without limitation the rights
6
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ // copies of the Software, and to permit persons to whom the Software is
8
+ // furnished to do so, subject to the following conditions:
9
+ //
10
+ // The above copyright notice and this permission notice shall be included in all
11
+ // copies or substantial portions of the Software.
12
+ //
13
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ // SOFTWARE.
20
+ import { fail, succeed } from '@fgv/ts-utils';
21
+ /**
22
+ * Maps an AiProviderId (registry key) to the coarse family discriminator used
23
+ * in IThinkingProviderConfig. Returns undefined for providers without thinking support.
24
+ * @internal
25
+ */
26
+ export function providerDiscriminatorForId(providerId) {
27
+ switch (providerId) {
28
+ case 'anthropic':
29
+ return 'anthropic';
30
+ case 'openai':
31
+ return 'openai';
32
+ case 'google-gemini':
33
+ return 'google';
34
+ case 'xai-grok':
35
+ return 'xai';
36
+ default:
37
+ return undefined;
38
+ }
39
+ }
40
+ // ============================================================================
41
+ // Common-subset mapping
42
+ // ============================================================================
43
+ /**
44
+ * Maps generic effort to Anthropic wire effort. @internal
45
+ */
46
+ function genericEffortToAnthropic(effort) {
47
+ return effort; // 1:1 mapping for the common subset
48
+ }
49
+ /**
50
+ * Maps Anthropic effort level to the `thinking.budget_tokens` integer that the
51
+ * Anthropic API requires when `thinking.type === 'enabled'`.
52
+ *
53
+ * Policy: low = 2048, medium = 8192, high = 24000, max = 32000. The lower three
54
+ * align with the Anthropic-published minimum-meaningful budget, a mid-range
55
+ * default, and a "deep thinking" allotment respectively. `max` targets Opus 4.6's
56
+ * deepest budget and stays within typical model limits.
57
+ *
58
+ * @public
59
+ */
60
+ export function anthropicEffortToBudgetTokens(effort) {
61
+ switch (effort) {
62
+ case 'low':
63
+ return 2048;
64
+ case 'medium':
65
+ return 8192;
66
+ case 'high':
67
+ return 24000;
68
+ case 'max':
69
+ return 32000;
70
+ }
71
+ }
72
+ /**
73
+ * Maps generic effort to OpenAI wire effort. @internal
74
+ */
75
+ function genericEffortToOpenAi(effort) {
76
+ return effort; // 1:1 mapping for the common subset
77
+ }
78
+ /**
79
+ * Maps generic effort to Gemini thinkingBudget. @internal
80
+ */
81
+ function genericEffortToGemini(effort) {
82
+ switch (effort) {
83
+ case 'low':
84
+ return 1024;
85
+ case 'medium':
86
+ return 4096;
87
+ case 'high':
88
+ return 8192;
89
+ }
90
+ }
91
+ /**
92
+ * Maps generic effort to xAI reasoning_effort. @internal
93
+ */
94
+ function genericEffortToXai(effort) {
95
+ return effort; // 1:1 mapping for the common subset
96
+ }
97
+ // ============================================================================
98
+ // Block applicability
99
+ // ============================================================================
100
+ /**
101
+ * Returns true when a provider config block applies to the given resolved model
102
+ * and provider discriminator.
103
+ *
104
+ * Applicability rules:
105
+ * - provider must match the coarse discriminator
106
+ * - if models array is present, resolved model must match (exact or base-name prefix)
107
+ * - if models array is absent, the block is provider-generic (applies to all)
108
+ *
109
+ * Prefix matching supports versioned IDs: `'claude-sonnet-4-5'` matches resolved
110
+ * `'claude-sonnet-4-5-20250929'`. An entry matches when it equals the resolved model
111
+ * or when the resolved model starts with the entry followed by a `-`.
112
+ *
113
+ * 'other' blocks require models to be present (enforced by the type).
114
+ * @internal
115
+ */
116
+ function modelNameMatches(resolvedModel, name) {
117
+ return resolvedModel === name || resolvedModel.startsWith(`${name}-`);
118
+ }
119
+ function blockApplies(block, resolvedModel, discriminator) {
120
+ if (block.provider !== discriminator && block.provider !== 'other') {
121
+ return false;
122
+ }
123
+ if (block.provider === 'other') {
124
+ return block.models.some((name) => modelNameMatches(resolvedModel, name));
125
+ }
126
+ if (block.models !== undefined) {
127
+ return block.models.some((name) => modelNameMatches(resolvedModel, name));
128
+ }
129
+ return true; // provider-generic block
130
+ }
131
+ /**
132
+ * Returns true when a block is model-specific (has a models array).
133
+ * Used to partition blocks into merge tiers.
134
+ * @internal
135
+ */
136
+ function isModelSpecific(block) {
137
+ if (block.provider === 'other') {
138
+ return true; // other blocks always require models
139
+ }
140
+ return block.models !== undefined;
141
+ }
142
+ // ============================================================================
143
+ // Merge function
144
+ // ============================================================================
145
+ /**
146
+ * Resolves the effective thinking wire parameters for a specific resolved model
147
+ * by merging all applicable config blocks in precedence order.
148
+ *
149
+ * Precedence (later tier wins; within tier, later declaration wins):
150
+ * 1. Generic effort (top-level IThinkingConfig.effort) → common-subset mapping
151
+ * 2. Provider-generic blocks (matching provider, no models filter)
152
+ * 3. Model-specific blocks (matching provider + models array includes resolved model)
153
+ * 4. Other blocks (provider: 'other', models includes resolved model) — same tier as 3
154
+ *
155
+ * Blocks whose provider does not match are silently skipped.
156
+ *
157
+ * Note: when the resolved OpenAI effort is `'none'`, reasoning is disabled and
158
+ * temperature is accepted; see {@link IOpenAiThinkingConfig.effort} for the full
159
+ * hybrid-mode semantics.
160
+ *
161
+ * @param config - The caller's IThinkingConfig
162
+ * @param resolvedModel - The concrete model string after registry resolution
163
+ * @param discriminator - Coarse provider family
164
+ * @returns Merged effective config for wire encoding
165
+ * @internal
166
+ */
167
+ export function mergeThinkingConfig(config, resolvedModel, discriminator) {
168
+ let resolved = {};
169
+ // Tier 1: generic effort → common-subset mapping
170
+ if (config.effort !== undefined) {
171
+ switch (discriminator) {
172
+ case 'anthropic':
173
+ resolved = Object.assign(Object.assign({}, resolved), { anthropicEffort: genericEffortToAnthropic(config.effort) });
174
+ break;
175
+ case 'openai':
176
+ resolved = Object.assign(Object.assign({}, resolved), { openAiEffort: genericEffortToOpenAi(config.effort) });
177
+ break;
178
+ case 'google':
179
+ resolved = Object.assign(Object.assign({}, resolved), { geminiThinkingBudget: genericEffortToGemini(config.effort) });
180
+ break;
181
+ case 'xai':
182
+ resolved = Object.assign(Object.assign({}, resolved), { xaiEffort: genericEffortToXai(config.effort) });
183
+ break;
184
+ }
185
+ }
186
+ if (!config.providers) {
187
+ return succeed(resolved);
188
+ }
189
+ // Partition into tiers 2 and 3+4
190
+ const applicableBlocks = config.providers.filter((b) => blockApplies(b, resolvedModel, discriminator));
191
+ const genericBlocks = applicableBlocks.filter((b) => !isModelSpecific(b));
192
+ const specificBlocks = applicableBlocks.filter((b) => isModelSpecific(b));
193
+ // Tier 2: provider-generic blocks (declaration order; later wins)
194
+ for (const block of genericBlocks) {
195
+ resolved = applyBlock(resolved, block, discriminator);
196
+ }
197
+ // Tier 3+4: model-specific + other blocks (declaration order; later wins)
198
+ for (const block of specificBlocks) {
199
+ resolved = applyBlock(resolved, block, discriminator);
200
+ }
201
+ return succeed(resolved);
202
+ }
203
+ /**
204
+ * Applies a single config block to the accumulated resolved config.
205
+ * @internal
206
+ */
207
+ function applyBlock(current, block, discriminator) {
208
+ if (block.provider === 'other') {
209
+ const merged = current.otherParams !== undefined ? Object.assign(Object.assign({}, current.otherParams), block.config) : block.config;
210
+ return Object.assign(Object.assign({}, current), { otherParams: merged });
211
+ }
212
+ switch (discriminator) {
213
+ case 'anthropic':
214
+ if (block.provider === 'anthropic') {
215
+ if (block.config.effort !== undefined) {
216
+ return Object.assign(Object.assign({}, current), { anthropicEffort: block.config.effort });
217
+ }
218
+ }
219
+ break;
220
+ case 'openai':
221
+ if (block.provider === 'openai') {
222
+ if (block.config.effort !== undefined) {
223
+ return Object.assign(Object.assign({}, current), { openAiEffort: block.config.effort });
224
+ }
225
+ }
226
+ break;
227
+ case 'google':
228
+ if (block.provider === 'google') {
229
+ const updated = Object.assign({}, current);
230
+ if (block.config.thinkingBudget !== undefined) {
231
+ return Object.assign(Object.assign({}, updated), { geminiThinkingBudget: block.config.thinkingBudget });
232
+ }
233
+ return updated;
234
+ }
235
+ /* c8 ignore next - blockApplies guarantees provider match; unreachable for google */
236
+ break;
237
+ case 'xai':
238
+ if (block.provider === 'xai') {
239
+ if (block.config.effort !== undefined) {
240
+ return Object.assign(Object.assign({}, current), { xaiEffort: block.config.effort });
241
+ }
242
+ }
243
+ break;
244
+ }
245
+ return current;
246
+ }
247
+ // ============================================================================
248
+ // Temperature conflict check
249
+ // ============================================================================
250
+ /**
251
+ * Returns a Result.fail if temperature conflicts with thinking mode for the
252
+ * given provider, otherwise succeed(undefined).
253
+ *
254
+ * Per D4: temperature + thinking = Result.fail for Anthropic, OpenAI (when
255
+ * effective effort is non-null and non-'none'), and xAI (conservative default
256
+ * pending live verification). Gemini accepts temperature alongside thinking.
257
+ *
258
+ * @internal
259
+ */
260
+ export function checkTemperatureConflict(resolved, discriminator, temperature) {
261
+ if (temperature === undefined) {
262
+ return succeed(undefined);
263
+ }
264
+ switch (discriminator) {
265
+ case 'anthropic':
266
+ if (resolved.anthropicEffort !== undefined) {
267
+ return fail('thinking mode is not compatible with temperature on provider anthropic: remove temperature or disable thinking');
268
+ }
269
+ break;
270
+ case 'openai':
271
+ // 'none' disables reasoning; temperature is accepted in that case
272
+ if (resolved.openAiEffort !== undefined && resolved.openAiEffort !== 'none') {
273
+ return fail('thinking mode is not compatible with temperature on provider openai: remove temperature or disable thinking');
274
+ }
275
+ break;
276
+ case 'xai':
277
+ // Conservative default: fail if xAI effort is active (per D8 — live verification pending)
278
+ if (resolved.xaiEffort !== undefined && resolved.xaiEffort !== 'none') {
279
+ return fail('thinking mode is not compatible with temperature on provider xai: remove temperature or disable thinking');
280
+ }
281
+ break;
282
+ case 'google':
283
+ // Gemini accepts temperature alongside thinkingConfig — no conflict
284
+ break;
285
+ }
286
+ return succeed(undefined);
287
+ }
288
+ //# sourceMappingURL=thinkingOptionsResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thinkingOptionsResolver.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/thinkingOptionsResolver.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Merge logic and runtime validation for thinking/reasoning options.\n * @packageDocumentation\n */\n\nimport { type JsonObject } from '@fgv/ts-json-base';\nimport { fail, Result, succeed } from '@fgv/ts-utils';\n\nimport type {\n IThinkingConfig,\n IThinkingProviderConfig,\n IAnthropicThinkingConfig,\n IOpenAiThinkingConfig,\n IXAiThinkingConfig\n} from './model';\n\n// ============================================================================\n// Provider discriminator\n// ============================================================================\n\n/**\n * Coarse provider family used to discriminate thinking config blocks.\n * Maps from AiProviderId to the IThinkingProviderConfig `provider` discriminator.\n * @internal\n */\nexport type ThinkingProviderDiscriminator = 'anthropic' | 'openai' | 'google' | 'xai';\n\n/**\n * Maps an AiProviderId (registry key) to the coarse family discriminator used\n * in IThinkingProviderConfig. Returns undefined for providers without thinking support.\n * @internal\n */\nexport function providerDiscriminatorForId(providerId: string): ThinkingProviderDiscriminator | undefined {\n switch (providerId) {\n case 'anthropic':\n return 'anthropic';\n case 'openai':\n return 'openai';\n case 'google-gemini':\n return 'google';\n case 'xai-grok':\n return 'xai';\n default:\n return undefined;\n }\n}\n\n// ============================================================================\n// Resolved wire shape\n// ============================================================================\n\n/**\n * Resolved thinking wire parameters for a specific provider, after merging\n * all applicable config blocks. Ready for provider-specific wire encoding.\n *\n * Callers that pre-resolve thinking config outside of the standard streaming\n * helpers (e.g. `executeClientToolTurn`) accept this type via the\n * `resolvedThinking` parameter and pass it directly to the adapter layer.\n * @public\n */\nexport interface IResolvedThinkingConfig {\n /** Anthropic: effort level; emit-site converts to `thinking.budget_tokens` via `anthropicEffortToBudgetTokens`. */\n readonly anthropicEffort?: IAnthropicThinkingConfig['effort'];\n /** OpenAI Chat: reasoning_effort value; OpenAI Responses: reasoning.effort */\n readonly openAiEffort?: IOpenAiThinkingConfig['effort'];\n /** Gemini: generationConfig.thinkingConfig.thinkingBudget */\n readonly geminiThinkingBudget?: number;\n /** xAI: reasoning_effort value (omit for grok-4) */\n readonly xaiEffort?: IXAiThinkingConfig['effort'];\n /** Other/passthrough: merged verbatim into wire request */\n readonly otherParams?: JsonObject;\n}\n\n// ============================================================================\n// Common-subset mapping\n// ============================================================================\n\n/**\n * Maps generic effort to Anthropic wire effort. @internal\n */\nfunction genericEffortToAnthropic(effort: 'low' | 'medium' | 'high'): IAnthropicThinkingConfig['effort'] {\n return effort; // 1:1 mapping for the common subset\n}\n\n/**\n * Maps Anthropic effort level to the `thinking.budget_tokens` integer that the\n * Anthropic API requires when `thinking.type === 'enabled'`.\n *\n * Policy: low = 2048, medium = 8192, high = 24000, max = 32000. The lower three\n * align with the Anthropic-published minimum-meaningful budget, a mid-range\n * default, and a \"deep thinking\" allotment respectively. `max` targets Opus 4.6's\n * deepest budget and stays within typical model limits.\n *\n * @public\n */\nexport function anthropicEffortToBudgetTokens(\n effort: NonNullable<IAnthropicThinkingConfig['effort']>\n): number {\n switch (effort) {\n case 'low':\n return 2048;\n case 'medium':\n return 8192;\n case 'high':\n return 24000;\n case 'max':\n return 32000;\n }\n}\n\n/**\n * Maps generic effort to OpenAI wire effort. @internal\n */\nfunction genericEffortToOpenAi(effort: 'low' | 'medium' | 'high'): IOpenAiThinkingConfig['effort'] {\n return effort; // 1:1 mapping for the common subset\n}\n\n/**\n * Maps generic effort to Gemini thinkingBudget. @internal\n */\nfunction genericEffortToGemini(effort: 'low' | 'medium' | 'high'): number {\n switch (effort) {\n case 'low':\n return 1024;\n case 'medium':\n return 4096;\n case 'high':\n return 8192;\n }\n}\n\n/**\n * Maps generic effort to xAI reasoning_effort. @internal\n */\nfunction genericEffortToXai(effort: 'low' | 'medium' | 'high'): IXAiThinkingConfig['effort'] {\n return effort; // 1:1 mapping for the common subset\n}\n\n// ============================================================================\n// Block applicability\n// ============================================================================\n\n/**\n * Returns true when a provider config block applies to the given resolved model\n * and provider discriminator.\n *\n * Applicability rules:\n * - provider must match the coarse discriminator\n * - if models array is present, resolved model must match (exact or base-name prefix)\n * - if models array is absent, the block is provider-generic (applies to all)\n *\n * Prefix matching supports versioned IDs: `'claude-sonnet-4-5'` matches resolved\n * `'claude-sonnet-4-5-20250929'`. An entry matches when it equals the resolved model\n * or when the resolved model starts with the entry followed by a `-`.\n *\n * 'other' blocks require models to be present (enforced by the type).\n * @internal\n */\nfunction modelNameMatches(resolvedModel: string, name: string): boolean {\n return resolvedModel === name || resolvedModel.startsWith(`${name}-`);\n}\n\nfunction blockApplies(\n block: IThinkingProviderConfig,\n resolvedModel: string,\n discriminator: ThinkingProviderDiscriminator\n): boolean {\n if (block.provider !== discriminator && block.provider !== 'other') {\n return false;\n }\n if (block.provider === 'other') {\n return block.models.some((name) => modelNameMatches(resolvedModel, name));\n }\n if (block.models !== undefined) {\n return (block.models as ReadonlyArray<string>).some((name) => modelNameMatches(resolvedModel, name));\n }\n return true; // provider-generic block\n}\n\n/**\n * Returns true when a block is model-specific (has a models array).\n * Used to partition blocks into merge tiers.\n * @internal\n */\nfunction isModelSpecific(block: IThinkingProviderConfig): boolean {\n if (block.provider === 'other') {\n return true; // other blocks always require models\n }\n return block.models !== undefined;\n}\n\n// ============================================================================\n// Merge function\n// ============================================================================\n\n/**\n * Resolves the effective thinking wire parameters for a specific resolved model\n * by merging all applicable config blocks in precedence order.\n *\n * Precedence (later tier wins; within tier, later declaration wins):\n * 1. Generic effort (top-level IThinkingConfig.effort) → common-subset mapping\n * 2. Provider-generic blocks (matching provider, no models filter)\n * 3. Model-specific blocks (matching provider + models array includes resolved model)\n * 4. Other blocks (provider: 'other', models includes resolved model) — same tier as 3\n *\n * Blocks whose provider does not match are silently skipped.\n *\n * Note: when the resolved OpenAI effort is `'none'`, reasoning is disabled and\n * temperature is accepted; see {@link IOpenAiThinkingConfig.effort} for the full\n * hybrid-mode semantics.\n *\n * @param config - The caller's IThinkingConfig\n * @param resolvedModel - The concrete model string after registry resolution\n * @param discriminator - Coarse provider family\n * @returns Merged effective config for wire encoding\n * @internal\n */\nexport function mergeThinkingConfig(\n config: IThinkingConfig,\n resolvedModel: string,\n discriminator: ThinkingProviderDiscriminator\n): Result<IResolvedThinkingConfig> {\n let resolved: IResolvedThinkingConfig = {};\n\n // Tier 1: generic effort → common-subset mapping\n if (config.effort !== undefined) {\n switch (discriminator) {\n case 'anthropic':\n resolved = { ...resolved, anthropicEffort: genericEffortToAnthropic(config.effort) };\n break;\n case 'openai':\n resolved = { ...resolved, openAiEffort: genericEffortToOpenAi(config.effort) };\n break;\n case 'google':\n resolved = { ...resolved, geminiThinkingBudget: genericEffortToGemini(config.effort) };\n break;\n case 'xai':\n resolved = { ...resolved, xaiEffort: genericEffortToXai(config.effort) };\n break;\n }\n }\n\n if (!config.providers) {\n return succeed(resolved);\n }\n\n // Partition into tiers 2 and 3+4\n const applicableBlocks = config.providers.filter((b) => blockApplies(b, resolvedModel, discriminator));\n const genericBlocks = applicableBlocks.filter((b) => !isModelSpecific(b));\n const specificBlocks = applicableBlocks.filter((b) => isModelSpecific(b));\n\n // Tier 2: provider-generic blocks (declaration order; later wins)\n for (const block of genericBlocks) {\n resolved = applyBlock(resolved, block, discriminator);\n }\n\n // Tier 3+4: model-specific + other blocks (declaration order; later wins)\n for (const block of specificBlocks) {\n resolved = applyBlock(resolved, block, discriminator);\n }\n\n return succeed(resolved);\n}\n\n/**\n * Applies a single config block to the accumulated resolved config.\n * @internal\n */\nfunction applyBlock(\n current: IResolvedThinkingConfig,\n block: IThinkingProviderConfig,\n discriminator: ThinkingProviderDiscriminator\n): IResolvedThinkingConfig {\n if (block.provider === 'other') {\n const merged =\n current.otherParams !== undefined ? { ...current.otherParams, ...block.config } : block.config;\n return { ...current, otherParams: merged };\n }\n\n switch (discriminator) {\n case 'anthropic':\n if (block.provider === 'anthropic') {\n if (block.config.effort !== undefined) {\n return { ...current, anthropicEffort: block.config.effort };\n }\n }\n break;\n case 'openai':\n if (block.provider === 'openai') {\n if (block.config.effort !== undefined) {\n return { ...current, openAiEffort: block.config.effort };\n }\n }\n break;\n case 'google':\n if (block.provider === 'google') {\n const updated: IResolvedThinkingConfig = { ...current };\n if (block.config.thinkingBudget !== undefined) {\n return { ...updated, geminiThinkingBudget: block.config.thinkingBudget };\n }\n return updated;\n }\n /* c8 ignore next - blockApplies guarantees provider match; unreachable for google */\n break;\n case 'xai':\n if (block.provider === 'xai') {\n if (block.config.effort !== undefined) {\n return { ...current, xaiEffort: block.config.effort };\n }\n }\n break;\n }\n return current;\n}\n\n// ============================================================================\n// Temperature conflict check\n// ============================================================================\n\n/**\n * Returns a Result.fail if temperature conflicts with thinking mode for the\n * given provider, otherwise succeed(undefined).\n *\n * Per D4: temperature + thinking = Result.fail for Anthropic, OpenAI (when\n * effective effort is non-null and non-'none'), and xAI (conservative default\n * pending live verification). Gemini accepts temperature alongside thinking.\n *\n * @internal\n */\nexport function checkTemperatureConflict(\n resolved: IResolvedThinkingConfig,\n discriminator: ThinkingProviderDiscriminator,\n temperature: number | undefined\n): Result<undefined> {\n if (temperature === undefined) {\n return succeed(undefined);\n }\n\n switch (discriminator) {\n case 'anthropic':\n if (resolved.anthropicEffort !== undefined) {\n return fail(\n 'thinking mode is not compatible with temperature on provider anthropic: remove temperature or disable thinking'\n );\n }\n break;\n case 'openai':\n // 'none' disables reasoning; temperature is accepted in that case\n if (resolved.openAiEffort !== undefined && resolved.openAiEffort !== 'none') {\n return fail(\n 'thinking mode is not compatible with temperature on provider openai: remove temperature or disable thinking'\n );\n }\n break;\n case 'xai':\n // Conservative default: fail if xAI effort is active (per D8 — live verification pending)\n if (resolved.xaiEffort !== undefined && resolved.xaiEffort !== 'none') {\n return fail(\n 'thinking mode is not compatible with temperature on provider xai: remove temperature or disable thinking'\n );\n }\n break;\n case 'google':\n // Gemini accepts temperature alongside thinkingConfig — no conflict\n break;\n }\n return succeed(undefined);\n}\n"]}
@@ -70,9 +70,21 @@ function webSearchToResponsesApi(config) {
70
70
  }
71
71
  return tool;
72
72
  }
73
+ /**
74
+ * Formats a client tool config for the xAI/OpenAI Responses API.
75
+ * @internal
76
+ */
77
+ function clientToolToResponsesApi(config) {
78
+ return {
79
+ type: 'function',
80
+ name: config.name,
81
+ description: config.description,
82
+ parameters: config.parametersSchema.toJson()
83
+ };
84
+ }
73
85
  /**
74
86
  * Formats tool configs for the xAI/OpenAI Responses API.
75
- * @param tools - The resolved tool configs
87
+ * @param tools - The resolved tool configs (server-side and/or client-defined)
76
88
  * @returns Provider-native tool objects for the `tools` request field
77
89
  * @public
78
90
  */
@@ -81,10 +93,12 @@ export function toResponsesApiTools(tools) {
81
93
  switch (t.type) {
82
94
  case 'web_search':
83
95
  return webSearchToResponsesApi(t);
96
+ case 'client_tool':
97
+ return clientToolToResponsesApi(t);
84
98
  /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */
85
99
  default: {
86
- const _exhaustive = t.type;
87
- return { type: String(_exhaustive) };
100
+ const _exhaustive = t;
101
+ return { type: `unknown:${JSON.stringify(_exhaustive)}` };
88
102
  }
89
103
  }
90
104
  });
@@ -112,9 +126,21 @@ function webSearchToAnthropic(config) {
112
126
  }
113
127
  return tool;
114
128
  }
129
+ /**
130
+ * Formats a client tool config for the Anthropic Messages API.
131
+ * Note: Anthropic client tools have no `type` field (unlike server tools).
132
+ * @internal
133
+ */
134
+ function clientToolToAnthropic(config) {
135
+ return {
136
+ name: config.name,
137
+ description: config.description,
138
+ input_schema: config.parametersSchema.toJson()
139
+ };
140
+ }
115
141
  /**
116
142
  * Formats tool configs for the Anthropic Messages API.
117
- * @param tools - The resolved tool configs
143
+ * @param tools - The resolved tool configs (server-side and/or client-defined)
118
144
  * @returns Provider-native tool objects for the `tools` request field
119
145
  * @public
120
146
  */
@@ -123,10 +149,12 @@ export function toAnthropicTools(tools) {
123
149
  switch (t.type) {
124
150
  case 'web_search':
125
151
  return webSearchToAnthropic(t);
152
+ case 'client_tool':
153
+ return clientToolToAnthropic(t);
126
154
  /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */
127
155
  default: {
128
- const _exhaustive = t.type;
129
- return { type: String(_exhaustive) };
156
+ const _exhaustive = t;
157
+ return { type: `unknown:${JSON.stringify(_exhaustive)}` };
130
158
  }
131
159
  }
132
160
  });
@@ -134,27 +162,95 @@ export function toAnthropicTools(tools) {
134
162
  // ============================================================================
135
163
  // Gemini generateContent API format
136
164
  // ============================================================================
165
+ /**
166
+ * Sanitizes a draft-07 JSON Schema (as emitted by `JsonSchema.object(...).toJson()`)
167
+ * into the OpenAPI 3.0 Schema Object subset that Gemini's `function_declarations[].parameters`
168
+ * accepts.
169
+ *
170
+ * @remarks
171
+ * Gemini's function-declaration schema is **not** full JSON Schema — it is a subset of
172
+ * the OpenAPI 3.0 Schema Object and **rejects** (rather than ignores) draft-07-only
173
+ * keywords. `JsonSchema` objects are strict-by-default, so `.toJson()` emits
174
+ * `additionalProperties: false` on every object node, which 400s the whole request on
175
+ * Gemini. This helper recursively strips the unsupported keywords so any
176
+ * `JsonSchema`-authored client tool works on Gemini without consumer awareness of the
177
+ * dialect difference. Stripping is infallible, so it returns a plain value rather than a
178
+ * `Result`.
179
+ *
180
+ * `additionalProperties` and `$schema` are stripped only where they appear as schema
181
+ * *keywords* (siblings of `type`/`properties`/etc.). Inside a `properties` map the keys
182
+ * are user-defined parameter names, not keywords, so they are preserved verbatim while
183
+ * each property's subschema value is still recursively sanitized — a tool parameter
184
+ * legitimately named `additionalProperties` survives.
185
+ *
186
+ * @internal
187
+ */
188
+ export function toGeminiParameterSchema(schema) {
189
+ if (Array.isArray(schema)) {
190
+ return schema.map(toGeminiParameterSchema);
191
+ }
192
+ if (schema !== null && typeof schema === 'object') {
193
+ const out = {};
194
+ for (const [key, value] of Object.entries(schema)) {
195
+ if (key === 'additionalProperties' || key === '$schema') {
196
+ continue;
197
+ }
198
+ if (key === 'properties' && value !== null && typeof value === 'object' && !Array.isArray(value)) {
199
+ // `properties` maps user-defined parameter names to subschemas: recurse each
200
+ // subschema value but never treat a parameter name as a strippable keyword.
201
+ const properties = {};
202
+ for (const [name, propSchema] of Object.entries(value)) {
203
+ properties[name] = toGeminiParameterSchema(propSchema);
204
+ }
205
+ out[key] = properties;
206
+ }
207
+ else {
208
+ out[key] = toGeminiParameterSchema(value);
209
+ }
210
+ }
211
+ return out;
212
+ }
213
+ return schema;
214
+ }
137
215
  /**
138
216
  * Formats tool configs for the Gemini generateContent API.
139
- * Gemini uses `google_search` for search grounding — no per-tool config options.
140
- * @param tools - The resolved tool configs
217
+ *
218
+ * @remarks
219
+ * Gemini uses `google_search` for search grounding (no per-tool config).
220
+ * Client-defined tools are accumulated into a single `function_declarations` entry.
221
+ * Each client tool's parameters schema is sanitized to Gemini's OpenAPI-subset
222
+ * dialect via {@link toGeminiParameterSchema} (the raw draft-07 `.toJson()` output
223
+ * carries `additionalProperties`, which Gemini rejects).
224
+ *
225
+ * @param tools - The resolved tool configs (server-side and/or client-defined)
141
226
  * @returns Provider-native tool objects for the `tools` request field
142
227
  * @public
143
228
  */
144
229
  export function toGeminiTools(tools) {
145
230
  const result = [];
231
+ const functionDeclarations = [];
146
232
  for (const t of tools) {
147
233
  switch (t.type) {
148
234
  case 'web_search':
149
235
  result.push({ google_search: {} });
150
236
  break;
237
+ case 'client_tool':
238
+ functionDeclarations.push({
239
+ name: t.name,
240
+ description: t.description,
241
+ parameters: toGeminiParameterSchema(t.parametersSchema.toJson())
242
+ });
243
+ break;
151
244
  /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */
152
245
  default: {
153
- const _exhaustive = t.type;
154
- result.push({ type: String(_exhaustive) });
246
+ const _exhaustive = t;
247
+ result.push({ type: `unknown:${JSON.stringify(_exhaustive)}` });
155
248
  }
156
249
  }
157
250
  }
251
+ if (functionDeclarations.length > 0) {
252
+ result.push({ function_declarations: functionDeclarations });
253
+ }
158
254
  return result;
159
255
  }
160
256
  //# sourceMappingURL=toolFormats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolFormats.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/toolFormats.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Provider-specific tool format translation and tool resolution logic.\n * @packageDocumentation\n */\n\nimport { type JsonObject, type JsonValue } from '@fgv/ts-json-base';\n\nimport {\n type AiServerToolConfig,\n type AiToolConfig,\n type IAiClientToolConfig,\n type IAiProviderDescriptor,\n type IAiToolEnablement,\n type IAiWebSearchToolConfig\n} from './model';\n\n// ============================================================================\n// Tool resolution\n// ============================================================================\n\n/**\n * Resolves the effective tools for a completion call.\n *\n * - If per-call tools are provided, they override settings-level tools entirely.\n * - Otherwise, settings-level enabled tools are used.\n * - Only tools supported by the provider are included.\n * - Returns an empty array if no tools are enabled (= no tools sent).\n *\n * @param descriptor - The provider descriptor (used to filter by supported tools)\n * @param settingsTools - Tool enablement from provider settings (optional)\n * @param perCallTools - Per-call tool override (optional)\n * @returns The resolved list of tool configs to include in the request\n * @public\n */\nexport function resolveEffectiveTools(\n descriptor: IAiProviderDescriptor,\n settingsTools?: ReadonlyArray<IAiToolEnablement>,\n perCallTools?: ReadonlyArray<AiServerToolConfig>\n): ReadonlyArray<AiServerToolConfig> {\n const supported = new Set(descriptor.supportedTools);\n\n if (perCallTools !== undefined) {\n return perCallTools.filter((t) => supported.has(t.type));\n }\n\n if (settingsTools === undefined) {\n return [];\n }\n\n return settingsTools\n .filter((e) => e.enabled && supported.has(e.type))\n .map((e): AiServerToolConfig => e.config ?? { type: e.type });\n}\n\n// ============================================================================\n// OpenAI / xAI Responses API format\n// ============================================================================\n\n/**\n * Formats a web search tool config for the xAI/OpenAI Responses API.\n * @internal\n */\nfunction webSearchToResponsesApi(config: IAiWebSearchToolConfig): JsonObject {\n const tool: Record<string, unknown> = { type: 'web_search' };\n\n if (config.allowedDomains || config.blockedDomains) {\n const filters: Record<string, unknown> = {};\n if (config.allowedDomains) {\n filters.allowed_domains = [...config.allowedDomains];\n }\n if (config.blockedDomains) {\n filters.excluded_domains = [...config.blockedDomains];\n }\n tool.filters = filters;\n }\n\n if (config.enableImageUnderstanding) {\n tool.enable_image_understanding = true;\n }\n\n return tool as JsonObject;\n}\n\n/**\n * Formats a client tool config for the xAI/OpenAI Responses API.\n * @internal\n */\nfunction clientToolToResponsesApi(config: IAiClientToolConfig): JsonObject {\n return {\n type: 'function',\n name: config.name,\n description: config.description,\n parameters: config.parametersSchema.toJson()\n } as JsonObject;\n}\n\n/**\n * Formats tool configs for the xAI/OpenAI Responses API.\n * @param tools - The resolved tool configs (server-side and/or client-defined)\n * @returns Provider-native tool objects for the `tools` request field\n * @public\n */\nexport function toResponsesApiTools(tools: ReadonlyArray<AiToolConfig>): ReadonlyArray<JsonObject> {\n return tools.map((t) => {\n switch (t.type) {\n case 'web_search':\n return webSearchToResponsesApi(t);\n case 'client_tool':\n return clientToolToResponsesApi(t);\n /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = t;\n return { type: `unknown:${JSON.stringify(_exhaustive)}` } as JsonObject;\n }\n }\n });\n}\n\n// ============================================================================\n// Anthropic Messages API format\n// ============================================================================\n\n/**\n * Formats a web search tool config for the Anthropic Messages API.\n * @internal\n */\nfunction webSearchToAnthropic(config: IAiWebSearchToolConfig): JsonObject {\n const tool: Record<string, unknown> = {\n type: 'web_search_20250305',\n name: 'web_search'\n };\n\n if (config.maxUses !== undefined) {\n tool.max_uses = config.maxUses;\n }\n if (config.allowedDomains) {\n tool.allowed_domains = [...config.allowedDomains];\n }\n if (config.blockedDomains) {\n tool.blocked_domains = [...config.blockedDomains];\n }\n\n return tool as JsonObject;\n}\n\n/**\n * Formats a client tool config for the Anthropic Messages API.\n * Note: Anthropic client tools have no `type` field (unlike server tools).\n * @internal\n */\nfunction clientToolToAnthropic(config: IAiClientToolConfig): JsonObject {\n return {\n name: config.name,\n description: config.description,\n input_schema: config.parametersSchema.toJson()\n } as JsonObject;\n}\n\n/**\n * Formats tool configs for the Anthropic Messages API.\n * @param tools - The resolved tool configs (server-side and/or client-defined)\n * @returns Provider-native tool objects for the `tools` request field\n * @public\n */\nexport function toAnthropicTools(tools: ReadonlyArray<AiToolConfig>): ReadonlyArray<JsonObject> {\n return tools.map((t) => {\n switch (t.type) {\n case 'web_search':\n return webSearchToAnthropic(t);\n case 'client_tool':\n return clientToolToAnthropic(t);\n /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = t;\n return { type: `unknown:${JSON.stringify(_exhaustive)}` } as JsonObject;\n }\n }\n });\n}\n\n// ============================================================================\n// Gemini generateContent API format\n// ============================================================================\n\n/**\n * Sanitizes a draft-07 JSON Schema (as emitted by `JsonSchema.object(...).toJson()`)\n * into the OpenAPI 3.0 Schema Object subset that Gemini's `function_declarations[].parameters`\n * accepts.\n *\n * @remarks\n * Gemini's function-declaration schema is **not** full JSON Schema — it is a subset of\n * the OpenAPI 3.0 Schema Object and **rejects** (rather than ignores) draft-07-only\n * keywords. `JsonSchema` objects are strict-by-default, so `.toJson()` emits\n * `additionalProperties: false` on every object node, which 400s the whole request on\n * Gemini. This helper recursively strips the unsupported keywords so any\n * `JsonSchema`-authored client tool works on Gemini without consumer awareness of the\n * dialect difference. Stripping is infallible, so it returns a plain value rather than a\n * `Result`.\n *\n * `additionalProperties` and `$schema` are stripped only where they appear as schema\n * *keywords* (siblings of `type`/`properties`/etc.). Inside a `properties` map the keys\n * are user-defined parameter names, not keywords, so they are preserved verbatim while\n * each property's subschema value is still recursively sanitized — a tool parameter\n * legitimately named `additionalProperties` survives.\n *\n * @internal\n */\nexport function toGeminiParameterSchema(schema: JsonValue): JsonValue {\n if (Array.isArray(schema)) {\n return schema.map(toGeminiParameterSchema);\n }\n if (schema !== null && typeof schema === 'object') {\n const out: JsonObject = {};\n for (const [key, value] of Object.entries(schema)) {\n if (key === 'additionalProperties' || key === '$schema') {\n continue;\n }\n if (key === 'properties' && value !== null && typeof value === 'object' && !Array.isArray(value)) {\n // `properties` maps user-defined parameter names to subschemas: recurse each\n // subschema value but never treat a parameter name as a strippable keyword.\n const properties: JsonObject = {};\n for (const [name, propSchema] of Object.entries(value)) {\n properties[name] = toGeminiParameterSchema(propSchema);\n }\n out[key] = properties;\n } else {\n out[key] = toGeminiParameterSchema(value);\n }\n }\n return out;\n }\n return schema;\n}\n\n/**\n * Formats tool configs for the Gemini generateContent API.\n *\n * @remarks\n * Gemini uses `google_search` for search grounding (no per-tool config).\n * Client-defined tools are accumulated into a single `function_declarations` entry.\n * Each client tool's parameters schema is sanitized to Gemini's OpenAPI-subset\n * dialect via {@link toGeminiParameterSchema} (the raw draft-07 `.toJson()` output\n * carries `additionalProperties`, which Gemini rejects).\n *\n * @param tools - The resolved tool configs (server-side and/or client-defined)\n * @returns Provider-native tool objects for the `tools` request field\n * @public\n */\nexport function toGeminiTools(tools: ReadonlyArray<AiToolConfig>): ReadonlyArray<JsonObject> {\n const result: JsonObject[] = [];\n const functionDeclarations: JsonObject[] = [];\n\n for (const t of tools) {\n switch (t.type) {\n case 'web_search':\n result.push({ google_search: {} } as JsonObject);\n break;\n case 'client_tool':\n functionDeclarations.push({\n name: t.name,\n description: t.description,\n parameters: toGeminiParameterSchema(t.parametersSchema.toJson())\n } as JsonObject);\n break;\n /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = t;\n result.push({ type: `unknown:${JSON.stringify(_exhaustive)}` } as JsonObject);\n }\n }\n }\n\n if (functionDeclarations.length > 0) {\n result.push({ function_declarations: functionDeclarations } as JsonObject);\n }\n\n return result;\n}\n"]}
@@ -60,15 +60,49 @@ export const isoDate = new Conversion.BaseConverter((from) => {
60
60
  else if (from instanceof Date) {
61
61
  return succeed(from);
62
62
  }
63
+ else if (from instanceof DateTime) {
64
+ if (from.isValid) {
65
+ return succeed(from.toJSDate());
66
+ }
67
+ return fail(`Invalid date: ${from.invalidExplanation}`);
68
+ }
63
69
  return fail(`Cannot convert ${JSON.stringify(from)} to Date`);
64
70
  });
71
+ /**
72
+ * A `Converter` which converts an iso formatted string, a number or a `Date` object to
73
+ * a `DateTime` object.
74
+ * @public
75
+ */
76
+ export const isoDateTime = new Conversion.BaseConverter((from) => {
77
+ if (typeof from === 'string') {
78
+ const dt = DateTime.fromISO(from);
79
+ if (dt.isValid) {
80
+ return succeed(dt);
81
+ }
82
+ return fail(`Invalid date: ${dt.invalidExplanation}`);
83
+ }
84
+ else if (typeof from === 'number') {
85
+ return succeed(DateTime.fromMillis(from));
86
+ /* c8 ignore next 3 - Date instance path not exercised in current test suite */
87
+ }
88
+ else if (from instanceof Date) {
89
+ return succeed(DateTime.fromJSDate(from));
90
+ }
91
+ else if (from instanceof DateTime) {
92
+ if (from.isValid) {
93
+ return succeed(from);
94
+ }
95
+ return fail(`Invalid date: ${from.invalidExplanation}`);
96
+ }
97
+ return fail(`Cannot convert ${JSON.stringify(from)} to DateTime`);
98
+ });
65
99
  /**
66
100
  * A helper function to create a `Converter` which converts `unknown` to {@link Experimental.ExtendedArray | ExtendedArray<T>}.
67
101
  * @remarks
68
102
  * If `onError` is `'failOnError'` (default), then the entire conversion fails if any element cannot
69
103
  * be converted. If `onError` is `'ignoreErrors'`, then failing elements are silently ignored.
70
104
  * @param converter - `Converter` used to convert each item in the array
71
- * @param ignoreErrors - Specifies treatment of unconvertible elements
105
+ * @param onError - Specifies treatment of unconvertible elements
72
106
  * @beta
73
107
  */
74
108
  export function extendedArrayOf(label, converter, onError = 'failOnError') {
@@ -0,0 +1 @@
1
+ {"version":3,"file":"converters.js","sourceRoot":"","sources":["../../../src/packlets/conversion/converters.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2020 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport { Conversion, Converter, Converters, Result, captureResult, fail, succeed } from '@fgv/ts-utils';\nimport { DateTime } from 'luxon';\nimport Mustache from 'mustache';\nimport { ExtendedArray, RangeOf, RangeOfProperties } from '../experimental';\n\n/**\n * Helper function to create a `StringConverter` which converts\n * `unknown` to `string`, applying template conversions supplied at construction time or at\n * runtime as context.\n * @remarks\n * Template conversions are applied using `mustache` syntax.\n * @param defaultContext - Optional default context to use for template values.\n * @returns A new `Converter` returning `string`.\n * @public\n */\nexport function templateString(defaultContext?: unknown): Conversion.StringConverter<string, unknown> {\n return new Conversion.StringConverter<string, unknown>(\n defaultContext,\n undefined,\n (from: unknown, __self: Converter<string, unknown>, context?: unknown) => {\n if (typeof from !== 'string') {\n return fail(`Not a string: ${JSON.stringify(from)}`);\n }\n return captureResult(() => Mustache.render(from, context));\n }\n );\n}\n\n/**\n * A `Converter` which converts an iso formatted string, a number or a `Date` object to\n * a `Date` object.\n * @public\n */\nexport const isoDate: Converter<Date, unknown> = new Conversion.BaseConverter<Date>((from: unknown) => {\n if (typeof from === 'string') {\n const dt = DateTime.fromISO(from);\n if (dt.isValid) {\n return succeed(dt.toJSDate());\n }\n return fail(`Invalid date: ${dt.invalidExplanation}`);\n } else if (typeof from === 'number') {\n return succeed(new Date(from));\n } else if (from instanceof Date) {\n return succeed(from);\n } else if (from instanceof DateTime) {\n if (from.isValid) {\n return succeed(from.toJSDate());\n }\n return fail(`Invalid date: ${from.invalidExplanation}`);\n }\n return fail(`Cannot convert ${JSON.stringify(from)} to Date`);\n});\n\n/**\n * A `Converter` which converts an iso formatted string, a number or a `Date` object to\n * a `DateTime` object.\n * @public\n */\nexport const isoDateTime: Converter<DateTime, unknown> = new Conversion.BaseConverter<DateTime>(\n (from: unknown) => {\n if (typeof from === 'string') {\n const dt = DateTime.fromISO(from);\n if (dt.isValid) {\n return succeed(dt);\n }\n return fail(`Invalid date: ${dt.invalidExplanation}`);\n } else if (typeof from === 'number') {\n return succeed(DateTime.fromMillis(from));\n /* c8 ignore next 3 - Date instance path not exercised in current test suite */\n } else if (from instanceof Date) {\n return succeed(DateTime.fromJSDate(from));\n } else if (from instanceof DateTime) {\n if (from.isValid) {\n return succeed(from);\n }\n return fail(`Invalid date: ${from.invalidExplanation}`);\n }\n return fail(`Cannot convert ${JSON.stringify(from)} to DateTime`);\n }\n);\n\n/**\n * A helper function to create a `Converter` which converts `unknown` to {@link Experimental.ExtendedArray | ExtendedArray<T>}.\n * @remarks\n * If `onError` is `'failOnError'` (default), then the entire conversion fails if any element cannot\n * be converted. If `onError` is `'ignoreErrors'`, then failing elements are silently ignored.\n * @param converter - `Converter` used to convert each item in the array\n * @param onError - Specifies treatment of unconvertible elements\n * @beta\n */\nexport function extendedArrayOf<T, TC = undefined>(\n label: string,\n converter: Converter<T, TC>,\n onError: Conversion.OnError = 'failOnError'\n): Converter<ExtendedArray<T>, TC> {\n return Converters.arrayOf(converter, onError).map((items: T[]) => {\n return captureResult(() => new ExtendedArray(label, ...items));\n });\n}\n\n/**\n * A helper wrapper to construct a `Converter` which converts to an arbitrary strongly-typed\n * range of some comparable type.\n * @param converter - `Converter` used to convert `min` and `max` extent of the range.\n * @param constructor - Static constructor to instantiate the object.\n * @public\n */\nexport function rangeTypeOf<T, RT extends RangeOf<T>, TC = unknown>(\n converter: Converter<T, TC>,\n constructor: (init: RangeOfProperties<T>) => Result<RT>\n): Converter<RT, TC> {\n return new Conversion.BaseConverter((from: unknown, __self, context?: TC) => {\n const result = Converters.object(\n {\n min: converter,\n max: converter\n },\n { optionalFields: ['min', 'max'] }\n ).convert(from, context);\n if (result.isSuccess()) {\n return constructor({ min: result.value.min, max: result.value.max });\n }\n return fail(result.message);\n });\n}\n\n/**\n * A helper wrapper to construct a `Converter` which converts to {@link Experimental.RangeOf | RangeOf<T>}\n * where `<T>` is some comparable type.\n * @param converter - `Converter` used to convert `min` and `max` extent of the range.\n * @public\n */\nexport function rangeOf<T, TC = unknown>(converter: Converter<T, TC>): Converter<RangeOf<T>, TC> {\n return rangeTypeOf<T, RangeOf<T>, TC>(converter, RangeOf.createRange);\n}\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/conversion/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAE,CAAC","sourcesContent":["/*\n * Copyright (c) 2023 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport * as Converters from './converters';\n\nexport { Converters };\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/packlets/crypto-utils/constants.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAChF,+EAA+E;AAC/E,4EAA4E;AAC5E,wEAAwE;AACxE,2DAA2D;AAC3D,EAAE;AACF,iFAAiF;AACjF,kDAAkD;AAClD,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,8EAA8E;AAC9E,yEAAyE;AACzE,gFAAgF;AAChF,gFAAgF;AAChF,YAAY;AAEZ,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,yBAAkC,CAAC;AAExE;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,aAAsB,CAAC;AAExD;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAW,EAAE,CAAC;AAE3C;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAW,EAAE,CAAC;AAEtC;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAW,EAAE,CAAC","sourcesContent":["// Copyright (c) 2024 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * Current format version for encrypted files.\n * @public\n */\nexport const ENCRYPTED_FILE_FORMAT = 'encrypted-collection-v1' as const;\n\n/**\n * Default encryption algorithm.\n * @public\n */\nexport const DEFAULT_ALGORITHM = 'AES-256-GCM' as const;\n\n/**\n * Key size in bytes for AES-256.\n * @public\n */\nexport const AES_256_KEY_SIZE: number = 32;\n\n/**\n * IV size in bytes for GCM mode.\n * @public\n */\nexport const GCM_IV_SIZE: number = 12;\n\n/**\n * Auth tag size in bytes for GCM mode.\n * @public\n */\nexport const GCM_AUTH_TAG_SIZE: number = 16;\n"]}