feat: add Amazon Nova 2 multimodal embeddings support - #222
Conversation
Adds support for `amazon.nova-2-multimodal-embeddings-v1:0` via the new `NovaEmbeddingsModel` class, using the `taskType`/`singleEmbeddingParams` request format documented in the Nova 2 user guide. - Supports single and batch text inputs - Respects the `dimensions` parameter (256/512/1024/2048/3072, default 3072) - Supports `float` and `base64` encoding formats - Includes `test_nova_embed.py` for quick end-to-end verification Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Test script moved to PR description instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add VALID_DIMENSIONS set and upfront validation with a clear error message - Fix `dimensions or DEFAULT` which would incorrectly ignore dimensions=0 - Add inline comment explaining approximate token counting (Nova API does not return token counts in the response)
zxkane
left a comment
There was a problem hiding this comment.
Thanks for adding Nova 2 multimodal embeddings support! The overall structure follows the existing patterns well. A few issues to address before merge:
Critical
1. VALID_DIMENSIONS values are incorrect per AWS documentation
According to the Nova 2 embeddings docs and the embeddings schema reference, the allowed embeddingDimension values are 256, 384, 1024, 3072.
The current code {256, 512, 1024, 2048, 3072} includes two invalid values (512, 2048) and omits one valid value (384).
# Fix:
VALID_DIMENSIONS = {256, 384, 1024, 3072}2. str(item) fallback silently embeds garbage
else:
texts.append(str(item))If an unexpected type reaches this branch, it silently converts to its string representation (e.g., "{'key': 'value'}") and returns HTTP 200 with meaningless embeddings. This is worse than an error — users won't know their results are wrong. Should raise an error instead:
else:
raise HTTPException(
status_code=400,
detail=f"Unsupported input item type: {type(item).__name__}. Expected str, int, or list of ints.",
)Important
3. Stale comment in schema.py:185
The dimensions field comment says # not used. but this PR makes it actively functional for Nova. Please update it, e.g.:
dimensions: int | None = None # Used by Nova embeddings; ignored by other models.4. getattr is unnecessary for a Pydantic model field
dimensions = getattr(embeddings_request, "dimensions", None)EmbeddingsRequest defines dimensions: int | None = None as a Pydantic field. Direct access works and is consistent with how all other attributes are accessed in this codebase:
dimensions = embeddings_request.dimensions5. Batch failure loses context
Since Nova processes each text as a separate API call, a failure mid-batch gives no indication of which item failed. Consider using enumerate and including the index in error context:
for idx, text in enumerate(texts):
# ... on error, include idx in the error detailSuggestions (optional)
- Move dimension validation before the loop (it's constant across texts but validated per-text currently)
- Add a comment explaining why
embeddingPurposeis hardcoded to"GENERIC_INDEX"(Nova supports 9 different purposes) - Consider using
isinstance(item, list)instead ofisinstance(item, Iterable)for more precise type matching
- Fix VALID_DIMENSIONS to {256, 384, 1024, 3072} per Nova embeddings schema docs
(previous values 512/2048 were mistakenly referenced from Titan embedding model docs)
- Replace str(item) fallback with HTTPException(400) to avoid silent garbage embeddings
- Update schema.py dimensions comment: 'not used' -> 'Used by Nova embeddings'
- Replace getattr() with direct .dimensions access on Pydantic model
- Move dimension validation before the loop (validates once, not per-text)
- Add enumerate to batch loop; include input index in error detail
- Switch isinstance(item, Iterable) to isinstance(item, list) for precise matching
- Add comment explaining embeddingPurpose hardcoded to GENERIC_INDEX
|
Thanks for the contribution @gabrielkoo! 🎉 Great work adding Nova 2 multimodal embeddings support. The implementation is clean, well-documented, and consistent with the existing codebase. Merging now! |
|
@zxkane @gabrielkoo note that this still only supports text embeddings, despite being a multimodal embedding model that supports image and video input. see #159 |
Summary
amazon.nova-2-multimodal-embeddings-v1:0toSUPPORTED_BEDROCK_EMBEDDING_MODELSNovaEmbeddingsModelusing thetaskType/singleEmbeddingParamsrequest format from the Nova 2 embeddings docsdimensions(256/512/1024/2048/3072, default 3072), andfloat/base64encoding formatsTest plan
Start the gateway:
Then run the following (requires
pip install openai):