Complete local hybrid search and improve agent reliability

This commit is contained in:
Hamza Ayed
2026-10-02 23:38:02 +03:00
parent 3563a104a3
commit 140f6eb287
62 changed files with 7546 additions and 314 deletions
+67
View File
@@ -2,6 +2,7 @@
from __future__ import annotations
import asyncio
import json
import os
from collections.abc import AsyncIterator
@@ -28,6 +29,10 @@ class ModelProvider(Protocol):
async def list_models(self) -> list[str]: ...
async def describe_models(
self, model_names: list[str]
) -> dict[str, dict[str, Any]]: ...
class OllamaProvider:
name = "ollama"
@@ -62,6 +67,11 @@ class OllamaProvider:
status_code=502,
detail=f"خطأ من خادم النموذج المحلي: {detail}",
) from exc
except httpx.TimeoutException as exc:
raise HTTPException(
status_code=504,
detail="انتهت مهلة انتظار خادم النموذج المحلي.",
) from exc
except httpx.RequestError as exc:
raise HTTPException(
status_code=503,
@@ -125,6 +135,63 @@ class OllamaProvider:
if isinstance(item, dict) and item.get("name")
]
async def describe_models(
self, model_names: list[str]
) -> dict[str, dict[str, Any]]:
"""Read capability metadata advertised by the installed Ollama models."""
ollama_base = (
self.base_url[:-3] if self.base_url.endswith("/v1") else self.base_url
)
capability_order = [
"completion",
"vision",
"audio",
"tools",
"thinking",
"embedding",
]
semaphore = asyncio.Semaphore(4)
async def describe(client: httpx.AsyncClient, model_name: str):
async with semaphore:
try:
response = await client.post(
f"{ollama_base}/api/show",
json={"model": model_name, "verbose": False},
)
response.raise_for_status()
payload = response.json()
raw = (
payload.get("capabilities")
if isinstance(payload, dict)
else None
)
verified = isinstance(raw, list)
return model_name, {
"verified": verified,
"capabilities": [
capability
for capability in capability_order
if capability in raw
]
if verified
else [],
}
except (httpx.HTTPError, ValueError, TypeError):
return model_name, {"verified": False, "capabilities": []}
try:
async with httpx.AsyncClient(timeout=10.0) as client:
described = await asyncio.gather(
*(describe(client, name) for name in model_names)
)
return dict(described)
except httpx.HTTPError:
return {
name: {"verified": False, "capabilities": []}
for name in model_names
}
def get_model_provider() -> ModelProvider:
provider_name = os.getenv("MODEL_PROVIDER", "ollama").strip().lower()