fix(backend/copilot): send initial operation_in_progress event before sync execution

Yield initial StreamToolOutputAvailable with OperationInProgressResponse before
starting synchronous execution of long-running tools (create_agent, edit_agent).

This ensures the frontend receives output immediately and can render the accordion
UI with mini-game while the synchronous operation is running. Previously, the
frontend only had input but no output until the tool completed, preventing the
UI from rendering.

Flow is now:
1. StreamToolInputAvailable - creates tool part
2. StreamToolOutputAvailable (OperationInProgressResponse) - triggers UI rendering
3. [synchronous execution with heartbeats]
4. StreamToolOutputAvailable (final result) - updates with actual result

Addresses user feedback: "why don't we update the event before calling the sync request"
This commit is contained in:
Zamil Majdy
2026-02-22 15:44:42 +07:00
parent bbfcfef20b
commit 20dea80fc9

View File

@@ -1475,6 +1475,29 @@ async def _yield_tool_call(
f"(operation_id={operation_id}, task_id={task_id})"
)
# Send initial operation_in_progress response so frontend can render UI immediately
# This ensures the accordion/mini-game shows while we execute synchronously
if tool_name == "create_agent":
in_progress_msg = (
"Creating agent, this may take a few minutes. Play while you wait."
)
elif tool_name == "edit_agent":
in_progress_msg = (
"Editing agent, this may take a few minutes. Play while you wait."
)
else:
in_progress_msg = f"{tool_name} in progress..."
yield StreamToolOutputAvailable(
toolCallId=tool_call_id,
toolName=tool_name,
output=OperationInProgressResponse(
message=in_progress_msg,
tool_call_id=tool_call_id,
).model_dump_json(),
success=True,
)
# Execute tool SYNCHRONOUSLY - blocks until complete
# Send heartbeats to keep SSE connection alive while waiting
try: