Skip to content

Commit e6cfbba

Browse files
committed
Merge remote-tracking branch 'upstream/main' into feature/normalize-foundry-project-endpoint
# Conflicts: # CHANGELOG.md
2 parents 74d25f8 + 08fa87a commit e6cfbba

6 files changed

Lines changed: 86 additions & 1 deletion

File tree

.env.template

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ AI_FOUNDRY_EMBEDDING_DEPLOYMENT_NAME=text-embedding-3-large
6060
AI_FOUNDRY_EMBEDDING_DIMENSIONS=1536
6161
AI_FOUNDRY_EMBEDDING_DATA_TYPE=float32
6262
AI_FOUNDRY_EMBEDDING_DISTANCE_FUNCTION=cosine
63+
# Optional. Vector index type for the memories container: diskANN (default),
64+
# quantizedFlat, or flat. diskANN requires the DiskANN capability on the Cosmos
65+
# DB account; use quantizedFlat or flat for accounts without it (e.g. the
66+
# classic Cosmos DB emulator).
67+
AI_FOUNDRY_EMBEDDING_VECTOR_INDEX_TYPE=diskANN
6368
COSMOS_DB_FULL_TEXT_LANGUAGE=en-US
6469

6570
AI_FOUNDRY_CHAT_DEPLOYMENT_NAME=<your-model-deployment>

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33
### Unreleased
44

55
#### Other Changes
6+
* The memories container's vector index type is now configurable instead of being
7+
hard-coded to `diskANN`. Set it via the `vector_index_type` argument to
8+
`create_memory_store(...)` or the `AI_FOUNDRY_EMBEDDING_VECTOR_INDEX_TYPE`
9+
environment variable. Allowed values are `diskANN` (default), `quantizedFlat`,
10+
and `flat`. This lets the toolkit run against Cosmos DB accounts without the
11+
DiskANN capability (for example the classic Cosmos DB emulator), enabling
12+
emulator-backed integration test pipelines.
613
* `ai_foundry_endpoint` now accepts a project-scoped Azure AI Foundry URL
714
(`https://<resource>.services.ai.azure.com/api/projects/<name>`) in addition
815
to the account-level inference endpoint. The project path is automatically

azure/cosmos/agent_memory/_utils.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ def normalize_ai_foundry_endpoint(endpoint: Optional[str]) -> Optional[str]:
219219

220220
_ALLOWED_EMBEDDING_DATA_TYPES = ("float32", "uint8", "int8")
221221
_ALLOWED_DISTANCE_FUNCTIONS = ("cosine", "dotproduct", "euclidean")
222+
_ALLOWED_VECTOR_INDEX_TYPES = ("diskANN", "quantizedFlat", "flat")
222223

223224

224225
def _resolve_embedding_data_type(val: Optional[str]) -> str:
@@ -255,6 +256,27 @@ def _resolve_distance_function(val: Optional[str]) -> str:
255256
return raw
256257

257258

259+
def _resolve_vector_index_type(val: Optional[str]) -> str:
260+
"""Resolve vector index type from explicit value or ``AI_FOUNDRY_EMBEDDING_VECTOR_INDEX_TYPE`` env var.
261+
262+
Defaults to ``diskANN``. Raises :class:`ConfigurationError` for unknown values.
263+
264+
``diskANN`` requires the Cosmos DB account to have the DiskANN vector index
265+
capability enabled. Accounts that do not (for example the classic Cosmos DB
266+
emulator) can use ``quantizedFlat`` or ``flat`` instead.
267+
"""
268+
raw = (val if val is not None else os.environ.get("AI_FOUNDRY_EMBEDDING_VECTOR_INDEX_TYPE") or "diskANN").strip()
269+
if raw not in _ALLOWED_VECTOR_INDEX_TYPES:
270+
raise ConfigurationError(
271+
message=(
272+
f"Invalid configuration for vector_index_type: must be one of "
273+
f"{_ALLOWED_VECTOR_INDEX_TYPES}, got {raw!r}"
274+
),
275+
parameter="vector_index_type",
276+
)
277+
return raw
278+
279+
258280
def _resolve_full_text_language(val: Optional[str]) -> str:
259281
"""Resolve full-text language from explicit value or ``COSMOS_DB_FULL_TEXT_LANGUAGE`` env var.
260282
@@ -412,6 +434,7 @@ def _container_policies(
412434
embedding_data_type: str,
413435
distance_function: str,
414436
full_text_language: str,
437+
vector_index_type: str = "diskANN",
415438
) -> tuple[dict, dict, dict]:
416439
"""Build the vector, indexing, and full-text policies for container creation."""
417440
vector_embedding_policy = {
@@ -432,7 +455,7 @@ def _container_policies(
432455
{"path": "/source_memory_ids/*"},
433456
{"path": "/supersedes_ids/*"},
434457
],
435-
"vectorIndexes": [{"path": "/embedding", "type": "diskANN"}],
458+
"vectorIndexes": [{"path": "/embedding", "type": vector_index_type}],
436459
"fullTextIndexes": [{"path": "/content"}],
437460
# Procedural synthesis selects TOP N by (salience DESC, created_at ASC, id ASC).
438461
# Cosmos requires a composite index for multi-property ORDER BY; without it the

azure/cosmos/agent_memory/aio/cosmos_memory_client.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
_resolve_distance_function,
1919
_resolve_embedding_data_type,
2020
_resolve_full_text_language,
21+
_resolve_vector_index_type,
2122
_validate_connection,
2223
)
2324
from azure.cosmos.agent_memory.aio.auto_trigger import maybe_trigger_steps
@@ -263,6 +264,7 @@ async def create_memory_store(
263264
full_text_language: Optional[str] = None,
264265
throughput_mode: Optional[str] = None,
265266
autoscale_max_ru: Optional[int] = None,
267+
vector_index_type: Optional[str] = None,
266268
) -> None:
267269
"""Create the Cosmos DB database and memory/counter/lease containers."""
268270
self._cosmos_endpoint = endpoint or self._cosmos_endpoint
@@ -310,6 +312,7 @@ async def create_memory_store(
310312
embedding_data_type=_resolve_embedding_data_type(embedding_data_type),
311313
distance_function=_resolve_distance_function(distance_function),
312314
full_text_language=_resolve_full_text_language(full_text_language),
315+
vector_index_type=_resolve_vector_index_type(vector_index_type),
313316
)
314317
self._memories_container_client = await db.create_container_if_not_exists(
315318
**_build_container_kwargs(

azure/cosmos/agent_memory/cosmos_memory_client.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
_resolve_distance_function,
2020
_resolve_embedding_data_type,
2121
_resolve_full_text_language,
22+
_resolve_vector_index_type,
2223
_validate_connection,
2324
)
2425
from .auto_trigger import maybe_trigger_steps
@@ -235,6 +236,7 @@ def create_memory_store(
235236
full_text_language: Optional[str] = None,
236237
throughput_mode: Optional[str] = None,
237238
autoscale_max_ru: Optional[int] = None,
239+
vector_index_type: Optional[str] = None,
238240
) -> None:
239241
"""Create the Cosmos DB database and memory/counter/lease containers."""
240242
self._cosmos_endpoint = endpoint or self._cosmos_endpoint
@@ -281,6 +283,7 @@ def create_memory_store(
281283
embedding_data_type=_resolve_embedding_data_type(embedding_data_type),
282284
distance_function=_resolve_distance_function(distance_function),
283285
full_text_language=_resolve_full_text_language(full_text_language),
286+
vector_index_type=_resolve_vector_index_type(vector_index_type),
284287
)
285288
self._memories_container_client = db.create_container_if_not_exists(
286289
**_build_container_kwargs(

tests/unit/test_utils.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
from azure.cosmos.agent_memory._utils import (
66
DEFAULT_TTL_BY_TYPE,
77
_build_container_kwargs,
8+
_container_policies,
89
_make_memory,
910
_resolve_distance_function,
1011
_resolve_embedding_data_type,
1112
_resolve_full_text_language,
13+
_resolve_vector_index_type,
1214
compute_content_hash,
1315
normalize_ai_foundry_endpoint,
1416
)
@@ -227,6 +229,48 @@ def test_resolve_distance_function_invalid_raises(monkeypatch):
227229
_resolve_distance_function(None)
228230

229231

232+
def test_resolve_vector_index_type_defaults(monkeypatch):
233+
monkeypatch.delenv("AI_FOUNDRY_EMBEDDING_VECTOR_INDEX_TYPE", raising=False)
234+
assert _resolve_vector_index_type(None) == "diskANN"
235+
236+
237+
def test_resolve_vector_index_type_from_env(monkeypatch):
238+
monkeypatch.setenv("AI_FOUNDRY_EMBEDDING_VECTOR_INDEX_TYPE", "quantizedFlat")
239+
assert _resolve_vector_index_type(None) == "quantizedFlat"
240+
241+
242+
def test_resolve_vector_index_type_explicit_overrides_env(monkeypatch):
243+
monkeypatch.setenv("AI_FOUNDRY_EMBEDDING_VECTOR_INDEX_TYPE", "quantizedFlat")
244+
assert _resolve_vector_index_type("flat") == "flat"
245+
246+
247+
def test_resolve_vector_index_type_invalid_raises(monkeypatch):
248+
monkeypatch.setenv("AI_FOUNDRY_EMBEDDING_VECTOR_INDEX_TYPE", "hnsw")
249+
with pytest.raises(ConfigurationError):
250+
_resolve_vector_index_type(None)
251+
252+
253+
def test_container_policies_defaults_to_diskann():
254+
_, indexing_policy, _ = _container_policies(
255+
embedding_dimensions=1536,
256+
embedding_data_type="float32",
257+
distance_function="cosine",
258+
full_text_language="en-US",
259+
)
260+
assert indexing_policy["vectorIndexes"] == [{"path": "/embedding", "type": "diskANN"}]
261+
262+
263+
def test_container_policies_uses_supplied_vector_index_type():
264+
_, indexing_policy, _ = _container_policies(
265+
embedding_dimensions=1536,
266+
embedding_data_type="float32",
267+
distance_function="cosine",
268+
full_text_language="en-US",
269+
vector_index_type="quantizedFlat",
270+
)
271+
assert indexing_policy["vectorIndexes"] == [{"path": "/embedding", "type": "quantizedFlat"}]
272+
273+
230274
def test_resolve_full_text_language_defaults(monkeypatch):
231275
monkeypatch.delenv("COSMOS_DB_FULL_TEXT_LANGUAGE", raising=False)
232276
assert _resolve_full_text_language(None) == "en-US"

0 commit comments

Comments
 (0)