Skip to content

Feat: Add Aliyun (DashScope) as new reranker model provider#81

Open
leejangthegreat wants to merge 28 commits intolfnovo:mainfrom
leejangthegreat:feature/dashscope
Open

Feat: Add Aliyun (DashScope) as new reranker model provider#81
leejangthegreat wants to merge 28 commits intolfnovo:mainfrom
leejangthegreat:feature/dashscope

Conversation

@leejangthegreat
Copy link
Contributor

Reference Issues/PRs

Feature #78

What does this implement/fix? Explain your changes.

This change implements support for Aliyun (DashScope) as a new provider for reranker models. Changes include:

  • Add DashScopeRerankerModel in .providers.reranker
  • Register that model class in factory and model_discovery
  • Update README.md, docs/providers/README.md, docs/capabilitiees/reranking.md
  • Add new doc for DashScope as a provider

Any other comments?

NOTE: This implementation includes partial support for a multi-modal reranker qwen3-vl-rerank. Currently this is done by extending interface of DashScopeRerankerModel.rerank without modifying its base class. As a result, the multi-modal capabilities are limited.
This should be re-implemented in future if we want better support for general multi-modal LLMs.

Copilot AI review requested due to automatic review settings February 8, 2026 17:24
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

6 issues found across 8 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/esperanto/model_discovery.py">

<violation number="1" location="src/esperanto/model_discovery.py:490">
P2: DashScope models are implemented but the provider registry omits a "dashscope" entry, so model discovery cannot route this provider through PROVIDER_MODELS_REGISTRY.</violation>

<violation number="2" location="src/esperanto/model_discovery.py:520">
P2: DashScope Qwen3-VL reranker context window is documented as 32k, but the hardcoded value is 800k. This mismatch can mislead callers into sending inputs far beyond supported limits.</violation>
</file>

<file name="docs/providers/README.md">

<violation number="1" location="docs/providers/README.md:19">
P3: DashScope is marked as a reranking provider in the support matrix but is missing from the “All Reranking Providers” list, leaving the selection guide inconsistent with the matrix.</violation>

<violation number="2" location="docs/providers/README.md:19">
P2: New documentation link points to ./dashscope.md, but docs/providers/dashscope.md is missing, so the link will be broken.</violation>
</file>

<file name="src/esperanto/providers/reranker/dashscope.py">

<violation number="1" location="src/esperanto/providers/reranker/dashscope.py:306">
P2: RerankResult.index is declared as a non-negative int, but _parse_response appends results even when doc_idx is None or out of bounds, which will raise a validation error and break parsing. Skip invalid results or coerce to a valid index before constructing RerankResult.</violation>

<violation number="2" location="src/esperanto/providers/reranker/dashscope.py:390">
P2: `arerank` declares `fps` as Optional[str] but passes it into `_validate_inputs`, which compares it to floats. If callers pass a string per the type hint (e.g., "0.5"), the comparison will raise a TypeError. Make the async signature accept Optional[float] to match `_validate_inputs` and the sync `rerank`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

id="gte-rerank-v2", owned_by="dashscope", context_window=30_000
),
Model(
id="qwen3-vl-rerank", owned_by="dashscope", context_window=800_000
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 8, 2026

Choose a reason for hiding this comment

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

P2: DashScope Qwen3-VL reranker context window is documented as 32k, but the hardcoded value is 800k. This mismatch can mislead callers into sending inputs far beyond supported limits.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/esperanto/model_discovery.py, line 520:

<comment>DashScope Qwen3-VL reranker context window is documented as 32k, but the hardcoded value is 800k. This mismatch can mislead callers into sending inputs far beyond supported limits.</comment>

<file context>
@@ -487,6 +487,46 @@ def get_jina_models(
+            id="gte-rerank-v2", owned_by="dashscope", context_window=30_000
+        ),
+        Model(
+            id="qwen3-vl-rerank", owned_by="dashscope", context_window=800_000
+        )
+    ]
</file context>
Suggested change
id="qwen3-vl-rerank", owned_by="dashscope", context_window=800_000
id="qwen3-vl-rerank", owned_by="dashscope", context_window=32_000
Fix with Cubic

| [Ollama](./ollama.md) | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| [Mistral](./mistral.md) | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ |
| [DeepSeek](./deepseek.md) | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
| [DashScope](./dashscope.md) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 8, 2026

Choose a reason for hiding this comment

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

P2: New documentation link points to ./dashscope.md, but docs/providers/dashscope.md is missing, so the link will be broken.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/providers/README.md, line 19:

<comment>New documentation link points to ./dashscope.md, but docs/providers/dashscope.md is missing, so the link will be broken.</comment>

<file context>
@@ -16,6 +16,7 @@ Welcome to the Esperanto provider guide. This page helps you choose the right AI
 | [Ollama](./ollama.md) | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
 | [Mistral](./mistral.md) | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ |
 | [DeepSeek](./deepseek.md) | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
+| [DashScope](./dashscope.md) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
 | [Perplexity](./perplexity.md) | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
 | [xAI](./xai.md) | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
</file context>
Fix with Cubic


for result, norm_score in zip(raw_results, normalized_scores):
doc_idx = result.get("index")
if doc_idx is None or doc_idx < -0 or doc_idx >= len(documents):
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 8, 2026

Choose a reason for hiding this comment

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

P2: RerankResult.index is declared as a non-negative int, but _parse_response appends results even when doc_idx is None or out of bounds, which will raise a validation error and break parsing. Skip invalid results or coerce to a valid index before constructing RerankResult.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/esperanto/providers/reranker/dashscope.py, line 306:

<comment>RerankResult.index is declared as a non-negative int, but _parse_response appends results even when doc_idx is None or out of bounds, which will raise a validation error and break parsing. Skip invalid results or coerce to a valid index before constructing RerankResult.</comment>

<file context>
@@ -0,0 +1,478 @@
+
+        for result, norm_score in zip(raw_results, normalized_scores):
+            doc_idx = result.get("index")
+            if doc_idx is None or doc_idx < -0 or doc_idx >= len(documents):
+                cur_doc = ""
+            else:
</file context>
Fix with Cubic

@leejangthegreat leejangthegreat marked this pull request as draft February 8, 2026 17:31
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new reranker provider implementation for Aliyun DashScope and wires it into the factory, with accompanying docs and tests.

Changes:

  • Implement DashScopeRerankerModel (sync/async, payload building, response parsing, LangChain adapter).
  • Register the provider in AIFactory and add a static model discovery function.
  • Add provider documentation and a dedicated test suite for DashScope reranking.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
tests/providers/reranker/test_dashscope.py Adds unit tests for DashScope reranker init/validation/payload/response parsing.
src/esperanto/providers/reranker/dashscope.py Implements the DashScope reranker provider (including partial multimodal support).
src/esperanto/model_discovery.py Adds a get_dashscope_models() discovery function (currently hardcoded).
src/esperanto/factory.py Registers "dashscope" under reranker providers.
docs/providers/dashscope.md Adds DashScope provider documentation and examples (including multimodal).
docs/providers/README.md Adds DashScope to provider support matrix and provider list.
docs/capabilities/reranking.md Mentions DashScope in reranker provider selection guidance.
README.md Adds DashScope to the main provider list/support matrix and example provider output.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

|------------|-----------|-------|
| Language Models (LLM) | ❌ | Not available |
| Embeddings | ❌ | Not available |
| Reranking | ⚠️ | qwen3-rerank, gte-rerank-v2, * qwen3-vl-rerank |
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

In the Supported Capabilities table, the Notes cell contains * qwen3-vl-rerank, which won’t render as intended (the leading * with a space isn’t italic/footnote). Consider removing the stray * or formatting it as a proper footnote/italic so the table renders cleanly.

Suggested change
| Reranking | ⚠️ | qwen3-rerank, gte-rerank-v2, * qwen3-vl-rerank |
| Reranking | ⚠️ | qwen3-rerank, gte-rerank-v2, qwen3-vl-rerank |

Copilot uses AI. Check for mistakes.
]

responses = reranker.rerank(
query=query,
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

The multi-modal reranker example has a tab before query=query, which makes the code block mis-indented and harder to copy/paste. Normalize indentation to spaces so the snippet is valid Python as-is.

Suggested change
query=query,
query=query,

Copilot uses AI. Check for mistakes.
Comment on lines +304 to +316
for result, norm_score in zip(raw_results, normalized_scores):
doc_idx = result.get("index")
if doc_idx is None or doc_idx < -0 or doc_idx >= len(documents):
cur_doc = ""
else:
cur_doc = str(documents[doc_idx])

# NOTE: For vl models, get a str for "{'text' | 'image' | 'video': value}"
rerank_results.append(RerankResult(
index=doc_idx,
document=cur_doc,
relevance_score=norm_score
))
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

In _parse_response, when doc_idx is None or out of range you set cur_doc to "", but still pass index=doc_idx into RerankResult. RerankResult.index is an int with ge=0, so None or negative indices will raise a Pydantic validation error and break reranking. Consider skipping invalid results or coercing to a safe non-negative index before constructing RerankResult.

Copilot uses AI. Check for mistakes.

return models


Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

get_dashscope_models is added, but DashScope is not registered in PROVIDER_MODELS_REGISTRY, so AIFactory.get_provider_models('dashscope', ...) will still raise "Provider not supported". Add an entry mapping "dashscope" -> get_dashscope_models so model discovery works as advertised.

Suggested change
# Register DashScope provider in the global provider models registry
PROVIDER_MODELS_REGISTRY["dashscope"] = get_dashscope_models

Copilot uses AI. Check for mistakes.
Comment on lines +58 to +60
assert len(reranker.models) > 0
# Model type is None when not explicitly provided by the API
assert all(model.type is None for model in reranker.models)
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

This test uses the .models property, which is deprecated in RerankerModel and emits a DeprecationWarning (scheduled for removal in v3.0). Consider switching the test to use AIFactory.get_provider_models('dashscope', ...) (once DashScope is registered) or the provider’s internal _get_models() to avoid locking tests onto deprecated API.

Suggested change
assert len(reranker.models) > 0
# Model type is None when not explicitly provided by the API
assert all(model.type is None for model in reranker.models)
models = reranker._get_models()
assert len(models) > 0
# Model type is None when not explicitly provided by the API
assert all(model.type is None for model in models)

Copilot uses AI. Check for mistakes.
__MULTI_MODAL = ["qwen3-vl-rerank"]

def __post_init__(self):
"""Initialize Jina reranker after dataclass initialization."""
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

__post_init__ docstring says "Initialize Jina reranker" but this is the DashScope provider. This looks like a copy/paste and should be corrected to avoid misleading documentation/search results.

Suggested change
"""Initialize Jina reranker after dataclass initialization."""
"""Initialize DashScope reranker after dataclass initialization."""

Copilot uses AI. Check for mistakes.
Comment on lines 140 to 146
```python
import asyncio

async def rerank_async():
reranker = AIFactory.create_reranker("dashscope", "qwen3-rerank")
results = await reranker.arerank(query, documents, top_k=3)
return results
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

The async example imports only asyncio but uses AIFactory without importing it in that snippet. Either add from esperanto.factory import AIFactory to the code block or include the import in the snippet header so it’s copy/pasteable.

Copilot uses AI. Check for mistakes.
@leejangthegreat leejangthegreat marked this pull request as ready for review February 8, 2026 17:58
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

3 issues found across 8 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/esperanto/model_discovery.py">

<violation number="1" location="src/esperanto/model_discovery.py:519">
P2: DashScope Qwen3-VL reranker context_window is set to 800,000, but public Qwen3-VL-Reranker docs indicate a ~32k context length. This misrepresents the model’s limits and can lead to incorrect token handling.</violation>
</file>

<file name="src/esperanto/providers/reranker/dashscope.py">

<violation number="1" location="src/esperanto/providers/reranker/dashscope.py:400">
P2: arerank declares fps as Optional[str] but _validate_inputs compares fps numerically, so passing a string (as the type hint allows) will raise a TypeError. Align the async signature with the sync one (Optional[float]).</violation>
</file>

<file name="docs/providers/dashscope.md">

<violation number="1" location="docs/providers/dashscope.md:194">
P3: Python example uses a tab for indentation while other lines use spaces, which can cause IndentationError if copied.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

id="gte-rerank-v2", owned_by="dashscope", context_window=30_000
),
Model(
id="qwen3-vl-rerank", owned_by="dashscope", context_window=800_000
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 8, 2026

Choose a reason for hiding this comment

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

P2: DashScope Qwen3-VL reranker context_window is set to 800,000, but public Qwen3-VL-Reranker docs indicate a ~32k context length. This misrepresents the model’s limits and can lead to incorrect token handling.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/esperanto/model_discovery.py, line 519:

<comment>DashScope Qwen3-VL reranker context_window is set to 800,000, but public Qwen3-VL-Reranker docs indicate a ~32k context length. This misrepresents the model’s limits and can lead to incorrect token handling.</comment>

<file context>
@@ -487,6 +487,45 @@ def get_jina_models(
+            id="gte-rerank-v2", owned_by="dashscope", context_window=30_000
+        ),
+        Model(
+            id="qwen3-vl-rerank", owned_by="dashscope", context_window=800_000
+        )
+    ]
</file context>
Suggested change
id="qwen3-vl-rerank", owned_by="dashscope", context_window=800_000
id="qwen3-vl-rerank", owned_by="dashscope", context_window=32_000
Fix with Cubic

]

responses = reranker.rerank(
query=query,
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 8, 2026

Choose a reason for hiding this comment

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

P3: Python example uses a tab for indentation while other lines use spaces, which can cause IndentationError if copied.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/providers/dashscope.md, line 194:

<comment>Python example uses a tab for indentation while other lines use spaces, which can cause IndentationError if copied.</comment>

<file context>
@@ -0,0 +1,233 @@
+]
+
+responses = reranker.rerank(
+	query=query,
+    documents=documents,
+    top_k=2,
</file context>
Fix with Cubic

leejangthegreat and others added 3 commits February 9, 2026 02:07
…odel

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Contributor Author

@leejangthegreat leejangthegreat left a comment

Choose a reason for hiding this comment

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

Done fixing some typo and docstring mismatches

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