@llumiverse/drivers 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/{types/anthropic → anthropic}/index.d.ts +4 -2
- package/lib/anthropic/index.d.ts.map +1 -0
- package/lib/{esm/anthropic → anthropic}/index.js +19 -8
- 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 +16 -5
- package/lib/openai/index.d.ts.map +1 -0
- package/lib/{esm/openai → openai}/index.js +242 -141
- 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/{types/shared → shared}/claude-messages.d.ts +25 -1
- package/lib/shared/claude-messages.d.ts.map +1 -0
- package/lib/{esm/shared → shared}/claude-messages.js +212 -59
- 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/{types/vertexai → vertexai}/models/claude.d.ts +4 -4
- package/lib/vertexai/models/claude.d.ts.map +1 -0
- package/lib/{esm/vertexai → vertexai}/models/claude.js +17 -20
- package/lib/vertexai/models/claude.js.map +1 -0
- package/lib/{types/vertexai → vertexai}/models/gemini.d.ts +28 -4
- package/lib/vertexai/models/gemini.d.ts.map +1 -0
- package/lib/{esm/vertexai → vertexai}/models/gemini.js +238 -116
- 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 +87 -36
- package/src/adobe/firefly.ts +60 -43
- package/src/anthropic/index.ts +37 -20
- 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 -16
- 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 +378 -248
- 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 +303 -97
- 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 +331 -244
- package/src/vertexai/models/claude-error-handling.test.ts +83 -36
- package/src/vertexai/models/claude-streaming-spacing.test.ts +82 -75
- package/src/vertexai/models/claude.ts +55 -40
- 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 +349 -172
- 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/anthropic/index.js +0 -64
- package/lib/cjs/anthropic/index.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 -32
- 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 -1135
- 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-messages.js +0 -737
- package/lib/cjs/shared/claude-messages.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 -72
- package/lib/cjs/vertexai/models/claude.js.map +0 -1
- package/lib/cjs/vertexai/models/gemini.js +0 -864
- 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/anthropic/index.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 -16
- 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-messages.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.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/anthropic/index.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 -16
- 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-messages.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.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
|
}
|
|
@@ -424,7 +502,7 @@ export class GeminiModelDefinition {
|
|
|
424
502
|
return { contents, system };
|
|
425
503
|
}
|
|
426
504
|
usageMetadataToTokenUsage(driver, usageMetadata) {
|
|
427
|
-
if (!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
520
|
// Token-accounting mismatch: warn-level diagnostic (the call still
|
|
442
521
|
// returns the best-effort tokenUsage). Use the driver's structured
|
|
443
522
|
// logger so we don't promote stderr writes to ERROR in serverless
|
|
444
523
|
// log aggregators — see the recoverable-tool-call sites below.
|
|
445
|
-
driver.logger.warn({ total: tokenUsage.total, prompt: tokenUsage.prompt, result: tokenUsage.result },
|
|
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,34 +547,37 @@ 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
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);
|
|
@@ -506,14 +588,14 @@ export class GeminiModelDefinition {
|
|
|
506
588
|
// to ERROR severity for what is, by definition, a recoverable event.
|
|
507
589
|
if (isRecoverableToolCall && tool_use && tool_use.length > 0) {
|
|
508
590
|
driver.logger.warn(`[Gemini] Recoverable tool call issue (${candidate.finishReason}): ` +
|
|
509
|
-
`Model tried to call undeclared tool(s): ${tool_use.map(t => t.tool_name).join(', ')}`);
|
|
591
|
+
`Model tried to call undeclared tool(s): ${tool_use.map((t) => t.tool_name).join(', ')}`);
|
|
510
592
|
}
|
|
511
593
|
result = extractCompletionResults(content);
|
|
512
594
|
conversation = updateConversation(conversation, [content]);
|
|
513
595
|
}
|
|
514
596
|
}
|
|
515
597
|
if (tool_use) {
|
|
516
|
-
finish_reason =
|
|
598
|
+
finish_reason = 'tool_use';
|
|
517
599
|
}
|
|
518
600
|
// Increment turn counter for deferred stripping
|
|
519
601
|
conversation = incrementConversationTurn(conversation);
|
|
@@ -522,7 +604,7 @@ export class GeminiModelDefinition {
|
|
|
522
604
|
const stripOptions = {
|
|
523
605
|
keepForTurns: options.stripImagesAfterTurns ?? Infinity,
|
|
524
606
|
currentTurn,
|
|
525
|
-
textMaxTokens: options.stripTextMaxTokens
|
|
607
|
+
textMaxTokens: options.stripTextMaxTokens,
|
|
526
608
|
};
|
|
527
609
|
let processedConversation = stripBase64ImagesFromConversation(conversation, stripOptions);
|
|
528
610
|
// Truncate large text content if configured
|
|
@@ -535,18 +617,18 @@ export class GeminiModelDefinition {
|
|
|
535
617
|
// Preserve system instruction in conversation for multi-turn support
|
|
536
618
|
const finalConversation = storeSystemInConversation(processedConversation, prompt.system);
|
|
537
619
|
return {
|
|
538
|
-
result: result && result.length > 0 ? result : [{ type:
|
|
620
|
+
result: result && result.length > 0 ? result : [{ type: 'text', value: '' }],
|
|
539
621
|
token_usage: token_usage,
|
|
540
622
|
finish_reason: finish_reason,
|
|
541
623
|
original_response: options.include_original_response ? response : undefined,
|
|
542
624
|
conversation: finalConversation,
|
|
543
|
-
tool_use
|
|
625
|
+
tool_use,
|
|
544
626
|
};
|
|
545
627
|
}
|
|
546
628
|
async requestTextCompletionStream(driver, prompt, options) {
|
|
547
|
-
const splits = options.model.split(
|
|
548
|
-
let region
|
|
549
|
-
if (splits[0] ===
|
|
629
|
+
const splits = options.model.split('/');
|
|
630
|
+
let region;
|
|
631
|
+
if (splits[0] === 'locations' && splits.length >= 2) {
|
|
550
632
|
region = splits[1];
|
|
551
633
|
}
|
|
552
634
|
const modelName = splits[splits.length - 1];
|
|
@@ -562,11 +644,11 @@ export class GeminiModelDefinition {
|
|
|
562
644
|
// Include conversation history in prompt contents (same as non-streaming)
|
|
563
645
|
const conversation = updateConversation(options.conversation, prompt.contents);
|
|
564
646
|
prompt.contents = conversation;
|
|
565
|
-
if (options.model.includes(
|
|
566
|
-
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
|
|
567
649
|
}
|
|
568
650
|
const model_options = options.model_options;
|
|
569
|
-
const client = driver.getGoogleGenAIClient(region, model_options?.flex ?? false);
|
|
651
|
+
const client = driver.getGoogleGenAIClient(region, model_options?.flex ?? false, options.httpTimeout);
|
|
570
652
|
const payload = getGeminiPayload(options, prompt);
|
|
571
653
|
const response = await client.models.generateContentStream(payload);
|
|
572
654
|
const stream = asyncMap(response, async (item) => {
|
|
@@ -577,33 +659,36 @@ export class GeminiModelDefinition {
|
|
|
577
659
|
let finish_reason;
|
|
578
660
|
switch (candidate.finishReason) {
|
|
579
661
|
case FinishReason.MAX_TOKENS:
|
|
580
|
-
finish_reason =
|
|
662
|
+
finish_reason = 'length';
|
|
581
663
|
break;
|
|
582
664
|
case FinishReason.STOP:
|
|
583
|
-
finish_reason =
|
|
665
|
+
finish_reason = 'stop';
|
|
584
666
|
break;
|
|
585
|
-
default:
|
|
667
|
+
default:
|
|
668
|
+
finish_reason = candidate.finishReason;
|
|
586
669
|
}
|
|
587
670
|
// Check for unsupported finish reasons, but allow recoverable tool call issues
|
|
588
671
|
const isRecoverableToolCall = recoverableToolCallReasons.includes(candidate.finishReason);
|
|
589
|
-
if (candidate.finishReason &&
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
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)}`);
|
|
593
678
|
}
|
|
594
679
|
if (candidate.content?.role === 'model') {
|
|
595
680
|
// Collect all parts in order (text and images)
|
|
596
681
|
const combinedResults = extractCompletionResults(candidate.content);
|
|
597
682
|
tool_use = collectToolUseParts(candidate.content);
|
|
598
683
|
if (tool_use) {
|
|
599
|
-
finish_reason =
|
|
684
|
+
finish_reason = 'tool_use';
|
|
600
685
|
// Log warning for recoverable tool call issues — see the
|
|
601
686
|
// matching site in `requestTextCompletion` above for why
|
|
602
687
|
// we route through the driver's logger instead of
|
|
603
688
|
// `console.warn`.
|
|
604
689
|
if (isRecoverableToolCall) {
|
|
605
690
|
driver.logger.warn(`[Gemini] Recoverable tool call issue (${candidate.finishReason}): ` +
|
|
606
|
-
`Model tried to call undeclared tool(s): ${tool_use.map(t => t.tool_name).join(', ')}`);
|
|
691
|
+
`Model tried to call undeclared tool(s): ${tool_use.map((t) => t.tool_name).join(', ')}`);
|
|
607
692
|
}
|
|
608
693
|
}
|
|
609
694
|
return {
|
|
@@ -617,8 +702,10 @@ export class GeminiModelDefinition {
|
|
|
617
702
|
}
|
|
618
703
|
//No normal output, returning block reason if it exists.
|
|
619
704
|
return {
|
|
620
|
-
result: item.promptFeedback?.blockReasonMessage
|
|
621
|
-
|
|
705
|
+
result: item.promptFeedback?.blockReasonMessage
|
|
706
|
+
? [{ type: 'text', value: item.promptFeedback.blockReasonMessage }]
|
|
707
|
+
: [],
|
|
708
|
+
finish_reason: item.promptFeedback?.blockReason ?? '',
|
|
622
709
|
token_usage: token_usage,
|
|
623
710
|
};
|
|
624
711
|
});
|
|
@@ -655,7 +742,7 @@ export class GeminiModelDefinition {
|
|
|
655
742
|
const apiError = error;
|
|
656
743
|
const httpStatusCode = apiError.status;
|
|
657
744
|
// Extract error message
|
|
658
|
-
const message = apiError.message
|
|
745
|
+
const message = apiError.message;
|
|
659
746
|
// Build user-facing message with status code
|
|
660
747
|
let userMessage = message;
|
|
661
748
|
// Include status code in message (for end-user visibility)
|
|
@@ -663,7 +750,7 @@ export class GeminiModelDefinition {
|
|
|
663
750
|
userMessage = `[${httpStatusCode}] ${userMessage}`;
|
|
664
751
|
}
|
|
665
752
|
// Determine retryability based on Google error codes
|
|
666
|
-
const retryable = this.isGeminiErrorRetryable(httpStatusCode);
|
|
753
|
+
const retryable = this.isGeminiErrorRetryable(httpStatusCode, message);
|
|
667
754
|
// Extract error name/type from message if present
|
|
668
755
|
const errorName = this.extractErrorName(message);
|
|
669
756
|
return new LlumiverseError(`[${context.provider}] ${userMessage}`, retryable, context, error, httpStatusCode, errorName);
|
|
@@ -676,13 +763,15 @@ export class GeminiModelDefinition {
|
|
|
676
763
|
typeof error === 'object' &&
|
|
677
764
|
'status' in error &&
|
|
678
765
|
typeof error.status === 'number' &&
|
|
679
|
-
'message' in error
|
|
766
|
+
'message' in error &&
|
|
767
|
+
typeof error.message === 'string');
|
|
680
768
|
}
|
|
681
769
|
/**
|
|
682
770
|
* Determine if a Google API error is retryable based on HTTP status code.
|
|
683
771
|
*
|
|
684
772
|
* Retryable errors (per Google AIP-194):
|
|
685
773
|
* - 408 (REQUEST_TIMEOUT): Request timeout
|
|
774
|
+
* - 499 (CANCELLED / Client Closed Request): Transport cancellation
|
|
686
775
|
* - 429 (RESOURCE_EXHAUSTED): Rate limit exceeded, quota exhausted
|
|
687
776
|
* - 500 (INTERNAL): Internal server error
|
|
688
777
|
* - 502 (BAD_GATEWAY): Bad gateway
|
|
@@ -697,15 +786,26 @@ export class GeminiModelDefinition {
|
|
|
697
786
|
* - 409 (CONFLICT): Resource conflict
|
|
698
787
|
* - Other 4xx client errors
|
|
699
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
|
+
*
|
|
700
795
|
* @param httpStatusCode - The HTTP status code from the API error
|
|
796
|
+
* @param message - The error message (used to detect transient 400 sub-cases)
|
|
701
797
|
* @returns True if retryable, false if not retryable, undefined if unknown
|
|
702
798
|
*/
|
|
703
|
-
isGeminiErrorRetryable(httpStatusCode) {
|
|
799
|
+
isGeminiErrorRetryable(httpStatusCode, message) {
|
|
800
|
+
if (message && this.isNonRetryableAuthError(message))
|
|
801
|
+
return false;
|
|
704
802
|
// Retryable status codes
|
|
705
803
|
if (httpStatusCode === 408)
|
|
706
804
|
return true; // Request timeout
|
|
707
805
|
if (httpStatusCode === 429)
|
|
708
806
|
return true; // Rate limit/quota
|
|
807
|
+
if (httpStatusCode === 499)
|
|
808
|
+
return true; // Client closed / operation cancelled
|
|
709
809
|
if (httpStatusCode === 502)
|
|
710
810
|
return true; // Bad gateway
|
|
711
811
|
if (httpStatusCode === 503)
|
|
@@ -714,12 +814,32 @@ export class GeminiModelDefinition {
|
|
|
714
814
|
return true; // Gateway timeout
|
|
715
815
|
if (httpStatusCode >= 500 && httpStatusCode < 600)
|
|
716
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
|
+
}
|
|
717
833
|
// Non-retryable 4xx client errors
|
|
718
834
|
if (httpStatusCode >= 400 && httpStatusCode < 500)
|
|
719
835
|
return false;
|
|
720
836
|
// Unknown status codes - let consumer decide retry strategy
|
|
721
837
|
return undefined;
|
|
722
838
|
}
|
|
839
|
+
isNonRetryableAuthError(message) {
|
|
840
|
+
const lowerMessage = message.toLowerCase();
|
|
841
|
+
return lowerMessage.includes('invalid_grant') || lowerMessage.includes("credential's issuer");
|
|
842
|
+
}
|
|
723
843
|
/**
|
|
724
844
|
* Extract error type name from error message.
|
|
725
845
|
* Google errors often include the error type in the message.
|
|
@@ -728,6 +848,7 @@ export class GeminiModelDefinition {
|
|
|
728
848
|
extractErrorName(message) {
|
|
729
849
|
// Common Google error patterns
|
|
730
850
|
const patterns = [
|
|
851
|
+
/^Error code ([a-zA-Z0-9_-]+):/, // "Error code invalid_grant: message"
|
|
731
852
|
/^([A-Z_]+):/, // "ERROR_NAME: message"
|
|
732
853
|
/\[([A-Z_]+)\]/, // "[ERROR_NAME] message"
|
|
733
854
|
/^(\w+Error):/, // "ErrorTypeError: message"
|
|
@@ -747,22 +868,23 @@ export class GeminiModelDefinition {
|
|
|
747
868
|
* tools/toolConfig to be defined in the API request.
|
|
748
869
|
*/
|
|
749
870
|
export function convertGeminiFunctionPartsToText(contents) {
|
|
750
|
-
return contents.map(content => {
|
|
871
|
+
return contents.map((content) => {
|
|
751
872
|
if (!content.parts)
|
|
752
873
|
return content;
|
|
753
|
-
const hasFunctionParts = content.parts.some(p => p.functionCall || p.functionResponse);
|
|
874
|
+
const hasFunctionParts = content.parts.some((p) => p.functionCall || p.functionResponse);
|
|
754
875
|
if (!hasFunctionParts)
|
|
755
876
|
return content;
|
|
756
|
-
const newParts = content.parts.map(part => {
|
|
877
|
+
const newParts = content.parts.map((part) => {
|
|
757
878
|
if (part.functionCall) {
|
|
758
879
|
const argsStr = part.functionCall.args ? JSON.stringify(part.functionCall.args) : '';
|
|
759
|
-
const truncated = argsStr.length > 500 ? argsStr.substring(0, 500)
|
|
880
|
+
const truncated = argsStr.length > 500 ? `${argsStr.substring(0, 500)}...` : argsStr;
|
|
760
881
|
return { text: `[Tool call: ${part.functionCall.name}(${truncated})]` };
|
|
761
882
|
}
|
|
762
883
|
if (part.functionResponse) {
|
|
763
884
|
const respStr = part.functionResponse.response
|
|
764
|
-
? JSON.stringify(part.functionResponse.response)
|
|
765
|
-
|
|
885
|
+
? JSON.stringify(part.functionResponse.response)
|
|
886
|
+
: 'No response';
|
|
887
|
+
const truncated = respStr.length > 500 ? `${respStr.substring(0, 500)}...` : respStr;
|
|
766
888
|
return { text: `[Tool result for ${part.functionResponse.name}: ${truncated}]` };
|
|
767
889
|
}
|
|
768
890
|
return part;
|
|
@@ -843,11 +965,11 @@ function storeSystemInConversation(conversation, system) {
|
|
|
843
965
|
*/
|
|
844
966
|
function formatFunctionResponse(response) {
|
|
845
967
|
response = response.trim();
|
|
846
|
-
if (response.startsWith(
|
|
968
|
+
if (response.startsWith('{') && response.endsWith('}')) {
|
|
847
969
|
try {
|
|
848
970
|
return JSON.parse(response);
|
|
849
971
|
}
|
|
850
|
-
catch
|
|
972
|
+
catch {
|
|
851
973
|
return { output: response };
|
|
852
974
|
}
|
|
853
975
|
}
|