mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
fix(copilot): add isLongRunning flag directly to StreamToolInputAvailable
Instead of sending a separate custom event, add isLongRunning boolean to the existing StreamToolInputAvailable event. This is much simpler and works with the AI SDK without needing custom event handling. Backend changes: - Add isLongRunning field to StreamToolInputAvailable - Check tool.is_long_running in response_adapter and set the flag - Remove separate StreamLongRunningStart emission Frontend changes: - Check part.isLongRunning directly on the tool part - Remove message prop from ToolWrapper (no longer needed) - Simplify detection logic This approach piggybacks on the existing tool-input-available event that the AI SDK already recognizes and adds to message.parts.
This commit is contained in:
@@ -148,6 +148,10 @@ class StreamToolInputAvailable(StreamBaseResponse):
|
||||
input: dict[str, Any] = Field(
|
||||
default_factory=dict, description="Tool input arguments"
|
||||
)
|
||||
isLongRunning: bool = Field(
|
||||
default=False,
|
||||
description="Whether this tool is long-running (triggers UI feedback)",
|
||||
)
|
||||
|
||||
|
||||
class StreamToolOutputAvailable(StreamBaseResponse):
|
||||
|
||||
@@ -34,6 +34,7 @@ from backend.copilot.response_model import (
|
||||
StreamToolInputStart,
|
||||
StreamToolOutputAvailable,
|
||||
)
|
||||
from backend.copilot.tools import get_tool
|
||||
|
||||
from .tool_adapter import MCP_TOOL_PREFIX, pop_pending_tool_output
|
||||
|
||||
@@ -111,6 +112,10 @@ class SDKResponseAdapter:
|
||||
# instead of "mcp__copilot__find_block".
|
||||
tool_name = block.name.removeprefix(MCP_TOOL_PREFIX)
|
||||
|
||||
# Check if this is a long-running tool to trigger UI feedback
|
||||
tool = get_tool(tool_name)
|
||||
is_long_running = tool.is_long_running if tool else False
|
||||
|
||||
responses.append(
|
||||
StreamToolInputStart(toolCallId=block.id, toolName=tool_name)
|
||||
)
|
||||
@@ -119,6 +124,7 @@ class SDKResponseAdapter:
|
||||
toolCallId=block.id,
|
||||
toolName=tool_name,
|
||||
input=block.input,
|
||||
isLongRunning=is_long_running,
|
||||
)
|
||||
)
|
||||
self.current_tool_calls[block.id] = {"name": tool_name}
|
||||
|
||||
@@ -25,14 +25,12 @@ from ..response_model import (
|
||||
StreamFinish,
|
||||
StreamFinishStep,
|
||||
StreamHeartbeat,
|
||||
StreamLongRunningStart,
|
||||
StreamStart,
|
||||
StreamTextDelta,
|
||||
StreamToolInputAvailable,
|
||||
StreamToolOutputAvailable,
|
||||
)
|
||||
from ..service import _build_system_prompt, _generate_session_title
|
||||
from ..tools import get_tool
|
||||
from ..tools.sandbox import WORKSPACE_PREFIX, make_session_path
|
||||
from ..tracking import track_user_message
|
||||
from .response_adapter import SDKResponseAdapter
|
||||
@@ -733,24 +731,6 @@ async def stream_chat_completion_sdk(
|
||||
|
||||
yield response
|
||||
|
||||
# Emit long-running notification for tools with is_long_running=True
|
||||
if isinstance(response, StreamToolInputAvailable):
|
||||
tool = get_tool(response.toolName)
|
||||
logger.info(
|
||||
f"[SDK] Tool check: {response.toolName}, "
|
||||
f"tool={tool}, is_long_running={tool.is_long_running if tool else 'N/A'}"
|
||||
)
|
||||
if tool and tool.is_long_running:
|
||||
logger.info(
|
||||
f"[SDK] Emitting StreamLongRunningStart for {response.toolName}"
|
||||
)
|
||||
yield StreamLongRunningStart(
|
||||
data={
|
||||
"toolCallId": response.toolCallId,
|
||||
"toolName": response.toolName,
|
||||
}
|
||||
)
|
||||
|
||||
if isinstance(response, StreamTextDelta):
|
||||
delta = response.delta or ""
|
||||
# After tool results, start a new assistant
|
||||
|
||||
@@ -212,8 +212,6 @@ export const ChatMessagesContainer = ({
|
||||
<ToolWrapper
|
||||
key={`${message.id}-${i}`}
|
||||
part={part as ToolUIPart}
|
||||
message={message}
|
||||
message={message}
|
||||
>
|
||||
<FindBlocksTool part={part as ToolUIPart} />
|
||||
</ToolWrapper>
|
||||
|
||||
@@ -1,31 +1,21 @@
|
||||
import type { ToolUIPart, UIDataTypes, UIMessage, UITools } from "ai";
|
||||
import type { ToolUIPart } from "ai";
|
||||
import { LongRunningToolDisplay } from "../LongRunningToolDisplay/LongRunningToolDisplay";
|
||||
|
||||
interface Props {
|
||||
part: ToolUIPart;
|
||||
message: UIMessage<unknown, UIDataTypes, UITools>;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for all tool components. Automatically shows UI feedback
|
||||
* for long-running tools by detecting StreamLongRunningStart events from the backend.
|
||||
* for long-running tools by detecting the isLongRunning flag on the tool part.
|
||||
*/
|
||||
export function ToolWrapper({ part, message, children }: Props) {
|
||||
export function ToolWrapper({ part, children }: Props) {
|
||||
const isStreaming =
|
||||
part.state === "input-streaming" || part.state === "input-available";
|
||||
|
||||
// Check if this tool has a data-long-running-start event in the message
|
||||
const isLongRunning = message.parts.some(
|
||||
(p) =>
|
||||
p.type === "data-long-running-start" &&
|
||||
"data" in p &&
|
||||
typeof p.data === "object" &&
|
||||
p.data !== null &&
|
||||
"toolCallId" in p.data &&
|
||||
"toolCallId" in part &&
|
||||
p.data.toolCallId === part.toolCallId,
|
||||
);
|
||||
// Check if this tool is marked as long-running in the part itself
|
||||
const isLongRunning = "isLongRunning" in part && part.isLongRunning === true;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user