From 74982fa5a68bf49678bba641f8767a5e9b9a8d1f Mon Sep 17 00:00:00 2001 From: whiterabbit1983 Date: Wed, 30 Oct 2024 21:20:02 +0300 Subject: [PATCH] MMR implementation (#770) > [!IMPORTANT] > Implements Maximal Marginal Relevance (MMR) in document search with a new `mmr_strength` parameter, updating search logic and API. > > - **Behavior**: > - Introduces `mmr_strength` parameter in `BaseDocSearchRequest` in `Docs.py` to control MMR behavior. > - Implements MMR logic in `maximal_marginal_relevance()` in `mmr.py`. > - Integrates MMR in `search_user_docs()` and `search_agent_docs()` in `search_docs.py`. > - **Search Logic**: > - Modifies `search_docs_by_embedding()` and `search_docs_hybrid()` to adjust `k` based on `mmr_strength`. > - Adds `embedding` field to `Snippet` model in `Docs.py` and `models.tsp`. > - **Dependencies**: > - Adds `simsimd` to `pyproject.toml` for optimized cosine similarity calculations. > - **Misc**: > - Updates OpenAPI spec in `openapi-1.0.0.yaml` to include `mmr_strength` and `embedding` fields. > > This description was created by [Ellipsis](https://www.ellipsis.dev?ref=julep-ai%2Fjulep&utm_source=github&utm_medium=referral) for 583f70ab5476f39f985c518700ea01a9709acdca. It will automatically update as commits are pushed. --------- Signed-off-by: Diwank Singh Tomer Co-authored-by: Diwank Singh Tomer --- agents-api/agents_api/autogen/Docs.py | 5 + agents-api/agents_api/models/docs/mmr.py | 106 +++++++++++++ .../models/docs/search_docs_by_embedding.py | 108 ++----------- .../models/docs/search_docs_hybrid.py | 4 +- .../agents_api/routers/docs/search_docs.py | 30 +++- agents-api/poetry.lock | 147 +++++++++++++++--- agents-api/pyproject.toml | 1 + agents-api/tests/fixtures.py | 2 + agents-api/tests/test_docs_routes.py | 28 +++- .../integrations/autogen/Docs.py | 5 + typespec/docs/models.tsp | 8 + .../@typespec/openapi3/openapi-1.0.0.yaml | 11 ++ 12 files changed, 341 insertions(+), 114 deletions(-) create mode 100644 agents-api/agents_api/models/docs/mmr.py diff --git a/agents-api/agents_api/autogen/Docs.py b/agents-api/agents_api/autogen/Docs.py index 14990652f..11af8e1f4 100644 --- a/agents-api/agents_api/autogen/Docs.py +++ b/agents-api/agents_api/autogen/Docs.py @@ -19,6 +19,10 @@ class BaseDocSearchRequest(BaseModel): The language to be used for text-only search. Support for other languages coming soon. """ metadata_filter: dict[str, float | str | StrictBool | None] = {} + mmr_strength: Annotated[float, Field(ge=0.0, lt=1.0)] = 0 + """ + MMR Strength (mmr_strength = 1 - mmr_lambda) + """ class CreateDocRequest(BaseModel): @@ -176,6 +180,7 @@ class Snippet(BaseModel): ) index: int content: str + embedding: list[float] | None = None class TextOnlyDocSearchRequest(BaseDocSearchRequest): diff --git a/agents-api/agents_api/models/docs/mmr.py b/agents-api/agents_api/models/docs/mmr.py new file mode 100644 index 000000000..6e02f266b --- /dev/null +++ b/agents-api/agents_api/models/docs/mmr.py @@ -0,0 +1,106 @@ +from __future__ import annotations + +import logging +from typing import Union + +import numpy as np + +Matrix = Union[list[list[float]], list[np.ndarray], np.ndarray] + +logger = logging.getLogger(__name__) + + +def _cosine_similarity(x: Matrix, y: Matrix) -> np.ndarray: + """Row-wise cosine similarity between two equal-width matrices. + + Args: + x: A matrix of shape (n, m). + y: A matrix of shape (k, m). + + Returns: + A matrix of shape (n, k) where each element (i, j) is the cosine similarity + between the ith row of X and the jth row of Y. + + Raises: + ValueError: If the number of columns in X and Y are not the same. + ImportError: If numpy is not installed. + """ + + if len(x) == 0 or len(y) == 0: + return np.array([]) + + x = np.array(x) + y = np.array(y) + if x.shape[1] != y.shape[1]: + msg = ( + f"Number of columns in X and Y must be the same. X has shape {x.shape} " + f"and Y has shape {y.shape}." + ) + raise ValueError(msg) + try: + import simsimd as simd # type: ignore + + x = np.array(x, dtype=np.float32) + y = np.array(y, dtype=np.float32) + z = 1 - np.array(simd.cdist(x, y, metric="cosine")) + return z + except ImportError: + logger.debug( + "Unable to import simsimd, defaulting to NumPy implementation. If you want " + "to use simsimd please install with `pip install simsimd`." + ) + x_norm = np.linalg.norm(x, axis=1) + y_norm = np.linalg.norm(y, axis=1) + # Ignore divide by zero errors run time warnings as those are handled below. + with np.errstate(divide="ignore", invalid="ignore"): + similarity = np.dot(x, y.T) / np.outer(x_norm, y_norm) + similarity[np.isnan(similarity) | np.isinf(similarity)] = 0.0 + return similarity + + +def maximal_marginal_relevance( + query_embedding: np.ndarray, + embedding_list: list, + lambda_mult: float = 0.5, + k: int = 4, +) -> list[int]: + """Calculate maximal marginal relevance. + + Args: + query_embedding: The query embedding. + embedding_list: A list of embeddings. + lambda_mult: The lambda parameter for MMR. Default is 0.5. + k: The number of embeddings to return. Default is 4. + + Returns: + A list of indices of the embeddings to return. + + Raises: + ImportError: If numpy is not installed. + """ + + if min(k, len(embedding_list)) <= 0: + return [] + if query_embedding.ndim == 1: + query_embedding = np.expand_dims(query_embedding, axis=0) + similarity_to_query = _cosine_similarity(query_embedding, embedding_list)[0] + most_similar = int(np.argmax(similarity_to_query)) + idxs = [most_similar] + selected = np.array([embedding_list[most_similar]]) + while len(idxs) < min(k, len(embedding_list)): + best_score = -np.inf + idx_to_add = -1 + similarity_to_selected = _cosine_similarity(embedding_list, selected) + for i, query_score in enumerate(similarity_to_query): + if i in idxs: + continue + redundant_score = max(similarity_to_selected[i]) + equation_score = ( + lambda_mult * query_score - (1 - lambda_mult) * redundant_score + ) + if equation_score > best_score: + best_score = equation_score + idx_to_add = i + idxs.append(idx_to_add) + selected = np.append(selected, [embedding_list[idx_to_add]], axis=0) + return idxs diff --git a/agents-api/agents_api/models/docs/search_docs_by_embedding.py b/agents-api/agents_api/models/docs/search_docs_by_embedding.py index 382bff069..8f8b7548e 100644 --- a/agents-api/agents_api/models/docs/search_docs_by_embedding.py +++ b/agents-api/agents_api/models/docs/search_docs_by_embedding.py @@ -50,7 +50,6 @@ def search_docs_by_embedding( k: int = 3, confidence: float = 0.5, ef: int = 50, - mmr_strength: float = 0.0, embedding_size: int = 1024, ann_threshold: int = 1_000_000, metadata_filter: dict[str, Any] = {}, @@ -71,9 +70,6 @@ def search_docs_by_embedding( assert len(query_embedding) == embedding_size assert sum(query_embedding) - assert 0 <= mmr_strength < 1, "MMR strength must be in [0, 1) interval" - - mmr_lambda: float = 1 - mmr_strength metadata_filter_str = ", ".join( [ @@ -138,6 +134,7 @@ def search_docs_by_embedding( title, content, distance, + embedding, ] := # Get input values input[owner_type, owner_id, query], @@ -157,10 +154,11 @@ def search_docs_by_embedding( content | query: query, - k: {k*(3 if mmr_strength else 1)}, # Get more candidates for diversity + k: {k}, ef: {ef}, radius: {radius}, bind_distance: distance, + bind_vector: embedding, }} :create _search_result {{ @@ -169,6 +167,7 @@ def search_docs_by_embedding( title, content, distance, + embedding, }} }} @@ -190,6 +189,7 @@ def search_docs_by_embedding( title, content, distance, + embedding, ] := # Get input values input[owner_type, owner_id, query], @@ -213,7 +213,7 @@ def search_docs_by_embedding( distance = cos_dist(query, embedding), distance <= {radius} - :limit {k*(3 if mmr_strength else 1)} # Get more candidates for diversity + :limit {k} # Get more candidates for diversity :create _search_result {{ doc_id, @@ -221,6 +221,7 @@ def search_docs_by_embedding( title, content, distance, + embedding, }} }} %end @@ -235,94 +236,15 @@ def search_docs_by_embedding( doc_id, snippet_data, distance, - mmr_score, title, + embedding, ] := owners[owner_type, owner_id_str], owner_id = to_uuid(owner_id_str), - *_search_result{{ doc_id, index, title, content, distance }}, - mmr_score = distance, + *_search_result{{ doc_id, index, title, content, distance, embedding, }}, snippet_data = [index, content] - # Sort the results by distance to find the closest matches - :sort -mmr_score - :limit {k*(3 if mmr_strength else 1)} # Get more candidates for diversity - - :create _interim {{ - owner_type, - owner_id, - doc_id, - snippet_data, - distance, - mmr_score, - title, - }} - """ - - mmr_interim_query = f""" - owners[owner_type, owner_id] <- $owners - - # Calculate the min distance between every doc and every snippet being compared - intersnippet_distance[ - doc_id, - index1, - min(dist) - ] := - *_search_result{{ doc_id: doc_id2, index: index2 }}, - *snippets {{ - doc_id, - index: index1, - embedding: embedding1 - }}, - *snippets {{ - doc_id: doc_id2, - index: index2, - embedding: embedding2 - }}, - is_null(embedding1) == false, - is_null(embedding2) == false, - - # When doc_id == doc_id2, dont compare the same snippet - doc_id != doc_id2 || index1 != index2, - dist = cos_dist(embedding1, embedding2) - - - apply_mmr[ - doc_id, - title, - snippet_data, - distance, - mmr_score, - ] := - *_search_result{{ doc_id, index, title, content, distance: original_distance }}, - intersnippet_distance[doc_id, index, intersnippet_distance], - mmr_score = ({mmr_lambda} * original_distance) - ((1.0 - {mmr_lambda}) * intersnippet_distance), - distance = max(0.0, min(1.0 - mmr_score, 1.0)), - snippet_data = [index, content] - - ?[ - owner_type, - owner_id, - doc_id, - snippet_data, - distance, - mmr_score, - title, - ] := - owners[owner_type, owner_id_str], - owner_id = to_uuid(owner_id_str), - - apply_mmr[ - doc_id, - title, - snippet_data, - distance, - mmr_score, - ] - - # Sort the results by distance to find the closest matches - :sort -mmr_score - :limit {k} + :limit {k} # Get more candidates for diversity :create _interim {{ owner_type, @@ -330,8 +252,8 @@ def search_docs_by_embedding( doc_id, snippet_data, distance, - mmr_score, title, + embedding, }} """ @@ -343,6 +265,7 @@ def search_docs_by_embedding( unique(snippet_data), distance, title, + embedding, ] := *_interim { owner_type, @@ -351,6 +274,7 @@ def search_docs_by_embedding( snippet_data, distance, title, + embedding, } m[ @@ -368,10 +292,12 @@ def search_docs_by_embedding( snippet_data, distance, title, + embedding, ], snippet = { "index": snippet_datum->0, - "content": snippet_datum->1 + "content": snippet_datum->1, + "embedding": embedding, }, snippet_datum in snippet_data @@ -408,7 +334,7 @@ def search_docs_by_embedding( {{ {verify_query} }} {{ {determine_knn_ann_query} }} {search_query} - {{ {normal_interim_query if mmr_strength == 0.0 else mmr_interim_query} }} + {{ {normal_interim_query} }} {{ {collect_query} }} """ diff --git a/agents-api/agents_api/models/docs/search_docs_hybrid.py b/agents-api/agents_api/models/docs/search_docs_hybrid.py index 1a682751e..409740956 100644 --- a/agents-api/agents_api/models/docs/search_docs_hybrid.py +++ b/agents-api/agents_api/models/docs/search_docs_hybrid.py @@ -107,7 +107,7 @@ def search_docs_hybrid( developer_id=developer_id, owners=owners, query=query, - k=2 * k, + k=k, metadata_filter=metadata_filter, **text_search_options, ) @@ -116,7 +116,7 @@ def search_docs_hybrid( developer_id=developer_id, owners=owners, query_embedding=query_embedding, - k=2 * k, + k=k, metadata_filter=metadata_filter, **embed_search_options, ) diff --git a/agents-api/agents_api/routers/docs/search_docs.py b/agents-api/agents_api/routers/docs/search_docs.py index bab2875f5..dbfe7e779 100644 --- a/agents-api/agents_api/routers/docs/search_docs.py +++ b/agents-api/agents_api/routers/docs/search_docs.py @@ -11,6 +11,7 @@ VectorDocSearchRequest, ) from ...dependencies.developer_id import get_developer_id +from ...models.docs.mmr import maximal_marginal_relevance from ...models.docs.search_docs_by_embedding import search_docs_by_embedding from ...models.docs.search_docs_by_text import search_docs_by_text from ...models.docs.search_docs_hybrid import search_docs_hybrid @@ -44,7 +45,7 @@ def get_search_fn_and_params( search_fn = search_docs_by_embedding params = dict( query_embedding=query_embedding, - k=k, + k=k * 3 if search_params.mmr_strength > 0 else k, confidence=confidence, metadata_filter=metadata_filter, ) @@ -61,7 +62,7 @@ def get_search_fn_and_params( params = dict( query=query, query_embedding=query_embedding, - k=k, + k=k * 3 if search_params.mmr_strength > 0 else k, embed_search_options=dict(confidence=confidence), alpha=alpha, metadata_filter=metadata_filter, @@ -78,6 +79,7 @@ async def search_user_docs( ), user_id: UUID, ) -> DocSearchResponse: + # MMR here search_fn, params = get_search_fn_and_params(search_params) start = time.time() @@ -87,6 +89,18 @@ async def search_user_docs( **params, ) + k = 3 + + if ( + not isinstance(search_params, TextOnlyDocSearchRequest) + and search_params.mmr_strength > 0 + and len(docs) > k + ): + indices = maximal_marginal_relevance( + params["query_embedding"], [doc.embedding for doc in docs], k=k + ) + docs = [doc for i, doc in enumerate(docs) if i in set(indices)] + end = time.time() time_taken = end - start @@ -114,6 +128,18 @@ async def search_agent_docs( **params, ) + k = 3 + + if ( + not isinstance(search_params, TextOnlyDocSearchRequest) + and search_params.mmr_strength > 0 + and len(docs) > k + ): + indices = maximal_marginal_relevance( + params["query_embedding"], [doc.embedding for doc in docs], k=k + ) + docs = [doc for i, doc in enumerate(docs) if i in set(indices)] + end = time.time() time_taken = end - start diff --git a/agents-api/poetry.lock b/agents-api/poetry.lock index 8ce32e16b..373da6c0b 100644 --- a/agents-api/poetry.lock +++ b/agents-api/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -965,7 +965,10 @@ inflect = ">=4.1.0,<6.0" isort = ">=4.3.21,<6.0" jinja2 = ">=2.10.1,<4.0" packaging = "*" -pydantic = {version = ">=1.10.0,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.4.0 || >2.4.0,<3.0", extras = ["email"], markers = "python_version >= \"3.12\" and python_version < \"4.0\""} +pydantic = [ + {version = ">=1.10.0,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.4.0 || >2.4.0,<3.0", extras = ["email"], markers = "python_version >= \"3.12\" and python_version < \"4.0\""}, + {version = ">=1.10.0,<2.4.0 || >2.4.0,<3.0", extras = ["email"], markers = "python_version >= \"3.11\" and python_version < \"4.0\""}, +] pyyaml = ">=6.0.1" [package.extras] @@ -1928,13 +1931,13 @@ referencing = ">=0.31.0" [[package]] name = "julep" -version = "1.24.0" +version = "1.25.0" description = "The official Python library for the julep API" optional = false python-versions = ">=3.7" files = [ - {file = "julep-1.24.0-py3-none-any.whl", hash = "sha256:6f9b12fcb5bda6bb6f390463e803b8bfbdbb46a05b581f8e74ceace7522a70e5"}, - {file = "julep-1.24.0.tar.gz", hash = "sha256:89e461af7c65b0a53c91ad40accee1d1d5204a932a482be0135e6b6f6496b41e"}, + {file = "julep-1.25.0-py3-none-any.whl", hash = "sha256:a99e18310f4932b038a0a5450302381f201c8a86634eea543c408574f384932d"}, + {file = "julep-1.25.0.tar.gz", hash = "sha256:29d851b063ad29508f795742ac2c9f07e02fd0aedc2cb07d6c18600fd326f036"}, ] [package.dependencies] @@ -2085,13 +2088,13 @@ test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (> [[package]] name = "jupyterlab" -version = "4.2.5" +version = "4.3.0" description = "JupyterLab computational environment" optional = false python-versions = ">=3.8" files = [ - {file = "jupyterlab-4.2.5-py3-none-any.whl", hash = "sha256:73b6e0775d41a9fee7ee756c80f58a6bed4040869ccc21411dc559818874d321"}, - {file = "jupyterlab-4.2.5.tar.gz", hash = "sha256:ae7f3a1b8cb88b4f55009ce79fa7c06f99d70cd63601ee4aa91815d054f46f75"}, + {file = "jupyterlab-4.3.0-py3-none-any.whl", hash = "sha256:f67e1095ad61ae04349024f0b40345062ab108a0c6998d9810fec6a3c1a70cd5"}, + {file = "jupyterlab-4.3.0.tar.gz", hash = "sha256:7c6835cbf8df0af0ec8a39332e85ff11693fb9a468205343b4fc0bfbc74817e5"}, ] [package.dependencies] @@ -2110,9 +2113,9 @@ tornado = ">=6.2.0" traitlets = "*" [package.extras] -dev = ["build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", "ruff (==0.3.5)"] -docs = ["jsx-lexer", "myst-parser", "pydata-sphinx-theme (>=0.13.0)", "pytest", "pytest-check-links", "pytest-jupyter", "sphinx (>=1.8,<7.3.0)", "sphinx-copybutton"] -docs-screenshots = ["altair (==5.3.0)", "ipython (==8.16.1)", "ipywidgets (==8.1.2)", "jupyterlab-geojson (==3.4.0)", "jupyterlab-language-pack-zh-cn (==4.1.post2)", "matplotlib (==3.8.3)", "nbconvert (>=7.0.0)", "pandas (==2.2.1)", "scipy (==1.12.0)", "vega-datasets (==0.9.0)"] +dev = ["build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", "ruff (==0.6.9)"] +docs = ["jsx-lexer", "myst-parser", "pydata-sphinx-theme (>=0.13.0)", "pytest", "pytest-check-links", "pytest-jupyter", "sphinx (>=1.8,<8.1.0)", "sphinx-copybutton"] +docs-screenshots = ["altair (==5.4.1)", "ipython (==8.16.1)", "ipywidgets (==8.1.5)", "jupyterlab-geojson (==3.4.0)", "jupyterlab-language-pack-zh-cn (==4.2.post3)", "matplotlib (==3.9.2)", "nbconvert (>=7.0.0)", "pandas (==2.2.3)", "scipy (==1.14.1)", "vega-datasets (==0.9.0)"] test = ["coverage", "pytest (>=7.0)", "pytest-check-links (>=0.7)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter (>=0.5.3)", "pytest-timeout", "pytest-tornasync", "requests", "requests-cache", "virtualenv"] upgrade-extension = ["copier (>=9,<10)", "jinja2-time (<0.3)", "pydantic (<3.0)", "pyyaml-include (<3.0)", "tomli-w (<2.0)"] @@ -3052,13 +3055,13 @@ files = [ [[package]] name = "openai" -version = "1.52.2" +version = "1.53.0" description = "The official Python library for the openai API" optional = false python-versions = ">=3.7.1" files = [ - {file = "openai-1.52.2-py3-none-any.whl", hash = "sha256:57e9e37bc407f39bb6ec3a27d7e8fb9728b2779936daa1fcf95df17d3edfaccc"}, - {file = "openai-1.52.2.tar.gz", hash = "sha256:87b7d0f69d85f5641678d414b7ee3082363647a5c66a462ed7f3ccb59582da0d"}, + {file = "openai-1.53.0-py3-none-any.whl", hash = "sha256:20f408c32fc5cb66e60c6882c994cdca580a5648e10045cd840734194f033418"}, + {file = "openai-1.53.0.tar.gz", hash = "sha256:be2c4e77721b166cce8130e544178b7d579f751b4b074ffbaade3854b6f85ec5"}, ] [package.dependencies] @@ -4784,6 +4787,114 @@ files = [ {file = "simpleeval-0.9.13.tar.gz", hash = "sha256:4a30f9cc01825fe4c719c785e3762623e350c4840d5e6855c2a8496baaa65fac"}, ] +[[package]] +name = "simsimd" +version = "5.9.7" +description = "Portable mixed-precision BLAS-like vector math library for x86 and ARM" +optional = false +python-versions = "*" +files = [ + {file = "simsimd-5.9.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:938c3131ba92d9354c8067ce8415c918348eed60fd97bdec926c7878f3943d38"}, + {file = "simsimd-5.9.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:75d637166b74df2998b11b7f5b51bbf31dae027e13e446505c6b29abcca4c340"}, + {file = "simsimd-5.9.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f8c0c053102822524e388346e8928a884a98708fdaa752543aa00f4e4d4753ea"}, + {file = "simsimd-5.9.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f38b1c685095b046ba630856297e1f3c149cbc6765dacc3dd234475c72b4620"}, + {file = "simsimd-5.9.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:51567ebac7039601522170fd9036f8ee4f50bc864ca33dc5ec84612c257a5398"}, + {file = "simsimd-5.9.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5af1d7b085e5da287c3c6bfd77192093d2f56632047f7b95cbf9f651348c134"}, + {file = "simsimd-5.9.7-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:512209d9be3d39782c68c3be6e8ccb003ef7ab239454009bf8127578c8762a1c"}, + {file = "simsimd-5.9.7-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:e0e0016a79a811fe7f9e979b7d2407735787974b57ab6579a4c74f6b7512afe2"}, + {file = "simsimd-5.9.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cbf42c563b91c275c006a5a61a95c2e98ef5b7a53588bee129a6d5aa925f4b6b"}, + {file = "simsimd-5.9.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:23740c8f5924ee970c2d5343dfc8b2c8e99377ff824c3ba35bbb612ae71214c2"}, + {file = "simsimd-5.9.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5b7ecc290a8e1764089729b0d459345381fbecfecd8aea166e934b183290944e"}, + {file = "simsimd-5.9.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:92b67f87872f44ff1196238841fd50ca92ea7e199dc767707b544b3cccbc518a"}, + {file = "simsimd-5.9.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:389f4f7262c869a520136c0c5bb2c785b8f75c99739fc6c807bbf8dccaf0b79e"}, + {file = "simsimd-5.9.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c7ff96ab0e2bed6e8af747179c5c6fa1ed45e17f2f43dd95d45034cb752ff812"}, + {file = "simsimd-5.9.7-cp310-cp310-win32.whl", hash = "sha256:629e00a4ab649111f4132af9cdf294b3ea8169b31e40a2e1bc59c0ccabc0b8a5"}, + {file = "simsimd-5.9.7-cp310-cp310-win_amd64.whl", hash = "sha256:3647f2bb6554c95c1ae852a4dbf7ace4873523c51d9ec13d2a55f0c9dcc3697c"}, + {file = "simsimd-5.9.7-cp310-cp310-win_arm64.whl", hash = "sha256:f703c4a54a4442e7ca8459ed14aa4e49421d53fedaa84874880511a871e69761"}, + {file = "simsimd-5.9.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4c4ce63e53ab245601ba812a8d573ec0225256407de1d1a9f7c08b616965d94c"}, + {file = "simsimd-5.9.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:716782eca1ce1dcf33ad978c052b6cf1af2a0a78a4570a299a9bb47b1ea75e5b"}, + {file = "simsimd-5.9.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4497ae34f47de3574ec76f2efcb32270f9e7f22a506800adf6b2e686b9104188"}, + {file = "simsimd-5.9.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a42c3f00f9c77716d6fe9be1f6d2ae88342a0696dd3f5a2a353b00eb53dfca1b"}, + {file = "simsimd-5.9.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:606ce52cdae2643e441a887611ec9f9db0cc3e4f5f90e6e5fc1a659bb9188069"}, + {file = "simsimd-5.9.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da3fd865ab7287b68af638a7d54a46e9b34832864f603d856b190126eae7025e"}, + {file = "simsimd-5.9.7-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:1f1e2b12b0a31656c6e42223fcddc90990f54f2c2f40a065bdff897a36edc064"}, + {file = "simsimd-5.9.7-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:2019ee8ef83ffce3f7bd980264b89fb29059f2e6e4d447cf640a41f12b6c1242"}, + {file = "simsimd-5.9.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8270d0f29f1db2989e8a55929557ca2b97650a685353774ddd6306c6422a3568"}, + {file = "simsimd-5.9.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f7e94bc9295eb2538cdb85887c21864121a9df715ecba05455691801be14ac65"}, + {file = "simsimd-5.9.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1553c287eb6be6a3fe5688affbdf92fb5a18809512f4c711bbb0dedf11957e63"}, + {file = "simsimd-5.9.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:529c67718ba0db6da3c082d1249815063c67e3938884bc3c432e85dbd06a6c03"}, + {file = "simsimd-5.9.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:dc7e3170edda3b119b6ed03422d11ba546583564a7314db28e72b3c1acbcd6d1"}, + {file = "simsimd-5.9.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b17ae04b8b0ad909d92fa6411583a4b99788034a619a088e60a3e7b8ae85a81b"}, + {file = "simsimd-5.9.7-cp311-cp311-win32.whl", hash = "sha256:8ad9f94458e94d9263d36f98c2fdc022e0c3215ca57526cbf9dd6aa309eb87ba"}, + {file = "simsimd-5.9.7-cp311-cp311-win_amd64.whl", hash = "sha256:90f03656b96127a0ae4aef7038590663a7f40a3eeb219f63ba3cf9aff19f316b"}, + {file = "simsimd-5.9.7-cp311-cp311-win_arm64.whl", hash = "sha256:24cf4d7093e92a1f0be609a06361f87d504efd66f1f73d4433079e9981389b46"}, + {file = "simsimd-5.9.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:aa859dd9af0a2363bda031fafc96a3580cc6607c6e9b7a73842d5dbfe1f3b3ea"}, + {file = "simsimd-5.9.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5dbe91bf1035d95db8d93f9ffa1b037945477122c1d49de690a9ac2134201208"}, + {file = "simsimd-5.9.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:84647c7d83cd31d9755af0aa7d6e73b842364b3b19b76af01ea69246c09b11e6"}, + {file = "simsimd-5.9.7-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5559b485acd6b90cce94cf5e8463f4ad345ef8551b7db40f9dce1b2dfeb4f1b6"}, + {file = "simsimd-5.9.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cdfd52cf44d5c3d1f9fed02b3724de790f7f34a7ba9e9368241e4385af84fd5"}, + {file = "simsimd-5.9.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ba99fe25291fa20b71da409607c8ba97624f85d0bff6eb1e02d7f68546334fa"}, + {file = "simsimd-5.9.7-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:a5564348dec3f08de79a0851d03d744cff7efd0e10c5e410e89663e56a890f31"}, + {file = "simsimd-5.9.7-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3a1224a0b85c642cfed341c6626e4a7c6d2d6bc5a290c312a041fd030f98c835"}, + {file = "simsimd-5.9.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4f49307f6e00bbd2694ccfeaf3726827fa53a9dd9f57707543633cf8974a897d"}, + {file = "simsimd-5.9.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f4ace050efe35d911b2f73c8a5493296478de6d041cdd751df3947dd51425449"}, + {file = "simsimd-5.9.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:03c060fbb718c21e715ef485b27d3068d95cf38d3681d367f5bd3ca56d0a2a8b"}, + {file = "simsimd-5.9.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:004d7d05d06fd53ba24c258bccd5524cf17a162c19948a62035dbb8f8c927159"}, + {file = "simsimd-5.9.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e48ce99ba425eb32935f5ca8b7cb5cfaeeb8f8b2642827ef09181595a401ca6b"}, + {file = "simsimd-5.9.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:119c4395e1fad9f1da5d40654f77b3501afb8576e310e0c568e7b8c85a46432f"}, + {file = "simsimd-5.9.7-cp312-cp312-win32.whl", hash = "sha256:8c35f8f122ab33f325d7818fef88e21159d34f224e9a9c40abc4a60f986cb1aa"}, + {file = "simsimd-5.9.7-cp312-cp312-win_amd64.whl", hash = "sha256:49527d4ec509d08157dfab5dc2ab66398e086d56bb6a6a9b640fd107c0e7f736"}, + {file = "simsimd-5.9.7-cp312-cp312-win_arm64.whl", hash = "sha256:25ab98e9de3322a5adc29446557e8770d45c2e42d7ab288f04c4437df5c9ee30"}, + {file = "simsimd-5.9.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7e1f90ca2dd3efc7de3fe317dad36c67bc0b4ae67937d98962c87856271077ce"}, + {file = "simsimd-5.9.7-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dddfbfff7bf7b298f085722ca882c19df1dd1e5fec3385e80efd236185c8f984"}, + {file = "simsimd-5.9.7-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7f14384d6d423f95bd31bccf2369f52769ae046e0417721a48f517a11757cae"}, + {file = "simsimd-5.9.7-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6cebe128e191a437fd7be2087442e6520a7f6acc15eb652b86cf533367c613c3"}, + {file = "simsimd-5.9.7-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:8b42da72779f1496b8a9dd63e101119bde32605535469783e3b78b1fa5443eea"}, + {file = "simsimd-5.9.7-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:cb2ffb7c026038d069a61249d609e5820ac71a1690de2ca6b5530394c2f1f5bd"}, + {file = "simsimd-5.9.7-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:edd26bc50214671df12bb4a4afc12006fef182ae6cbfab2b4041ff5e1b5dde04"}, + {file = "simsimd-5.9.7-cp37-cp37m-musllinux_1_2_armv7l.whl", hash = "sha256:58b4f355d7a1ce57e07892091f4d8fc9a80895ee2bcca5245537e0623e5ac693"}, + {file = "simsimd-5.9.7-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:12d105e88a2bdb5b6a8546c2d1f3e11a1f476928d1f9876c0ce9d41e1e64b4c1"}, + {file = "simsimd-5.9.7-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:d6e68b8ebf05a8ba317b6b976fc372645994bf196ef2206b775d093fc89a6855"}, + {file = "simsimd-5.9.7-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2bef6b9bc9ce1e548b48c0f8ac59552d0fa53be4d3d424927db7e5e4f5941318"}, + {file = "simsimd-5.9.7-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:5a921b35ef507dccd86c41afb236d7c353a129f498559bb994893ff5a3850baa"}, + {file = "simsimd-5.9.7-cp37-cp37m-win32.whl", hash = "sha256:a4f78746f2e5f892e523fd22d84c93036f227a876a2ee5d8b8a53698d241ecf1"}, + {file = "simsimd-5.9.7-cp37-cp37m-win_amd64.whl", hash = "sha256:be3c6726a3e0cf90301a1172dbdbc8fa5f6e886b93bbc4d8aad2984081c87dfc"}, + {file = "simsimd-5.9.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fff0935f5dcc84669a4091b36bf476d4bd30adef76fafe77814299fabbff2ab4"}, + {file = "simsimd-5.9.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8dc83551684cd547ca6aab662eda4b2e48aa7460dd8eb103fb6e9a453320971d"}, + {file = "simsimd-5.9.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c358756518243835a329da4eb3e454226562d8cc7a4b10eef8338753e41e9aa7"}, + {file = "simsimd-5.9.7-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb8d590664865cb607c9c540a5a09d77a109c4ef18bd68053fbe7b889721a4db"}, + {file = "simsimd-5.9.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bf35cfb12d43f8901b66a7d1f055531426d27b47b31831873801d039b5d69c1"}, + {file = "simsimd-5.9.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:06244ea5ca32758de43680c1df1dac3e17e2d1164e572545769913318685a409"}, + {file = "simsimd-5.9.7-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:edf732a4bec34ead58e93f94c9fc8af6d14c709920825ca4533f25dbf9537906"}, + {file = "simsimd-5.9.7-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:6e8c93fd9d488fe3cc6ebf8de47473f41c7496b3781c6af1d2d9235dd4480f5f"}, + {file = "simsimd-5.9.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:fa214449499a02ff3a37173a53984b59f8915e31e9f2ae1a0e837c8a3c2def5b"}, + {file = "simsimd-5.9.7-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:049e6472a6c8c667ec02328747acabbb9e17d543d15147fc9ebd56ddd94457be"}, + {file = "simsimd-5.9.7-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ae812b06784791b3cdbf5690058f0d20b48dfca50e606fa647361229e00b5f9d"}, + {file = "simsimd-5.9.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:bbaba24ffc5a27853c7a295318b309a6486c4585c2015936f7693114181a8ca6"}, + {file = "simsimd-5.9.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:be5c6a747ead4b68634dfd7fc38ab3488fbdd5ead5ea68042644e6408be8364e"}, + {file = "simsimd-5.9.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:add53369966db2087f8d18aadeaf844480f1f8a53ba05d59306b83b05082c7b8"}, + {file = "simsimd-5.9.7-cp38-cp38-win32.whl", hash = "sha256:bc884c797cbcd02b2002d96dfd892d61e03c54d49f62014cb81e1f6174bc7594"}, + {file = "simsimd-5.9.7-cp38-cp38-win_amd64.whl", hash = "sha256:695ce472cbdb0bfc76f724f4cc45537bb9b47e5dd56f0204a3044c0c59f09630"}, + {file = "simsimd-5.9.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cdd2eb4aaea4295dceeee019948d5cbf03b436e02db4c725762b3a8f84eeedd3"}, + {file = "simsimd-5.9.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:383ec8b0da899193280269474ee13b2393a5312da8d5a00c6d2241f00e6011a6"}, + {file = "simsimd-5.9.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:046b0a8e2124d99c72aa0bb1faaa6994c9877707cfae9d4edcb92bacd2e18d03"}, + {file = "simsimd-5.9.7-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c9c6b52460791ee39143aef8e99be10e0adc934bfdd22258ec121bfa385e26b"}, + {file = "simsimd-5.9.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e991d112f061a106ee76786080b1316567e31dddd583cac331921eaf377b43b"}, + {file = "simsimd-5.9.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:be6e79473daeca18ba355d0296b8202d7602c7cc5d674ecc5e2b665530c5163e"}, + {file = "simsimd-5.9.7-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:42b92127c1c5a01ea8aa54b309f4a137e55660beb9706145bc8be51aa70abb04"}, + {file = "simsimd-5.9.7-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:f5449609732d2ab785f273069bcde228d68b9d168db30c85a006d8d6d01f83aa"}, + {file = "simsimd-5.9.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1df7750149c5762070506bc54000233f3328ea78a2287cd4af065d8426d3ab5f"}, + {file = "simsimd-5.9.7-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:8912ab45874d6f4eb4805c369380afebcfccf5944211d96d40f387c00cdc5bf5"}, + {file = "simsimd-5.9.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2dec5916eebb83a3eb66bc596d68398f3b8f7c3c745c2d6ee50fefe3e419f5fa"}, + {file = "simsimd-5.9.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:67bb890385a765043ec092b5bdf2336df857eedbbae396d288aea07b54842409"}, + {file = "simsimd-5.9.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:49b9bc13ae251bdfdac6f527d37746d7ca411340d702e2e3736920f759201ae4"}, + {file = "simsimd-5.9.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:36cf86ca1e5f3ad91c9faa48db6835bbdc3284bad2d9d280a0e9bb1fcd781423"}, + {file = "simsimd-5.9.7-cp39-cp39-win32.whl", hash = "sha256:1e868e6dab93a1f0493e549e25d94948da1ce46f990cc84404421916024f3ab3"}, + {file = "simsimd-5.9.7-cp39-cp39-win_amd64.whl", hash = "sha256:2eb4332914095b935a725fa61493d8c1088ba53ae43c69cf514225a4de38d8a8"}, + {file = "simsimd-5.9.7-cp39-cp39-win_arm64.whl", hash = "sha256:760313023711b7a4d1c5969e0bdd933502a4639f150b324055571a80f11fceb9"}, + {file = "simsimd-5.9.7.tar.gz", hash = "sha256:7612f7087aee7c5415385089080fdcdd3c52b3988e33cdf1f779f26d8ab54ac8"}, +] + [[package]] name = "six" version = "1.16.0" @@ -5498,13 +5609,13 @@ typing-extensions = ">=3.7.4.3" [[package]] name = "types-protobuf" -version = "5.28.3.20241029" +version = "5.28.3.20241030" description = "Typing stubs for protobuf" optional = false python-versions = ">=3.8" files = [ - {file = "types-protobuf-5.28.3.20241029.tar.gz", hash = "sha256:58e6c547601102e0601e3ad95ad326f85c27cda41dc9bd8c5f29ad2f3b6c6967"}, - {file = "types_protobuf-5.28.3.20241029-py3-none-any.whl", hash = "sha256:7536ea95a7f0a19710a5e0520dd096c985333ae49b7c5eb29e1367703096f17a"}, + {file = "types-protobuf-5.28.3.20241030.tar.gz", hash = "sha256:f7e6b45845d75393fb41c0b3ce82c46d775f9771fae2097414a1dbfe5b51a988"}, + {file = "types_protobuf-5.28.3.20241030-py3-none-any.whl", hash = "sha256:f3dae16adf342d4fb5bb3673cabb22549a6252e5dd66fc52d8310b1a39c64ba9"}, ] [[package]] @@ -6101,4 +6212,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.12,<3.13" -content-hash = "6ff127e0f08e26e00272cd1eb57449405ecc84f05f1e369ff76e567cc79c2ef3" +content-hash = "b5c209bcbd8a1243162e29016abd222456ef980e6c1770573bdfba33143ac8f2" diff --git a/agents-api/pyproject.toml b/agents-api/pyproject.toml index 72f239a73..ae16d630c 100644 --- a/agents-api/pyproject.toml +++ b/agents-api/pyproject.toml @@ -49,6 +49,7 @@ thefuzz = "^0.22.1" gunicorn = "^23.0.0" uvloop = "^0.21.0" anthropic = "^0.37.1" +simsimd = "^5.9.4" [tool.poetry.group.dev.dependencies] ipython = "^8.26.0" ruff = "^0.5.5" diff --git a/agents-api/tests/fixtures.py b/agents-api/tests/fixtures.py index c4856112f..dbe495836 100644 --- a/agents-api/tests/fixtures.py +++ b/agents-api/tests/fixtures.py @@ -205,6 +205,8 @@ def test_user_doc( client=client, ) + time.sleep(0.5) + yield doc delete_doc( diff --git a/agents-api/tests/test_docs_routes.py b/agents-api/tests/test_docs_routes.py index ef33cb9f8..0f54a5176 100644 --- a/agents-api/tests/test_docs_routes.py +++ b/agents-api/tests/test_docs_routes.py @@ -178,7 +178,33 @@ async def _(make_request=make_request, user=test_user, doc=test_user_doc): assert isinstance(docs, list) # FIXME: This test is failing because the search is not returning the expected results - # assert len(docs) >= 1 + assert len(docs) >= 1 + + +@test("route: search agent docs hybrid with mmr") +async def _(make_request=make_request, agent=test_agent, doc=test_doc): + await asyncio.sleep(0.5) + + EMBEDDING_SIZE = 1024 + search_params = dict( + text=doc.content[0], + vector=[1.0] * EMBEDDING_SIZE, + mmr_strength=0.5, + limit=1, + ) + + response = make_request( + method="POST", + url=f"/agents/{agent.id}/search", + json=search_params, + ) + + assert response.status_code == 200 + response = response.json() + docs = response["docs"] + + assert isinstance(docs, list) + assert len(docs) >= 1 @test("routes: embed route") diff --git a/integrations-service/integrations/autogen/Docs.py b/integrations-service/integrations/autogen/Docs.py index 14990652f..11af8e1f4 100644 --- a/integrations-service/integrations/autogen/Docs.py +++ b/integrations-service/integrations/autogen/Docs.py @@ -19,6 +19,10 @@ class BaseDocSearchRequest(BaseModel): The language to be used for text-only search. Support for other languages coming soon. """ metadata_filter: dict[str, float | str | StrictBool | None] = {} + mmr_strength: Annotated[float, Field(ge=0.0, lt=1.0)] = 0 + """ + MMR Strength (mmr_strength = 1 - mmr_lambda) + """ class CreateDocRequest(BaseModel): @@ -176,6 +180,7 @@ class Snippet(BaseModel): ) index: int content: str + embedding: list[float] | None = None class TextOnlyDocSearchRequest(BaseDocSearchRequest): diff --git a/typespec/docs/models.tsp b/typespec/docs/models.tsp index f1d7318aa..c914579be 100644 --- a/typespec/docs/models.tsp +++ b/typespec/docs/models.tsp @@ -46,6 +46,7 @@ model DocOwner { model Snippet { index: uint16; content: string; + embedding?: float[]; } model DocReference { @@ -95,6 +96,11 @@ model BaseDocSearchRequest { /** The language to be used for text-only search. Support for other languages coming soon. */ lang: "en-US" = "en-US"; metadata_filter: MetadataFilter = #{}, + + /** MMR Strength (mmr_strength = 1 - mmr_lambda) */ + @minValue(0) + @maxValueExclusive(1) + mmr_strength?: float = 0.0; } model VectorDocSearchRequest extends BaseDocSearchRequest { @@ -107,6 +113,8 @@ model VectorDocSearchRequest extends BaseDocSearchRequest { vector: float[]; text?: never; + + mmr_strength?: never; } model TextOnlyDocSearchRequest extends BaseDocSearchRequest { diff --git a/typespec/tsp-output/@typespec/openapi3/openapi-1.0.0.yaml b/typespec/tsp-output/@typespec/openapi3/openapi-1.0.0.yaml index a50b83813..bd58048ee 100644 --- a/typespec/tsp-output/@typespec/openapi3/openapi-1.0.0.yaml +++ b/typespec/tsp-output/@typespec/openapi3/openapi-1.0.0.yaml @@ -2458,6 +2458,13 @@ components: - type: boolean nullable: true default: {} + mmr_strength: + type: number + minimum: 0 + maximum: 1 + exclusiveMaximum: true + description: MMR Strength (mmr_strength = 1 - mmr_lambda) + default: 0 Docs.CreateDocRequest: type: object required: @@ -2676,6 +2683,10 @@ components: format: uint16 content: type: string + embedding: + type: array + items: + type: number Docs.TextOnlyDocSearchRequest: type: object required: