Skip to content

docs: multimodal embeddings - #3367

Open
TejasGhatte wants to merge 1 commit into
graphite-base/3367from
05-10-docs_multimodal_embeddings
Open

docs: multimodal embeddings#3367
TejasGhatte wants to merge 1 commit into
graphite-base/3367from
05-10-docs_multimodal_embeddings

Conversation

@TejasGhatte

@TejasGhatte TejasGhatte commented May 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR expands the embedding API to support multimodal inputs (text, image, audio, video, file, and tokens) and introduces a new /v1/embeddings/batch endpoint. It also refactors the EmbeddingInput schema from a flat union of string/token arrays into a structured EmbeddingContent model composed of typed parts, and replaces the flat EmbeddingStruct response type with a richer EmbeddingsByType object that supports multiple quantisation formats simultaneously.

Changes

  • New /v1/embeddings/batch endpoint backed by BatchEmbeddingRequest, currently supported by Gemini via batchEmbedContents. Each batch item can carry its own parameter overrides (task_type, dimensions, title, auto_truncate) that override the top-level defaults.
  • Refactored EmbeddingInput from a raw oneOf of strings/token arrays into a three-way union: single string shorthand, array of strings shorthand, or the full multimodal form ([]EmbeddingContent).
  • New EmbeddingContent / EmbeddingContentPart schemas representing typed parts (text, image, audio, file, video, tokens) that together produce one output embedding vector.
  • New EmbeddingMediaPart for inline base64 or URL-referenced media, with optional mime_type and filename fields.
  • New EmbeddingVideoConfig for Vertex multimodalembedding@001 per-segment video sampling parameters.
  • Refactored EmbeddingData to include modality and video_segment fields, enabling providers that return separate vectors per modality (Vertex multimodalembedding@001) to be represented correctly.
  • New EmbeddingsByType response structure supporting float, int8, uint8, binary, ubinary, and base64 embedding formats, enabling Cohere embed-v4 multi-quantisation responses.
  • EmbeddingRequest now explicitly documents task_type, title, auto_truncate, encoding_format, dimensions, and fallbacks fields with provider-specific notes.
  • Go SDK examples across Azure, Cohere, Gemini, and Vertex provider docs updated to use the new []EmbeddingContent input structure.
  • New multimodal embedding documentation added to both the HTTP gateway and Go SDK quickstart guides, covering text, image+text, audio, PDF, and video embedding examples with provider-specific notes.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

go test ./...
  • Send a POST /v1/embeddings request with a multimodal input array (e.g. text + image parts) to a Cohere or Gemini model and verify the response contains the expected embedding vectors.
  • Send a POST /v1/embeddings/batch request to a Gemini model with multiple items, some with item-level params overrides, and verify each item produces a separate embedding entry in the response.
  • Send a POST /v1/embeddings request to vertex/multimodalembedding@001 with text and image parts and verify the response contains separate EmbeddingData entries with modality set to "text" and "image" respectively.

Breaking changes

  • Yes
  • No

The EmbeddingInput type has changed from a flat union of strings/token arrays to a structured []EmbeddingContent model. Existing Go SDK callers using &schemas.EmbeddingInput{Texts: []string{...}} must be updated to []schemas.EmbeddingContent{{{Type: schemas.EmbeddingContentPartTypeText, Text: schemas.Ptr("...")}}}. The HTTP API remains backward-compatible for string and string-array shorthands.

Related issues

Security considerations

No new authentication mechanisms or secret handling introduced. Media payloads passed as base64 data URIs or URLs are forwarded to the upstream provider as-is; callers should ensure URLs do not expose sensitive resources to unintended providers.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added a batch embeddings endpoint with per-item parameter overrides.
    • Expanded multimodal embeddings: text, image, audio, video, file inputs and per-video-segment metadata.
    • Returned embeddings now support multiple vector formats (float, quantized, binary, base64) and modality-specific metadata.
  • Documentation

    • Added multimodal embeddings quickstarts and updated provider examples and usage guidance.

Walkthrough

This PR extends embeddings to support multimodal inputs (text, image, audio, video, file), adds POST /v1/embeddings/batch with per-item overrides, refactors input and response schemas (typed content parts, modality-labeled EmbeddingData, and EmbeddingsByType), and updates provider and quickstart docs and examples.

Changes

Embeddings Multimodal & Batch Specification

Layer / File(s) Summary
Input Schema & Multimodal Support
docs/openapi/schemas/inference/embeddings.yaml, docs/openapi/openapi.json
EmbeddingInput redefined as oneOf accepting single string, string array, or multimodal EmbeddingContent[].
Content Modality & Media Structures
docs/openapi/schemas/inference/embeddings.yaml, docs/openapi/openapi.json
Adds EmbeddingContentPart with type enum (text/image/audio/file/video/tokens), EmbeddingMediaPart (inline data or external url plus mime_type/filename), and EmbeddingVideoConfig for segment sampling.
Embedding Response Structures
docs/openapi/schemas/inference/embeddings.yaml, docs/openapi/openapi.json
EmbeddingData adds modality and optional video_segment; EmbeddingsByType exposes typed fields (float, int8, uint8, binary, ubinary, base64), replacing prior union.
Embedding Request Parameters
docs/openapi/schemas/inference/embeddings.yaml, docs/openapi/openapi.json
EmbeddingRequest extended with fallbacks, encoding_format, dimensions, task_type, title, and auto_truncate.
Batch Request Structures
docs/openapi/schemas/inference/embeddings.yaml, docs/openapi/openapi.json
BatchEmbeddingRequest defines model and items: EmbeddingBatchItem[]; per-item params may override batch defaults.
Endpoint Documentation
docs/openapi/paths/inference/embeddings.yaml, docs/openapi/openapi.json
POST /embeddings description expanded (text shorthand vs multimodal array), provider notes on modality support and batching.
Batch Embeddings Endpoint
docs/openapi/paths/inference/embeddings.yaml, docs/openapi/openapi.json
New POST /v1/embeddings/batch (createBatchEmbedding) wired to BatchEmbeddingRequest with per-item override semantics and standard responses.
OpenAPI Component References
docs/openapi/openapi.yaml
Added /v1/embeddings/batch path reference and expanded components.schemas to include new batch and multimodal schema entries.
Provider SDK Examples
docs/providers/supported-providers/azure.mdx, cohere.mdx, gemini.mdx, vertex.mdx
Go SDK examples updated to use []EmbeddingContent typed parts; Gemini docs clarify mapping of input items to requests[].
Gateway API Quickstart
docs/quickstart/gateway/multimodal.mdx
New "Multimodal Embeddings" section with cURL examples (text, image+text, Gemini text+audio, PDF file part, Vertex image+text+video).
Go SDK Quickstart
docs/quickstart/go-sdk/multimodal.mdx
New multimodal Go examples: text, image+text, Gemini text+audio/PDF, Vertex multimodal and video with EmbeddingVideoConfig.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • akshaydeo

Poem

🐰 I stitched words, images, sounds, and frames,
Batches snug together, each part keeps its name.
Vectors in many flavors, small and grand,
Multimodal carrots, ready in hand! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'docs: multimodal embeddings' is concise and clearly describes the primary change: adding multimodal embedding support documentation.
Description check ✅ Passed The PR description is comprehensive, covering summary, changes, type of change, affected areas, testing instructions, breaking changes, and security considerations. All major template sections are completed with substantial detail.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 05-10-docs_multimodal_embeddings

Comment @coderabbitai help to get the list of available commands and usage tips.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


tejas ghatte seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@TejasGhatte TejasGhatte mentioned this pull request May 11, 2026
18 tasks

TejasGhatte commented May 11, 2026

Copy link
Copy Markdown
Collaborator Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@TejasGhatte
TejasGhatte marked this pull request as ready for review May 11, 2026 04:34
@greptile-apps

greptile-apps Bot commented May 11, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 5/5

This is a purely documentation and OpenAPI schema change with no runtime logic; all changes are additive or clearly intentional breaking changes already called out in the PR description.

All changed files are docs, OpenAPI specs, and quickstart guides. The schema additions are well-structured and the prose is accurate; the few schema gaps (missing minimum constraint, missing required guard on EmbeddingMediaPart) are quality improvements rather than correctness blockers.

docs/openapi/schemas/inference/embeddings.yaml has schema constraint gaps worth tightening before the spec is consumed by code generators.

Important Files Changed

Filename Overview
docs/openapi/schemas/inference/embeddings.yaml Major schema refactor introducing EmbeddingContent, EmbeddingContentPart, EmbeddingMediaPart, EmbeddingVideoConfig, EmbeddingsByType, and batch types; prose constraints on EmbeddingMediaPart and interval_sec are not enforced by the schema
docs/openapi/paths/inference/embeddings.yaml Adds /v1/embeddings/batch path and expands /v1/embeddings description with provider capability notes
docs/quickstart/gateway/multimodal.mdx New Multimodal Embeddings section added; response JSON example shows embedding as a flat array instead of EmbeddingsByType object, and PDF/video input snippets are orphaned fragments without curl wrappers (flagged in prior threads)
docs/quickstart/go-sdk/multimodal.mdx New Go SDK multimodal embedding examples covering text, image+text, audio, PDF, and video; examples are syntactically correct and consistent with the new EmbeddingContent slice-of-slices structure
docs/openapi/openapi.yaml Registers all new embedding schemas in components and adds /v1/embeddings/batch path
docs/providers/supported-providers/azure.mdx Go SDK example updated to use new []EmbeddingContent input structure
docs/providers/supported-providers/cohere.mdx Go SDK example updated to use new []EmbeddingContent input structure
docs/providers/supported-providers/gemini.mdx Updated note and parameter mapping description to reflect the new multimodal batch semantics
docs/providers/supported-providers/vertex.mdx Go SDK example updated to use new []EmbeddingContent input structure

Reviews (2): Last reviewed commit: "docs: multimodal embeddings" | Re-trigger Greptile

Comment on lines +424 to +430
```json
{
"data": [
{ "index": 0, "modality": "text", "embedding": [0.12, -0.34, ...] },
{ "index": 1, "modality": "image", "embedding": [0.56, -0.78, ...] }
]
}

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.

P1 The response JSON example uses a flat array for "embedding", but EmbeddingData.embedding is now EmbeddingsByType — an object with named fields (float, int8, base64, etc.). A reader following this example will expect a plain array from the API and be confused when they receive an object instead.

Suggested change
```json
{
"data": [
{ "index": 0, "modality": "text", "embedding": [0.12, -0.34, ...] },
{ "index": 1, "modality": "image", "embedding": [0.56, -0.78, ...] }
]
}
```json
{
"data": [
{ "index": 0, "modality": "text", "embedding": { "float": [0.12, -0.34, ...] } },
{ "index": 1, "modality": "image", "embedding": { "float": [0.56, -0.78, ...] } }
]
}

Comment thread docs/openapi/schemas/inference/embeddings.yaml
Comment on lines +394 to +400
```bash
"input": [
[
{ "type": "file", "file": { "url": "https://example.com/doc.pdf", "mime_type": "application/pdf" } }
]
]
```

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.

P2 Orphaned code snippet without curl wrapper

The PDF file part example is a bare JSON fragment with no surrounding curl command or HTTP context, unlike every other example in this section. Readers can't copy-paste it as-is.

Comment thread docs/quickstart/gateway/multimodal.mdx

@coderabbitai coderabbitai 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.

Actionable comments posted: 4

🧹 Nitpick comments (1)
docs/quickstart/gateway/multimodal.mdx (1)

341-352: ⚡ Quick win

Clarify provider scope in the “Text Embedding (all providers)” example.

The example uses Cohere-specific input_type, so the heading can imply broader compatibility than the snippet shows.

✏️ Suggested wording tweak
-### Text Embedding (all providers)
+### Text Embedding (Cohere example)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/quickstart/gateway/multimodal.mdx` around lines 341 - 352, The heading
"Text Embedding (all providers)" is misleading because the snippet uses
Cohere-specific fields; update the docs by either renaming the heading to
something like "Text Embedding (Cohere example)" or modifying the example
payload to be provider-agnostic (remove or replace the Cohere-only "input_type":
"search_document" and the "model": "cohere/embed-v4.0" with a generic model
placeholder). Ensure you reference the heading text "Text Embedding (all
providers)" and the payload keys "model" and "input_type" when making the change
so readers know this snippet is Cohere-specific or converted to a generic
example.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/openapi/schemas/inference/embeddings.yaml`:
- Around line 211-222: The EmbeddingVideoConfig schema is missing numeric
constraints: update the properties for start_offset_sec and end_offset_sec to
include "minimum: 0" (to enforce non-negative offsets) and add "minimum: 4" to
interval_sec (to enforce the documented 4s lower bound); modify the YAML entries
for the properties start_offset_sec, end_offset_sec, and interval_sec
accordingly so validators and generated clients will enforce these limits.
- Around line 142-178: The EmbeddingContentPart schema currently allows
mismatched or missing payloads; update EmbeddingContentPart to a discriminated
union so that the "type" field drives the required payload shape: replace the
current flat properties with a oneOf array of separate schemas (e.g.,
EmbeddingContentPartText, EmbeddingContentPartImage, EmbeddingContentPartAudio,
EmbeddingContentPartFile, EmbeddingContentPartVideo,
EmbeddingContentPartTokens), each requiring the matching payload (text, image,
audio, file, video with optional video_config, tokens) and forbid other payload
properties; add a discriminator on "type" with mappings for each subtype to
enforce that exactly one payload is present and tied to the declared type in
generated clients and docs.
- Around line 180-204: The EmbeddingMediaPart schema currently allows both or
neither of data and url; update the EmbeddingMediaPart definition to enforce
"exactly one of data or url" by adding a oneOf with two alternatives—one
requiring ["data"] and the other requiring ["url"]—while keeping the existing
properties (data, url, mime_type, filename) and descriptions; follow the same
pattern used by OCRDocument in ocr.yaml so downstream image/audio/file/video
refs inherit the constraint.

In `@docs/quickstart/go-sdk/multimodal.mdx`:
- Around line 485-506: The narrative and code example diverge: the sentence says
“alongside text/image” but the snippet only shows a video part; either update
the sentence to say “For video, add a Video part:” or modify the code to include
text/image parts alongside the video (e.g., add additional entries to the Input
slice such as an EmbeddingContent with Type:
schemas.EmbeddingContentPartTypeText and/or Type:
schemas.EmbeddingContentPartTypeImage using the same client.EmbeddingRequest and
schemas.BifrostEmbeddingRequest/EmbeddingContent structures like videoGCS
shown).

---

Nitpick comments:
In `@docs/quickstart/gateway/multimodal.mdx`:
- Around line 341-352: The heading "Text Embedding (all providers)" is
misleading because the snippet uses Cohere-specific fields; update the docs by
either renaming the heading to something like "Text Embedding (Cohere example)"
or modifying the example payload to be provider-agnostic (remove or replace the
Cohere-only "input_type": "search_document" and the "model": "cohere/embed-v4.0"
with a generic model placeholder). Ensure you reference the heading text "Text
Embedding (all providers)" and the payload keys "model" and "input_type" when
making the change so readers know this snippet is Cohere-specific or converted
to a generic example.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9bf6eb00-4dc0-4b3f-b82a-03e25aba5a45

📥 Commits

Reviewing files that changed from the base of the PR and between 1fd13e8 and 35b2866.

📒 Files selected for processing (10)
  • docs/openapi/openapi.json
  • docs/openapi/openapi.yaml
  • docs/openapi/paths/inference/embeddings.yaml
  • docs/openapi/schemas/inference/embeddings.yaml
  • docs/providers/supported-providers/azure.mdx
  • docs/providers/supported-providers/cohere.mdx
  • docs/providers/supported-providers/gemini.mdx
  • docs/providers/supported-providers/vertex.mdx
  • docs/quickstart/gateway/multimodal.mdx
  • docs/quickstart/go-sdk/multimodal.mdx

Comment on lines +142 to +178
EmbeddingContentPart:
type: object
required:
- type
properties:
type:
type: string
enum: [text, image, audio, file, video, tokens]
description: Modality of this content part
text:
type: string
description: Text payload — required when type is "text"
image:
$ref: '#/EmbeddingMediaPart'
description: Image payload — required when type is "image"
audio:
$ref: '#/EmbeddingMediaPart'
description: Audio payload — required when type is "audio"
file:
$ref: '#/EmbeddingMediaPart'
description: File payload — required when type is "file"
video:
$ref: '#/EmbeddingMediaPart'
description: Video payload — required when type is "video"
video_config:
$ref: '#/EmbeddingVideoConfig'
description: >
Optional video segment parameters. Only meaningful when type is "video" and the
provider supports per-segment embeddings (Vertex multimodalembedding@001).
tokens:
type: array
items:
type: array
items:
type: integer
description: Input for embedding - text or token arrays
type: integer
description: Pre-tokenised integer token IDs — required when type is "tokens" (OpenAI only)
description: >
Exactly one of text / image / audio / file / video / tokens must be set,
matching the declared type.

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Enforce the type → payload mapping in EmbeddingContentPart using a discriminated union.

The schema currently accepts invalid shapes like {type: "text"} (missing payload) and {type: "text", image: {...}} (wrong payload type), despite the description stating exactly one payload must be set and match type. Since this is the core multimodal contract for the stack, generated clients and documentation will advertise impossible requests as valid. Use OpenAPI 3.1's oneOf with discriminator or if/then patterns to enforce this constraint.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/openapi/schemas/inference/embeddings.yaml` around lines 142 - 178, The
EmbeddingContentPart schema currently allows mismatched or missing payloads;
update EmbeddingContentPart to a discriminated union so that the "type" field
drives the required payload shape: replace the current flat properties with a
oneOf array of separate schemas (e.g., EmbeddingContentPartText,
EmbeddingContentPartImage, EmbeddingContentPartAudio, EmbeddingContentPartFile,
EmbeddingContentPartVideo, EmbeddingContentPartTokens), each requiring the
matching payload (text, image, audio, file, video with optional video_config,
tokens) and forbid other payload properties; add a discriminator on "type" with
mappings for each subtype to enforce that exactly one payload is present and
tied to the declared type in generated clients and docs.

Comment on lines +180 to +204
EmbeddingMediaPart:
type: object
description: >
Media payload for image, audio, file, or video parts.
Exactly one of data or url must be provided.
properties:
data:
type: string
description: >
Base64-encoded media data, optionally as a data URI
(data:<mime>;base64,<data>). Used for inline uploads.
url:
type: string
description: >
URL pointing to the media. For Vertex multimodal embeddings this must be
a GCS URI (gs://…). For Gemini this can be any accessible URL.
mime_type:
type: string
description: >
MIME type of the media (e.g. "image/jpeg", "audio/mpeg", "video/mp4").
Optional when the type can be inferred from a data URI or file extension.
filename:
type: string
description: Original filename, used as display name in Gemini File API uploads.

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, let me check the file and see the current schema
cat -n docs/openapi/schemas/inference/embeddings.yaml | sed -n '170,220p'

Repository: maximhq/bifrost

Length of output: 2175


🏁 Script executed:

# Check if there's a git history or stack context
git log --oneline -n 20 docs/openapi/schemas/inference/embeddings.yaml 2>/dev/null | head -20

Repository: maximhq/bifrost

Length of output: 96


🏁 Script executed:

# Search for other uses of EmbeddingMediaPart in the codebase
rg "EmbeddingMediaPart" --type yaml

Repository: maximhq/bifrost

Length of output: 600


🏁 Script executed:

# Check git log for related changes
git log --oneline -n 10

Repository: maximhq/bifrost

Length of output: 96


🏁 Script executed:

# Check the references to EmbeddingMediaPart in embeddings.yaml to see how it's used
rg -A 5 -B 5 "EmbeddingMediaPart" docs/openapi/schemas/inference/embeddings.yaml

Repository: maximhq/bifrost

Length of output: 1206


🏁 Script executed:

# Check if there are any existing uses of oneOf in the OpenAPI schemas
rg "oneOf" docs/openapi/schemas/

Repository: maximhq/bifrost

Length of output: 1846


🏁 Script executed:

# Check if there are existing uses of 'required' constraint in the schema
rg "required:" docs/openapi/schemas/inference/embeddings.yaml | head -20

Repository: maximhq/bifrost

Length of output: 107


🏁 Script executed:

# Check examples of oneOf usage with required in the codebase
rg -B 5 -A 10 "oneOf:" docs/openapi/schemas/inference/embeddings.yaml

Repository: maximhq/bifrost

Length of output: 542


🏁 Script executed:

# Look for patterns of oneOf with required constraints
rg -B 3 -A 8 "oneOf:" docs/openapi/schemas/management/mcp.yaml | head -50

Repository: maximhq/bifrost

Length of output: 1340


🏁 Script executed:

# Check if there are examples of 'not' being used with required
rg -B 3 -A 3 "not:" docs/openapi/schemas/

Repository: maximhq/bifrost

Length of output: 41


🏁 Script executed:

# Check OpenAPI version used in the project
head -20 docs/openapi/openapi.yaml

Repository: maximhq/bifrost

Length of output: 911


🏁 Script executed:

# Look for examples of oneOf with required constraints to see the pattern used
rg -B 2 -A 8 "required:" docs/openapi/schemas/ | grep -A 8 -B 2 "oneOf" | head -40

Repository: maximhq/bifrost

Length of output: 746


🏁 Script executed:

# Check if there's a cleaner oneOf pattern with required in existing code
rg -A 15 "type: object" docs/openapi/schemas/inference/embeddings.yaml | grep -A 15 "oneOf"

Repository: maximhq/bifrost

Length of output: 41


🏁 Script executed:

# Check for more examples of oneOf with required in the codebase
rg -B 5 -A 12 "oneOf:" docs/openapi/schemas/integrations/openai/embeddings.yaml

Repository: maximhq/bifrost

Length of output: 485


🏁 Script executed:

# Look at the git status to check for stack/multiple PRs
git status

Repository: maximhq/bifrost

Length of output: 259


🏁 Script executed:

# Check git branches to see if there's a stack of PRs
git branch -a

Repository: maximhq/bifrost

Length of output: 192


🏁 Script executed:

# Verify the exact syntax pattern: look at a complete oneOf example with required
cat -n docs/openapi/schemas/inference/ocr.yaml | grep -A 25 "oneOf:"

Repository: maximhq/bifrost

Length of output: 2511


🏁 Script executed:

# Let me verify that the simpler oneOf pattern (without 'not') would work
# by checking if OpenAPI 3.1.0 examples use this pattern
rg -B 3 -A 8 "oneOf:" docs/openapi/schemas/ | grep -A 8 "required:" | head -50

Repository: maximhq/bifrost

Length of output: 3021


🏁 Script executed:

# Check the exact context where EmbeddingMediaPart is used to understand the validation impact
cat -n docs/openapi/schemas/inference/embeddings.yaml | sed -n '100,180p'

Repository: maximhq/bifrost

Length of output: 3422


🏁 Script executed:

# Let me get the simpler oneOf pattern that's already used in the codebase
cat -n docs/openapi/schemas/inference/ocr.yaml | sed -n '147,156p'

Repository: maximhq/bifrost

Length of output: 333


🏁 Script executed:

# Check if there are any other uses of data/url patterns in the schema
rg -B 2 -A 2 "data.*url|url.*data" docs/openapi/schemas/inference/embeddings.yaml

Repository: maximhq/bifrost

Length of output: 207


🏁 Script executed:

# Verify if the feature branch is the only one or if there's a stack
git log --oneline --graph --all -n 20

Repository: maximhq/bifrost

Length of output: 1442


Use oneOf to enforce exactly one of data/url.

The schema allows both data and url to be omitted or provided simultaneously, contradicting the stated requirement that "Exactly one of data or url must be provided." This underspecified constraint propagates to all four reuses of EmbeddingMediaPart (image, audio, file, video fields).

The codebase already uses a simpler pattern for similar constraints (see OCRDocument in ocr.yaml). Apply the same approach here:

Fix
 EmbeddingMediaPart:
   type: object
+  oneOf:
+    - required: [data]
+    - required: [url]
   description: >
     Media payload for image, audio, file, or video parts.
     Exactly one of data or url must be provided.
   properties:
     data:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
EmbeddingMediaPart:
type: object
description: >
Media payload for image, audio, file, or video parts.
Exactly one of data or url must be provided.
properties:
data:
type: string
description: >
Base64-encoded media data, optionally as a data URI
(data:<mime>;base64,<data>). Used for inline uploads.
url:
type: string
description: >
URL pointing to the media. For Vertex multimodal embeddings this must be
a GCS URI (gs://…). For Gemini this can be any accessible URL.
mime_type:
type: string
description: >
MIME type of the media (e.g. "image/jpeg", "audio/mpeg", "video/mp4").
Optional when the type can be inferred from a data URI or file extension.
filename:
type: string
description: Original filename, used as display name in Gemini File API uploads.
EmbeddingMediaPart:
type: object
oneOf:
- required: [data]
- required: [url]
description: >
Media payload for image, audio, file, or video parts.
Exactly one of data or url must be provided.
properties:
data:
type: string
description: >
Base64-encoded media data, optionally as a data URI
(data:<mime>;base64,<data>). Used for inline uploads.
url:
type: string
description: >
URL pointing to the media. For Vertex multimodal embeddings this must be
a GCS URI (gs://…). For Gemini this can be any accessible URL.
mime_type:
type: string
description: >
MIME type of the media (e.g. "image/jpeg", "audio/mpeg", "video/mp4").
Optional when the type can be inferred from a data URI or file extension.
filename:
type: string
description: Original filename, used as display name in Gemini File API uploads.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/openapi/schemas/inference/embeddings.yaml` around lines 180 - 204, The
EmbeddingMediaPart schema currently allows both or neither of data and url;
update the EmbeddingMediaPart definition to enforce "exactly one of data or url"
by adding a oneOf with two alternatives—one requiring ["data"] and the other
requiring ["url"]—while keeping the existing properties (data, url, mime_type,
filename) and descriptions; follow the same pattern used by OCRDocument in
ocr.yaml so downstream image/audio/file/video refs inherit the constraint.

Comment on lines +211 to +222
properties:
start_offset_sec:
type: integer
description: Start of the sampling window in seconds
end_offset_sec:
type: integer
description: End of the sampling window in seconds
interval_sec:
type: integer
description: >
Interval between consecutive segment embeddings in seconds (minimum 4).
When set, the model returns multiple EmbeddingData entries, one per segment.

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, check if the file exists and read the relevant section
if [ -f "docs/openapi/schemas/inference/embeddings.yaml" ]; then
  echo "=== File structure (first 30 lines) ==="
  head -30 "docs/openapi/schemas/inference/embeddings.yaml"
  echo ""
  echo "=== Lines 200-230 ==="
  sed -n '200,230p' "docs/openapi/schemas/inference/embeddings.yaml"
  echo ""
  echo "=== Total lines in file ==="
  wc -l "docs/openapi/schemas/inference/embeddings.yaml"
else
  echo "File not found"
fi

Repository: maximhq/bifrost

Length of output: 2034


🏁 Script executed:

#!/bin/bash
# Check for similar integer constraints in other YAML schema files
echo "=== Searching for 'minimum:' constraints in schema files ==="
rg "minimum:" docs/openapi/schemas/ -A 1 -B 1 | head -50

Repository: maximhq/bifrost

Length of output: 3764


🏁 Script executed:

#!/bin/bash
# Check git status to see if this is part of a PR stack
echo "=== Git log for the file (recent commits) ==="
git log --oneline -10 -- docs/openapi/schemas/inference/embeddings.yaml 2>/dev/null || echo "Git history not available"

Repository: maximhq/bifrost

Length of output: 142


Add explicit minimum constraints to video segment parameters.

The EmbeddingVideoConfig schema documents interval_sec as having a minimum of 4 seconds and assumes non-negative offsets, but these constraints are not enforced in the schema itself. Without explicit minimum properties, validators and generated clients cannot enforce these limits.

Suggested additions
    start_offset_sec:
      type: integer
+     minimum: 0
      description: Start of the sampling window in seconds
    end_offset_sec:
      type: integer
+     minimum: 0
      description: End of the sampling window in seconds
    interval_sec:
      type: integer
+     minimum: 4
      description: >
        Interval between consecutive segment embeddings in seconds (minimum 4).
        When set, the model returns multiple EmbeddingData entries, one per segment.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/openapi/schemas/inference/embeddings.yaml` around lines 211 - 222, The
EmbeddingVideoConfig schema is missing numeric constraints: update the
properties for start_offset_sec and end_offset_sec to include "minimum: 0" (to
enforce non-negative offsets) and add "minimum: 4" to interval_sec (to enforce
the documented 4s lower bound); modify the YAML entries for the properties
start_offset_sec, end_offset_sec, and interval_sec accordingly so validators and
generated clients will enforce these limits.

Comment on lines +485 to +506
For video, add a `Video` part alongside text/image:

```go
videoGCS := "gs://my-bucket/clip.mp4"
resp, err := client.EmbeddingRequest(schemas.NewBifrostContext(ctx, schemas.NoDeadline), &schemas.BifrostEmbeddingRequest{
Provider: schemas.Vertex,
Model: "multimodalembedding@001",
Input: []schemas.EmbeddingContent{
{
{
Type: schemas.EmbeddingContentPartTypeVideo,
Video: &schemas.EmbeddingMediaPart{URL: &videoGCS},
VideoConfig: &schemas.EmbeddingVideoConfig{
StartOffsetSec: schemas.Ptr(0),
EndOffsetSec: schemas.Ptr(30),
},
},
},
},
})
// resp.Data[].Modality == "video", each entry has a VideoSegment with timestamps
```

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Narrative and code diverge in the video embedding example.

The text says “alongside text/image,” but the snippet shows only a video part. Align either the sentence or the code sample.

✏️ Suggested wording fix
-For video, add a `Video` part alongside text/image:
+For video embeddings, add a `Video` part (optionally alongside text/image):
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/quickstart/go-sdk/multimodal.mdx` around lines 485 - 506, The narrative
and code example diverge: the sentence says “alongside text/image” but the
snippet only shows a video part; either update the sentence to say “For video,
add a Video part:” or modify the code to include text/image parts alongside the
video (e.g., add additional entries to the Input slice such as an
EmbeddingContent with Type: schemas.EmbeddingContentPartTypeText and/or Type:
schemas.EmbeddingContentPartTypeImage using the same client.EmbeddingRequest and
schemas.BifrostEmbeddingRequest/EmbeddingContent structures like videoGCS
shown).

@TejasGhatte
TejasGhatte force-pushed the 04-03-feat_multimodal_embeddings branch from 1fd13e8 to e2a6b4c Compare May 18, 2026 05:30
@TejasGhatte
TejasGhatte force-pushed the 05-10-docs_multimodal_embeddings branch from 35b2866 to 323d60b Compare May 18, 2026 05:30
@coderabbitai
coderabbitai Bot requested a review from akshaydeo May 18, 2026 05:31

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
docs/openapi/schemas/inference/embeddings.yaml (1)

23-25: 💤 Low value

Add minimum: 1 constraint to dimensions.

The dimensions property should not accept zero or negative values. Adding a constraint prevents invalid requests at the schema validation level.

    dimensions:
      type: integer
+     minimum: 1
      description: Number of output dimensions
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/openapi/schemas/inference/embeddings.yaml` around lines 23 - 25, The
OpenAPI schema's embeddings property "dimensions" lacks a lower bound; update
the "dimensions" property in the embeddings schema to include a "minimum: 1"
constraint so zero or negative integers are rejected by schema validation.
Locate the "dimensions" entry in the embeddings schema and add the numeric
minimum constraint directly under the existing "type: integer" declaration.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@docs/openapi/schemas/inference/embeddings.yaml`:
- Around line 23-25: The OpenAPI schema's embeddings property "dimensions" lacks
a lower bound; update the "dimensions" property in the embeddings schema to
include a "minimum: 1" constraint so zero or negative integers are rejected by
schema validation. Locate the "dimensions" entry in the embeddings schema and
add the numeric minimum constraint directly under the existing "type: integer"
declaration.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 410b88b7-ad19-42e5-997e-ce13706ef126

📥 Commits

Reviewing files that changed from the base of the PR and between 35b2866 and 323d60b.

📒 Files selected for processing (10)
  • docs/openapi/openapi.json
  • docs/openapi/openapi.yaml
  • docs/openapi/paths/inference/embeddings.yaml
  • docs/openapi/schemas/inference/embeddings.yaml
  • docs/providers/supported-providers/azure.mdx
  • docs/providers/supported-providers/cohere.mdx
  • docs/providers/supported-providers/gemini.mdx
  • docs/providers/supported-providers/vertex.mdx
  • docs/quickstart/gateway/multimodal.mdx
  • docs/quickstart/go-sdk/multimodal.mdx
✅ Files skipped from review due to trivial changes (3)
  • docs/providers/supported-providers/azure.mdx
  • docs/providers/supported-providers/cohere.mdx
  • docs/quickstart/gateway/multimodal.mdx
🚧 Files skipped from review as they are similar to previous changes (6)
  • docs/providers/supported-providers/gemini.mdx
  • docs/providers/supported-providers/vertex.mdx
  • docs/quickstart/go-sdk/multimodal.mdx
  • docs/openapi/paths/inference/embeddings.yaml
  • docs/openapi/openapi.yaml
  • docs/openapi/openapi.json

@TejasGhatte
TejasGhatte changed the base branch from 04-03-feat_multimodal_embeddings to graphite-base/3367 May 25, 2026 03:23
@stepsecurity-app

Copy link
Copy Markdown
Contributor

Security Policy Alert: Secret Policy Violation

This workflow run has been blocked by StepSecurity's secrets policy because it accesses secrets and the workflow file differs from the default branch.

To approve this workflow, please add the workflows-approved label to this PR.

Note: The label must be added by someone other than the PR author (TejasGhatte) or automation bots to ensure proper security review.

After the label is added, you can re-run the blocked workflow to proceed.

This workflow will be automatically approved once merged into the default branch.

For more information, see StepSecurity's Secret Exfiltration Policy documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants