mirror of
https://github.com/langgenius/dify.git
synced 2026-10-04 13:47:55 +08:00
- test_wiring.py: expected dict was missing SessionView's new `model` field - model_resolver.normalize_completion_params: a string `stop` was being char-split into a list of letters instead of wrapped in a single-element list; added a regression test - controllers/console/dify_builder._ping: log the exception server-side before returning the ok:false envelope - ruff-clean the slice's new/extended test files (ARG001/ARG002/ARG005 via precise noqa, PT018 compound-assert splits, E306, E501) with no change to test behavior or assertion meaning Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
62 lines
2.7 KiB
Python
62 lines
2.7 KiB
Python
"""Resolve the user's per-session model choice to a live ModelInstance.
|
|
|
|
The choice is Dify's model-selector shape (a ``model_config`` dict:
|
|
{provider, name, mode, completion_params}). Empty/None means "use the
|
|
tenant's configured default LLM". This module is the only place in the
|
|
Dify Builder services layer that touches the model runtime for resolution.
|
|
"""
|
|
|
|
from typing import Any
|
|
|
|
from core.app.app_config.entities import ModelConfig
|
|
from core.dify_builder.errors import BadRequestError
|
|
from core.model_manager import ModelInstance, ModelManager
|
|
from graphon.model_runtime.entities.model_entities import ModelType
|
|
|
|
|
|
def normalize_completion_params(completion_params: dict[str, Any]) -> tuple[dict[str, Any], list[str] | None]:
|
|
"""Split ``stop`` out of completion_params (invoke_llm takes it separately)."""
|
|
params = dict(completion_params or {})
|
|
stop = params.pop("stop", None)
|
|
if isinstance(stop, str):
|
|
stop = [stop]
|
|
elif stop is not None and not isinstance(stop, list):
|
|
stop = list(stop)
|
|
return params, stop
|
|
|
|
|
|
def resolve_model_instance(tenant_id: str, model_config: dict[str, Any] | None) -> ModelInstance:
|
|
"""A chosen model_config -> that model; empty/None -> the tenant default LLM."""
|
|
manager = ModelManager.for_tenant(tenant_id)
|
|
if model_config:
|
|
mc = ModelConfig.model_validate(model_config)
|
|
return manager.get_model_instance(
|
|
tenant_id=tenant_id, provider=mc.provider, model_type=ModelType.LLM, model=mc.name
|
|
)
|
|
return manager.get_default_model_instance(tenant_id=tenant_id, model_type=ModelType.LLM)
|
|
|
|
|
|
def validate_model_config(tenant_id: str, model_config: dict[str, Any]) -> None:
|
|
"""Fail fast at session creation if an explicit pick can't be resolved.
|
|
|
|
Surfaces the failure as BadRequestError (-> 400) rather than silently
|
|
downgrading to canned behavior.
|
|
"""
|
|
try:
|
|
mc = ModelConfig.model_validate(model_config)
|
|
ModelManager.for_tenant(tenant_id).get_model_instance(
|
|
tenant_id=tenant_id, provider=mc.provider, model_type=ModelType.LLM, model=mc.name
|
|
)
|
|
except Exception as exc:
|
|
raise BadRequestError(f"invalid model_config: {exc}") from exc
|
|
|
|
|
|
def resolved_model_names(tenant_id: str, model_config: dict[str, Any] | None) -> dict[str, str]:
|
|
"""Provider+name for display: the explicit pick, or the tenant default names."""
|
|
if model_config:
|
|
return {"provider": model_config.get("provider", ""), "name": model_config.get("name", "")}
|
|
provider, name = ModelManager.for_tenant(tenant_id).get_default_provider_model_name(
|
|
tenant_id=tenant_id, model_type=ModelType.LLM
|
|
)
|
|
return {"provider": provider or "", "name": name or ""}
|