new: update models to 1.18, add create_named_vector and delete_named_vector#1201
Conversation
✅ Deploy Preview for poetic-froyo-8baba7 ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds named-vector management (create/delete vector name) across public, async, remote (gRPC/REST), and local clients; introduces Dense/Sparse vector creation configs and a VectorNameConfig alias. Adds gRPC messages/RPCs and HTTP endpoints for vector name lifecycle. Extends conversion layer, HTTP models, inspection cache, and protobufs to support new TurboQuantization and additional strict-mode/telemetry fields. Updates local collection storage and local remote persistence to handle named vectors. Adds congruence tests for named-vector operations and updates proto-generation tooling. Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
qdrant_client/proto/collections.proto (1)
368-370: ⚡ Quick winResolve TODO field lifecycle in public schema before merge.
Line 368 introduces
pluswith a TODO in a public proto message. If this field is temporary, remove it now and reserve tag3to avoid future wire-compatibility ambiguity.Suggested schema adjustment
message TurboQuantization{ optional bool always_ram = 1; optional TurboQuantBitSize bits = 2; - - // TODO(turbo): Remove before release - optional bool plus = 3; + // Reserved to prevent accidental tag reuse from pre-release experiments. + reserved 3; }🤖 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 `@qdrant_client/proto/collections.proto` around lines 368 - 370, Remove the temporary optional field "plus" (optional bool plus = 3;) from the public proto message and replace it by reserving tag 3 (reserve 3;) to preserve wire compatibility; remove the TODO comment and ensure any references to the "plus" field in code/clients are deleted or migrated to avoid compilation/runtime errors.qdrant_client/http/models/models.py (1)
2952-2960: ⚡ Quick winConstrain
modeto known values instead of plainstr.At Line 2957,
modeis documented ashigh_cpu/high_iobut typed asstr. UsingLiteral["high_cpu", "high_io"](or a small enum) improves validation and generated client typing.Proposed change
+from typing import Literal ... class SearchThreadPoolTelemetry(BaseModel): @@ - mode: str = Field(..., description="Currently active mode (`high_cpu` or `high_io`).") + mode: Literal["high_cpu", "high_io"] = Field( + ..., description="Currently active mode (`high_cpu` or `high_io`)." + )🤖 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 `@qdrant_client/http/models/models.py` around lines 2952 - 2960, Change the SearchThreadPoolTelemetry.mode field from a plain str to a constrained type so only "high_cpu" or "high_io" are accepted: update the type annotation for mode in the SearchThreadPoolTelemetry model to either typing.Literal["high_cpu", "high_io"] or a small enum (e.g., class SearchMode(Enum): HIGH_CPU="high_cpu"; HIGH_IO="high_io") and adjust the Field import/usage accordingly so Pydantic validation and generated client typing reflect the two allowed values.tests/conversions/fixtures.py (1)
260-281: ⚡ Quick winAdd a TurboQuant fixture variant with
model_idto close a round-trip coverage gap.Current turbo fixtures validate bits variants, but they don’t exercise
model_idpreservation. Adding one fixture withmodel_idwould catch mapping regressions immediately.Proposed fixture extension
+turbo_quantization_with_model = grpc.TurboQuantization( + model_id="test-model-v1", + bits=grpc.TurboQuantBitSize.Bits2, +) + +turbo_quantization_config_with_model = grpc.QuantizationConfig( + turboquant=turbo_quantization_with_model, +) + +quantization_config_diff_turbo_with_model = grpc.QuantizationConfigDiff( + turboquant=turbo_quantization_with_model, +)"QuantizationConfig": [ quantization_config, binary_quantization_config, binary_quantization_config_0, binary_quantization_config_1, binary_quantization_config_2, binary_quantization_config_3, turbo_quantization_config, turbo_quantization_config_minimal, turbo_quantization_config_bits1, turbo_quantization_config_bits1_5, turbo_quantization_config_bits4, + turbo_quantization_config_with_model, ] + product_quantizations, "QuantizationConfigDiff": [ quantization_config_diff_disabled, quantization_config_diff_scalar, quantization_config_diff_product, quantization_config_diff_turbo, quantization_config_diff_binary, + quantization_config_diff_turbo_with_model, ],Also applies to: 855-874, 1777-1783
🤖 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 `@tests/conversions/fixtures.py` around lines 260 - 281, Add a TurboQuantization fixture that includes a model_id field to exercise round-trip preservation of model identifiers: create a new variable (e.g., turbo_quantization_with_model_id) alongside the existing fixtures (turbo_quantization, turbo_quantization_minimal, turbo_quantization_bits1, turbo_quantization_bits1_5, turbo_quantization_bits4) and instantiate grpc.TurboQuantization with a representative model_id string plus whatever other fields you want (e.g., bits or always_ram) so serializers/mappers preserve model_id during conversion tests.
🤖 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 `@qdrant_client/local/local_collection.py`:
- Around line 2878-2881: The code silently no-ops when self.config.vectors is a
models.VectorParams instance (single unnamed vector); detect that case in the
block around the assignment and replace self.config.vectors with a dict that
preserves the original unnamed VectorParams and adds the new named vector:
convert the existing VectorParams into a dict entry (e.g., key "" or other
implicit-name used elsewhere) and set self.config.vectors[vector_name] = params
so info() and consumers see the updated config; update the logic around
self.config.vectors, vector_name and params to handle both dict and VectorParams
cases consistently.
In `@qdrant_client/qdrant_remote.py`:
- Around line 2420-2467: The gRPC branch of create vector-name/update code
ignores the ordering argument (seen where CreateVectorNameRequest is built and
sent via self.grpc_points.CreateVectorName), causing transport-dependent
semantics; modify the gRPC request construction to include ordering (map
types.WriteOrdering to the corresponding grpc ordering enum/field using
RestToGrpc.convert_* or a new converter) and pass it into
grpc.CreateVectorNameRequest (or, if gRPC truly cannot support ordering,
explicitly raise a clear UnsupportedOperationError when ordering is provided) so
behavior matches the REST path; update the analogous block handling the other
CreateVectorName/CreateVector logic referenced around the later range
(2484-2498) as well.
---
Nitpick comments:
In `@qdrant_client/http/models/models.py`:
- Around line 2952-2960: Change the SearchThreadPoolTelemetry.mode field from a
plain str to a constrained type so only "high_cpu" or "high_io" are accepted:
update the type annotation for mode in the SearchThreadPoolTelemetry model to
either typing.Literal["high_cpu", "high_io"] or a small enum (e.g., class
SearchMode(Enum): HIGH_CPU="high_cpu"; HIGH_IO="high_io") and adjust the Field
import/usage accordingly so Pydantic validation and generated client typing
reflect the two allowed values.
In `@qdrant_client/proto/collections.proto`:
- Around line 368-370: Remove the temporary optional field "plus" (optional bool
plus = 3;) from the public proto message and replace it by reserving tag 3
(reserve 3;) to preserve wire compatibility; remove the TODO comment and ensure
any references to the "plus" field in code/clients are deleted or migrated to
avoid compilation/runtime errors.
In `@tests/conversions/fixtures.py`:
- Around line 260-281: Add a TurboQuantization fixture that includes a model_id
field to exercise round-trip preservation of model identifiers: create a new
variable (e.g., turbo_quantization_with_model_id) alongside the existing
fixtures (turbo_quantization, turbo_quantization_minimal,
turbo_quantization_bits1, turbo_quantization_bits1_5, turbo_quantization_bits4)
and instantiate grpc.TurboQuantization with a representative model_id string
plus whatever other fields you want (e.g., bits or always_ram) so
serializers/mappers preserve model_id during conversion tests.
🪄 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: 731edda5-8d1b-4a96-b79b-b6eb2b9b2253
📒 Files selected for processing (27)
qdrant_client/async_client_base.pyqdrant_client/async_qdrant_client.pyqdrant_client/async_qdrant_remote.pyqdrant_client/client_base.pyqdrant_client/conversions/common_types.pyqdrant_client/conversions/conversion.pyqdrant_client/embed/_inspection_cache.pyqdrant_client/grpc/collections_pb2.pyqdrant_client/grpc/collections_pb2.pyiqdrant_client/grpc/points_pb2.pyqdrant_client/grpc/points_pb2.pyiqdrant_client/grpc/points_service_pb2.pyqdrant_client/grpc/points_service_pb2_grpc.pyqdrant_client/http/api/collections_api.pyqdrant_client/http/api/service_api.pyqdrant_client/http/models/models.pyqdrant_client/local/async_qdrant_local.pyqdrant_client/local/local_collection.pyqdrant_client/local/qdrant_local.pyqdrant_client/proto/collections.protoqdrant_client/proto/points.protoqdrant_client/proto/points_service.protoqdrant_client/qdrant_client.pyqdrant_client/qdrant_remote.pytests/congruence_tests/test_modify_named_vector.pytests/conversions/fixtures.pytools/generate_grpc_client.sh
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@qdrant_client/local/local_collection.py`:
- Around line 2860-2864: The VectorParams construction assigned to params is
dropping the datatype from DenseVectorConfig; update the params =
models.VectorParams(...) call (where params is built from config) to include
datatype=config.datatype so the DenseVectorConfig.datatype value is forwarded
into VectorParams; locate the VectorParams instantiation in local_collection
(the params variable creation) and add the datatype field.
- Around line 2890-2892: The conversion of SparseVectorConfig to
models.SparseVectorParams is dropping the datatype property; update the
conversion so datatype is preserved by either adding a datatype field to
models.SparseVectorParams and including datatype=config.datatype when
constructing params in local_collection.py (the SparseVectorConfig -> params
creation block), or if models.SparseVectorParams should not hold datatype, route
config.datatype to the appropriate consumer (e.g., the index creation or vector
schema builder) instead—ensure SparseVectorConfig.datatype is forwarded from the
place where params are built (the params variable in local_collection.py) to
wherever the vector type is used.
🪄 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: ae8a5d73-ff5d-447c-8423-47f311c56a07
📒 Files selected for processing (1)
qdrant_client/local/local_collection.py
| params = models.VectorParams( | ||
| size=config.size, | ||
| distance=config.distance, | ||
| multivector_config=config.multivector_config, | ||
| ) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Show all fields defined on DenseVectorConfig and VectorParams to compare.
# Find DenseVectorConfig class definition and its fields
rg -n "DenseVectorConfig" --type py -A 30
# Show VectorParams fields for comparison
rg -n "class VectorParams" --type py -A 30Repository: qdrant/qdrant-client
Length of output: 22410
Forward the datatype field from DenseVectorConfig to VectorParams.
The datatype field exists in DenseVectorConfig but is not passed when constructing VectorParams at line 2860-2864, causing that configuration to be silently dropped. Include it in the constructor:
Suggested fix
params = models.VectorParams(
size=config.size,
distance=config.distance,
multivector_config=config.multivector_config,
datatype=config.datatype,
)🤖 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 `@qdrant_client/local/local_collection.py` around lines 2860 - 2864, The
VectorParams construction assigned to params is dropping the datatype from
DenseVectorConfig; update the params = models.VectorParams(...) call (where
params is built from config) to include datatype=config.datatype so the
DenseVectorConfig.datatype value is forwarded into VectorParams; locate the
VectorParams instantiation in local_collection (the params variable creation)
and add the datatype field.
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
qdrant_client/local/local_collection.py (1)
2311-2327:⚠️ Potential issue | 🟠 Major | ⚡ Quick winReject sparse/multi relevance feedback here or add a matching scorer.
_preprocess_vector_input()can resolveusingto sparse or multivector data, but this branch always builds aNaiveFeedbackQuerythat later goes through the dense search path. In local mode that turns sparse feedback into a misleading “Dense vector … not found” failure instead of a supported query.Suggested guard
strategy = relevance_feedback.strategy if isinstance(strategy, models.NaiveFeedbackStrategy): + if vector_name in self.sparse_vectors or vector_name in self.multivectors: + raise ValueError( + "Naive feedback is only supported for dense vectors in local mode" + ) params = strategy.naive coefficients = NaiveFeedbackCoefficients(a=params.a, b=params.b, c=params.c) naive_query = NaiveFeedbackQuery( target=target_vector, feedback=feedback_items,🤖 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 `@qdrant_client/local/local_collection.py` around lines 2311 - 2327, The NaiveFeedbackStrategy branch always builds a NaiveFeedbackQuery and sends it down the dense search path (via search), but _preprocess_vector_input can resolve the `using` vector to sparse or multivector types causing incorrect "Dense vector ... not found" failures; update the branch that handles isinstance(strategy, models.NaiveFeedbackStrategy) to inspect the preprocessed vector type (the output from _preprocess_vector_input or the resolved `vector_name`/target_vector) and either (a) reject sparse/multivector feedback with a clear error, or (b) route to or construct a matching scorer for sparse/multivector inputs before calling search; reference NaiveFeedbackStrategy, NaiveFeedbackQuery, _preprocess_vector_input, and search when implementing the guard/routing.
♻️ Duplicate comments (1)
qdrant_client/local/local_collection.py (1)
2860-2864:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPreserve
datatypewhen creating dense named vectors.The new dense-vector path still drops
DenseVectorConfig.datatype, so local collections silently create the vector with the default dtype even when the caller requested another one.Suggested fix
params = models.VectorParams( size=config.size, distance=config.distance, multivector_config=config.multivector_config, + datatype=config.datatype, )🤖 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 `@qdrant_client/local/local_collection.py` around lines 2860 - 2864, The dense-vector creation path drops the DenseVectorConfig.datatype so vectors use the default dtype; update the VectorParams construction to preserve the requested dtype by setting the datatype field from the DenseVectorConfig (e.g. change the models.VectorParams call that builds params to include datatype=config.datatype). Locate the vector creation code using models.VectorParams and the DenseVectorConfig instance named config and pass config.datatype through so the local collection creates the named dense vector with the correct dtype.
🤖 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 `@qdrant_client/async_qdrant_remote.py`:
- Around line 2207-2297: The public methods create_vector_name and
delete_vector_name accept an ordering parameter but when self._prefer_grpc is
True the ordering is not forwarded to grpc.CreateVectorNameRequest /
grpc.DeleteVectorNameRequest (proto has no ordering), causing silent behavior
drift; update both functions to check if ordering is not None when
self._prefer_grpc is True and raise a ValueError (with a clear message like
"ordering is not supported with gRPC; set prefer_grpc=False or omit ordering")
so callers are prevented from accidentally losing write-ordering semantics.
- Around line 2217-2243: The gRPC branch handling of vector_name_config in
async_qdrant_remote.py silently allows unknown types by leaving dense_config and
sparse_config as None; update the if/elif block that checks
isinstance(vector_name_config, models.DenseVectorNameConfig) and
isinstance(vector_name_config, models.SparseVectorNameConfig) to add an explicit
else that raises a TypeError with a clear message (mentioning the unexpected
type and the value of vector_name_config) so the client fails fast; follow the
pattern used in _try_argument_to_grpc_selector and cluster_collection_update for
message style and placement so callers get immediate, descriptive feedback
instead of sending an empty CreateVectorNameRequest.
In `@qdrant_client/local/local_collection.py`:
- Around line 2913-2931: delete_vector_name currently only mutates in-memory
structures and meta.json, leaving the vector data present in on-disk persisted
points; fix by, after removing the in-memory/vector-config entries in
delete_vector_name, detecting persistent collections and scanning all persisted
point records to remove the field(s) corresponding to vector_name (handle dense
vectors, sparse_vectors_idf entries and multivectors appropriately) and
re-persist each point (or rewrite each point file) so the vector data is
actually removed from disk; use the collection's existing persistence/write API
(or add a helper to load a point, delete the vector entry, write to a temp file
and atomically replace) and ensure meta.json/delete markers remain consistent
and errors are handled so the operation is durable.
In `@qdrant_client/proto/collections.proto`:
- Around line 368-370: Remove the temporary TurboQuantization.plus proto field
and all usages: delete the optional bool plus = 3; from the TurboQuantization
message in collections.proto, then remove the corresponding property from the
HTTP REST model TurboQuantQuantizationConfig, strip handling of .plus from the
gRPC<->REST conversion logic (conversion functions that read/write
TurboQuantization/TurboQuantQuantizationConfig), and update tests and fixtures
that reference TurboQuantization.plus; alternatively, if you must keep it for
experimentation, move it into a clearly versioned/experimental proto
message/path and update conversions and tests to use that experimental type
instead.
In `@qdrant_client/proto/points.proto`:
- Around line 378-405: Add an optional WriteOrdering field to both
CreateVectorNameRequest and DeleteVectorNameRequest so callers can enforce
Medium/Strong write consistency for named-vector schema changes: in
CreateVectorNameRequest (which currently ends with optional uint64 timeout = 6)
add "optional WriteOrdering ordering = 7;" and in DeleteVectorNameRequest (which
currently ends with optional uint64 timeout = 4) add "optional WriteOrdering
ordering = 5;". Ensure WriteOrdering is available/imported in this proto file
and run protoc to validate.
In `@qdrant_client/qdrant_remote.py`:
- Around line 2424-2476: The create_vector_name implementation must accept
grpc-native config objects: detect if vector_name_config is a
grpc.DenseVectorCreationConfig or grpc.SparseVectorCreationConfig and convert
them to the proper variants instead of treating them as REST models (and
conversely, in the gRPC branch accept models.DenseVectorNameConfig/
SparseVectorNameConfig). Update the logic in create_vector_name to: when
self._prefer_grpc is True, if vector_name_config is a
grpc.DenseVectorCreationConfig or grpc.SparseVectorCreationConfig, map/unwrap
those into the dense_config/sparse_config fields (reuse RestToGrpc.convert_*
helpers where appropriate); when self._prefer_grpc is False, if
vector_name_config is a grpc.*CreationConfig, wrap/translate it into
models.DenseVectorNameConfig or models.SparseVectorNameConfig before calling
http.collections_api.create_vector_name so serialization succeeds. Reference
symbols: create_vector_name, vector_name_config, grpc.DenseVectorCreationConfig,
grpc.SparseVectorCreationConfig, models.DenseVectorNameConfig,
models.SparseVectorNameConfig,
RestToGrpc.convert_datatype/convert_multivector_config/convert_modifier.
---
Outside diff comments:
In `@qdrant_client/local/local_collection.py`:
- Around line 2311-2327: The NaiveFeedbackStrategy branch always builds a
NaiveFeedbackQuery and sends it down the dense search path (via search), but
_preprocess_vector_input can resolve the `using` vector to sparse or multivector
types causing incorrect "Dense vector ... not found" failures; update the branch
that handles isinstance(strategy, models.NaiveFeedbackStrategy) to inspect the
preprocessed vector type (the output from _preprocess_vector_input or the
resolved `vector_name`/target_vector) and either (a) reject sparse/multivector
feedback with a clear error, or (b) route to or construct a matching scorer for
sparse/multivector inputs before calling search; reference
NaiveFeedbackStrategy, NaiveFeedbackQuery, _preprocess_vector_input, and search
when implementing the guard/routing.
---
Duplicate comments:
In `@qdrant_client/local/local_collection.py`:
- Around line 2860-2864: The dense-vector creation path drops the
DenseVectorConfig.datatype so vectors use the default dtype; update the
VectorParams construction to preserve the requested dtype by setting the
datatype field from the DenseVectorConfig (e.g. change the models.VectorParams
call that builds params to include datatype=config.datatype). Locate the vector
creation code using models.VectorParams and the DenseVectorConfig instance named
config and pass config.datatype through so the local collection creates the
named dense vector with the correct dtype.
🪄 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: 57e7ec5e-68b6-4f37-959e-f146a34ada63
📒 Files selected for processing (27)
qdrant_client/async_client_base.pyqdrant_client/async_qdrant_client.pyqdrant_client/async_qdrant_remote.pyqdrant_client/client_base.pyqdrant_client/conversions/common_types.pyqdrant_client/conversions/conversion.pyqdrant_client/embed/_inspection_cache.pyqdrant_client/grpc/collections_pb2.pyqdrant_client/grpc/collections_pb2.pyiqdrant_client/grpc/points_pb2.pyqdrant_client/grpc/points_pb2.pyiqdrant_client/grpc/points_service_pb2.pyqdrant_client/grpc/points_service_pb2_grpc.pyqdrant_client/http/api/collections_api.pyqdrant_client/http/api/service_api.pyqdrant_client/http/models/models.pyqdrant_client/local/async_qdrant_local.pyqdrant_client/local/local_collection.pyqdrant_client/local/qdrant_local.pyqdrant_client/proto/collections.protoqdrant_client/proto/points.protoqdrant_client/proto/points_service.protoqdrant_client/qdrant_client.pyqdrant_client/qdrant_remote.pytests/congruence_tests/test_modify_named_vector.pytests/conversions/fixtures.pytools/generate_grpc_client.sh
✅ Files skipped from review due to trivial changes (1)
- qdrant_client/conversions/common_types.py
There was a problem hiding this comment.
♻️ Duplicate comments (4)
qdrant_client/async_qdrant_remote.py (2)
2220-2243:⚠️ Potential issue | 🟠 Major | ⚡ Quick winFail fast on unsupported
vector_name_configtypes in gRPC path.At Line [2220], only REST-model configs are matched. Any other runtime value leaves both
dense_configandsparse_configunset, and Line [2249] still sends the request with an empty config instead of raising a client-side error.💡 Suggested fix
if isinstance(vector_name_config, models.DenseVectorNameConfig): cfg = vector_name_config.dense dense_config = grpc.DenseVectorCreationConfig( size=cfg.size, distance=RestToGrpc.convert_distance(cfg.distance), multivector_config=RestToGrpc.convert_multivector_config( cfg.multivector_config ) if cfg.multivector_config is not None else None, datatype=RestToGrpc.convert_datatype(cfg.datatype) if cfg.datatype is not None else None, ) elif isinstance(vector_name_config, models.SparseVectorNameConfig): cfg = vector_name_config.sparse sparse_config = grpc.SparseVectorCreationConfig( modifier=RestToGrpc.convert_modifier(cfg.modifier) if cfg.modifier is not None else None, datatype=RestToGrpc.convert_datatype(cfg.datatype) if cfg.datatype is not None else None, ) + else: + raise TypeError( + f"Unsupported vector_name_config type: {type(vector_name_config)}; " + f"value={vector_name_config!r}" + )🤖 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 `@qdrant_client/async_qdrant_remote.py` around lines 2220 - 2243, The code path that builds grpc.DenseVectorCreationConfig / grpc.SparseVectorCreationConfig only handles models.DenseVectorNameConfig and models.SparseVectorNameConfig, leaving dense_config and sparse_config unset for any other runtime type; update the logic around the vector_name_config handling (the block that uses RestToGrpc.convert_* and constructs DenseVectorCreationConfig/SparseVectorCreationConfig) to detect unsupported types and immediately raise a clear client-side error (e.g., ValueError or TypeError) referencing vector_name_config, instead of falling through and sending an empty config; ensure the exception is thrown before the request is built/sent so callers get fast, explicit failure when an unexpected vector_name_config type is provided.
2244-2248:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDo not drop grpc-native
orderingvalues.At Line [2244] and Line [2284], non-
models.WriteOrderinginputs are coerced toNone. That silently discards valid grpc ordering values in gRPC mode.💡 Suggested fix
- grpc_ordering = ( - RestToGrpc.convert_write_ordering(ordering) - if isinstance(ordering, models.WriteOrdering) - else None - ) + grpc_ordering = ordering + if isinstance(ordering, models.WriteOrdering): + grpc_ordering = RestToGrpc.convert_write_ordering(ordering) ... - grpc_ordering = ( - RestToGrpc.convert_write_ordering(ordering) - if isinstance(ordering, models.WriteOrdering) - else None - ) + grpc_ordering = ordering + if isinstance(ordering, models.WriteOrdering): + grpc_ordering = RestToGrpc.convert_write_ordering(ordering)Also applies to: 2284-2288
🤖 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 `@qdrant_client/async_qdrant_remote.py` around lines 2244 - 2248, The code currently coerces non-models.WriteOrdering inputs to None, which drops valid gRPC-native ordering values; update both places where grpc_ordering (and the similar variable at the second occurrence) is set — using RestToGrpc.convert_write_ordering(ordering) if isinstance(ordering, models.WriteOrdering) else keep the original ordering value (i.e., pass through the incoming grpc-native ordering) instead of None — so replace the else branch to return the original ordering; reference the grpc_ordering assignment and RestToGrpc.convert_write_ordering usages in async_qdrant_remote.py (also apply the same change at the second occurrence around the later lines).qdrant_client/qdrant_remote.py (2)
2427-2456:⚠️ Potential issue | 🟠 Major | ⚡ Quick winReject unsupported
vector_name_configinputs before sending gRPC request.At Line [2427], only two model variants are parsed. For any other runtime type, both configs stay unset and Line [2462] still sends
CreateVectorNameRequest, leading to a server-side failure instead of a clear client error.💡 Suggested fix
if isinstance(vector_name_config, models.DenseVectorNameConfig): cfg = vector_name_config.dense dense_config = grpc.DenseVectorCreationConfig( size=cfg.size, distance=RestToGrpc.convert_distance(cfg.distance), multivector_config=( RestToGrpc.convert_multivector_config(cfg.multivector_config) if cfg.multivector_config is not None else None ), datatype=( RestToGrpc.convert_datatype(cfg.datatype) if cfg.datatype is not None else None ), ) elif isinstance(vector_name_config, models.SparseVectorNameConfig): cfg = vector_name_config.sparse sparse_config = grpc.SparseVectorCreationConfig( modifier=( RestToGrpc.convert_modifier(cfg.modifier) if cfg.modifier is not None else None ), datatype=( RestToGrpc.convert_datatype(cfg.datatype) if cfg.datatype is not None else None ), ) + else: + raise TypeError( + f"Unsupported vector_name_config type: {type(vector_name_config)}; " + f"value={vector_name_config!r}" + )🤖 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 `@qdrant_client/qdrant_remote.py` around lines 2427 - 2456, The code only handles models.DenseVectorNameConfig and models.SparseVectorNameConfig but proceeds to call CreateVectorNameRequest even when neither branch ran; add an explicit else that rejects unsupported vector_name_config types (e.g., raise TypeError or ValueError with a clear message) before building/sending the gRPC CreateVectorNameRequest so the client fails fast; update the logic around vector_name_config, dense_config, and sparse_config (same block that checks isinstance against models.DenseVectorNameConfig and models.SparseVectorNameConfig) to validate input and surface a helpful error instead of letting the server return an opaque failure.
2457-2461:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPreserve grpc
orderingvalues in gRPC mode.At Line [2457] and Line [2496],
orderingis dropped toNoneunless it ismodels.WriteOrdering. This can silently remove requested ordering semantics.💡 Suggested fix
- grpc_ordering = ( - RestToGrpc.convert_write_ordering(ordering) - if isinstance(ordering, models.WriteOrdering) - else None - ) + grpc_ordering = ordering + if isinstance(ordering, models.WriteOrdering): + grpc_ordering = RestToGrpc.convert_write_ordering(ordering) ... - grpc_ordering = ( - RestToGrpc.convert_write_ordering(ordering) - if isinstance(ordering, models.WriteOrdering) - else None - ) + grpc_ordering = ordering + if isinstance(ordering, models.WriteOrdering): + grpc_ordering = RestToGrpc.convert_write_ordering(ordering)Also applies to: 2496-2500
🤖 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 `@qdrant_client/qdrant_remote.py` around lines 2457 - 2461, The code currently sets grpc_ordering to None unless ordering is a models.WriteOrdering, which drops already-formed gRPC ordering enums; update the logic around grpc_ordering (the assignment using RestToGrpc.convert_write_ordering) so it preserves ordering when it is already a gRPC enum: if ordering is an instance of models.WriteOrdering call RestToGrpc.convert_write_ordering(ordering), else if ordering is not None assign grpc_ordering = ordering (preserve existing gRPC enum), otherwise None; apply the same change for both places that set grpc_ordering (the blocks referencing RestToGrpc.convert_write_ordering and models.WriteOrdering).
🤖 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.
Duplicate comments:
In `@qdrant_client/async_qdrant_remote.py`:
- Around line 2220-2243: The code path that builds
grpc.DenseVectorCreationConfig / grpc.SparseVectorCreationConfig only handles
models.DenseVectorNameConfig and models.SparseVectorNameConfig, leaving
dense_config and sparse_config unset for any other runtime type; update the
logic around the vector_name_config handling (the block that uses
RestToGrpc.convert_* and constructs
DenseVectorCreationConfig/SparseVectorCreationConfig) to detect unsupported
types and immediately raise a clear client-side error (e.g., ValueError or
TypeError) referencing vector_name_config, instead of falling through and
sending an empty config; ensure the exception is thrown before the request is
built/sent so callers get fast, explicit failure when an unexpected
vector_name_config type is provided.
- Around line 2244-2248: The code currently coerces non-models.WriteOrdering
inputs to None, which drops valid gRPC-native ordering values; update both
places where grpc_ordering (and the similar variable at the second occurrence)
is set — using RestToGrpc.convert_write_ordering(ordering) if
isinstance(ordering, models.WriteOrdering) else keep the original ordering value
(i.e., pass through the incoming grpc-native ordering) instead of None — so
replace the else branch to return the original ordering; reference the
grpc_ordering assignment and RestToGrpc.convert_write_ordering usages in
async_qdrant_remote.py (also apply the same change at the second occurrence
around the later lines).
In `@qdrant_client/qdrant_remote.py`:
- Around line 2427-2456: The code only handles models.DenseVectorNameConfig and
models.SparseVectorNameConfig but proceeds to call CreateVectorNameRequest even
when neither branch ran; add an explicit else that rejects unsupported
vector_name_config types (e.g., raise TypeError or ValueError with a clear
message) before building/sending the gRPC CreateVectorNameRequest so the client
fails fast; update the logic around vector_name_config, dense_config, and
sparse_config (same block that checks isinstance against
models.DenseVectorNameConfig and models.SparseVectorNameConfig) to validate
input and surface a helpful error instead of letting the server return an opaque
failure.
- Around line 2457-2461: The code currently sets grpc_ordering to None unless
ordering is a models.WriteOrdering, which drops already-formed gRPC ordering
enums; update the logic around grpc_ordering (the assignment using
RestToGrpc.convert_write_ordering) so it preserves ordering when it is already a
gRPC enum: if ordering is an instance of models.WriteOrdering call
RestToGrpc.convert_write_ordering(ordering), else if ordering is not None assign
grpc_ordering = ordering (preserve existing gRPC enum), otherwise None; apply
the same change for both places that set grpc_ordering (the blocks referencing
RestToGrpc.convert_write_ordering and models.WriteOrdering).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 45c53da8-3643-4657-8e4b-a920d40672b0
📒 Files selected for processing (12)
qdrant_client/async_qdrant_remote.pyqdrant_client/conversions/conversion.pyqdrant_client/embed/_inspection_cache.pyqdrant_client/grpc/collections_pb2.pyqdrant_client/grpc/collections_pb2.pyiqdrant_client/grpc/points_pb2.pyqdrant_client/grpc/points_pb2.pyiqdrant_client/http/models/models.pyqdrant_client/proto/collections.protoqdrant_client/proto/points.protoqdrant_client/qdrant_remote.pytests/conversions/fixtures.py
✅ Files skipped from review due to trivial changes (1)
- qdrant_client/grpc/collections_pb2.pyi
🚧 Files skipped from review as they are similar to previous changes (5)
- tests/conversions/fixtures.py
- qdrant_client/proto/collections.proto
- qdrant_client/conversions/conversion.py
- qdrant_client/embed/_inspection_cache.py
- qdrant_client/grpc/points_pb2.pyi
…vector (#1201) * new: update models to 1.18, add create_named_vector and delete_named_vector * fix: add missing strict mode config updates * fix: fix local mode create and delete vector name * new: update turbo quant fields * fix: persist vector deletion
No description provided.