@llumiverse/drivers 1.2.0 → 1.4.0-dev.20260629.090753Z
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/lib/{types/adobe → adobe}/firefly.d.ts +2 -1
- package/lib/adobe/firefly.d.ts.map +1 -0
- package/lib/adobe/firefly.js +120 -0
- package/lib/adobe/firefly.js.map +1 -0
- package/lib/anthropic/index.d.ts +23 -0
- package/lib/anthropic/index.d.ts.map +1 -0
- package/lib/anthropic/index.js +68 -0
- package/lib/anthropic/index.js.map +1 -0
- package/lib/{types/azure → azure}/azure_foundry.d.ts +9 -7
- package/lib/azure/azure_foundry.d.ts.map +1 -0
- package/lib/{esm/azure → azure}/azure_foundry.js +138 -124
- package/lib/azure/azure_foundry.js.map +1 -0
- package/lib/{types/bedrock → bedrock}/converse.d.ts +2 -2
- package/lib/bedrock/converse.d.ts.map +1 -0
- package/lib/{esm/bedrock → bedrock}/converse.js +86 -79
- package/lib/bedrock/converse.js.map +1 -0
- package/lib/bedrock/embeddings.d.ts +4 -0
- package/lib/bedrock/embeddings.d.ts.map +1 -0
- package/lib/bedrock/embeddings.js +359 -0
- package/lib/bedrock/embeddings.js.map +1 -0
- package/lib/{types/bedrock → bedrock}/index.d.ts +33 -9
- package/lib/bedrock/index.d.ts.map +1 -0
- package/lib/{esm/bedrock → bedrock}/index.js +599 -324
- package/lib/bedrock/index.js.map +1 -0
- package/lib/{types/bedrock → bedrock}/nova-image-payload.d.ts +5 -5
- package/lib/bedrock/nova-image-payload.d.ts.map +1 -0
- package/lib/{esm/bedrock → bedrock}/nova-image-payload.js +31 -36
- package/lib/bedrock/nova-image-payload.js.map +1 -0
- package/lib/{types/bedrock → bedrock}/payloads.d.ts +1 -1
- package/lib/bedrock/payloads.d.ts.map +1 -0
- package/lib/{cjs/bedrock → bedrock}/payloads.js.map +1 -1
- package/lib/{types/bedrock → bedrock}/s3.d.ts +3 -2
- package/lib/bedrock/s3.d.ts.map +1 -0
- package/lib/{esm/bedrock → bedrock}/s3.js +27 -23
- package/lib/bedrock/s3.js.map +1 -0
- package/lib/{types/bedrock → bedrock}/twelvelabs.d.ts +8 -9
- package/lib/bedrock/twelvelabs.d.ts.map +1 -0
- package/lib/{esm/bedrock → bedrock}/twelvelabs.js +17 -21
- package/lib/bedrock/twelvelabs.js.map +1 -0
- package/lib/{types/groq → groq}/index.d.ts +6 -4
- package/lib/groq/index.d.ts.map +1 -0
- package/lib/{esm/groq → groq}/index.js +72 -39
- package/lib/groq/index.js.map +1 -0
- package/lib/{types/huggingface_ie.d.ts → huggingface_ie.d.ts} +4 -3
- package/lib/huggingface_ie.d.ts.map +1 -0
- package/lib/{esm/huggingface_ie.js → huggingface_ie.js} +32 -31
- package/lib/huggingface_ie.js.map +1 -0
- package/lib/index.d.ts +16 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +16 -0
- package/lib/index.js.map +1 -0
- package/lib/{types/mistral → mistral}/index.d.ts +6 -5
- package/lib/mistral/index.d.ts.map +1 -0
- package/lib/{esm/mistral → mistral}/index.js +66 -38
- package/lib/mistral/index.js.map +1 -0
- package/lib/{types/mistral → mistral}/types.d.ts +1 -0
- package/lib/mistral/types.d.ts.map +1 -0
- package/lib/mistral/types.js.map +1 -0
- package/lib/{types/openai → openai}/azure_openai.d.ts +5 -4
- package/lib/openai/azure_openai.d.ts.map +1 -0
- package/lib/{esm/openai → openai}/azure_openai.js +17 -14
- package/lib/openai/azure_openai.js.map +1 -0
- package/lib/openai/drivers.d.ts +4 -0
- package/lib/openai/drivers.d.ts.map +1 -0
- package/lib/openai/drivers.js +9 -0
- package/lib/openai/drivers.js.map +1 -0
- package/lib/{types/openai → openai}/index.d.ts +17 -5
- package/lib/openai/index.d.ts.map +1 -0
- package/lib/{esm/openai → openai}/index.js +254 -148
- package/lib/openai/index.js.map +1 -0
- package/lib/{types/openai → openai}/openai.d.ts +3 -3
- package/lib/openai/openai.d.ts.map +1 -0
- package/lib/openai/openai.js +15 -0
- package/lib/openai/openai.js.map +1 -0
- package/lib/{types/openai → openai}/openai_compatible.d.ts +3 -3
- package/lib/openai/openai_compatible.d.ts.map +1 -0
- package/lib/{esm/openai → openai}/openai_compatible.js +14 -11
- package/lib/openai/openai_compatible.js.map +1 -0
- package/lib/{types/openai → openai}/openai_format.d.ts +3 -2
- package/lib/openai/openai_format.d.ts.map +1 -0
- package/lib/{esm/openai → openai}/openai_format.js +66 -24
- package/lib/openai/openai_format.js.map +1 -0
- package/lib/{types/replicate.d.ts → replicate.d.ts} +3 -2
- package/lib/replicate.d.ts.map +1 -0
- package/lib/{esm/replicate.js → replicate.js} +59 -49
- package/lib/replicate.js.map +1 -0
- package/lib/shared/claude-messages.d.ts +99 -0
- package/lib/shared/claude-messages.d.ts.map +1 -0
- package/lib/shared/claude-messages.js +869 -0
- package/lib/shared/claude-messages.js.map +1 -0
- package/lib/{types/shared → shared}/claude-thinking.d.ts +1 -1
- package/lib/shared/claude-thinking.d.ts.map +1 -0
- package/lib/{esm/shared → shared}/claude-thinking.js +5 -7
- package/lib/shared/claude-thinking.js.map +1 -0
- package/lib/shared/debug-prompt.d.ts +5 -0
- package/lib/shared/debug-prompt.d.ts.map +1 -0
- package/lib/shared/debug-prompt.js +25 -0
- package/lib/shared/debug-prompt.js.map +1 -0
- package/lib/{types/test-driver → test-driver}/TestErrorCompletionStream.d.ts +1 -1
- package/lib/test-driver/TestErrorCompletionStream.d.ts.map +1 -0
- package/lib/test-driver/TestErrorCompletionStream.js +16 -0
- package/lib/test-driver/TestErrorCompletionStream.js.map +1 -0
- package/lib/{types/test-driver → test-driver}/TestValidationErrorCompletionStream.d.ts +1 -1
- package/lib/test-driver/TestValidationErrorCompletionStream.d.ts.map +1 -0
- package/lib/{esm/test-driver → test-driver}/TestValidationErrorCompletionStream.js +4 -4
- package/lib/test-driver/TestValidationErrorCompletionStream.js.map +1 -0
- package/lib/{types/test-driver → test-driver}/index.d.ts +3 -3
- package/lib/test-driver/index.d.ts.map +1 -0
- package/lib/{esm/test-driver → test-driver}/index.js +20 -20
- package/lib/test-driver/index.js.map +1 -0
- package/lib/{types/test-driver → test-driver}/utils.d.ts +1 -1
- package/lib/test-driver/utils.d.ts.map +1 -0
- package/lib/{esm/test-driver → test-driver}/utils.js +4 -4
- package/lib/test-driver/utils.js.map +1 -0
- package/lib/togetherai/index.d.ts +15 -0
- package/lib/togetherai/index.d.ts.map +1 -0
- package/lib/togetherai/index.js +54 -0
- package/lib/togetherai/index.js.map +1 -0
- package/lib/{types/togetherai → togetherai}/interfaces.d.ts +1 -1
- package/lib/togetherai/interfaces.d.ts.map +1 -0
- package/lib/{cjs/watsonx → togetherai}/interfaces.js.map +1 -1
- package/lib/vertexai/debug.d.ts +2 -0
- package/lib/vertexai/debug.d.ts.map +1 -0
- package/lib/{esm/vertexai → vertexai}/debug.js +1 -1
- package/lib/vertexai/debug.js.map +1 -0
- package/lib/vertexai/embeddings/embed-legacy-multimodal.d.ts +9 -0
- package/lib/vertexai/embeddings/embed-legacy-multimodal.d.ts.map +1 -0
- package/lib/vertexai/embeddings/embed-legacy-multimodal.js +141 -0
- package/lib/vertexai/embeddings/embed-legacy-multimodal.js.map +1 -0
- package/lib/vertexai/embeddings/embed.d.ts +13 -0
- package/lib/vertexai/embeddings/embed.d.ts.map +1 -0
- package/lib/vertexai/embeddings/embed.js +162 -0
- package/lib/vertexai/embeddings/embed.js.map +1 -0
- package/lib/vertexai/embeddings/source-utils.d.ts +9 -0
- package/lib/vertexai/embeddings/source-utils.d.ts.map +1 -0
- package/lib/vertexai/embeddings/source-utils.js +18 -0
- package/lib/vertexai/embeddings/source-utils.js.map +1 -0
- package/lib/{types/vertexai → vertexai}/index.d.ts +31 -19
- package/lib/vertexai/index.d.ts.map +1 -0
- package/lib/{esm/vertexai → vertexai}/index.js +221 -159
- package/lib/vertexai/index.js.map +1 -0
- package/lib/vertexai/models/claude.d.ts +16 -0
- package/lib/vertexai/models/claude.d.ts.map +1 -0
- package/lib/vertexai/models/claude.js +65 -0
- package/lib/vertexai/models/claude.js.map +1 -0
- package/lib/{types/vertexai → vertexai}/models/gemini.d.ts +29 -5
- package/lib/vertexai/models/gemini.d.ts.map +1 -0
- package/lib/{esm/vertexai → vertexai}/models/gemini.js +255 -127
- package/lib/vertexai/models/gemini.js.map +1 -0
- package/lib/{types/vertexai → vertexai}/models/imagen.d.ts +12 -11
- package/lib/vertexai/models/imagen.d.ts.map +1 -0
- package/lib/{esm/vertexai → vertexai}/models/imagen.js +74 -47
- package/lib/vertexai/models/imagen.js.map +1 -0
- package/lib/{types/vertexai → vertexai}/models/llama.d.ts +4 -4
- package/lib/vertexai/models/llama.d.ts.map +1 -0
- package/lib/{esm/vertexai → vertexai}/models/llama.js +37 -33
- package/lib/vertexai/models/llama.js.map +1 -0
- package/lib/vertexai/models.d.ts +21 -0
- package/lib/vertexai/models.d.ts.map +1 -0
- package/lib/{esm/vertexai → vertexai}/models.js +12 -9
- package/lib/vertexai/models.js.map +1 -0
- package/lib/{types/watsonx → watsonx}/index.d.ts +4 -3
- package/lib/watsonx/index.d.ts.map +1 -0
- package/lib/{esm/watsonx → watsonx}/index.js +69 -41
- package/lib/watsonx/index.js.map +1 -0
- package/lib/watsonx/interfaces.d.ts.map +1 -0
- package/lib/{esm/watsonx → watsonx}/interfaces.js.map +1 -1
- package/lib/{types/xai → xai}/index.d.ts +4 -4
- package/lib/xai/index.d.ts.map +1 -0
- package/lib/{esm/xai → xai}/index.js +22 -18
- package/lib/xai/index.js.map +1 -0
- package/package.json +88 -36
- package/src/adobe/firefly.ts +60 -43
- package/src/anthropic/index.ts +121 -0
- package/src/azure/azure_foundry.ts +210 -165
- package/src/bedrock/converse.ts +124 -101
- package/src/bedrock/embeddings.test.ts +508 -0
- package/src/bedrock/embeddings.ts +517 -0
- package/src/bedrock/error-handling.test.ts +62 -14
- package/src/bedrock/index.ts +832 -466
- package/src/bedrock/nova-image-payload.ts +98 -91
- package/src/bedrock/payloads.ts +9 -9
- package/src/bedrock/s3.test.ts +39 -0
- package/src/bedrock/s3.ts +57 -38
- package/src/bedrock/streaming-tool-use.test.ts +86 -69
- package/src/bedrock/twelvelabs.ts +35 -32
- package/src/groq/index.ts +143 -60
- package/src/http-timeout-wiring.test.ts +263 -0
- package/src/huggingface_ie.ts +45 -61
- package/src/index.ts +15 -15
- package/src/mistral/index.ts +97 -48
- package/src/mistral/types.ts +13 -12
- package/src/openai/azure_openai.ts +35 -27
- package/src/openai/drivers.ts +9 -0
- package/src/openai/error-handling.test.ts +308 -113
- package/src/openai/index.ts +389 -254
- package/src/openai/openai.ts +6 -13
- package/src/openai/openai_compatible.ts +35 -25
- package/src/openai/openai_format.ts +90 -40
- package/src/replicate.ts +108 -86
- package/src/shared/claude-messages.test.ts +37 -0
- package/src/shared/claude-messages.ts +1085 -0
- package/src/shared/claude-thinking.ts +6 -12
- package/src/shared/debug-prompt.ts +28 -0
- package/src/test-driver/TestErrorCompletionStream.ts +9 -10
- package/src/test-driver/TestValidationErrorCompletionStream.ts +9 -10
- package/src/test-driver/index.ts +43 -27
- package/src/test-driver/utils.ts +8 -8
- package/src/togetherai/index.test.ts +32 -0
- package/src/togetherai/index.ts +64 -128
- package/src/togetherai/interfaces.ts +5 -5
- package/src/vertexai/debug.ts +3 -3
- package/src/vertexai/embeddings/embed-legacy-multimodal.ts +211 -0
- package/src/vertexai/embeddings/embed.ts +206 -0
- package/src/vertexai/embeddings/embeddings.test.ts +497 -0
- package/src/vertexai/embeddings/source-utils.test.ts +54 -0
- package/src/vertexai/embeddings/source-utils.ts +29 -0
- package/src/vertexai/index.ts +339 -253
- package/src/vertexai/models/claude-error-handling.test.ts +86 -39
- package/src/vertexai/models/claude-streaming-spacing.test.ts +82 -75
- package/src/vertexai/models/claude.ts +84 -1041
- package/src/vertexai/models/gemini-conversation-mutation.test.ts +65 -23
- package/src/vertexai/models/gemini-error-handling.test.ts +126 -10
- package/src/vertexai/models/gemini-orphaned-tool-result.test.ts +118 -0
- package/src/vertexai/models/gemini.ts +372 -182
- package/src/vertexai/models/imagen.ts +164 -100
- package/src/vertexai/models/llama.ts +70 -48
- package/src/vertexai/models.ts +36 -16
- package/src/watsonx/index.ts +101 -65
- package/src/watsonx/interfaces.ts +10 -15
- package/src/xai/index.ts +30 -30
- package/lib/cjs/adobe/firefly.js +0 -120
- package/lib/cjs/adobe/firefly.js.map +0 -1
- package/lib/cjs/azure/azure_foundry.js +0 -432
- package/lib/cjs/azure/azure_foundry.js.map +0 -1
- package/lib/cjs/bedrock/converse.js +0 -359
- package/lib/cjs/bedrock/converse.js.map +0 -1
- package/lib/cjs/bedrock/index.js +0 -1508
- package/lib/cjs/bedrock/index.js.map +0 -1
- package/lib/cjs/bedrock/nova-image-payload.js +0 -207
- package/lib/cjs/bedrock/nova-image-payload.js.map +0 -1
- package/lib/cjs/bedrock/payloads.js +0 -3
- package/lib/cjs/bedrock/s3.js +0 -107
- package/lib/cjs/bedrock/s3.js.map +0 -1
- package/lib/cjs/bedrock/twelvelabs.js +0 -87
- package/lib/cjs/bedrock/twelvelabs.js.map +0 -1
- package/lib/cjs/groq/index.js +0 -328
- package/lib/cjs/groq/index.js.map +0 -1
- package/lib/cjs/huggingface_ie.js +0 -201
- package/lib/cjs/huggingface_ie.js.map +0 -1
- package/lib/cjs/index.js +0 -31
- package/lib/cjs/index.js.map +0 -1
- package/lib/cjs/mistral/index.js +0 -176
- package/lib/cjs/mistral/index.js.map +0 -1
- package/lib/cjs/mistral/types.js +0 -83
- package/lib/cjs/mistral/types.js.map +0 -1
- package/lib/cjs/openai/azure_openai.js +0 -72
- package/lib/cjs/openai/azure_openai.js.map +0 -1
- package/lib/cjs/openai/index.js +0 -1129
- package/lib/cjs/openai/index.js.map +0 -1
- package/lib/cjs/openai/openai.js +0 -21
- package/lib/cjs/openai/openai.js.map +0 -1
- package/lib/cjs/openai/openai_compatible.js +0 -63
- package/lib/cjs/openai/openai_compatible.js.map +0 -1
- package/lib/cjs/openai/openai_format.js +0 -131
- package/lib/cjs/openai/openai_format.js.map +0 -1
- package/lib/cjs/package.json +0 -3
- package/lib/cjs/replicate.js +0 -275
- package/lib/cjs/replicate.js.map +0 -1
- package/lib/cjs/shared/claude-thinking.js +0 -60
- package/lib/cjs/shared/claude-thinking.js.map +0 -1
- package/lib/cjs/test-driver/TestErrorCompletionStream.js +0 -20
- package/lib/cjs/test-driver/TestErrorCompletionStream.js.map +0 -1
- package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js +0 -24
- package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js.map +0 -1
- package/lib/cjs/test-driver/index.js +0 -109
- package/lib/cjs/test-driver/index.js.map +0 -1
- package/lib/cjs/test-driver/utils.js +0 -30
- package/lib/cjs/test-driver/utils.js.map +0 -1
- package/lib/cjs/togetherai/index.js +0 -126
- package/lib/cjs/togetherai/index.js.map +0 -1
- package/lib/cjs/togetherai/interfaces.js +0 -3
- package/lib/cjs/togetherai/interfaces.js.map +0 -1
- package/lib/cjs/vertexai/debug.js +0 -12
- package/lib/cjs/vertexai/debug.js.map +0 -1
- package/lib/cjs/vertexai/embeddings/embeddings-image.js +0 -27
- package/lib/cjs/vertexai/embeddings/embeddings-image.js.map +0 -1
- package/lib/cjs/vertexai/embeddings/embeddings-text.js +0 -23
- package/lib/cjs/vertexai/embeddings/embeddings-text.js.map +0 -1
- package/lib/cjs/vertexai/index.js +0 -644
- package/lib/cjs/vertexai/index.js.map +0 -1
- package/lib/cjs/vertexai/models/claude.js +0 -917
- package/lib/cjs/vertexai/models/claude.js.map +0 -1
- package/lib/cjs/vertexai/models/gemini.js +0 -858
- package/lib/cjs/vertexai/models/gemini.js.map +0 -1
- package/lib/cjs/vertexai/models/imagen.js +0 -303
- package/lib/cjs/vertexai/models/imagen.js.map +0 -1
- package/lib/cjs/vertexai/models/llama.js +0 -183
- package/lib/cjs/vertexai/models/llama.js.map +0 -1
- package/lib/cjs/vertexai/models.js +0 -35
- package/lib/cjs/vertexai/models.js.map +0 -1
- package/lib/cjs/watsonx/index.js +0 -161
- package/lib/cjs/watsonx/index.js.map +0 -1
- package/lib/cjs/watsonx/interfaces.js +0 -3
- package/lib/cjs/xai/index.js +0 -65
- package/lib/cjs/xai/index.js.map +0 -1
- package/lib/esm/adobe/firefly.js +0 -116
- package/lib/esm/adobe/firefly.js.map +0 -1
- package/lib/esm/azure/azure_foundry.js.map +0 -1
- package/lib/esm/bedrock/converse.js.map +0 -1
- package/lib/esm/bedrock/index.js.map +0 -1
- package/lib/esm/bedrock/nova-image-payload.js.map +0 -1
- package/lib/esm/bedrock/payloads.js.map +0 -1
- package/lib/esm/bedrock/s3.js.map +0 -1
- package/lib/esm/bedrock/twelvelabs.js.map +0 -1
- package/lib/esm/groq/index.js.map +0 -1
- package/lib/esm/huggingface_ie.js.map +0 -1
- package/lib/esm/index.js +0 -15
- package/lib/esm/index.js.map +0 -1
- package/lib/esm/mistral/index.js.map +0 -1
- package/lib/esm/mistral/types.js.map +0 -1
- package/lib/esm/openai/azure_openai.js.map +0 -1
- package/lib/esm/openai/index.js.map +0 -1
- package/lib/esm/openai/openai.js +0 -14
- package/lib/esm/openai/openai.js.map +0 -1
- package/lib/esm/openai/openai_compatible.js.map +0 -1
- package/lib/esm/openai/openai_format.js.map +0 -1
- package/lib/esm/replicate.js.map +0 -1
- package/lib/esm/shared/claude-thinking.js.map +0 -1
- package/lib/esm/test-driver/TestErrorCompletionStream.js +0 -16
- package/lib/esm/test-driver/TestErrorCompletionStream.js.map +0 -1
- package/lib/esm/test-driver/TestValidationErrorCompletionStream.js.map +0 -1
- package/lib/esm/test-driver/index.js.map +0 -1
- package/lib/esm/test-driver/utils.js.map +0 -1
- package/lib/esm/togetherai/index.js +0 -122
- package/lib/esm/togetherai/index.js.map +0 -1
- package/lib/esm/togetherai/interfaces.js.map +0 -1
- package/lib/esm/vertexai/debug.js.map +0 -1
- package/lib/esm/vertexai/embeddings/embeddings-image.js +0 -24
- package/lib/esm/vertexai/embeddings/embeddings-image.js.map +0 -1
- package/lib/esm/vertexai/embeddings/embeddings-text.js +0 -20
- package/lib/esm/vertexai/embeddings/embeddings-text.js.map +0 -1
- package/lib/esm/vertexai/index.js.map +0 -1
- package/lib/esm/vertexai/models/claude.js +0 -906
- package/lib/esm/vertexai/models/claude.js.map +0 -1
- package/lib/esm/vertexai/models/gemini.js.map +0 -1
- package/lib/esm/vertexai/models/imagen.js.map +0 -1
- package/lib/esm/vertexai/models/llama.js.map +0 -1
- package/lib/esm/vertexai/models.js.map +0 -1
- package/lib/esm/watsonx/index.js.map +0 -1
- package/lib/esm/xai/index.js.map +0 -1
- package/lib/types/adobe/firefly.d.ts.map +0 -1
- package/lib/types/azure/azure_foundry.d.ts.map +0 -1
- package/lib/types/bedrock/converse.d.ts.map +0 -1
- package/lib/types/bedrock/index.d.ts.map +0 -1
- package/lib/types/bedrock/nova-image-payload.d.ts.map +0 -1
- package/lib/types/bedrock/payloads.d.ts.map +0 -1
- package/lib/types/bedrock/s3.d.ts.map +0 -1
- package/lib/types/bedrock/twelvelabs.d.ts.map +0 -1
- package/lib/types/groq/index.d.ts.map +0 -1
- package/lib/types/huggingface_ie.d.ts.map +0 -1
- package/lib/types/index.d.ts +0 -15
- package/lib/types/index.d.ts.map +0 -1
- package/lib/types/mistral/index.d.ts.map +0 -1
- package/lib/types/mistral/types.d.ts.map +0 -1
- package/lib/types/openai/azure_openai.d.ts.map +0 -1
- package/lib/types/openai/index.d.ts.map +0 -1
- package/lib/types/openai/openai.d.ts.map +0 -1
- package/lib/types/openai/openai_compatible.d.ts.map +0 -1
- package/lib/types/openai/openai_format.d.ts.map +0 -1
- package/lib/types/replicate.d.ts.map +0 -1
- package/lib/types/shared/claude-thinking.d.ts.map +0 -1
- package/lib/types/test-driver/TestErrorCompletionStream.d.ts.map +0 -1
- package/lib/types/test-driver/TestValidationErrorCompletionStream.d.ts.map +0 -1
- package/lib/types/test-driver/index.d.ts.map +0 -1
- package/lib/types/test-driver/utils.d.ts.map +0 -1
- package/lib/types/togetherai/index.d.ts +0 -23
- package/lib/types/togetherai/index.d.ts.map +0 -1
- package/lib/types/togetherai/interfaces.d.ts.map +0 -1
- package/lib/types/vertexai/debug.d.ts +0 -2
- package/lib/types/vertexai/debug.d.ts.map +0 -1
- package/lib/types/vertexai/embeddings/embeddings-image.d.ts +0 -11
- package/lib/types/vertexai/embeddings/embeddings-image.d.ts.map +0 -1
- package/lib/types/vertexai/embeddings/embeddings-text.d.ts +0 -10
- package/lib/types/vertexai/embeddings/embeddings-text.d.ts.map +0 -1
- package/lib/types/vertexai/index.d.ts.map +0 -1
- package/lib/types/vertexai/models/claude.d.ts +0 -119
- package/lib/types/vertexai/models/claude.d.ts.map +0 -1
- package/lib/types/vertexai/models/gemini.d.ts.map +0 -1
- package/lib/types/vertexai/models/imagen.d.ts.map +0 -1
- package/lib/types/vertexai/models/llama.d.ts.map +0 -1
- package/lib/types/vertexai/models.d.ts +0 -20
- package/lib/types/vertexai/models.d.ts.map +0 -1
- package/lib/types/watsonx/index.d.ts.map +0 -1
- package/lib/types/watsonx/interfaces.d.ts.map +0 -1
- package/lib/types/xai/index.d.ts.map +0 -1
- package/src/vertexai/embeddings/embeddings-image.ts +0 -52
- package/src/vertexai/embeddings/embeddings-text.ts +0 -54
- /package/lib/{esm/bedrock → bedrock}/payloads.js +0 -0
- /package/lib/{esm/mistral → mistral}/types.js +0 -0
- /package/lib/{esm/togetherai → togetherai}/interfaces.js +0 -0
- /package/lib/{types/watsonx → watsonx}/interfaces.d.ts +0 -0
- /package/lib/{esm/watsonx → watsonx}/interfaces.js +0 -0
|
@@ -1,62 +1,92 @@
|
|
|
1
|
-
import { FinishReason, FunctionCallingConfigMode, HarmBlockThreshold, HarmCategory, Modality, ProminentPeople, ThinkingLevel } from
|
|
2
|
-
import { getConversationMeta, getGeminiModelVersion, incrementConversationTurn, isGeminiModelVersionGte, LlumiverseError, ModelType, PromptRole, readStreamAsBase64, stripBase64ImagesFromConversation, stripHeartbeatsFromConversation, truncateLargeTextInConversation, unwrapConversationArray } from
|
|
3
|
-
import { asyncMap } from
|
|
1
|
+
import { FinishReason, FunctionCallingConfigMode, HarmBlockThreshold, HarmCategory, Modality, ProminentPeople, ThinkingLevel, } from '@google/genai';
|
|
2
|
+
import { getConversationMeta, getGeminiModelVersion, incrementConversationTurn, isGeminiModelVersionGte, LlumiverseError, ModelType, PromptRole, readStreamAsBase64, stripBase64ImagesFromConversation, stripHeartbeatsFromConversation, truncateLargeTextInConversation, unwrapConversationArray, } from '@llumiverse/core';
|
|
3
|
+
import { asyncMap } from '@llumiverse/core/async';
|
|
4
|
+
import { truncateBinaryForDebug } from '../../shared/debug-prompt.js';
|
|
4
5
|
function supportsStructuredOutput(options) {
|
|
5
6
|
// Gemini 1.0 Ultra does not support JSON output, 1.0 Pro does.
|
|
6
|
-
return !!options.result_schema && !options.model.includes(
|
|
7
|
+
return !!options.result_schema && !options.model.includes('ultra');
|
|
7
8
|
}
|
|
8
9
|
const geminiSafetySettings = [
|
|
9
10
|
{
|
|
10
11
|
category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
|
|
11
|
-
threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH
|
|
12
|
+
threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH,
|
|
12
13
|
},
|
|
13
14
|
{
|
|
14
15
|
category: HarmCategory.HARM_CATEGORY_HARASSMENT,
|
|
15
|
-
threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH
|
|
16
|
+
threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH,
|
|
16
17
|
},
|
|
17
18
|
{
|
|
18
19
|
category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
|
|
19
|
-
threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH
|
|
20
|
+
threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH,
|
|
20
21
|
},
|
|
21
22
|
{
|
|
22
23
|
category: HarmCategory.HARM_CATEGORY_HATE_SPEECH,
|
|
23
|
-
threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH
|
|
24
|
+
threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH,
|
|
24
25
|
},
|
|
25
26
|
{
|
|
26
27
|
category: HarmCategory.HARM_CATEGORY_UNSPECIFIED,
|
|
27
|
-
threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH
|
|
28
|
+
threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH,
|
|
28
29
|
},
|
|
29
30
|
{
|
|
30
31
|
category: HarmCategory.HARM_CATEGORY_CIVIC_INTEGRITY,
|
|
31
|
-
threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH
|
|
32
|
-
}
|
|
32
|
+
threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH,
|
|
33
|
+
},
|
|
33
34
|
];
|
|
35
|
+
function formatGeminiContentForDebug(content) {
|
|
36
|
+
return {
|
|
37
|
+
...content,
|
|
38
|
+
parts: content.parts?.map((part) => {
|
|
39
|
+
if (!part.inlineData?.data) {
|
|
40
|
+
return part;
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
...part,
|
|
44
|
+
inlineData: {
|
|
45
|
+
...part.inlineData,
|
|
46
|
+
data: truncateBinaryForDebug(part.inlineData.data),
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export function formatGeminiDebugPrompt(prompt) {
|
|
53
|
+
return {
|
|
54
|
+
...prompt,
|
|
55
|
+
contents: prompt.contents.map(formatGeminiContentForDebug),
|
|
56
|
+
system: prompt.system ? formatGeminiContentForDebug(prompt.system) : undefined,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
34
59
|
// We do the mapping here rather than in common to avoid bringing the SDK into the common package.
|
|
35
60
|
function getProminentPeopleOption(prominentPeople) {
|
|
36
61
|
switch (prominentPeople) {
|
|
37
|
-
case
|
|
62
|
+
case 'ALLOW_PROMINENT_PEOPLE':
|
|
38
63
|
return ProminentPeople.ALLOW_PROMINENT_PEOPLE;
|
|
39
|
-
case
|
|
64
|
+
case 'BLOCK_PROMINENT_PEOPLE':
|
|
40
65
|
return ProminentPeople.BLOCK_PROMINENT_PEOPLE;
|
|
41
|
-
case
|
|
66
|
+
case 'PROMINENT_PEOPLE_UNSPECIFIED':
|
|
42
67
|
return ProminentPeople.PROMINENT_PEOPLE_UNSPECIFIED;
|
|
43
68
|
default:
|
|
44
69
|
return undefined;
|
|
45
70
|
}
|
|
46
71
|
}
|
|
47
|
-
function getGeminiPayload(options, prompt) {
|
|
72
|
+
export function getGeminiPayload(options, prompt) {
|
|
48
73
|
const model_options = options.model_options;
|
|
49
74
|
const tools = getToolDefinitions(options.tools);
|
|
50
75
|
// When no tools are provided but conversation contains functionCall/functionResponse parts
|
|
51
76
|
// (e.g. checkpoint summary calls), convert them to text to avoid API errors.
|
|
52
77
|
// Use a local variable to avoid mutating the caller's conversation object.
|
|
53
|
-
let payloadContents = prompt.contents;
|
|
78
|
+
let payloadContents = mergeConsecutiveRole(prompt.contents);
|
|
54
79
|
if (!tools && payloadContents) {
|
|
55
|
-
const hasToolParts = payloadContents.some(c => c.parts?.some(p => p.functionCall || p.functionResponse));
|
|
80
|
+
const hasToolParts = payloadContents.some((c) => c.parts?.some((p) => p.functionCall || p.functionResponse));
|
|
56
81
|
if (hasToolParts) {
|
|
57
82
|
payloadContents = convertGeminiFunctionPartsToText(payloadContents);
|
|
58
83
|
}
|
|
59
84
|
}
|
|
85
|
+
// Drop functionResponse parts whose functionCall was lost (e.g. compaction),
|
|
86
|
+
// which would otherwise trip Gemini's functionCall/functionResponse pairing.
|
|
87
|
+
if (payloadContents) {
|
|
88
|
+
payloadContents = fixOrphanedToolResults(payloadContents);
|
|
89
|
+
}
|
|
60
90
|
const useStructuredOutput = supportsStructuredOutput(options) && !tools;
|
|
61
91
|
const configNanoBanana = {
|
|
62
92
|
systemInstruction: prompt.system,
|
|
@@ -77,20 +107,22 @@ function getGeminiPayload(options, prompt) {
|
|
|
77
107
|
prominentPeople: getProminentPeopleOption(model_options?.prominent_people),
|
|
78
108
|
outputMimeType: model_options?.output_mime_type,
|
|
79
109
|
outputCompressionQuality: model_options?.output_compression_quality,
|
|
80
|
-
}
|
|
110
|
+
},
|
|
81
111
|
};
|
|
82
112
|
const config = {
|
|
83
113
|
systemInstruction: prompt.system,
|
|
84
114
|
safetySettings: geminiSafetySettings,
|
|
85
115
|
tools: tools ? [tools] : undefined,
|
|
86
|
-
toolConfig: tools
|
|
87
|
-
|
|
88
|
-
|
|
116
|
+
toolConfig: tools
|
|
117
|
+
? {
|
|
118
|
+
functionCallingConfig: {
|
|
119
|
+
mode: FunctionCallingConfigMode.AUTO,
|
|
120
|
+
},
|
|
89
121
|
}
|
|
90
|
-
|
|
122
|
+
: undefined,
|
|
91
123
|
candidateCount: 1,
|
|
92
124
|
//JSON/Structured output
|
|
93
|
-
responseMimeType: useStructuredOutput ?
|
|
125
|
+
responseMimeType: useStructuredOutput ? 'application/json' : undefined,
|
|
94
126
|
responseJsonSchema: useStructuredOutput ? options.result_schema : undefined,
|
|
95
127
|
//Model options
|
|
96
128
|
temperature: model_options?.temperature,
|
|
@@ -107,7 +139,7 @@ function getGeminiPayload(options, prompt) {
|
|
|
107
139
|
return {
|
|
108
140
|
model: options.model,
|
|
109
141
|
contents: payloadContents,
|
|
110
|
-
config: options.model.toLowerCase().includes(
|
|
142
|
+
config: options.model.toLowerCase().includes('image') ? configNanoBanana : config,
|
|
111
143
|
};
|
|
112
144
|
}
|
|
113
145
|
/**
|
|
@@ -121,17 +153,17 @@ function extractCompletionResults(content) {
|
|
|
121
153
|
for (const part of parts) {
|
|
122
154
|
if (part.text) {
|
|
123
155
|
results.push({
|
|
124
|
-
type:
|
|
125
|
-
value: part.text
|
|
156
|
+
type: 'text',
|
|
157
|
+
value: part.text,
|
|
126
158
|
});
|
|
127
159
|
}
|
|
128
160
|
else if (part.inlineData) {
|
|
129
|
-
const base64ImageBytes = part.inlineData.data ??
|
|
130
|
-
const mimeType = part.inlineData.mimeType ??
|
|
161
|
+
const base64ImageBytes = part.inlineData.data ?? '';
|
|
162
|
+
const mimeType = part.inlineData.mimeType ?? 'image/png';
|
|
131
163
|
const imageUrl = `data:${mimeType};base64,${base64ImageBytes}`;
|
|
132
164
|
results.push({
|
|
133
|
-
type:
|
|
134
|
-
value: imageUrl
|
|
165
|
+
type: 'image',
|
|
166
|
+
value: imageUrl,
|
|
135
167
|
});
|
|
136
168
|
}
|
|
137
169
|
}
|
|
@@ -182,6 +214,49 @@ export function mergeConsecutiveRole(contents) {
|
|
|
182
214
|
result.push(currentContent);
|
|
183
215
|
return result;
|
|
184
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* Drop functionResponse parts whose name has no matching functionCall in the
|
|
219
|
+
* immediately-preceding `model` content. Gemini pairs a functionResponse to its
|
|
220
|
+
* functionCall by name; a response left dangling after its call was dropped
|
|
221
|
+
* (e.g. by conversation compaction/trimming, or an unmergeable parallel batch)
|
|
222
|
+
* causes the API to reject the request. Mirrors the same guard added to the
|
|
223
|
+
* Claude, Bedrock, and OpenAI drivers.
|
|
224
|
+
*
|
|
225
|
+
* Run after mergeConsecutiveRole so parallel responses that were split across
|
|
226
|
+
* user contents are first recombined under the model turn that issued the calls,
|
|
227
|
+
* and are therefore not mistaken for orphans.
|
|
228
|
+
*/
|
|
229
|
+
export function fixOrphanedToolResults(contents) {
|
|
230
|
+
if (contents.length === 0)
|
|
231
|
+
return contents;
|
|
232
|
+
const result = [];
|
|
233
|
+
for (let i = 0; i < contents.length; i++) {
|
|
234
|
+
const content = contents[i];
|
|
235
|
+
if (content.role !== 'user' || !content.parts) {
|
|
236
|
+
result.push(content);
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const hasFunctionResponse = content.parts.some((part) => part.functionResponse);
|
|
240
|
+
if (!hasFunctionResponse) {
|
|
241
|
+
result.push(content);
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
const prev = contents[i - 1];
|
|
245
|
+
const allowedNames = new Set();
|
|
246
|
+
if (prev && prev.role === 'model' && prev.parts) {
|
|
247
|
+
for (const part of prev.parts) {
|
|
248
|
+
if (part.functionCall?.name)
|
|
249
|
+
allowedNames.add(part.functionCall.name);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const filtered = content.parts.filter((part) => part.functionResponse ? allowedNames.has(part.functionResponse.name ?? '') : true);
|
|
253
|
+
// Drop the content if every part was an orphaned functionResponse.
|
|
254
|
+
if (filtered.length === 0)
|
|
255
|
+
continue;
|
|
256
|
+
result.push(filtered.length === content.parts.length ? content : { ...content, parts: filtered });
|
|
257
|
+
}
|
|
258
|
+
return result;
|
|
259
|
+
}
|
|
185
260
|
const supportedFinishReasons = [
|
|
186
261
|
FinishReason.MAX_TOKENS,
|
|
187
262
|
FinishReason.STOP,
|
|
@@ -205,7 +280,7 @@ function geminiThinkingBudget(option) {
|
|
|
205
280
|
// Set minimum thinking level by default.
|
|
206
281
|
// Docs: https://ai.google.dev/gemini-api/docs/thinking#set-budget
|
|
207
282
|
if (getGeminiModelVersion(option.model) === '2.5') {
|
|
208
|
-
if (option.model.includes(
|
|
283
|
+
if (option.model.includes('pro')) {
|
|
209
284
|
return 128;
|
|
210
285
|
}
|
|
211
286
|
return 0;
|
|
@@ -213,28 +288,28 @@ function geminiThinkingBudget(option) {
|
|
|
213
288
|
return undefined;
|
|
214
289
|
}
|
|
215
290
|
function geminiThinkingLevelForEffort(model, effort) {
|
|
216
|
-
if (model.includes(
|
|
291
|
+
if (model.includes('gemini-3-pro-image')) {
|
|
217
292
|
return ThinkingLevel.HIGH;
|
|
218
293
|
}
|
|
219
|
-
if (model.includes(
|
|
220
|
-
return effort ===
|
|
294
|
+
if (model.includes('gemini-3.1-flash-image')) {
|
|
295
|
+
return effort === 'low' ? ThinkingLevel.MINIMAL : ThinkingLevel.HIGH;
|
|
221
296
|
}
|
|
222
297
|
switch (effort) {
|
|
223
|
-
case
|
|
298
|
+
case 'low':
|
|
224
299
|
return ThinkingLevel.LOW;
|
|
225
|
-
case
|
|
300
|
+
case 'medium':
|
|
226
301
|
return ThinkingLevel.MEDIUM;
|
|
227
|
-
case
|
|
302
|
+
case 'high':
|
|
228
303
|
return ThinkingLevel.HIGH;
|
|
229
304
|
default:
|
|
230
305
|
return undefined;
|
|
231
306
|
}
|
|
232
307
|
}
|
|
233
308
|
function geminiBudgetForEffort(model, effort) {
|
|
234
|
-
const isFlashLite = model.includes(
|
|
235
|
-
const isFlash = model.includes(
|
|
236
|
-
const isPro = model.includes(
|
|
237
|
-
if (effort ===
|
|
309
|
+
const isFlashLite = model.includes('flash-lite');
|
|
310
|
+
const isFlash = model.includes('flash') && !isFlashLite;
|
|
311
|
+
const isPro = model.includes('pro');
|
|
312
|
+
if (effort === 'low') {
|
|
238
313
|
if (isPro)
|
|
239
314
|
return 128;
|
|
240
315
|
if (isFlashLite)
|
|
@@ -243,7 +318,7 @@ function geminiBudgetForEffort(model, effort) {
|
|
|
243
318
|
return 1;
|
|
244
319
|
return 1024;
|
|
245
320
|
}
|
|
246
|
-
if (effort ===
|
|
321
|
+
if (effort === 'medium') {
|
|
247
322
|
return 8192;
|
|
248
323
|
}
|
|
249
324
|
if (isPro)
|
|
@@ -281,14 +356,14 @@ function geminiThinkingConfig(option) {
|
|
|
281
356
|
if (isGeminiModelVersionGte(option.model, '3.0')) {
|
|
282
357
|
return {
|
|
283
358
|
includeThoughts: include_thoughts,
|
|
284
|
-
thinkingLevel: option.model.includes(
|
|
359
|
+
thinkingLevel: option.model.includes('gemini-3-pro-image') ? ThinkingLevel.HIGH : ThinkingLevel.LOW,
|
|
285
360
|
};
|
|
286
361
|
}
|
|
287
362
|
if (isGeminiModelVersionGte(option.model, '2.5')) {
|
|
288
363
|
const thinking_budget_tokens = geminiThinkingBudget(option) ?? 0;
|
|
289
364
|
return {
|
|
290
365
|
includeThoughts: include_thoughts,
|
|
291
|
-
thinkingBudget: thinking_budget_tokens
|
|
366
|
+
thinkingBudget: thinking_budget_tokens,
|
|
292
367
|
};
|
|
293
368
|
}
|
|
294
369
|
}
|
|
@@ -300,33 +375,33 @@ export class GeminiModelDefinition {
|
|
|
300
375
|
name: modelId,
|
|
301
376
|
provider: 'vertexai',
|
|
302
377
|
type: ModelType.Text,
|
|
303
|
-
can_stream: true
|
|
378
|
+
can_stream: true,
|
|
304
379
|
};
|
|
305
380
|
}
|
|
306
381
|
async createPrompt(_driver, segments, options) {
|
|
307
|
-
const splits = options.model.split(
|
|
382
|
+
const splits = options.model.split('/');
|
|
308
383
|
const modelName = splits[splits.length - 1];
|
|
309
384
|
options = { ...options, model: modelName };
|
|
310
385
|
const schema = options.result_schema;
|
|
311
386
|
let contents = [];
|
|
312
|
-
let system = { role:
|
|
387
|
+
let system = { role: 'user', parts: [] }; // Single content block for system messages
|
|
313
388
|
const safety = [];
|
|
314
389
|
for (const msg of segments) {
|
|
315
390
|
// Role specific handling
|
|
316
391
|
if (msg.role === PromptRole.system) {
|
|
317
392
|
// Text only for system messages
|
|
318
393
|
if (msg.files && msg.files.length > 0) {
|
|
319
|
-
throw new Error(
|
|
394
|
+
throw new Error('Gemini does not support files/images etc. in system messages. Only text content is allowed.');
|
|
320
395
|
}
|
|
321
396
|
if (msg.content) {
|
|
322
397
|
system.parts?.push({
|
|
323
|
-
text: msg.content
|
|
398
|
+
text: msg.content,
|
|
324
399
|
});
|
|
325
400
|
}
|
|
326
401
|
}
|
|
327
402
|
else if (msg.role === PromptRole.tool) {
|
|
328
403
|
if (!msg.tool_use_id) {
|
|
329
|
-
throw new Error(
|
|
404
|
+
throw new Error('Tool response missing tool_use_id');
|
|
330
405
|
}
|
|
331
406
|
// Build functionResponse part with optional thought_signature for Gemini thinking models
|
|
332
407
|
const functionResponsePart = {
|
|
@@ -339,10 +414,11 @@ export class GeminiModelDefinition {
|
|
|
339
414
|
};
|
|
340
415
|
contents.push({
|
|
341
416
|
role: 'user',
|
|
342
|
-
parts: [functionResponsePart]
|
|
417
|
+
parts: [functionResponsePart],
|
|
343
418
|
});
|
|
344
419
|
}
|
|
345
|
-
else {
|
|
420
|
+
else {
|
|
421
|
+
// PromptRole.user, PromptRole.assistant, PromptRole.safety
|
|
346
422
|
const parts = [];
|
|
347
423
|
// Text content handling
|
|
348
424
|
if (msg.content) {
|
|
@@ -353,14 +429,14 @@ export class GeminiModelDefinition {
|
|
|
353
429
|
// File content handling
|
|
354
430
|
if (msg.files) {
|
|
355
431
|
for (const f of msg.files) {
|
|
356
|
-
const
|
|
357
|
-
const
|
|
358
|
-
if (
|
|
432
|
+
const fileUri = await f.getURI();
|
|
433
|
+
const isGsUri = fileUri.startsWith('gs://') || fileUri.startsWith('https://storage.googleapis.com/');
|
|
434
|
+
if (isGsUri) {
|
|
359
435
|
parts.push({
|
|
360
436
|
fileData: {
|
|
361
|
-
fileUri
|
|
362
|
-
mimeType: f.mime_type
|
|
363
|
-
}
|
|
437
|
+
fileUri,
|
|
438
|
+
mimeType: f.mime_type,
|
|
439
|
+
},
|
|
364
440
|
});
|
|
365
441
|
}
|
|
366
442
|
else {
|
|
@@ -370,8 +446,8 @@ export class GeminiModelDefinition {
|
|
|
370
446
|
parts.push({
|
|
371
447
|
inlineData: {
|
|
372
448
|
data,
|
|
373
|
-
mimeType: f.mime_type
|
|
374
|
-
}
|
|
449
|
+
mimeType: f.mime_type,
|
|
450
|
+
},
|
|
375
451
|
});
|
|
376
452
|
}
|
|
377
453
|
}
|
|
@@ -397,17 +473,19 @@ export class GeminiModelDefinition {
|
|
|
397
473
|
if (supportsStructuredOutput(options) && !options.tools) {
|
|
398
474
|
// Gemini structured output is unnecessarily sparse. Adding encouragement to fill the fields.
|
|
399
475
|
// Putting JSON in prompt is not recommended by Google, when using structured output.
|
|
400
|
-
system.parts?.push({ text:
|
|
476
|
+
system.parts?.push({ text: 'Fill all appropriate fields in the JSON output.' });
|
|
401
477
|
}
|
|
402
478
|
else {
|
|
403
479
|
// Fallback to putting the schema in the system instructions, if not using structured output.
|
|
404
480
|
if (options.tools) {
|
|
405
481
|
system.parts?.push({
|
|
406
|
-
text:
|
|
482
|
+
text: `When not calling tools, the output must be a JSON object using the following JSON Schema:\n${JSON.stringify(schema)}`,
|
|
407
483
|
});
|
|
408
484
|
}
|
|
409
485
|
else {
|
|
410
|
-
system.parts?.push({
|
|
486
|
+
system.parts?.push({
|
|
487
|
+
text: `The output must be a JSON object using the following JSON Schema:\n${JSON.stringify(schema)}`,
|
|
488
|
+
});
|
|
411
489
|
}
|
|
412
490
|
}
|
|
413
491
|
}
|
|
@@ -423,8 +501,8 @@ export class GeminiModelDefinition {
|
|
|
423
501
|
contents = mergeConsecutiveRole(contents);
|
|
424
502
|
return { contents, system };
|
|
425
503
|
}
|
|
426
|
-
usageMetadataToTokenUsage(usageMetadata) {
|
|
427
|
-
if (!usageMetadata
|
|
504
|
+
usageMetadataToTokenUsage(driver, usageMetadata) {
|
|
505
|
+
if (!usageMetadata?.totalTokenCount) {
|
|
428
506
|
return {};
|
|
429
507
|
}
|
|
430
508
|
const tokenUsage = {
|
|
@@ -434,15 +512,16 @@ export class GeminiModelDefinition {
|
|
|
434
512
|
prompt_new: (usageMetadata.promptTokenCount ?? 0) - (usageMetadata.cachedContentTokenCount ?? 0),
|
|
435
513
|
};
|
|
436
514
|
//Output/Response side
|
|
437
|
-
tokenUsage.result =
|
|
438
|
-
|
|
439
|
-
|
|
515
|
+
tokenUsage.result =
|
|
516
|
+
(usageMetadata.candidatesTokenCount ?? 0) +
|
|
517
|
+
(usageMetadata.thoughtsTokenCount ?? 0) +
|
|
518
|
+
(usageMetadata.toolUsePromptTokenCount ?? 0);
|
|
440
519
|
if ((tokenUsage.total ?? 0) !== (tokenUsage.prompt ?? 0) + tokenUsage.result) {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
});
|
|
520
|
+
// Token-accounting mismatch: warn-level diagnostic (the call still
|
|
521
|
+
// returns the best-effort tokenUsage). Use the driver's structured
|
|
522
|
+
// logger so we don't promote stderr writes to ERROR in serverless
|
|
523
|
+
// log aggregators — see the recoverable-tool-call sites below.
|
|
524
|
+
driver.logger.warn({ total: tokenUsage.total, prompt: tokenUsage.prompt, result: tokenUsage.result }, '[VertexAI] Gemini token usage mismatch: total does not equal prompt + result');
|
|
446
525
|
}
|
|
447
526
|
if (!tokenUsage.result) {
|
|
448
527
|
tokenUsage.result = undefined; // If no result, mark as undefined
|
|
@@ -450,9 +529,9 @@ export class GeminiModelDefinition {
|
|
|
450
529
|
return tokenUsage;
|
|
451
530
|
}
|
|
452
531
|
async requestTextCompletion(driver, prompt, options) {
|
|
453
|
-
const splits = options.model.split(
|
|
454
|
-
let region
|
|
455
|
-
if (splits[0] ===
|
|
532
|
+
const splits = options.model.split('/');
|
|
533
|
+
let region;
|
|
534
|
+
if (splits[0] === 'locations' && splits.length >= 2) {
|
|
456
535
|
region = splits[1];
|
|
457
536
|
}
|
|
458
537
|
const modelName = splits[splits.length - 1];
|
|
@@ -468,49 +547,55 @@ export class GeminiModelDefinition {
|
|
|
468
547
|
let conversation = updateConversation(options.conversation, prompt.contents);
|
|
469
548
|
prompt.contents = conversation;
|
|
470
549
|
// TODO: Remove hack, use global endpoint manually if needed.
|
|
471
|
-
if (options.model.includes(
|
|
472
|
-
region =
|
|
550
|
+
if (options.model.includes('gemini-2.5-flash-image')) {
|
|
551
|
+
region = 'global'; // Gemini Flash Image only available in global region, this is for nano-banana model
|
|
473
552
|
}
|
|
474
553
|
const model_options = options.model_options;
|
|
475
|
-
const client = driver.getGoogleGenAIClient(region, model_options?.flex ?? false);
|
|
554
|
+
const client = driver.getGoogleGenAIClient(region, model_options?.flex ?? false, options.httpTimeout);
|
|
476
555
|
const payload = getGeminiPayload(options, prompt);
|
|
477
556
|
const response = await client.models.generateContent(payload);
|
|
478
|
-
const token_usage = this.usageMetadataToTokenUsage(response.usageMetadata);
|
|
557
|
+
const token_usage = this.usageMetadataToTokenUsage(driver, response.usageMetadata);
|
|
479
558
|
let tool_use;
|
|
480
559
|
let finish_reason, result;
|
|
481
|
-
const candidate = response.candidates
|
|
560
|
+
const candidate = response.candidates?.[0];
|
|
482
561
|
if (candidate) {
|
|
483
562
|
switch (candidate.finishReason) {
|
|
484
563
|
case FinishReason.MAX_TOKENS:
|
|
485
|
-
finish_reason =
|
|
564
|
+
finish_reason = 'length';
|
|
486
565
|
break;
|
|
487
566
|
case FinishReason.STOP:
|
|
488
|
-
finish_reason =
|
|
567
|
+
finish_reason = 'stop';
|
|
489
568
|
break;
|
|
490
|
-
default:
|
|
569
|
+
default:
|
|
570
|
+
finish_reason = candidate.finishReason;
|
|
491
571
|
}
|
|
492
572
|
const content = candidate.content;
|
|
493
573
|
// Check for unsupported finish reasons, but allow recoverable tool call issues
|
|
494
574
|
const isRecoverableToolCall = recoverableToolCallReasons.includes(candidate.finishReason);
|
|
495
|
-
if (candidate.finishReason &&
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
575
|
+
if (candidate.finishReason &&
|
|
576
|
+
!supportedFinishReasons.includes(candidate.finishReason) &&
|
|
577
|
+
!isRecoverableToolCall) {
|
|
578
|
+
throw new Error(`Unsupported finish reason: ${candidate.finishReason}, ` +
|
|
579
|
+
`finish message: ${candidate.finishMessage}, ` +
|
|
580
|
+
`content: ${JSON.stringify(content, null, 2)}, safety: ${JSON.stringify(candidate.safetyRatings, null, 2)}`);
|
|
499
581
|
}
|
|
500
582
|
if (content) {
|
|
501
583
|
tool_use = collectToolUseParts(content);
|
|
502
584
|
// For recoverable tool call issues, log warning but continue processing
|
|
503
|
-
// The workflow will handle the invalid tool call gracefully
|
|
585
|
+
// The workflow will handle the invalid tool call gracefully.
|
|
586
|
+
// Route through the driver's structured logger instead of `console.warn`
|
|
587
|
+
// so downstream runtimes (e.g. Cloud Run) don't promote stderr writes
|
|
588
|
+
// to ERROR severity for what is, by definition, a recoverable event.
|
|
504
589
|
if (isRecoverableToolCall && tool_use && tool_use.length > 0) {
|
|
505
|
-
|
|
506
|
-
`Model tried to call undeclared tool(s): ${tool_use.map(t => t.tool_name).join(', ')}`);
|
|
590
|
+
driver.logger.warn(`[Gemini] Recoverable tool call issue (${candidate.finishReason}): ` +
|
|
591
|
+
`Model tried to call undeclared tool(s): ${tool_use.map((t) => t.tool_name).join(', ')}`);
|
|
507
592
|
}
|
|
508
593
|
result = extractCompletionResults(content);
|
|
509
594
|
conversation = updateConversation(conversation, [content]);
|
|
510
595
|
}
|
|
511
596
|
}
|
|
512
597
|
if (tool_use) {
|
|
513
|
-
finish_reason =
|
|
598
|
+
finish_reason = 'tool_use';
|
|
514
599
|
}
|
|
515
600
|
// Increment turn counter for deferred stripping
|
|
516
601
|
conversation = incrementConversationTurn(conversation);
|
|
@@ -519,7 +604,7 @@ export class GeminiModelDefinition {
|
|
|
519
604
|
const stripOptions = {
|
|
520
605
|
keepForTurns: options.stripImagesAfterTurns ?? Infinity,
|
|
521
606
|
currentTurn,
|
|
522
|
-
textMaxTokens: options.stripTextMaxTokens
|
|
607
|
+
textMaxTokens: options.stripTextMaxTokens,
|
|
523
608
|
};
|
|
524
609
|
let processedConversation = stripBase64ImagesFromConversation(conversation, stripOptions);
|
|
525
610
|
// Truncate large text content if configured
|
|
@@ -532,18 +617,18 @@ export class GeminiModelDefinition {
|
|
|
532
617
|
// Preserve system instruction in conversation for multi-turn support
|
|
533
618
|
const finalConversation = storeSystemInConversation(processedConversation, prompt.system);
|
|
534
619
|
return {
|
|
535
|
-
result: result && result.length > 0 ? result : [{ type:
|
|
620
|
+
result: result && result.length > 0 ? result : [{ type: 'text', value: '' }],
|
|
536
621
|
token_usage: token_usage,
|
|
537
622
|
finish_reason: finish_reason,
|
|
538
623
|
original_response: options.include_original_response ? response : undefined,
|
|
539
624
|
conversation: finalConversation,
|
|
540
|
-
tool_use
|
|
625
|
+
tool_use,
|
|
541
626
|
};
|
|
542
627
|
}
|
|
543
628
|
async requestTextCompletionStream(driver, prompt, options) {
|
|
544
|
-
const splits = options.model.split(
|
|
545
|
-
let region
|
|
546
|
-
if (splits[0] ===
|
|
629
|
+
const splits = options.model.split('/');
|
|
630
|
+
let region;
|
|
631
|
+
if (splits[0] === 'locations' && splits.length >= 2) {
|
|
547
632
|
region = splits[1];
|
|
548
633
|
}
|
|
549
634
|
const modelName = splits[splits.length - 1];
|
|
@@ -559,45 +644,51 @@ export class GeminiModelDefinition {
|
|
|
559
644
|
// Include conversation history in prompt contents (same as non-streaming)
|
|
560
645
|
const conversation = updateConversation(options.conversation, prompt.contents);
|
|
561
646
|
prompt.contents = conversation;
|
|
562
|
-
if (options.model.includes(
|
|
563
|
-
region =
|
|
647
|
+
if (options.model.includes('gemini-2.5-flash-image')) {
|
|
648
|
+
region = 'global'; // Gemini Flash Image only available in global region, this is for nano-banana model
|
|
564
649
|
}
|
|
565
650
|
const model_options = options.model_options;
|
|
566
|
-
const client = driver.getGoogleGenAIClient(region, model_options?.flex ?? false);
|
|
651
|
+
const client = driver.getGoogleGenAIClient(region, model_options?.flex ?? false, options.httpTimeout);
|
|
567
652
|
const payload = getGeminiPayload(options, prompt);
|
|
568
653
|
const response = await client.models.generateContentStream(payload);
|
|
569
654
|
const stream = asyncMap(response, async (item) => {
|
|
570
|
-
const token_usage = this.usageMetadataToTokenUsage(item.usageMetadata);
|
|
655
|
+
const token_usage = this.usageMetadataToTokenUsage(driver, item.usageMetadata);
|
|
571
656
|
if (item.candidates && item.candidates.length > 0) {
|
|
572
657
|
for (const candidate of item.candidates) {
|
|
573
658
|
let tool_use;
|
|
574
659
|
let finish_reason;
|
|
575
660
|
switch (candidate.finishReason) {
|
|
576
661
|
case FinishReason.MAX_TOKENS:
|
|
577
|
-
finish_reason =
|
|
662
|
+
finish_reason = 'length';
|
|
578
663
|
break;
|
|
579
664
|
case FinishReason.STOP:
|
|
580
|
-
finish_reason =
|
|
665
|
+
finish_reason = 'stop';
|
|
581
666
|
break;
|
|
582
|
-
default:
|
|
667
|
+
default:
|
|
668
|
+
finish_reason = candidate.finishReason;
|
|
583
669
|
}
|
|
584
670
|
// Check for unsupported finish reasons, but allow recoverable tool call issues
|
|
585
671
|
const isRecoverableToolCall = recoverableToolCallReasons.includes(candidate.finishReason);
|
|
586
|
-
if (candidate.finishReason &&
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
672
|
+
if (candidate.finishReason &&
|
|
673
|
+
!supportedFinishReasons.includes(candidate.finishReason) &&
|
|
674
|
+
!isRecoverableToolCall) {
|
|
675
|
+
throw new Error(`Unsupported finish reason: ${candidate.finishReason}, ` +
|
|
676
|
+
`finish message: ${candidate.finishMessage}, ` +
|
|
677
|
+
`content: ${JSON.stringify(candidate.content, null, 2)}, safety: ${JSON.stringify(candidate.safetyRatings, null, 2)}`);
|
|
590
678
|
}
|
|
591
679
|
if (candidate.content?.role === 'model') {
|
|
592
680
|
// Collect all parts in order (text and images)
|
|
593
681
|
const combinedResults = extractCompletionResults(candidate.content);
|
|
594
682
|
tool_use = collectToolUseParts(candidate.content);
|
|
595
683
|
if (tool_use) {
|
|
596
|
-
finish_reason =
|
|
597
|
-
// Log warning for recoverable tool call issues
|
|
684
|
+
finish_reason = 'tool_use';
|
|
685
|
+
// Log warning for recoverable tool call issues — see the
|
|
686
|
+
// matching site in `requestTextCompletion` above for why
|
|
687
|
+
// we route through the driver's logger instead of
|
|
688
|
+
// `console.warn`.
|
|
598
689
|
if (isRecoverableToolCall) {
|
|
599
|
-
|
|
600
|
-
`Model tried to call undeclared tool(s): ${tool_use.map(t => t.tool_name).join(', ')}`);
|
|
690
|
+
driver.logger.warn(`[Gemini] Recoverable tool call issue (${candidate.finishReason}): ` +
|
|
691
|
+
`Model tried to call undeclared tool(s): ${tool_use.map((t) => t.tool_name).join(', ')}`);
|
|
601
692
|
}
|
|
602
693
|
}
|
|
603
694
|
return {
|
|
@@ -611,8 +702,10 @@ export class GeminiModelDefinition {
|
|
|
611
702
|
}
|
|
612
703
|
//No normal output, returning block reason if it exists.
|
|
613
704
|
return {
|
|
614
|
-
result: item.promptFeedback?.blockReasonMessage
|
|
615
|
-
|
|
705
|
+
result: item.promptFeedback?.blockReasonMessage
|
|
706
|
+
? [{ type: 'text', value: item.promptFeedback.blockReasonMessage }]
|
|
707
|
+
: [],
|
|
708
|
+
finish_reason: item.promptFeedback?.blockReason ?? '',
|
|
616
709
|
token_usage: token_usage,
|
|
617
710
|
};
|
|
618
711
|
});
|
|
@@ -649,7 +742,7 @@ export class GeminiModelDefinition {
|
|
|
649
742
|
const apiError = error;
|
|
650
743
|
const httpStatusCode = apiError.status;
|
|
651
744
|
// Extract error message
|
|
652
|
-
const message = apiError.message
|
|
745
|
+
const message = apiError.message;
|
|
653
746
|
// Build user-facing message with status code
|
|
654
747
|
let userMessage = message;
|
|
655
748
|
// Include status code in message (for end-user visibility)
|
|
@@ -657,7 +750,7 @@ export class GeminiModelDefinition {
|
|
|
657
750
|
userMessage = `[${httpStatusCode}] ${userMessage}`;
|
|
658
751
|
}
|
|
659
752
|
// Determine retryability based on Google error codes
|
|
660
|
-
const retryable = this.isGeminiErrorRetryable(httpStatusCode);
|
|
753
|
+
const retryable = this.isGeminiErrorRetryable(httpStatusCode, message);
|
|
661
754
|
// Extract error name/type from message if present
|
|
662
755
|
const errorName = this.extractErrorName(message);
|
|
663
756
|
return new LlumiverseError(`[${context.provider}] ${userMessage}`, retryable, context, error, httpStatusCode, errorName);
|
|
@@ -670,13 +763,15 @@ export class GeminiModelDefinition {
|
|
|
670
763
|
typeof error === 'object' &&
|
|
671
764
|
'status' in error &&
|
|
672
765
|
typeof error.status === 'number' &&
|
|
673
|
-
'message' in error
|
|
766
|
+
'message' in error &&
|
|
767
|
+
typeof error.message === 'string');
|
|
674
768
|
}
|
|
675
769
|
/**
|
|
676
770
|
* Determine if a Google API error is retryable based on HTTP status code.
|
|
677
771
|
*
|
|
678
772
|
* Retryable errors (per Google AIP-194):
|
|
679
773
|
* - 408 (REQUEST_TIMEOUT): Request timeout
|
|
774
|
+
* - 499 (CANCELLED / Client Closed Request): Transport cancellation
|
|
680
775
|
* - 429 (RESOURCE_EXHAUSTED): Rate limit exceeded, quota exhausted
|
|
681
776
|
* - 500 (INTERNAL): Internal server error
|
|
682
777
|
* - 502 (BAD_GATEWAY): Bad gateway
|
|
@@ -691,15 +786,26 @@ export class GeminiModelDefinition {
|
|
|
691
786
|
* - 409 (CONFLICT): Resource conflict
|
|
692
787
|
* - Other 4xx client errors
|
|
693
788
|
*
|
|
789
|
+
* Exception: certain 400s from Vertex AI's inline URL fetcher (used when
|
|
790
|
+
* passing a file by URL to multimodal models) surface as INVALID_ARGUMENT
|
|
791
|
+
* but are actually transient throttling/rate-limit signals on the
|
|
792
|
+
* fetcher, not a bad request. Detect those by message substring and
|
|
793
|
+
* treat them as retryable.
|
|
794
|
+
*
|
|
694
795
|
* @param httpStatusCode - The HTTP status code from the API error
|
|
796
|
+
* @param message - The error message (used to detect transient 400 sub-cases)
|
|
695
797
|
* @returns True if retryable, false if not retryable, undefined if unknown
|
|
696
798
|
*/
|
|
697
|
-
isGeminiErrorRetryable(httpStatusCode) {
|
|
799
|
+
isGeminiErrorRetryable(httpStatusCode, message) {
|
|
800
|
+
if (message && this.isNonRetryableAuthError(message))
|
|
801
|
+
return false;
|
|
698
802
|
// Retryable status codes
|
|
699
803
|
if (httpStatusCode === 408)
|
|
700
804
|
return true; // Request timeout
|
|
701
805
|
if (httpStatusCode === 429)
|
|
702
806
|
return true; // Rate limit/quota
|
|
807
|
+
if (httpStatusCode === 499)
|
|
808
|
+
return true; // Client closed / operation cancelled
|
|
703
809
|
if (httpStatusCode === 502)
|
|
704
810
|
return true; // Bad gateway
|
|
705
811
|
if (httpStatusCode === 503)
|
|
@@ -708,12 +814,32 @@ export class GeminiModelDefinition {
|
|
|
708
814
|
return true; // Gateway timeout
|
|
709
815
|
if (httpStatusCode >= 500 && httpStatusCode < 600)
|
|
710
816
|
return true; // Other 5xx server errors
|
|
817
|
+
// Vertex AI URL fetcher transient throttling, surfaced as 400 INVALID_ARGUMENT
|
|
818
|
+
// but really a Google-side rate limit on the inline-content fetcher.
|
|
819
|
+
if (httpStatusCode === 400 && message) {
|
|
820
|
+
if (message.includes('URL_REJECTED-REJECTED_CLIENT_THROTTLED') ||
|
|
821
|
+
message.includes('URL_REJECTED-REJECTED_RATE_LIMITED')) {
|
|
822
|
+
return true;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
// A transport-level abort/cancel (request-timeout / dropped connection, sometimes reported
|
|
826
|
+
// as 499 client-closed) or a deadline-exceeded is transient and should be retried,
|
|
827
|
+
// even though it carries a 4xx status. Honor it before the 4xx -> non-retryable rule.
|
|
828
|
+
if (message) {
|
|
829
|
+
const lower = message.toLowerCase();
|
|
830
|
+
if (lower.includes('aborted') || lower.includes('cancelled') || lower.includes('deadline'))
|
|
831
|
+
return true;
|
|
832
|
+
}
|
|
711
833
|
// Non-retryable 4xx client errors
|
|
712
834
|
if (httpStatusCode >= 400 && httpStatusCode < 500)
|
|
713
835
|
return false;
|
|
714
836
|
// Unknown status codes - let consumer decide retry strategy
|
|
715
837
|
return undefined;
|
|
716
838
|
}
|
|
839
|
+
isNonRetryableAuthError(message) {
|
|
840
|
+
const lowerMessage = message.toLowerCase();
|
|
841
|
+
return lowerMessage.includes('invalid_grant') || lowerMessage.includes("credential's issuer");
|
|
842
|
+
}
|
|
717
843
|
/**
|
|
718
844
|
* Extract error type name from error message.
|
|
719
845
|
* Google errors often include the error type in the message.
|
|
@@ -722,6 +848,7 @@ export class GeminiModelDefinition {
|
|
|
722
848
|
extractErrorName(message) {
|
|
723
849
|
// Common Google error patterns
|
|
724
850
|
const patterns = [
|
|
851
|
+
/^Error code ([a-zA-Z0-9_-]+):/, // "Error code invalid_grant: message"
|
|
725
852
|
/^([A-Z_]+):/, // "ERROR_NAME: message"
|
|
726
853
|
/\[([A-Z_]+)\]/, // "[ERROR_NAME] message"
|
|
727
854
|
/^(\w+Error):/, // "ErrorTypeError: message"
|
|
@@ -741,22 +868,23 @@ export class GeminiModelDefinition {
|
|
|
741
868
|
* tools/toolConfig to be defined in the API request.
|
|
742
869
|
*/
|
|
743
870
|
export function convertGeminiFunctionPartsToText(contents) {
|
|
744
|
-
return contents.map(content => {
|
|
871
|
+
return contents.map((content) => {
|
|
745
872
|
if (!content.parts)
|
|
746
873
|
return content;
|
|
747
|
-
const hasFunctionParts = content.parts.some(p => p.functionCall || p.functionResponse);
|
|
874
|
+
const hasFunctionParts = content.parts.some((p) => p.functionCall || p.functionResponse);
|
|
748
875
|
if (!hasFunctionParts)
|
|
749
876
|
return content;
|
|
750
|
-
const newParts = content.parts.map(part => {
|
|
877
|
+
const newParts = content.parts.map((part) => {
|
|
751
878
|
if (part.functionCall) {
|
|
752
879
|
const argsStr = part.functionCall.args ? JSON.stringify(part.functionCall.args) : '';
|
|
753
|
-
const truncated = argsStr.length > 500 ? argsStr.substring(0, 500)
|
|
880
|
+
const truncated = argsStr.length > 500 ? `${argsStr.substring(0, 500)}...` : argsStr;
|
|
754
881
|
return { text: `[Tool call: ${part.functionCall.name}(${truncated})]` };
|
|
755
882
|
}
|
|
756
883
|
if (part.functionResponse) {
|
|
757
884
|
const respStr = part.functionResponse.response
|
|
758
|
-
? JSON.stringify(part.functionResponse.response)
|
|
759
|
-
|
|
885
|
+
? JSON.stringify(part.functionResponse.response)
|
|
886
|
+
: 'No response';
|
|
887
|
+
const truncated = respStr.length > 500 ? `${respStr.substring(0, 500)}...` : respStr;
|
|
760
888
|
return { text: `[Tool result for ${part.functionResponse.name}: ${truncated}]` };
|
|
761
889
|
}
|
|
762
890
|
return part;
|
|
@@ -837,11 +965,11 @@ function storeSystemInConversation(conversation, system) {
|
|
|
837
965
|
*/
|
|
838
966
|
function formatFunctionResponse(response) {
|
|
839
967
|
response = response.trim();
|
|
840
|
-
if (response.startsWith(
|
|
968
|
+
if (response.startsWith('{') && response.endsWith('}')) {
|
|
841
969
|
try {
|
|
842
970
|
return JSON.parse(response);
|
|
843
971
|
}
|
|
844
|
-
catch
|
|
972
|
+
catch {
|
|
845
973
|
return { output: response };
|
|
846
974
|
}
|
|
847
975
|
}
|