feat: restore source parity and harden agent runtime

This commit is contained in:
2026-06-22 11:17:26 +08:00
parent e33f08277b
commit 0793eb82d6
596 changed files with 168879 additions and 290 deletions
@@ -64,6 +64,26 @@ class LLMService:
logger.info("No model_id supplied, fallback to default chat model %s", model.id)
return str(model.id)
@staticmethod
def _run_async_sync(coro):
import asyncio
import concurrent.futures
try:
loop = asyncio.get_event_loop()
except RuntimeError:
return asyncio.run(coro)
if loop.is_running():
with concurrent.futures.ThreadPoolExecutor() as executor:
return executor.submit(asyncio.run, coro).result()
return loop.run_until_complete(coro)
def resolve_chat_model_id_sync(self, model_id: Optional[str]) -> str:
"""同步解析 chat 模型,供同步节点和流式生成器复用。"""
return self._run_async_sync(self.resolve_chat_model_id(model_id))
async def _get_provider_async(self, model_id: str) -> tuple:
"""
@@ -272,6 +292,34 @@ class LLMService:
return provider.chat(llm_messages, config)
except Exception as exc:
raise RuntimeError(self._format_provider_error(exc, provider, model_name)) from exc
def chat(
self,
model_id: Optional[str],
messages: List[Dict[str, str]],
temperature: float = 0.7,
max_tokens: int = 2048,
tools: List[Dict] = None,
tool_choice: str = 'auto',
**kwargs
) -> LLMResponse:
"""
同步对话入口。
旧节点仍会调用该方法;这里统一走 provider 解析和默认 chat 模型兜底,
避免不同节点各自处理 model_id 为空的情况。
"""
provider, model_name = self._run_async_sync(self._get_provider_async(model_id))
return self.chat_with_provider(
provider=provider,
model_name=model_name,
messages=messages,
temperature=temperature,
max_tokens=max_tokens,
tools=tools,
tool_choice=tool_choice,
**kwargs,
)
def _convert_messages(self, messages: List[Dict]) -> List[LLMMessage]:
"""转换消息格式,支持 tool 消息"""