Skip to content

feat(py/plugins/amazon-bedrock): add embedders (Titan, Cohere v3, Nova) - #6010

Open
hilariie wants to merge 7 commits into
py-bedrock-converse-streamfrom
py-bedrock-embedders
Open

feat(py/plugins/amazon-bedrock): add embedders (Titan, Cohere v3, Nova)#6010
hilariie wants to merge 7 commits into
py-bedrock-converse-streamfrom
py-bedrock-embedders

Conversation

@hilariie

@hilariie hilariie commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Why

Slice 5 of #5820: embedders. Stacked on #5970. Embedding isn't part of Converse (bedrock-runtime has no embedding operation), so embedders go through InvokeModel with a raw per-provider JSON body. So this slice routes by model ID instead of reusing the Converse converters.

Changes

New embedders.py: Titan text (one call per document), Titan multimodal (text and/or image in one call), Cohere v3 (text batched 96 per call) and Nova-2, plus invoke_model on the transport seam. Per-document calls fan out under a semaphore of 10 and reassemble by index; a batch cancels its outstanding calls on the first failure, matching Go's context.WithCancel, and reports the lowest-indexed failure among the calls that ran. resolve() gains an embedder branch and a cross-guard, so an embedding model ID no longer resolves as a Converse chat model, and list_actions only lists what resolve can serve.

Four divergences from the Go plugin, all checked against AWS:

  • Nova targets the real amazon.nova-2-multimodal-embeddings-v1:0 SINGLE_EMBEDDING schema. Go registers amazon.nova-embed-text-v1:0, which doesn't exist, sends a Titan-shaped body, and routes on a substring that can't match the real ID.
  • Cohere is text-only. The parameters page documents an images field for v3, but get-foundation-model reports inputModalities: [TEXT] and a live image call returns Invalid parameter combination. Go's image path can't work whatever the encoding.
  • Routing is on cohere.embed, not bare cohere, which would swallow cohere.rerank-* and cohere.command-*.
  • Titan multimodal's in-band message is raised. Bedrock reports input errors there on a 200, and Go drops it.

cohere.embed-v4 is recognised and fails UNIMPLEMENTED: different request schema, and where Cohere image embedding will land. Per-request options aren't wired yet, so Cohere is pinned to input_type: search_document.

Verification

Unit tests pin each family's request body, Cohere's 96-document chunking, ordering when calls finish out of order, and the concurrency cap. Live tests (BEDROCK_LIVE_TESTS=1) hit all six models against real Bedrock, Nova-2 in us-east-1. The sample app gains embed_text, embed_batch, embed_similarity and embed_image.

Worth a closer look

invoke_model is new in this slice and slice 6 will reuse it, so flagging it while it is still cheap to change.

It returns the parsed body: the boto3 call, the body.read() and the json.loads all happen inside one to_thread hop. The read has to be off the loop regardless since botocore classes InvokeModel as a streaming-output operation, so it hands back an unread StreamingBody and read() blocks on the socket. Keeping the parse in that same hop means the decode stays off the loop too, which is cheap for a 1 KB vector but less so for the base64 image bodies slice 6 pulls back.

The tradeoff is that the codec sits on both sides of the seam: embedders.py does the json.dumps going in, transport does the json.loads coming out. Would like your read on whether that is the right home for the parse. Worth stating that there is no Go precedent to lean on here as aws-sdk-go-v2 materialises the InvokeModel body as []byte before the caller sees it, so Go has no read to place and no seam to place it across. Would like your read on whether that is the right home for the parse.

Screenshots

Screenshot 2026-08-11 at 09 09 21 Screenshot 2026-08-11 at 09 09 42 Screenshot 2026-08-11 at 09 10 04 Screenshot 2026-08-11 at 09 10 20 Screenshot 2026-08-11 at 09 10 44 Screenshot 2026-08-11 at 09 15 05 Screenshot 2026-08-11 at 09 15 40

@hilariie
hilariie requested a review from cabljac August 11, 2026 09:16
@github-actions github-actions Bot added docs Improvements or additions to documentation python Python labels Aug 11, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements Amazon Bedrock embedders using the InvokeModel API for the Genkit Python plugin, porting functionality from the Go plugin with support for Titan, Cohere, and Nova embedding models. The review feedback highlights opportunities to improve robustness and performance, including adding defensive checks for media URLs to prevent potential AttributeError crashes, explicitly rejecting unsupported remote image URLs instead of silently skipping them, optimizing Cohere batch processing to run chunks concurrently using asyncio.gather, and evaluating the fail-fast behavior of concurrent document embedding.

Comment thread py/packages/genkit-amazon-bedrock/src/genkit_amazon_bedrock/embedders.py Outdated
Comment thread py/packages/genkit-amazon-bedrock/src/genkit_amazon_bedrock/embedders.py Outdated
@hilariie hilariie changed the title feat(py/plugins/amazon-bedrock): add embedders (Titan, Cohere v3, Nov… feat(py/plugins/amazon-bedrock): add embedders (Titan, Cohere v3, Nova) Aug 11, 2026
@hilariie
hilariie force-pushed the py-bedrock-embedders branch from 974de8f to b9e26a2 Compare August 14, 2026 09:40
@cabljac
cabljac force-pushed the py-bedrock-embedders branch from b9e26a2 to af83c8c Compare August 14, 2026 12:19
@cabljac
cabljac force-pushed the py-bedrock-embedders branch from af83c8c to 4c81831 Compare August 14, 2026 13:05

@cabljac cabljac left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Embedders look good, the per-family split reads clearly and the batching and cancellation behaviour is well covered by the tests. Two nits inline, neither blocking.

Comment thread py/packages/genkit-amazon-bedrock/src/genkit_amazon_bedrock/plugin.py Outdated
Comment thread py/packages/genkit-amazon-bedrock/src/genkit_amazon_bedrock/transport.py Outdated
@hilariie

Copy link
Copy Markdown
Contributor Author

Both issues fixed

Transport now isinstance-checks the parsed body so a non-object raises INTERNAL instead of an AttributeError downstream, docstring updated to match.

For resolve I added looks_like_embedding_model, an 'embed' substring check, and swapped both guards to it. Unknown embedding families now fail UNIMPLEMENTED by name. is_embedding_model still gates what gets listed.

…a-2)

Embedding models go through InvokeModel with a per-provider JSON body, so
routing is by model ID. Diverges from the Go plugin in a few places; see the
PR body.
json.loads can hand back a list or a scalar, and the four payload.get()
callers would raise AttributeError on it instead of a GenkitError.
…he chat path

An embedding ID from a family with no entry in the routing table used to
resolve as a Converse model and fail with a Bedrock validation error.
@hilariie
hilariie force-pushed the py-bedrock-embedders branch from 568de9b to fa0e6b6 Compare August 17, 2026 08:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Improvements or additions to documentation python Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants