fixed injection watcher
This commit is contained in:
@@ -48,8 +48,15 @@ async def send_message(
|
||||
if not service.get_session(session_id):
|
||||
raise HTTPException(status_code=404, detail="Session not found")
|
||||
|
||||
# Сохраняем user до стрима: иначе при обрыве SSE сообщение не попадает в БД.
|
||||
service.save_user_message(session_id, payload.content)
|
||||
|
||||
async def event_stream():
|
||||
async for chunk in service.stream_response(session_id, payload.content):
|
||||
async for chunk in service.stream_response(
|
||||
session_id,
|
||||
payload.content,
|
||||
user_message_saved=True,
|
||||
):
|
||||
yield chunk
|
||||
|
||||
return StreamingResponse(
|
||||
|
||||
@@ -172,13 +172,23 @@ class ChatService:
|
||||
self.db.refresh(message)
|
||||
return message
|
||||
|
||||
async def stream_response(self, session_id: int, user_text: str) -> AsyncIterator[str]:
|
||||
def save_user_message(self, session_id: int, user_text: str) -> None:
|
||||
self._save_message(session_id, "user", user_text)
|
||||
|
||||
async def stream_response(
|
||||
self,
|
||||
session_id: int,
|
||||
user_text: str,
|
||||
*,
|
||||
user_message_saved: bool = False,
|
||||
) -> AsyncIterator[str]:
|
||||
session = self.get_session(session_id)
|
||||
if not session:
|
||||
yield self._sse("error", {"message": "Session not found"})
|
||||
return
|
||||
|
||||
self._save_message(session_id, "user", user_text)
|
||||
if not user_message_saved:
|
||||
self._save_message(session_id, "user", user_text)
|
||||
yield self._sse("status", {"phase": "preparing"})
|
||||
t0 = time.monotonic()
|
||||
messages = await asyncio.to_thread(_build_messages_for_session, session_id)
|
||||
@@ -299,10 +309,15 @@ class ChatService:
|
||||
if not final_content and reasoning:
|
||||
final_content = reasoning.strip()
|
||||
if not final_content and all_tool_notices:
|
||||
# Notices уже ушли в SSE event: notice; здесь только финальный текст в БД.
|
||||
final_content = "\n\n".join(all_tool_notices)
|
||||
yield self._sse("token", {"content": final_content})
|
||||
if not final_content and tools_executed:
|
||||
retry = await self.llm.complete(messages, tools=None, temperature=0.4)
|
||||
retry = await self.llm.complete(
|
||||
messages,
|
||||
tools=None,
|
||||
temperature=0.4,
|
||||
visible_reply=True,
|
||||
)
|
||||
final_content = (retry.get("content") or "").strip()
|
||||
if final_content:
|
||||
yield self._sse("token", {"content": final_content})
|
||||
|
||||
@@ -171,6 +171,7 @@ class LLMClient:
|
||||
temperature: float = 0.7,
|
||||
model: str | None = None,
|
||||
for_extraction: bool = False,
|
||||
visible_reply: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
use_tools = bool(tools) and self.tools_enabled and not for_extraction
|
||||
kwargs: dict[str, Any] = {
|
||||
@@ -198,7 +199,7 @@ class LLMClient:
|
||||
reasoning = str(value)
|
||||
break
|
||||
|
||||
if not content and reasoning:
|
||||
if not content and reasoning and not visible_reply:
|
||||
content = reasoning
|
||||
|
||||
result: dict[str, Any] = {
|
||||
|
||||
Reference in New Issue
Block a user