feat(decisions-openai): judge images in blob properties by jfrancoa · Pull Request #13534 · weaviate/weaviate · GitHub
Skip to content

feat(decisions-openai): judge images in blob properties - #13534

Draft
jfrancoa wants to merge 6 commits into
jose/rerank-decidefrom
jose/decisions-images
Draft

jfrancoa wants to merge 6 commits into
jose/rerank-decidefrom
jose/decisions-images

Conversation

@jfrancoa

@jfrancoa jfrancoa commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

What's being changed:

decisions-openai judges images. A question of decide or a rerank by a decision about a blob property sends the property's content to the Decisions API as an inline image, the way the API takes it: one user message with an input_image part whose image_url is a data URL. The MIME type comes from the first bytes of the content (PNG, JPEG, GIF, WebP). Every blob of a call is checked before the first request: one that holds anything else, or an image above 20 MB, fails the call naming the document's position, so nothing is sent and billed. A Decide call about two properties is refused, since a call judges one. Text properties are sent as before. The RFC section is "Data types".

Validation. The module declares blob next to text in its DecisionLimits, so the pre-search check lets a question about a blob property through; decisions-typesafeai keeps text only and rejects it with "property "photo" is of type "blob", decisions-typesafeai judges [text]". A rerank by a decision is now checked against the property's type before the search as well, through the same Limits.CheckProperty as decide.

Rank provider. Rank(query, documents, cfg) does not name the property the documents come from. The shared rank provider now prefers an optional PropertyRanker interface, RankProperty(query, property, decision, documents, cfg), which decisions-openai implements; every other reranker is called as before. The module reads the property's type from the class config. decision is set for rerank.decision: the module then sends the query as the statement question whatever the class's question setting says, because the query of a decision rerank is a condition, not a search query. The question class setting is dropped: a plain rerank asks the relevance question, a rerank by a decision sends the statement, nothing is left to configure (the setting came in with #13409; found in the RFC review of 2026-10-14; before this change Rerank.decide(query="The customer is angry") on a class with the default relevance question asked "Does the document answer or directly address this query? Query: The customer is angry").

decisions-dummy accepts a blob as the text of its base64, so client integration tests can exercise the image path without a provider.

Verified against the API with two 64x64 PNGs: "Is the image mostly red?" answered 1.00 for the red square and 0.00 for the blue one, the colour choice named each, and rerank=Rerank.decide(query="The image is blue.", min_probability=0.5) returned the blue square only.

Tests. MIME detection table (four formats, text, not base64, empty), the request shape for Decide and RankProperty with an image and with text, the error for a non-image blob before any request, the limits, the rank provider naming the property and passing the decision flag, a decision rerank sending the statement on a class with the relevance question, the parser rejecting a decision about a property of another type, and an acceptance case for a blob question on decisions-dummy.

Stacked on #13528. Client: the question factories and Rerank.decide already take a blob property; docstrings and an integration test are in weaviate/weaviate-python-client#2204.

Review checklist

  • Documentation has been updated, if necessary. Link to changed documentation:
  • Chaos pipeline run or not necessary. Link to pipeline:
  • All new code is covered by tests where it is reasonable.
  • Performance tests have been run or not necessary.

@orca-security-eu orca-security-eu Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Orca Security Scan Summary

Status Check Issues by priority
Passed Passed Secrets high 0   medium 0   low 0   info 0 View in Orca

A question or a rerank by a decision about a blob property sends the
content to the Decisions API as an inline image: a data URL whose MIME
type is read from the first bytes (PNG, JPEG, GIF, WebP); other content
is an error before any request. The module declares blob among the types
it judges, so the pre-search validation lets the question through; a
rerank by a decision is now checked against the property type as well.
The rank provider names the property to a client that reads it, and
decisions-dummy accepts a blob as the text of its base64 so clients can
test the path without a provider.

[api]
…re a request

An image above 20 MB is refused, and a blob that is not an image fails
the call before any document is sent and billed, naming its position. A
Decide call about two properties is refused: it judges one. Dead test
variable removed.
jfrancoa added a commit to weaviate/weaviate-python-client that referenced this pull request Oct 13, 2026
The server's decisions-openai judges blob properties as images
(weaviate/weaviate#13534); the client needs no code change. An
integration test covers the path on decisions-dummy.
@jfrancoa
jfrancoa force-pushed the jose/decisions-images branch from c919f5a to 11748d0 Compare October 13, 2026 17:12
decisions-openai phrased a rerank by its question class setting, so
Rerank.decide(query="The customer is angry") on a class with the default
relevance question asked "Does the document answer or directly address
this query? Query: The customer is angry". The provider now tells a
PropertyRanker when the rerank is a decision, and decisions-openai sends
the statement question in that case; question shapes only the plain
rerank fallback. Also the decisions.proto comment for property names
blob.
Comments on the setting, on Rank and on ent.DecisionQuestion said what the
code did before the statement rule and before blob properties. A provider
test pins that a plain rerank through a decisions module is not a decision.

Copilot AI 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.

🟡 Changes recommended

Image preflight has size-boundary, validity, and excessive-allocation defects that undermine its validation guarantees.

3 open findings
What changed in this PR

Adds blob-image judging to decisions-openai for decide and decision rerank flows.

Changes:

  • Adds blob-property validation and property-aware reranking.
  • Builds inline OpenAI image inputs with MIME detection and size checks.
  • Extends unit and acceptance coverage for image decisions.
File Description
usecases/​modulecomponents/​ent/​decide.go Documents blob decision questions.
usecases/​modulecomponents/​additional/​rank/​rank.go Adds property-aware ranker interface.
usecases/​modulecomponents/​additional/​rank/​rank_test.go Tests property and decision forwarding.
usecases/​modulecomponents/​additional/​rank/​rank_result.go Dispatches to property-aware rankers.
usecases/​modulecomponents/​additional/​decide/​params.go Shares property-type validation.
test/​acceptance/​decisions/​decide_test.go Covers blob decisions end-to-end.
modules/​decisions-openai/​module.go Enables blob decision properties.
modules/​decisions-openai/​module_test.go Updates decision-limit expectations.
modules/​decisions-openai/​config/​class_settings.go Clarifies decision-rerank question behavior.
modules/​decisions-openai/​clients/​ranker.go Sends blob rerank inputs as images.
modules/​decisions-openai/​clients/​ranker_test.go Tests image reranking requests.
modules/​decisions-openai/​clients/​image.go Adds image detection and data URLs.
modules/​decisions-openai/​clients/​image_test.go Tests image formats and limits.
modules/​decisions-openai/​clients/​decide.go Adds image support to decisions.
modules/​decisions-openai/​clients/​decide_test.go Tests image decision requests.
modules/​decisions-dummy/​module.go Allows blob integration testing.
grpc/​proto/​v1/​decisions.proto Documents blob properties.
grpc/​generated/​protocol/​v1/​decisions.pb.go Regenerates protocol documentation.
adapters/​handlers/​grpc/​v1/​parse_search_request.go Validates decision-rerank property types.
adapters/​handlers/​grpc/​v1/​parse_search_request_test.go Tests rerank property validation.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +49 to +52
{"image/png", 0, []byte("\x89PNG")},
{"image/jpeg", 0, []byte("\xff\xd8\xff")},
{"image/gif", 0, []byte("GIF8")},
{"image/webp", 8, []byte("WEBP")},
// maxImageChars is the same bound on the base64.
const (
maxImageBytes = 20 << 20
maxImageChars = maxImageBytes / 3 * 4
// not an image the API takes, before any request is sent and billed.
func checkImages(documents []string, positions []int) error {
for _, position := range positions {
if _, err := imageDataURL(documents[position]); err != nil {
A plain rerank asks the relevance question, a rerank by a decision sends
its query as the statement; there is nothing left to configure. The
setting was introduced in #13409 and shaped every rerank until the
statement rule of the previous commit.
@jfrancoa
jfrancoa requested a balanced review from Copilot October 14, 2026 13:49
@sonarqubecloud

Copy link
Copy Markdown

Copilot AI 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.

🔵 Needs a closer look

Image boundary handling, WebP detection, and preflight allocation behavior need correction.

3 open findings

🧠 Review effort: Balanced

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