feat(engine): #873 dual-Claw event contract + SseAdapter/BufferAdapter + chat.py SSE delegate + im_llm EngineCore thin-shell (gray-gated)
- app/core/engine_event.py (#880): EngineEvent dataclass + make_* factories, single construction entry, byte-compatible wire with legacy ChatPage.tsx - app/core/claw_adapters.py (#884): SseAdapter (hot frames zero-metadata, terminal keeps trace_id) + BufferAdapter (assemble() preserves __media__) - app/api/chat.py (#881): /messages/stream now delegates to SseAdapter; wire bytes unchanged (46B delta / done+message_id) - app/api/im_llm.py (#883): IM_USE_ENGINE_CORE gray gate; _call_engine_core reuses EngineCore via BufferAdapter (default OFF, preserves media fast-path) - app/api/chat_service.py: capture 3 container-ahead fixes (stray import asyncio removed, logger.info format, LiteLLM master key)
This commit is contained in:
1 parent
34648e4810
commit
037c965c26
5 files changed
+752
-21
No files matched your search
@@ -84,6 +84,7 @@ from ..auth import get_current_user
|
||||
from ..platform_knowledge import get_platform_knowledge
|
||||
|
||||
from ..mcp_client import list_mcp_tools, call_mcp_tool
|
||||
from ..core.claw_adapters import SseAdapter
|
||||
|
||||
from ..middleware.log_service import LogService
|
||||
|
||||
@@ -1570,38 +1571,37 @@ async def send_message_stream(
|
||||
req: SendMessageRequest,
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""SSE 流式聊天端点(Phase 0)。
|
||||
与普通 /messages 共用 _send_message_core,仅通过 stream=True + on_event
|
||||
回调实时吐出增量(delta/reasoning),末尾推 done 事件(含 message_id)。
|
||||
"""SSE 流式聊天端点(#873)。
|
||||
|
||||
与 /messages 共用 EngineCore(_send_message_core),仅通过 stream=True +
|
||||
on_event=SseAdapter 实时吐出增量(delta/reasoning/step),末尾推 done 终帧
|
||||
(含 message_id 等)。SseAdapter 保证线格式与改造前逐字节一致。
|
||||
"""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
queue = asyncio.Queue()
|
||||
|
||||
async def on_event(e):
|
||||
await queue.put(e)
|
||||
adapter = SseAdapter(
|
||||
trace_id=f"sse-{conv_id}",
|
||||
tenant_id=str(getattr(current_user, "tenant_id", "") or ""),
|
||||
)
|
||||
|
||||
async def runner():
|
||||
try:
|
||||
await _send_message_core(
|
||||
conv_id, req, db, current_user,
|
||||
stream=True, on_event=on_event,
|
||||
stream=True, on_event=adapter,
|
||||
)
|
||||
except Exception as exc:
|
||||
logger.warning(f"[sse] chat stream error: {exc}", exc_info=True)
|
||||
await queue.put({"type": "error", "message": str(exc)})
|
||||
await adapter.emit_error(str(exc))
|
||||
finally:
|
||||
await queue.put({"type": "__end__"})
|
||||
await adapter.close()
|
||||
|
||||
task = asyncio.create_task(runner())
|
||||
|
||||
async def event_gen():
|
||||
try:
|
||||
while True:
|
||||
e = await queue.get()
|
||||
if e.get("type") == "__end__":
|
||||
break
|
||||
yield f"data: {json.dumps(e, ensure_ascii=False)}\n\n"
|
||||
async for frame in adapter.frames():
|
||||
yield frame
|
||||
finally:
|
||||
await task
|
||||
db.close()
|
||||
@@ -1611,10 +1611,6 @@ async def send_message_stream(
|
||||
db.close()
|
||||
raise
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@router.post("/conversations/{conv_id}/clear")
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user