@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.
- package/dist/index.browser.js +4 -2
- package/dist/index.browser.js.map +1 -0
- package/dist/index.js.map +1 -0
- package/dist/packlets/ai-assist/apiClient.js +886 -158
- package/dist/packlets/ai-assist/apiClient.js.map +1 -0
- package/dist/packlets/ai-assist/chatRequestBuilders.js +282 -0
- package/dist/packlets/ai-assist/chatRequestBuilders.js.map +1 -0
- package/dist/packlets/ai-assist/converters.js +47 -3
- package/dist/packlets/ai-assist/converters.js.map +1 -0
- package/dist/packlets/ai-assist/embeddingClient.js +345 -0
- package/dist/packlets/ai-assist/embeddingClient.js.map +1 -0
- package/dist/packlets/ai-assist/endpoint.js +78 -0
- package/dist/packlets/ai-assist/endpoint.js.map +1 -0
- package/dist/packlets/ai-assist/http.js +75 -0
- package/dist/packlets/ai-assist/http.js.map +1 -0
- package/dist/packlets/ai-assist/imageOptionsResolver.js +193 -0
- package/dist/packlets/ai-assist/imageOptionsResolver.js.map +1 -0
- package/dist/packlets/ai-assist/index.js +10 -4
- package/dist/packlets/ai-assist/index.js.map +1 -0
- package/dist/packlets/ai-assist/jsonCompletion.js +93 -0
- package/dist/packlets/ai-assist/jsonCompletion.js.map +1 -0
- package/dist/packlets/ai-assist/jsonResponse.js +149 -0
- package/dist/packlets/ai-assist/jsonResponse.js.map +1 -0
- package/dist/packlets/ai-assist/model.js +193 -9
- package/dist/packlets/ai-assist/model.js.map +1 -0
- package/dist/packlets/ai-assist/registry.js +314 -12
- package/dist/packlets/ai-assist/registry.js.map +1 -0
- package/dist/packlets/ai-assist/sseParser.js +123 -0
- package/dist/packlets/ai-assist/sseParser.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js +368 -0
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +687 -0
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/common.js +187 -0
- package/dist/packlets/ai-assist/streamingAdapters/common.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/gemini.js +204 -0
- package/dist/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js +170 -0
- package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js +386 -0
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/proxy.js +173 -0
- package/dist/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -0
- package/dist/packlets/ai-assist/streamingClient.js +140 -0
- package/dist/packlets/ai-assist/streamingClient.js.map +1 -0
- package/dist/packlets/ai-assist/thinkingOptionsResolver.js +288 -0
- package/dist/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -0
- package/dist/packlets/ai-assist/toolFormats.js +106 -10
- package/dist/packlets/ai-assist/toolFormats.js.map +1 -0
- package/dist/packlets/conversion/converters.js +35 -1
- package/dist/packlets/conversion/converters.js.map +1 -0
- package/dist/packlets/conversion/index.js.map +1 -0
- package/dist/packlets/crypto-utils/constants.js.map +1 -0
- package/dist/packlets/crypto-utils/converters.js +42 -4
- package/dist/packlets/crypto-utils/converters.js.map +1 -0
- package/dist/packlets/crypto-utils/directEncryptionProvider.js.map +1 -0
- package/dist/packlets/crypto-utils/encryptedFile.js.map +1 -0
- package/dist/packlets/crypto-utils/hpkeProvider.js +333 -0
- package/dist/packlets/crypto-utils/hpkeProvider.js.map +1 -0
- package/dist/packlets/crypto-utils/index.browser.js +10 -2
- package/dist/packlets/crypto-utils/index.browser.js.map +1 -0
- package/dist/packlets/crypto-utils/index.js +6 -0
- package/dist/packlets/crypto-utils/index.js.map +1 -0
- package/dist/packlets/crypto-utils/keyPairAlgorithmParams.js +71 -0
- package/dist/packlets/crypto-utils/keyPairAlgorithmParams.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/converters.js +103 -11
- package/dist/packlets/crypto-utils/keystore/converters.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js +287 -0
- package/dist/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/index.browser.js +36 -0
- package/dist/packlets/crypto-utils/keystore/index.browser.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/index.js +3 -0
- package/dist/packlets/crypto-utils/keystore/index.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/keyStore.js +633 -118
- package/dist/packlets/crypto-utils/keystore/keyStore.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/model.js +22 -1
- package/dist/packlets/crypto-utils/keystore/model.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/privateKeyStorage.js +21 -0
- package/dist/packlets/crypto-utils/keystore/privateKeyStorage.js.map +1 -0
- package/dist/packlets/crypto-utils/model.js +32 -0
- package/dist/packlets/crypto-utils/model.js.map +1 -0
- package/dist/packlets/crypto-utils/nodeCryptoProvider.js +270 -1
- package/dist/packlets/crypto-utils/nodeCryptoProvider.js.map +1 -0
- package/dist/packlets/crypto-utils/spkiHelpers.js +209 -0
- package/dist/packlets/crypto-utils/spkiHelpers.js.map +1 -0
- package/dist/packlets/csv/csvFileHelpers.js +0 -14
- package/dist/packlets/csv/csvFileHelpers.js.map +1 -0
- package/dist/packlets/csv/csvHelpers.js +14 -0
- package/dist/packlets/csv/csvHelpers.js.map +1 -0
- package/dist/packlets/csv/index.browser.js +1 -3
- package/dist/packlets/csv/index.browser.js.map +1 -0
- package/dist/packlets/csv/index.js.map +1 -0
- package/dist/packlets/experimental/extendedArray.js.map +1 -0
- package/dist/packlets/experimental/formatter.js.map +1 -0
- package/dist/packlets/experimental/index.js.map +1 -0
- package/dist/packlets/experimental/rangeOf.js.map +1 -0
- package/dist/packlets/hash/index.browser.js.map +1 -0
- package/dist/packlets/hash/index.js.map +1 -0
- package/dist/packlets/hash/index.node.js.map +1 -0
- package/dist/packlets/hash/md5Normalizer.browser.js.map +1 -0
- package/dist/packlets/hash/md5Normalizer.js.map +1 -0
- package/dist/packlets/mustache/index.js.map +1 -0
- package/dist/packlets/mustache/interfaces.js.map +1 -0
- package/dist/packlets/mustache/mustacheTemplate.js +42 -4
- package/dist/packlets/mustache/mustacheTemplate.js.map +1 -0
- package/dist/packlets/record-jar/index.browser.js +1 -3
- package/dist/packlets/record-jar/index.browser.js.map +1 -0
- package/dist/packlets/record-jar/index.js.map +1 -0
- package/dist/packlets/record-jar/recordJarFileHelpers.js +0 -18
- package/dist/packlets/record-jar/recordJarFileHelpers.js.map +1 -0
- package/dist/packlets/record-jar/recordJarHelpers.js +18 -0
- package/dist/packlets/record-jar/recordJarHelpers.js.map +1 -0
- package/dist/packlets/yaml/converters.js.map +1 -0
- package/dist/packlets/yaml/index.js +1 -0
- package/dist/packlets/yaml/index.js.map +1 -0
- package/dist/packlets/yaml/serializers.js +48 -0
- package/dist/packlets/yaml/serializers.js.map +1 -0
- package/dist/packlets/zip-file-tree/index.js.map +1 -0
- package/dist/packlets/zip-file-tree/zipFileTreeAccessors.js +2 -2
- package/dist/packlets/zip-file-tree/zipFileTreeAccessors.js.map +1 -0
- package/dist/packlets/zip-file-tree/zipFileTreeWriter.js.map +1 -0
- package/dist/ts-extras.d.ts +3880 -105
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/index.browser.d.ts +4 -2
- package/lib/index.browser.d.ts.map +1 -0
- package/lib/index.browser.js +8 -3
- package/lib/index.browser.js.map +1 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js.map +1 -0
- package/lib/packlets/ai-assist/apiClient.d.ts +115 -32
- package/lib/packlets/ai-assist/apiClient.d.ts.map +1 -0
- package/lib/packlets/ai-assist/apiClient.js +888 -156
- package/lib/packlets/ai-assist/apiClient.js.map +1 -0
- package/lib/packlets/ai-assist/chatRequestBuilders.d.ts +149 -0
- package/lib/packlets/ai-assist/chatRequestBuilders.d.ts.map +1 -0
- package/lib/packlets/ai-assist/chatRequestBuilders.js +293 -0
- package/lib/packlets/ai-assist/chatRequestBuilders.js.map +1 -0
- package/lib/packlets/ai-assist/converters.d.ts +15 -1
- package/lib/packlets/ai-assist/converters.d.ts.map +1 -0
- package/lib/packlets/ai-assist/converters.js +47 -3
- package/lib/packlets/ai-assist/converters.js.map +1 -0
- package/lib/packlets/ai-assist/embeddingClient.d.ts +69 -0
- package/lib/packlets/ai-assist/embeddingClient.d.ts.map +1 -0
- package/lib/packlets/ai-assist/embeddingClient.js +349 -0
- package/lib/packlets/ai-assist/embeddingClient.js.map +1 -0
- package/lib/packlets/ai-assist/endpoint.d.ts +28 -0
- package/lib/packlets/ai-assist/endpoint.d.ts.map +1 -0
- package/lib/packlets/ai-assist/endpoint.js +82 -0
- package/lib/packlets/ai-assist/endpoint.js.map +1 -0
- package/lib/packlets/ai-assist/http.d.ts +24 -0
- package/lib/packlets/ai-assist/http.d.ts.map +1 -0
- package/lib/packlets/ai-assist/http.js +78 -0
- package/lib/packlets/ai-assist/http.js.map +1 -0
- package/lib/packlets/ai-assist/imageOptionsResolver.d.ts +66 -0
- package/lib/packlets/ai-assist/imageOptionsResolver.d.ts.map +1 -0
- package/lib/packlets/ai-assist/imageOptionsResolver.js +197 -0
- package/lib/packlets/ai-assist/imageOptionsResolver.js.map +1 -0
- package/lib/packlets/ai-assist/index.d.ts +10 -4
- package/lib/packlets/ai-assist/index.d.ts.map +1 -0
- package/lib/packlets/ai-assist/index.js +36 -1
- package/lib/packlets/ai-assist/index.js.map +1 -0
- package/lib/packlets/ai-assist/jsonCompletion.d.ts +93 -0
- package/lib/packlets/ai-assist/jsonCompletion.d.ts.map +1 -0
- package/lib/packlets/ai-assist/jsonCompletion.js +97 -0
- package/lib/packlets/ai-assist/jsonCompletion.js.map +1 -0
- package/lib/packlets/ai-assist/jsonResponse.d.ts +91 -0
- package/lib/packlets/ai-assist/jsonResponse.d.ts.map +1 -0
- package/lib/packlets/ai-assist/jsonResponse.js +154 -0
- package/lib/packlets/ai-assist/jsonResponse.js.map +1 -0
- package/lib/packlets/ai-assist/model.d.ts +1202 -12
- package/lib/packlets/ai-assist/model.d.ts.map +1 -0
- package/lib/packlets/ai-assist/model.js +198 -10
- package/lib/packlets/ai-assist/model.js.map +1 -0
- package/lib/packlets/ai-assist/registry.d.ts +56 -1
- package/lib/packlets/ai-assist/registry.d.ts.map +1 -0
- package/lib/packlets/ai-assist/registry.js +319 -13
- package/lib/packlets/ai-assist/registry.js.map +1 -0
- package/lib/packlets/ai-assist/sseParser.d.ts +45 -0
- package/lib/packlets/ai-assist/sseParser.d.ts.map +1 -0
- package/lib/packlets/ai-assist/sseParser.js +128 -0
- package/lib/packlets/ai-assist/sseParser.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts +72 -0
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js +371 -0
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts +260 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +694 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts +154 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.js +193 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts +43 -0
- package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/gemini.js +207 -0
- package/lib/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts +19 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js +173 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts +33 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js +389 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts +34 -0
- package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/proxy.js +176 -0
- package/lib/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -0
- package/lib/packlets/ai-assist/streamingClient.d.ts +50 -0
- package/lib/packlets/ai-assist/streamingClient.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingClient.js +146 -0
- package/lib/packlets/ai-assist/streamingClient.js.map +1 -0
- package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts +87 -0
- package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts.map +1 -0
- package/lib/packlets/ai-assist/thinkingOptionsResolver.js +294 -0
- package/lib/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -0
- package/lib/packlets/ai-assist/toolFormats.d.ts +40 -9
- package/lib/packlets/ai-assist/toolFormats.d.ts.map +1 -0
- package/lib/packlets/ai-assist/toolFormats.js +107 -10
- package/lib/packlets/ai-assist/toolFormats.js.map +1 -0
- package/lib/packlets/conversion/converters.d.ts +8 -1
- package/lib/packlets/conversion/converters.d.ts.map +1 -0
- package/lib/packlets/conversion/converters.js +36 -2
- package/lib/packlets/conversion/converters.js.map +1 -0
- package/lib/packlets/conversion/index.d.ts.map +1 -0
- package/lib/packlets/conversion/index.js.map +1 -0
- package/lib/packlets/crypto-utils/constants.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/constants.js.map +1 -0
- package/lib/packlets/crypto-utils/converters.d.ts +20 -1
- package/lib/packlets/crypto-utils/converters.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/converters.js +43 -5
- package/lib/packlets/crypto-utils/converters.js.map +1 -0
- package/lib/packlets/crypto-utils/directEncryptionProvider.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/directEncryptionProvider.js.map +1 -0
- package/lib/packlets/crypto-utils/encryptedFile.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/encryptedFile.js.map +1 -0
- package/lib/packlets/crypto-utils/hpkeProvider.d.ts +142 -0
- package/lib/packlets/crypto-utils/hpkeProvider.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/hpkeProvider.js +337 -0
- package/lib/packlets/crypto-utils/hpkeProvider.js.map +1 -0
- package/lib/packlets/crypto-utils/index.browser.d.ts +4 -1
- package/lib/packlets/crypto-utils/index.browser.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/index.browser.js +21 -3
- package/lib/packlets/crypto-utils/index.browser.js.map +1 -0
- package/lib/packlets/crypto-utils/index.d.ts +3 -0
- package/lib/packlets/crypto-utils/index.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/index.js +17 -1
- package/lib/packlets/crypto-utils/index.js.map +1 -0
- package/lib/packlets/crypto-utils/keyPairAlgorithmParams.d.ts +54 -0
- package/lib/packlets/crypto-utils/keyPairAlgorithmParams.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keyPairAlgorithmParams.js +74 -0
- package/lib/packlets/crypto-utils/keyPairAlgorithmParams.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/converters.d.ts +68 -6
- package/lib/packlets/crypto-utils/keystore/converters.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/converters.js +101 -9
- package/lib/packlets/crypto-utils/keystore/converters.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.d.ts +148 -0
- package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js +324 -0
- package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/index.browser.d.ts +10 -0
- package/lib/packlets/crypto-utils/keystore/index.browser.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/index.browser.js +76 -0
- package/lib/packlets/crypto-utils/keystore/index.browser.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/index.d.ts +2 -0
- package/lib/packlets/crypto-utils/keystore/index.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/index.js +5 -1
- package/lib/packlets/crypto-utils/keystore/index.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/keyStore.d.ts +205 -13
- package/lib/packlets/crypto-utils/keystore/keyStore.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/keyStore.js +639 -124
- package/lib/packlets/crypto-utils/keystore/keyStore.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/model.d.ts +275 -19
- package/lib/packlets/crypto-utils/keystore/model.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/model.js +24 -2
- package/lib/packlets/crypto-utils/keystore/model.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/privateKeyStorage.d.ts +53 -0
- package/lib/packlets/crypto-utils/keystore/privateKeyStorage.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/privateKeyStorage.js +22 -0
- package/lib/packlets/crypto-utils/keystore/privateKeyStorage.js.map +1 -0
- package/lib/packlets/crypto-utils/model.d.ts +348 -10
- package/lib/packlets/crypto-utils/model.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/model.js +33 -1
- package/lib/packlets/crypto-utils/model.js.map +1 -0
- package/lib/packlets/crypto-utils/nodeCryptoProvider.d.ts +110 -2
- package/lib/packlets/crypto-utils/nodeCryptoProvider.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/nodeCryptoProvider.js +269 -0
- package/lib/packlets/crypto-utils/nodeCryptoProvider.js.map +1 -0
- package/lib/packlets/crypto-utils/spkiHelpers.d.ts +110 -0
- package/lib/packlets/crypto-utils/spkiHelpers.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/spkiHelpers.js +219 -0
- package/lib/packlets/crypto-utils/spkiHelpers.js.map +1 -0
- package/lib/packlets/csv/csvFileHelpers.d.ts +0 -10
- package/lib/packlets/csv/csvFileHelpers.d.ts.map +1 -0
- package/lib/packlets/csv/csvFileHelpers.js +0 -15
- package/lib/packlets/csv/csvFileHelpers.js.map +1 -0
- package/lib/packlets/csv/csvHelpers.d.ts +10 -0
- package/lib/packlets/csv/csvHelpers.d.ts.map +1 -0
- package/lib/packlets/csv/csvHelpers.js +15 -0
- package/lib/packlets/csv/csvHelpers.js.map +1 -0
- package/lib/packlets/csv/index.browser.d.ts +0 -1
- package/lib/packlets/csv/index.browser.d.ts.map +1 -0
- package/lib/packlets/csv/index.browser.js +1 -5
- package/lib/packlets/csv/index.browser.js.map +1 -0
- package/lib/packlets/csv/index.d.ts.map +1 -0
- package/lib/packlets/csv/index.js.map +1 -0
- package/lib/packlets/experimental/extendedArray.d.ts.map +1 -0
- package/lib/packlets/experimental/extendedArray.js.map +1 -0
- package/lib/packlets/experimental/formatter.d.ts.map +1 -0
- package/lib/packlets/experimental/formatter.js.map +1 -0
- package/lib/packlets/experimental/index.d.ts.map +1 -0
- package/lib/packlets/experimental/index.js.map +1 -0
- package/lib/packlets/experimental/rangeOf.d.ts.map +1 -0
- package/lib/packlets/experimental/rangeOf.js.map +1 -0
- package/lib/packlets/hash/index.browser.d.ts.map +1 -0
- package/lib/packlets/hash/index.browser.js.map +1 -0
- package/lib/packlets/hash/index.d.ts.map +1 -0
- package/lib/packlets/hash/index.js.map +1 -0
- package/lib/packlets/hash/index.node.d.ts.map +1 -0
- package/lib/packlets/hash/index.node.js.map +1 -0
- package/lib/packlets/hash/md5Normalizer.browser.d.ts.map +1 -0
- package/lib/packlets/hash/md5Normalizer.browser.js.map +1 -0
- package/lib/packlets/hash/md5Normalizer.d.ts.map +1 -0
- package/lib/packlets/hash/md5Normalizer.js.map +1 -0
- package/lib/packlets/mustache/index.d.ts +1 -1
- package/lib/packlets/mustache/index.d.ts.map +1 -0
- package/lib/packlets/mustache/index.js.map +1 -0
- package/lib/packlets/mustache/interfaces.d.ts +34 -0
- package/lib/packlets/mustache/interfaces.d.ts.map +1 -0
- package/lib/packlets/mustache/interfaces.js.map +1 -0
- package/lib/packlets/mustache/mustacheTemplate.d.ts +2 -0
- package/lib/packlets/mustache/mustacheTemplate.d.ts.map +1 -0
- package/lib/packlets/mustache/mustacheTemplate.js +42 -4
- package/lib/packlets/mustache/mustacheTemplate.js.map +1 -0
- package/lib/packlets/record-jar/index.browser.d.ts +0 -1
- package/lib/packlets/record-jar/index.browser.d.ts.map +1 -0
- package/lib/packlets/record-jar/index.browser.js +1 -5
- package/lib/packlets/record-jar/index.browser.js.map +1 -0
- package/lib/packlets/record-jar/index.d.ts.map +1 -0
- package/lib/packlets/record-jar/index.js.map +1 -0
- package/lib/packlets/record-jar/recordJarFileHelpers.d.ts +0 -11
- package/lib/packlets/record-jar/recordJarFileHelpers.d.ts.map +1 -0
- package/lib/packlets/record-jar/recordJarFileHelpers.js +0 -19
- package/lib/packlets/record-jar/recordJarFileHelpers.js.map +1 -0
- package/lib/packlets/record-jar/recordJarHelpers.d.ts +11 -0
- package/lib/packlets/record-jar/recordJarHelpers.d.ts.map +1 -0
- package/lib/packlets/record-jar/recordJarHelpers.js +19 -0
- package/lib/packlets/record-jar/recordJarHelpers.js.map +1 -0
- package/lib/packlets/yaml/converters.d.ts.map +1 -0
- package/lib/packlets/yaml/converters.js.map +1 -0
- package/lib/packlets/yaml/index.d.ts +1 -0
- package/lib/packlets/yaml/index.d.ts.map +1 -0
- package/lib/packlets/yaml/index.js +1 -0
- package/lib/packlets/yaml/index.js.map +1 -0
- package/lib/packlets/yaml/serializers.d.ts +45 -0
- package/lib/packlets/yaml/serializers.d.ts.map +1 -0
- package/lib/packlets/yaml/serializers.js +84 -0
- package/lib/packlets/yaml/serializers.js.map +1 -0
- package/lib/packlets/zip-file-tree/index.d.ts.map +1 -0
- package/lib/packlets/zip-file-tree/index.js.map +1 -0
- package/lib/packlets/zip-file-tree/zipFileTreeAccessors.d.ts +2 -2
- package/lib/packlets/zip-file-tree/zipFileTreeAccessors.d.ts.map +1 -0
- package/lib/packlets/zip-file-tree/zipFileTreeAccessors.js +2 -2
- package/lib/packlets/zip-file-tree/zipFileTreeAccessors.js.map +1 -0
- package/lib/packlets/zip-file-tree/zipFileTreeWriter.d.ts.map +1 -0
- package/lib/packlets/zip-file-tree/zipFileTreeWriter.js.map +1 -0
- package/package.json +20 -15
|
@@ -0,0 +1,687 @@
|
|
|
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
|
+
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
21
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
22
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
23
|
+
var m = o[Symbol.asyncIterator], i;
|
|
24
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
25
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
26
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
27
|
+
};
|
|
28
|
+
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
29
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
30
|
+
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
31
|
+
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
32
|
+
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
|
|
33
|
+
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
|
|
34
|
+
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
35
|
+
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
36
|
+
function fulfill(value) { resume("next", value); }
|
|
37
|
+
function reject(value) { resume("throw", value); }
|
|
38
|
+
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Per-provider continuation message builders and the `executeClientToolTurn`
|
|
42
|
+
* helper for orchestrating a single client-tool round-trip.
|
|
43
|
+
*
|
|
44
|
+
* Each provider requires a different wire format for the follow-up request:
|
|
45
|
+
* - **Anthropic**: assistant turn reconstructed from the ordered accumulation
|
|
46
|
+
* buffer (thinking / redacted_thinking / text / tool_use in original stream
|
|
47
|
+
* order) + user turn with `tool_result` blocks. When thinking is active, the
|
|
48
|
+
* follow-up request must NOT set `tool_choice: { type: 'any' }` or
|
|
49
|
+
* `tool_choice: { type: 'tool', ... }` (E3 / §5.4 of b4-spike-findings).
|
|
50
|
+
* - **OpenAI / xAI Responses API**: `function_call` input items +
|
|
51
|
+
* `function_call_output` input items.
|
|
52
|
+
* - **Gemini**: model turn with `functionCall` parts + user turn with
|
|
53
|
+
* `functionResponse` parts (correlation by tool name).
|
|
54
|
+
*
|
|
55
|
+
* @packageDocumentation
|
|
56
|
+
*/
|
|
57
|
+
import { captureAsyncResult, fail, succeed } from '@fgv/ts-utils';
|
|
58
|
+
import { resolveProviderModel } from '../model';
|
|
59
|
+
import { splitChatRequest } from '../chatRequestBuilders';
|
|
60
|
+
import { resolveEffectiveBaseUrl } from '../endpoint';
|
|
61
|
+
import { callAnthropicStream } from './anthropic';
|
|
62
|
+
import { callOpenAiResponsesStream } from './openaiResponses';
|
|
63
|
+
import { callGeminiStream } from './gemini';
|
|
64
|
+
// ============================================================================
|
|
65
|
+
// Anthropic continuation builder
|
|
66
|
+
// ============================================================================
|
|
67
|
+
/**
|
|
68
|
+
* Returns `true` when `id` is a usable correlation id — present and non-empty.
|
|
69
|
+
*
|
|
70
|
+
* `??` is NOT sufficient for this check: an empty string is a *bad* id (a
|
|
71
|
+
* `tool_use_id: ''` is rejected by Anthropic as a "malformed identifier") but
|
|
72
|
+
* `'' ?? fallback` yields `''`, silently passing the empty id through. Every id
|
|
73
|
+
* correlation in this module must use this predicate, never `??`.
|
|
74
|
+
*
|
|
75
|
+
* @internal
|
|
76
|
+
*/
|
|
77
|
+
function isUsableId(id) {
|
|
78
|
+
return id !== undefined && id.length > 0;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Builds the Anthropic follow-up messages for a client-tool round-trip.
|
|
82
|
+
*
|
|
83
|
+
* Reconstructs the assistant turn from the ordered accumulation buffer
|
|
84
|
+
* (all block types in original stream order) and appends a user turn
|
|
85
|
+
* with `tool_result` blocks for each executed tool call.
|
|
86
|
+
*
|
|
87
|
+
* **Single source of truth for the id (id-correlation fix).** Each
|
|
88
|
+
* `tool_result.tool_use_id` is drawn from — and validated against — the set of
|
|
89
|
+
* assistant `tool_use.id`s actually present in the accumulation buffer. The id
|
|
90
|
+
* is NEVER derived from the tool name: a tool name can never match a `toolu_*`
|
|
91
|
+
* id, so a name fallback produces exactly the "malformed identifier" the
|
|
92
|
+
* provider rejects. If any tool result cannot be correlated to a buffered
|
|
93
|
+
* `tool_use` block with a non-empty id, the build fails loud (naming the tool)
|
|
94
|
+
* rather than emitting a malformed continuation.
|
|
95
|
+
*
|
|
96
|
+
* **Constraint (E3):** The returned continuation does NOT include a forced
|
|
97
|
+
* `tool_choice` field. When thinking is active, Anthropic rejects
|
|
98
|
+
* `tool_choice: { type: 'any' }` and `tool_choice: { type: 'tool', ... }`
|
|
99
|
+
* with an HTTP 400 error. Only `tool_choice: { type: 'auto' }` (the default,
|
|
100
|
+
* i.e. omitted) is compatible with extended thinking.
|
|
101
|
+
*
|
|
102
|
+
* @internal
|
|
103
|
+
*/
|
|
104
|
+
export function buildAnthropicContinuation(accBuffer, toolResults, logger) {
|
|
105
|
+
// Reconstruct the assistant turn from the ordered accumulation buffer.
|
|
106
|
+
// Sort by buffer key (SSE index) to restore original stream order.
|
|
107
|
+
const sortedKeys = Array.from(accBuffer.keys()).sort((a, b) => a - b);
|
|
108
|
+
const assistantContent = [];
|
|
109
|
+
// The set of assistant tool_use ids — the single source of truth every
|
|
110
|
+
// tool_result.tool_use_id must be drawn from.
|
|
111
|
+
const bufferedToolUseIds = new Set();
|
|
112
|
+
for (const key of sortedKeys) {
|
|
113
|
+
const block = accBuffer.get(key);
|
|
114
|
+
/* c8 ignore next 1 - defensive: key always exists in map since we iterate its keys */
|
|
115
|
+
if (!block)
|
|
116
|
+
continue;
|
|
117
|
+
if (block.type === 'thinking') {
|
|
118
|
+
assistantContent.push({
|
|
119
|
+
type: 'thinking',
|
|
120
|
+
thinking: block.thinking,
|
|
121
|
+
signature: block.signature
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
else if (block.type === 'redacted_thinking') {
|
|
125
|
+
assistantContent.push({
|
|
126
|
+
type: 'redacted_thinking',
|
|
127
|
+
data: block.data
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
else if (block.type === 'text') {
|
|
131
|
+
if (block.text.length > 0) {
|
|
132
|
+
assistantContent.push({ type: 'text', text: block.text });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else if (block.type === 'tool_use') {
|
|
136
|
+
// A buffered tool_use with an empty id can never be referenced by a valid
|
|
137
|
+
// tool_result; emitting it would corrupt the assistant turn. Fail loud.
|
|
138
|
+
if (!isUsableId(block.id)) {
|
|
139
|
+
return fail(`Anthropic continuation: buffered tool_use block for tool '${block.name}' has an empty id; ` +
|
|
140
|
+
`cannot build a valid continuation`);
|
|
141
|
+
}
|
|
142
|
+
let parsedInput;
|
|
143
|
+
try {
|
|
144
|
+
/* c8 ignore next 1 - defensive: argsBuffer is JSON-parsed in the adapter before emitting client-tool-call-done */
|
|
145
|
+
parsedInput = JSON.parse(block.argsBuffer || '{}');
|
|
146
|
+
/* c8 ignore start - defensive: malformed argsBuffer defaults to empty object */
|
|
147
|
+
}
|
|
148
|
+
catch (_a) {
|
|
149
|
+
parsedInput = {};
|
|
150
|
+
}
|
|
151
|
+
/* c8 ignore stop */
|
|
152
|
+
bufferedToolUseIds.add(block.id);
|
|
153
|
+
assistantContent.push({
|
|
154
|
+
type: 'tool_use',
|
|
155
|
+
id: block.id,
|
|
156
|
+
name: block.name,
|
|
157
|
+
input: parsedInput
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Build user turn with tool_result blocks for each tool call. Correlate each
|
|
162
|
+
// result to a buffered tool_use id — the SAME id that keys the assistant
|
|
163
|
+
// tool_use block — and fail loud on a missing / empty / mismatched id. A
|
|
164
|
+
// missing callId is a bug to surface, not paper over with a name fallback.
|
|
165
|
+
const userContent = [];
|
|
166
|
+
for (const r of toolResults) {
|
|
167
|
+
if (!isUsableId(r.callId)) {
|
|
168
|
+
return fail(`Anthropic continuation: tool '${r.toolName}' result has no call id (missing or empty); ` +
|
|
169
|
+
`cannot correlate it to an assistant tool_use block`);
|
|
170
|
+
}
|
|
171
|
+
if (!bufferedToolUseIds.has(r.callId)) {
|
|
172
|
+
return fail(`Anthropic continuation: tool '${r.toolName}' call id '${r.callId}' does not match any ` +
|
|
173
|
+
`buffered assistant tool_use block id`);
|
|
174
|
+
}
|
|
175
|
+
const block = {
|
|
176
|
+
type: 'tool_result',
|
|
177
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
178
|
+
tool_use_id: r.callId,
|
|
179
|
+
content: r.result
|
|
180
|
+
};
|
|
181
|
+
userContent.push(r.isError ? Object.assign(Object.assign({}, block), { is_error: true }) : block);
|
|
182
|
+
}
|
|
183
|
+
// Decisive diagnostic: the tool_use.id ↔ tool_result.tool_use_id pairing for
|
|
184
|
+
// the outgoing continuation. A failing turn is field-confirmable by capturing
|
|
185
|
+
// this line (the pairing is by construction matched here — divergence fails
|
|
186
|
+
// loud above, before reaching this point).
|
|
187
|
+
if (logger) {
|
|
188
|
+
const pairing = toolResults.map((r) => `${r.toolName}:${r.callId}`).join(', ');
|
|
189
|
+
logger.detail(`ai-assist:anthropic-continuation tool_use.id↔tool_result.tool_use_id [${pairing}]`);
|
|
190
|
+
}
|
|
191
|
+
const assistantMessage = {
|
|
192
|
+
role: 'assistant',
|
|
193
|
+
content: assistantContent
|
|
194
|
+
};
|
|
195
|
+
const userMessage = {
|
|
196
|
+
role: 'user',
|
|
197
|
+
content: userContent
|
|
198
|
+
};
|
|
199
|
+
return succeed({
|
|
200
|
+
messages: [assistantMessage, userMessage],
|
|
201
|
+
toolCallsSummary: toolResults.map((r) => ({
|
|
202
|
+
toolName: r.toolName,
|
|
203
|
+
callId: r.callId,
|
|
204
|
+
args: r.args,
|
|
205
|
+
result: r.result,
|
|
206
|
+
isError: r.isError
|
|
207
|
+
}))
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
// ============================================================================
|
|
211
|
+
// OpenAI / xAI Responses API continuation builder
|
|
212
|
+
// ============================================================================
|
|
213
|
+
/**
|
|
214
|
+
* Builds the OpenAI / xAI Responses API follow-up input items for a
|
|
215
|
+
* client-tool round-trip.
|
|
216
|
+
*
|
|
217
|
+
* Emits `function_call` items (the model's call) followed by
|
|
218
|
+
* `function_call_output` items (the harness execution result), one pair
|
|
219
|
+
* per executed tool call.
|
|
220
|
+
*
|
|
221
|
+
* **Single source of truth for the id (id-correlation fix).** Each
|
|
222
|
+
* `function_call_output.call_id` is drawn from — and validated against — the
|
|
223
|
+
* set of `function_call.call_id`s in the accumulation map. It is NEVER derived
|
|
224
|
+
* from the tool name (the OpenAI parity of the Anthropic `tool_use_id` fix). A
|
|
225
|
+
* missing / empty / unmatched call id fails the build loud rather than emitting
|
|
226
|
+
* a continuation the provider would reject.
|
|
227
|
+
*
|
|
228
|
+
* @internal
|
|
229
|
+
*/
|
|
230
|
+
export function buildOpenAiContinuation(calls, toolResults, logger) {
|
|
231
|
+
const items = [];
|
|
232
|
+
// Emit function_call items for each call (model's side). Per the Responses API spec
|
|
233
|
+
// (ResponseFunctionToolCall), `call_id` is the required correlation field — it must
|
|
234
|
+
// match the matching function_call_output's `call_id` below. The optional `id` field
|
|
235
|
+
// is the output-item id (`fc_*`) used to reference the streamed item; we omit it
|
|
236
|
+
// because it is not load-bearing for input items.
|
|
237
|
+
const bufferedCallIds = new Set();
|
|
238
|
+
for (const [callId, call] of calls) {
|
|
239
|
+
bufferedCallIds.add(callId);
|
|
240
|
+
items.push({
|
|
241
|
+
type: 'function_call',
|
|
242
|
+
call_id: callId,
|
|
243
|
+
name: call.name,
|
|
244
|
+
arguments: call.argsBuffer
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
// Emit function_call_output items (harness execution results). Correlate each
|
|
248
|
+
// to a buffered function_call call_id — never the tool name — and fail loud on
|
|
249
|
+
// a missing / empty / mismatched id.
|
|
250
|
+
for (const r of toolResults) {
|
|
251
|
+
if (!isUsableId(r.callId)) {
|
|
252
|
+
return fail(`OpenAI continuation: tool '${r.toolName}' result has no call id (missing or empty); ` +
|
|
253
|
+
`cannot correlate it to a function_call item`);
|
|
254
|
+
}
|
|
255
|
+
if (!bufferedCallIds.has(r.callId)) {
|
|
256
|
+
return fail(`OpenAI continuation: tool '${r.toolName}' call id '${r.callId}' does not match any ` +
|
|
257
|
+
`accumulated function_call call_id`);
|
|
258
|
+
}
|
|
259
|
+
items.push({
|
|
260
|
+
type: 'function_call_output',
|
|
261
|
+
call_id: r.callId,
|
|
262
|
+
output: r.result
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
// Decisive diagnostic: the function_call.call_id ↔ function_call_output.call_id
|
|
266
|
+
// pairing for the outgoing continuation (matched by construction here).
|
|
267
|
+
if (logger) {
|
|
268
|
+
const pairing = toolResults.map((r) => `${r.toolName}:${r.callId}`).join(', ');
|
|
269
|
+
logger.detail(`ai-assist:openai-continuation function_call.call_id↔output.call_id [${pairing}]`);
|
|
270
|
+
}
|
|
271
|
+
return succeed({
|
|
272
|
+
messages: items,
|
|
273
|
+
toolCallsSummary: toolResults.map((r) => ({
|
|
274
|
+
toolName: r.toolName,
|
|
275
|
+
callId: r.callId,
|
|
276
|
+
args: r.args,
|
|
277
|
+
result: r.result,
|
|
278
|
+
isError: r.isError
|
|
279
|
+
}))
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
// ============================================================================
|
|
283
|
+
// Gemini continuation builder
|
|
284
|
+
// ============================================================================
|
|
285
|
+
/**
|
|
286
|
+
* Builds the Gemini follow-up contents for a client-tool round-trip.
|
|
287
|
+
*
|
|
288
|
+
* Emits a model turn with `functionCall` parts (one per tool call) and a
|
|
289
|
+
* user turn with `functionResponse` parts (correlation by tool name, since
|
|
290
|
+
* Gemini does not assign call IDs).
|
|
291
|
+
*
|
|
292
|
+
* When thinking is enabled, Gemini stamps an opaque `thoughtSignature` on each
|
|
293
|
+
* `functionCall` part and requires it echoed back, verbatim, as a sibling of
|
|
294
|
+
* `functionCall` on the continuation's model turn — otherwise the follow-up is
|
|
295
|
+
* rejected with "Function call is missing a thought_signature in functionCall
|
|
296
|
+
* parts". The captured signature (see {@link IAccumulatedGeminiFunctionCall})
|
|
297
|
+
* is replayed here only when present; the key is omitted entirely when thinking
|
|
298
|
+
* was disabled. See https://ai.google.dev/gemini-api/docs/thought-signatures.
|
|
299
|
+
*
|
|
300
|
+
* @internal
|
|
301
|
+
*/
|
|
302
|
+
export function buildGeminiContinuation(calls, toolResults) {
|
|
303
|
+
// Model turn: functionCall parts for each call. Replay the part-level
|
|
304
|
+
// thoughtSignature as a sibling of functionCall only when present.
|
|
305
|
+
const modelParts = calls.map((call) => (Object.assign({ functionCall: {
|
|
306
|
+
name: call.name,
|
|
307
|
+
args: call.args
|
|
308
|
+
} }, (call.thoughtSignature !== undefined ? { thoughtSignature: call.thoughtSignature } : {}))));
|
|
309
|
+
// User turn: functionResponse parts for each executed result.
|
|
310
|
+
// Correlation is by name since Gemini has no call IDs.
|
|
311
|
+
const userParts = toolResults.map((r) => ({
|
|
312
|
+
functionResponse: {
|
|
313
|
+
name: r.toolName,
|
|
314
|
+
response: Object.assign({ content: r.result }, (r.isError ? { error: true } : {}))
|
|
315
|
+
}
|
|
316
|
+
}));
|
|
317
|
+
const modelMessage = {
|
|
318
|
+
role: 'model',
|
|
319
|
+
parts: modelParts
|
|
320
|
+
};
|
|
321
|
+
const userMessage = {
|
|
322
|
+
role: 'user',
|
|
323
|
+
parts: userParts
|
|
324
|
+
};
|
|
325
|
+
return {
|
|
326
|
+
messages: [modelMessage, userMessage],
|
|
327
|
+
toolCallsSummary: toolResults.map((r) => ({
|
|
328
|
+
toolName: r.toolName,
|
|
329
|
+
callId: r.callId,
|
|
330
|
+
args: r.args,
|
|
331
|
+
result: r.result,
|
|
332
|
+
isError: r.isError
|
|
333
|
+
}))
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
// ============================================================================
|
|
337
|
+
// executeClientToolTurn
|
|
338
|
+
// ============================================================================
|
|
339
|
+
/**
|
|
340
|
+
* True when a request would combine Gemini built-in grounding (a `web_search`
|
|
341
|
+
* server tool) with client (function) tools — a combination Gemini's
|
|
342
|
+
* `generateContent` API rejects with HTTP 400 (`INVALID_ARGUMENT`). Callers gate
|
|
343
|
+
* on `descriptor.apiFormat === 'gemini'` before consulting this; other providers
|
|
344
|
+
* accept the mix. Kept as a pure predicate so the conflict rule is unit-testable
|
|
345
|
+
* without a live stream.
|
|
346
|
+
*
|
|
347
|
+
* @internal
|
|
348
|
+
*/
|
|
349
|
+
export function hasGeminiToolConflict(tools, clientTools) {
|
|
350
|
+
var _a;
|
|
351
|
+
return clientTools.length > 0 && ((_a = tools === null || tools === void 0 ? void 0 : tools.some((t) => t.type === 'web_search')) !== null && _a !== void 0 ? _a : false);
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Orchestrates a single client-tool streaming turn for any supported provider.
|
|
355
|
+
*
|
|
356
|
+
* Starts a streaming request, iterates the underlying provider stream, and:
|
|
357
|
+
* - Forwards `text-delta`, `tool-event`, `client-tool-call-start`, and
|
|
358
|
+
* `client-tool-call-done` events through to the consumer.
|
|
359
|
+
* - For each `client-tool-call-done` event: validates the raw args against the
|
|
360
|
+
* tool's `parametersSchema`, invokes `execute(typedArgs)`, and emits a
|
|
361
|
+
* `client-tool-result` event.
|
|
362
|
+
* - After stream completion: builds the per-provider continuation (or
|
|
363
|
+
* `{ continuation: undefined }` when no tool calls occurred) and resolves
|
|
364
|
+
* `nextTurn`.
|
|
365
|
+
*
|
|
366
|
+
* **Anthropic constraint (E3):** The continuation for Anthropic does not set
|
|
367
|
+
* a forced `tool_choice`. Only `tool_choice: 'auto'` (the default, i.e.
|
|
368
|
+
* omitted) is compatible with extended thinking.
|
|
369
|
+
*
|
|
370
|
+
* @param params - Turn parameters
|
|
371
|
+
* @returns `{ events, nextTurn }` — stream iterable + completion promise
|
|
372
|
+
* @public
|
|
373
|
+
*/
|
|
374
|
+
export function executeClientToolTurn(params) {
|
|
375
|
+
const { descriptor, apiKey, system, messages, continuationMessages, temperature, tools, clientTools, signal, logger, resolvedThinking, model, endpoint, onBeforeToolExecute } = params;
|
|
376
|
+
const splitResult = splitChatRequest(system, messages);
|
|
377
|
+
if (splitResult.isFailure()) {
|
|
378
|
+
return fail(splitResult.message);
|
|
379
|
+
}
|
|
380
|
+
const { prompt, head } = splitResult.value;
|
|
381
|
+
if (prompt.attachments.length > 0 && !descriptor.acceptsImageInput) {
|
|
382
|
+
return fail(`provider "${descriptor.id}" does not accept image input`);
|
|
383
|
+
}
|
|
384
|
+
// Build a lookup map of client tools by name for fast access.
|
|
385
|
+
// Fail fast on duplicate names — silently overwriting would cause one tool
|
|
386
|
+
// to shadow another with no observable signal.
|
|
387
|
+
const toolsByName = new Map();
|
|
388
|
+
for (const tool of clientTools) {
|
|
389
|
+
if (toolsByName.has(tool.config.name)) {
|
|
390
|
+
return fail(`executeClientToolTurn: duplicate client tool name '${tool.config.name}'`);
|
|
391
|
+
}
|
|
392
|
+
toolsByName.set(tool.config.name, tool);
|
|
393
|
+
}
|
|
394
|
+
// Merge server tools and client tool configs into a single array for the provider.
|
|
395
|
+
// This is the fix for P1-1: client tools were never sent to the provider because
|
|
396
|
+
// the adapters only received `tools` (server tools). Both must coexist per design §2.5.
|
|
397
|
+
const effectiveTools = clientTools.length > 0 ? [...(tools !== null && tools !== void 0 ? tools : []), ...clientTools.map((t) => t.config)] : tools;
|
|
398
|
+
// Gemini pre-flight: its generateContent API HTTP-400s (INVALID_ARGUMENT) when
|
|
399
|
+
// built-in grounding (`web_search`) and function calling (client tools) are
|
|
400
|
+
// combined in one request. Fail fast with a clear, actionable message rather
|
|
401
|
+
// than letting the opaque wire 400 surface. Other providers accept the mix.
|
|
402
|
+
if (descriptor.apiFormat === 'gemini' && hasGeminiToolConflict(tools, clientTools)) {
|
|
403
|
+
return fail('executeClientToolTurn: Gemini cannot combine web_search grounding with client (function) tools in the same request; send one or the other');
|
|
404
|
+
}
|
|
405
|
+
const modelResult = resolveProviderModel(descriptor, model);
|
|
406
|
+
if (modelResult.isFailure()) {
|
|
407
|
+
return fail(modelResult.message);
|
|
408
|
+
}
|
|
409
|
+
const resolvedModel = modelResult.value;
|
|
410
|
+
const baseUrlResult = resolveEffectiveBaseUrl(descriptor, endpoint);
|
|
411
|
+
if (baseUrlResult.isFailure()) {
|
|
412
|
+
return fail(baseUrlResult.message);
|
|
413
|
+
}
|
|
414
|
+
const config = {
|
|
415
|
+
baseUrl: baseUrlResult.value,
|
|
416
|
+
apiKey,
|
|
417
|
+
model: resolvedModel
|
|
418
|
+
};
|
|
419
|
+
// Accumulation buffers — populated by the adapter, read by the builder.
|
|
420
|
+
const anthropicBuffer = new Map();
|
|
421
|
+
const openAiCallMap = new Map();
|
|
422
|
+
const geminiCalls = [];
|
|
423
|
+
// Collected tool results, populated as each client-tool-call-done is processed.
|
|
424
|
+
const toolResults = [];
|
|
425
|
+
// Stream start: open the underlying adapter stream.
|
|
426
|
+
const streamPromise = (() => {
|
|
427
|
+
switch (descriptor.apiFormat) {
|
|
428
|
+
case 'anthropic':
|
|
429
|
+
return callAnthropicStream(config, prompt, head, temperature, effectiveTools, logger, signal, resolvedThinking, anthropicBuffer, continuationMessages);
|
|
430
|
+
case 'openai':
|
|
431
|
+
return callOpenAiResponsesStream(config, prompt,
|
|
432
|
+
/* c8 ignore next 1 - defensive: openai path requires tools; empty array fallback unreachable in practice */
|
|
433
|
+
effectiveTools !== null && effectiveTools !== void 0 ? effectiveTools : [], head, temperature, logger, signal, resolvedThinking, openAiCallMap, continuationMessages);
|
|
434
|
+
case 'gemini':
|
|
435
|
+
return callGeminiStream(config, prompt, head, temperature, effectiveTools, logger, signal, resolvedThinking, geminiCalls, continuationMessages);
|
|
436
|
+
/* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */
|
|
437
|
+
default: {
|
|
438
|
+
const _exhaustive = descriptor.apiFormat;
|
|
439
|
+
return Promise.resolve(fail(`unsupported API format: ${String(_exhaustive)}`));
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
})();
|
|
443
|
+
// Resolve controls for `nextTurn`.
|
|
444
|
+
let resolveNextTurn;
|
|
445
|
+
const nextTurn = new Promise((resolve) => {
|
|
446
|
+
resolveNextTurn = resolve;
|
|
447
|
+
});
|
|
448
|
+
// The unified-event generator: opens the stream, proxies events, executes tools.
|
|
449
|
+
function eventGenerator() {
|
|
450
|
+
return __asyncGenerator(this, arguments, function* eventGenerator_1() {
|
|
451
|
+
var _a, e_1, _b, _c;
|
|
452
|
+
const streamResult = yield __await(streamPromise);
|
|
453
|
+
if (streamResult.isFailure()) {
|
|
454
|
+
resolveNextTurn(fail(streamResult.message));
|
|
455
|
+
yield yield __await({ type: 'error', message: streamResult.message });
|
|
456
|
+
return yield __await(void 0);
|
|
457
|
+
}
|
|
458
|
+
let truncated = false;
|
|
459
|
+
let fullText = '';
|
|
460
|
+
let streamError;
|
|
461
|
+
try {
|
|
462
|
+
for (var _d = true, _e = __asyncValues(streamResult.value), _f; _f = yield __await(_e.next()), _a = _f.done, !_a; _d = true) {
|
|
463
|
+
_c = _f.value;
|
|
464
|
+
_d = false;
|
|
465
|
+
const event = _c;
|
|
466
|
+
if (event.type === 'done') {
|
|
467
|
+
truncated = event.truncated;
|
|
468
|
+
fullText = event.fullText;
|
|
469
|
+
yield yield __await(event);
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
if (event.type === 'error') {
|
|
473
|
+
streamError = event.message;
|
|
474
|
+
yield yield __await(event);
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
if (event.type === 'text-delta') {
|
|
478
|
+
yield yield __await(event);
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
if (event.type === 'tool-event') {
|
|
482
|
+
yield yield __await(event);
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
if (event.type === 'client-tool-call-start') {
|
|
486
|
+
yield yield __await(event);
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
if (event.type === 'client-tool-call-done') {
|
|
490
|
+
yield yield __await(event);
|
|
491
|
+
const { toolName, callId, args } = event;
|
|
492
|
+
const tool = toolsByName.get(toolName);
|
|
493
|
+
if (!tool) {
|
|
494
|
+
const errMsg = `model called unknown tool: ${toolName}`;
|
|
495
|
+
const resultEvent = {
|
|
496
|
+
type: 'client-tool-result',
|
|
497
|
+
toolName,
|
|
498
|
+
callId,
|
|
499
|
+
result: errMsg,
|
|
500
|
+
isError: true
|
|
501
|
+
};
|
|
502
|
+
yield yield __await(resultEvent);
|
|
503
|
+
toolResults.push({ toolName, callId, args, result: errMsg, isError: true });
|
|
504
|
+
resolveNextTurn(fail(errMsg));
|
|
505
|
+
return yield __await(void 0);
|
|
506
|
+
}
|
|
507
|
+
const validationResult = tool.config.parametersSchema.validate(args);
|
|
508
|
+
if (validationResult.isFailure()) {
|
|
509
|
+
const errMsg = `${toolName} (callId=${callId}): ${validationResult.message}`;
|
|
510
|
+
const resultEvent = {
|
|
511
|
+
type: 'client-tool-result',
|
|
512
|
+
toolName,
|
|
513
|
+
callId,
|
|
514
|
+
result: errMsg,
|
|
515
|
+
isError: true
|
|
516
|
+
};
|
|
517
|
+
yield yield __await(resultEvent);
|
|
518
|
+
toolResults.push({ toolName, callId, args, result: errMsg, isError: true });
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
// Host gate: run after arg-validation, before execute. A `deny` decision
|
|
522
|
+
// synthesizes a denial tool-result and continues the turn; a `fail`/reject
|
|
523
|
+
// from the gate itself is a hard error (mirrors an execute failure), never
|
|
524
|
+
// a silent deny.
|
|
525
|
+
if (onBeforeToolExecute !== undefined) {
|
|
526
|
+
const decisionResult = (yield __await(captureAsyncResult(async () => onBeforeToolExecute(tool, validationResult.value)))).onSuccess((decision) => decision);
|
|
527
|
+
if (decisionResult.isFailure()) {
|
|
528
|
+
const errMsg = `${toolName} (callId=${callId}): ${decisionResult.message}`;
|
|
529
|
+
const resultEvent = {
|
|
530
|
+
type: 'client-tool-result',
|
|
531
|
+
toolName,
|
|
532
|
+
callId,
|
|
533
|
+
result: errMsg,
|
|
534
|
+
isError: true
|
|
535
|
+
};
|
|
536
|
+
yield yield __await(resultEvent);
|
|
537
|
+
// Gate-fail is a hard, turn-terminating error (unlike a non-fatal `deny`, whose
|
|
538
|
+
// generator continues). Emit an explicit `error` event so a consumer watching only
|
|
539
|
+
// `events` sees the fatal failure inline and can distinguish it from a deny — matching
|
|
540
|
+
// the stream-open / continuation hard-error paths.
|
|
541
|
+
yield yield __await({ type: 'error', message: errMsg });
|
|
542
|
+
toolResults.push({ toolName, callId, args, result: errMsg, isError: true });
|
|
543
|
+
resolveNextTurn(fail(errMsg));
|
|
544
|
+
return yield __await(void 0);
|
|
545
|
+
}
|
|
546
|
+
if (decisionResult.value.action === 'deny') {
|
|
547
|
+
const denialMsg = `${toolName} (callId=${callId}): tool execution denied: ${decisionResult.value.reason}`;
|
|
548
|
+
const resultEvent = {
|
|
549
|
+
type: 'client-tool-result',
|
|
550
|
+
toolName,
|
|
551
|
+
callId,
|
|
552
|
+
result: denialMsg,
|
|
553
|
+
isError: true
|
|
554
|
+
};
|
|
555
|
+
yield yield __await(resultEvent);
|
|
556
|
+
toolResults.push({ toolName, callId, args, result: denialMsg, isError: true });
|
|
557
|
+
continue;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
const executeResult = yield __await(captureAsyncResult(async () => tool.execute(validationResult.value)));
|
|
561
|
+
const executionResult = executeResult.isSuccess()
|
|
562
|
+
? executeResult.value
|
|
563
|
+
: executeResult;
|
|
564
|
+
if (executionResult.isFailure()) {
|
|
565
|
+
const errMsg = `${toolName} (callId=${callId}): ${executionResult.message}`;
|
|
566
|
+
const resultEvent = {
|
|
567
|
+
type: 'client-tool-result',
|
|
568
|
+
toolName,
|
|
569
|
+
callId,
|
|
570
|
+
result: errMsg,
|
|
571
|
+
isError: true
|
|
572
|
+
};
|
|
573
|
+
yield yield __await(resultEvent);
|
|
574
|
+
toolResults.push({ toolName, callId, args, result: errMsg, isError: true });
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
// JSON.stringify can throw (circular references) or return undefined
|
|
578
|
+
// (e.g. for a bare `undefined` value, or a value of type `function`).
|
|
579
|
+
// Either outcome violates the client-tool-result event contract, so
|
|
580
|
+
// emit an isError result with diagnostic context instead.
|
|
581
|
+
let resultStr;
|
|
582
|
+
try {
|
|
583
|
+
const stringified = JSON.stringify(executionResult.value);
|
|
584
|
+
if (stringified === undefined) {
|
|
585
|
+
const errMsg = `${toolName} (callId=${callId}): tool returned a non-serializable value (JSON.stringify produced undefined)`;
|
|
586
|
+
const resultEvent = {
|
|
587
|
+
type: 'client-tool-result',
|
|
588
|
+
toolName,
|
|
589
|
+
callId,
|
|
590
|
+
result: errMsg,
|
|
591
|
+
isError: true
|
|
592
|
+
};
|
|
593
|
+
yield yield __await(resultEvent);
|
|
594
|
+
toolResults.push({ toolName, callId, args, result: errMsg, isError: true });
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
597
|
+
resultStr = stringified;
|
|
598
|
+
}
|
|
599
|
+
catch (e) {
|
|
600
|
+
const errMsg = `${toolName} (callId=${callId}): failed to serialize tool result: ${e.message}`;
|
|
601
|
+
const resultEvent = {
|
|
602
|
+
type: 'client-tool-result',
|
|
603
|
+
toolName,
|
|
604
|
+
callId,
|
|
605
|
+
result: errMsg,
|
|
606
|
+
isError: true
|
|
607
|
+
};
|
|
608
|
+
yield yield __await(resultEvent);
|
|
609
|
+
toolResults.push({ toolName, callId, args, result: errMsg, isError: true });
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
612
|
+
const resultEvent = {
|
|
613
|
+
type: 'client-tool-result',
|
|
614
|
+
toolName,
|
|
615
|
+
callId,
|
|
616
|
+
result: resultStr,
|
|
617
|
+
isError: false
|
|
618
|
+
};
|
|
619
|
+
yield yield __await(resultEvent);
|
|
620
|
+
toolResults.push({ toolName, callId, args, result: resultStr, isError: false });
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
626
|
+
finally {
|
|
627
|
+
try {
|
|
628
|
+
if (!_d && !_a && (_b = _e.return)) yield __await(_b.call(_e));
|
|
629
|
+
}
|
|
630
|
+
finally { if (e_1) throw e_1.error; }
|
|
631
|
+
}
|
|
632
|
+
// Stream has ended. Build the continuation.
|
|
633
|
+
if (streamError !== undefined) {
|
|
634
|
+
resolveNextTurn(fail(streamError));
|
|
635
|
+
return yield __await(void 0);
|
|
636
|
+
}
|
|
637
|
+
if (toolResults.length === 0) {
|
|
638
|
+
resolveNextTurn(succeed({ continuation: undefined, truncated, fullText }));
|
|
639
|
+
return yield __await(void 0);
|
|
640
|
+
}
|
|
641
|
+
let continuationResult;
|
|
642
|
+
switch (descriptor.apiFormat) {
|
|
643
|
+
case 'anthropic':
|
|
644
|
+
continuationResult = buildAnthropicContinuation(anthropicBuffer, toolResults, logger);
|
|
645
|
+
break;
|
|
646
|
+
case 'openai':
|
|
647
|
+
continuationResult = buildOpenAiContinuation(openAiCallMap, toolResults, logger);
|
|
648
|
+
break;
|
|
649
|
+
case 'gemini':
|
|
650
|
+
// Gemini correlates by tool name by design (no call ids) — its builder
|
|
651
|
+
// cannot mis-key and stays non-fallible.
|
|
652
|
+
continuationResult = succeed(buildGeminiContinuation(geminiCalls, toolResults));
|
|
653
|
+
break;
|
|
654
|
+
/* c8 ignore next 5 - defensive coding: exhaustive switch guaranteed by TypeScript */
|
|
655
|
+
default: {
|
|
656
|
+
const _exhaustive = descriptor.apiFormat;
|
|
657
|
+
resolveNextTurn(fail(`unsupported API format: ${String(_exhaustive)}`));
|
|
658
|
+
return yield __await(void 0);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
// A bad id-correlation fails loud here rather than emitting a malformed
|
|
662
|
+
// continuation the provider would reject as a "malformed identifier". Mirror
|
|
663
|
+
// the stream-open-failure path above: surface an `error` event so a consumer
|
|
664
|
+
// iterating `events` sees the failure inline, not only via `nextTurn`.
|
|
665
|
+
if (continuationResult.isFailure()) {
|
|
666
|
+
resolveNextTurn(fail(continuationResult.message));
|
|
667
|
+
yield yield __await({ type: 'error', message: continuationResult.message });
|
|
668
|
+
return yield __await(void 0);
|
|
669
|
+
}
|
|
670
|
+
let continuation = continuationResult.value;
|
|
671
|
+
// Prepend inbound continuationMessages so the returned continuation is cumulative.
|
|
672
|
+
// A consumer that does `tail = outcome.continuation.messages` (replace) is then
|
|
673
|
+
// correct for all N rounds — messages always contains the full wire tail from
|
|
674
|
+
// round 1 through the current round. toolCallsSummary stays per-round (this
|
|
675
|
+
// round's calls only); messages is the accumulated tail to re-send.
|
|
676
|
+
if (continuationMessages && continuationMessages.length > 0) {
|
|
677
|
+
continuation = Object.assign(Object.assign({}, continuation), { messages: [...continuationMessages, ...continuation.messages] });
|
|
678
|
+
}
|
|
679
|
+
resolveNextTurn(succeed({ continuation, truncated, fullText }));
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
return succeed({
|
|
683
|
+
events: { [Symbol.asyncIterator]: () => eventGenerator() },
|
|
684
|
+
nextTurn
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
//# sourceMappingURL=clientToolContinuationBuilder.js.map
|