feat(assistant): add multi-dialog UX, task-aware llm settings, and i18n cleanup
This commit is contained in:
@@ -61,23 +61,109 @@ DEFAULT_LLM_PROMPTS: Dict[str, str] = {
|
||||
# [/DEF:DEFAULT_LLM_PROMPTS:Constant]
|
||||
|
||||
|
||||
# [DEF:DEFAULT_LLM_PROVIDER_BINDINGS:Constant]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Default provider binding per task domain.
|
||||
DEFAULT_LLM_PROVIDER_BINDINGS: Dict[str, str] = {
|
||||
"dashboard_validation": "",
|
||||
"documentation": "",
|
||||
"git_commit": "",
|
||||
}
|
||||
# [/DEF:DEFAULT_LLM_PROVIDER_BINDINGS:Constant]
|
||||
|
||||
|
||||
# [DEF:DEFAULT_LLM_ASSISTANT_SETTINGS:Constant]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Default planner settings for assistant chat intent model/provider resolution.
|
||||
DEFAULT_LLM_ASSISTANT_SETTINGS: Dict[str, str] = {
|
||||
"assistant_planner_provider": "",
|
||||
"assistant_planner_model": "",
|
||||
}
|
||||
# [/DEF:DEFAULT_LLM_ASSISTANT_SETTINGS:Constant]
|
||||
|
||||
|
||||
# [DEF:normalize_llm_settings:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Ensure llm settings contain stable schema with prompts section and default templates.
|
||||
# @PRE: llm_settings is dictionary-like value or None.
|
||||
# @POST: Returned dict contains prompts with all required template keys.
|
||||
def normalize_llm_settings(llm_settings: Any) -> Dict[str, Any]:
|
||||
normalized: Dict[str, Any] = {"providers": [], "default_provider": "", "prompts": {}}
|
||||
normalized: Dict[str, Any] = {
|
||||
"providers": [],
|
||||
"default_provider": "",
|
||||
"prompts": {},
|
||||
"provider_bindings": {},
|
||||
**DEFAULT_LLM_ASSISTANT_SETTINGS,
|
||||
}
|
||||
if isinstance(llm_settings, dict):
|
||||
normalized.update({k: v for k, v in llm_settings.items() if k in ("providers", "default_provider", "prompts")})
|
||||
normalized.update(
|
||||
{
|
||||
k: v
|
||||
for k, v in llm_settings.items()
|
||||
if k
|
||||
in (
|
||||
"providers",
|
||||
"default_provider",
|
||||
"prompts",
|
||||
"provider_bindings",
|
||||
"assistant_planner_provider",
|
||||
"assistant_planner_model",
|
||||
)
|
||||
}
|
||||
)
|
||||
prompts = normalized.get("prompts") if isinstance(normalized.get("prompts"), dict) else {}
|
||||
merged_prompts = deepcopy(DEFAULT_LLM_PROMPTS)
|
||||
merged_prompts.update({k: v for k, v in prompts.items() if isinstance(v, str) and v.strip()})
|
||||
normalized["prompts"] = merged_prompts
|
||||
bindings = normalized.get("provider_bindings") if isinstance(normalized.get("provider_bindings"), dict) else {}
|
||||
merged_bindings = deepcopy(DEFAULT_LLM_PROVIDER_BINDINGS)
|
||||
merged_bindings.update({k: v for k, v in bindings.items() if isinstance(v, str)})
|
||||
normalized["provider_bindings"] = merged_bindings
|
||||
for key, default_value in DEFAULT_LLM_ASSISTANT_SETTINGS.items():
|
||||
value = normalized.get(key, default_value)
|
||||
normalized[key] = value.strip() if isinstance(value, str) else default_value
|
||||
return normalized
|
||||
# [/DEF:normalize_llm_settings:Function]
|
||||
|
||||
|
||||
# [DEF:is_multimodal_model:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Heuristically determine whether model supports image input required for dashboard validation.
|
||||
# @PRE: model_name may be empty or mixed-case.
|
||||
# @POST: Returns True when model likely supports multimodal input.
|
||||
def is_multimodal_model(model_name: str) -> bool:
|
||||
token = (model_name or "").strip().lower()
|
||||
if not token:
|
||||
return False
|
||||
multimodal_markers = (
|
||||
"gpt-4o",
|
||||
"gpt-4.1",
|
||||
"vision",
|
||||
"vl",
|
||||
"gemini",
|
||||
"claude-3",
|
||||
"claude-sonnet-4",
|
||||
)
|
||||
return any(marker in token for marker in multimodal_markers)
|
||||
# [/DEF:is_multimodal_model:Function]
|
||||
|
||||
|
||||
# [DEF:resolve_bound_provider_id:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Resolve provider id configured for a task binding with fallback to default provider.
|
||||
# @PRE: llm_settings is normalized or raw dict from config.
|
||||
# @POST: Returns configured provider id or fallback id/empty string when not defined.
|
||||
def resolve_bound_provider_id(llm_settings: Any, task_key: str) -> str:
|
||||
normalized = normalize_llm_settings(llm_settings)
|
||||
bindings = normalized.get("provider_bindings", {})
|
||||
bound = bindings.get(task_key)
|
||||
if isinstance(bound, str) and bound.strip():
|
||||
return bound.strip()
|
||||
default_provider = normalized.get("default_provider", "")
|
||||
return default_provider.strip() if isinstance(default_provider, str) else ""
|
||||
# [/DEF:resolve_bound_provider_id:Function]
|
||||
|
||||
|
||||
# [DEF:render_prompt:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Render prompt template using deterministic placeholder replacement with graceful fallback.
|
||||
|
||||
Reference in New Issue
Block a user