fix(llm): adapt async tool results for compatible APIs
This commit is contained in:
@@ -117,7 +117,7 @@ def create_llm(cfg: AssistantConfig):
|
|||||||
raise ValueError(f"不支持的 LLM 接口类型: {cfg.llm_interface_type}")
|
raise ValueError(f"不支持的 LLM 接口类型: {cfg.llm_interface_type}")
|
||||||
extra_body = cfg.llm_values.get("extraBody")
|
extra_body = cfg.llm_values.get("extraBody")
|
||||||
extra = {"extra_body": extra_body} if isinstance(extra_body, dict) else {}
|
extra = {"extra_body": extra_body} if isinstance(extra_body, dict) else {}
|
||||||
return OpenAILLMService(
|
service = OpenAILLMService(
|
||||||
api_key=_require(cfg.llm_api_key, "LLM apiKey"),
|
api_key=_require(cfg.llm_api_key, "LLM apiKey"),
|
||||||
base_url=_require(cfg.llm_base_url, "LLM apiUrl"),
|
base_url=_require(cfg.llm_base_url, "LLM apiUrl"),
|
||||||
settings=OpenAILLMService.Settings(
|
settings=OpenAILLMService.Settings(
|
||||||
@@ -125,6 +125,15 @@ def create_llm(cfg: AssistantConfig):
|
|||||||
extra=extra,
|
extra=extra,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
# Pipecat represents late async-tool results with the newer `developer`
|
||||||
|
# role. Most OpenAI-compatible providers (including DeepSeek) only accept
|
||||||
|
# system/assistant/user/tool. This flag uses Pipecat's built-in adapter to
|
||||||
|
# downgrade developer messages before sending the request. Official or
|
||||||
|
# otherwise compatible endpoints can opt in through the resource values.
|
||||||
|
service.supports_developer_role = (
|
||||||
|
cfg.llm_values.get("supportsDeveloperRole") is True
|
||||||
|
)
|
||||||
|
return service
|
||||||
|
|
||||||
|
|
||||||
def create_tts(cfg: AssistantConfig):
|
def create_tts(cfg: AssistantConfig):
|
||||||
|
|||||||
@@ -4,13 +4,61 @@ import unittest
|
|||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from models import AssistantConfig
|
from models import AssistantConfig
|
||||||
|
from pipecat.processors.aggregators.llm_context import LLMContext
|
||||||
from services.pipecat.service_factory import (
|
from services.pipecat.service_factory import (
|
||||||
HTTP_TTS_STOP_FRAME_TIMEOUT_S,
|
HTTP_TTS_STOP_FRAME_TIMEOUT_S,
|
||||||
WEBSOCKET_TTS_STOP_FRAME_TIMEOUT_S,
|
WEBSOCKET_TTS_STOP_FRAME_TIMEOUT_S,
|
||||||
|
create_llm,
|
||||||
create_tts,
|
create_tts,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class LLMServiceFactoryTest(unittest.TestCase):
|
||||||
|
def test_openai_compatible_llm_converts_async_tool_developer_result(self):
|
||||||
|
service = create_llm(
|
||||||
|
AssistantConfig(
|
||||||
|
llm_interface_type="openai-llm",
|
||||||
|
model="deepseek-chat",
|
||||||
|
llm_api_key="test-key",
|
||||||
|
llm_base_url="https://llm.example.test/v1",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
context = LLMContext(
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": "你是助手"},
|
||||||
|
{
|
||||||
|
"role": "developer",
|
||||||
|
"content": '{"type":"async_tool","status":"finished"}',
|
||||||
|
},
|
||||||
|
{"role": "user", "content": "ok"},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
params = service.get_llm_adapter().get_llm_invocation_params(
|
||||||
|
context,
|
||||||
|
convert_developer_to_user=not service.supports_developer_role,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
[message["role"] for message in params["messages"]],
|
||||||
|
["system", "user", "user"],
|
||||||
|
)
|
||||||
|
self.assertNotIn("developer", str(params["messages"]))
|
||||||
|
|
||||||
|
def test_provider_can_explicitly_enable_developer_role(self):
|
||||||
|
service = create_llm(
|
||||||
|
AssistantConfig(
|
||||||
|
llm_interface_type="openai-llm",
|
||||||
|
model="gpt-compatible",
|
||||||
|
llm_api_key="test-key",
|
||||||
|
llm_base_url="https://llm.example.test/v1",
|
||||||
|
llm_values={"supportsDeveloperRole": True},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertTrue(service.supports_developer_role)
|
||||||
|
|
||||||
|
|
||||||
class TTSServiceFactoryTest(unittest.TestCase):
|
class TTSServiceFactoryTest(unittest.TestCase):
|
||||||
def test_http_tts_keeps_wider_audio_chunk_timeout(self):
|
def test_http_tts_keeps_wider_audio_chunk_timeout(self):
|
||||||
config = AssistantConfig(
|
config = AssistantConfig(
|
||||||
|
|||||||
Reference in New Issue
Block a user