Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions agentrun/integration/langgraph/agent_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from typing import Any, Dict, Iterator, List, Optional, Union

from agentrun.server.model import AgentResult, EventType
from agentrun.utils.error_utils import build_error_event_data, is_model_error
from agentrun.utils.log import logger

# 需要从工具输入中过滤掉的内部字段(LangGraph/MCP 注入的运行时对象)
Expand Down Expand Up @@ -952,10 +953,15 @@ def _convert_astream_events_event(

yield AgentResult(
event=EventType.ERROR,
data={
"message": f"LLM error: {error_message}",
"code": "LLM_ERROR",
},
data=build_error_event_data(
error,
fallback_code="LLM_ERROR",
fallback_message=(
error_message
if is_model_error(error)
else f"LLM error: {error_message}"
),
),
)

# 8. Chain 错误
Expand Down
24 changes: 19 additions & 5 deletions agentrun/server/agui_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@
# ============================================================================

DEFAULT_PREFIX = "/ag-ui/agent"
RUN_ERROR_EXTRA_FIELDS = (
"retryable",
"retryAfterMs",
"traceId",
"requestId",
"statusCode",
"providerCode",
)


@dataclass
Expand Down Expand Up @@ -743,12 +751,18 @@ def _process_event_with_boundaries(

# ERROR 事件
if event.event == EventType.ERROR:
yield self._encoder.encode(
RunErrorEvent(
message=event.data.get("message", ""),
code=event.data.get("code"),
)
agui_event = RunErrorEvent(
message=event.data.get("message", ""),
code=event.data.get("code"),
)
extra_fields = {
key: event.data[key]
for key in RUN_ERROR_EXTRA_FIELDS
if key in event.data
}
if extra_fields:
agui_event = agui_event.model_copy(update=extra_fields)
yield self._encoder.encode(agui_event)
return

# STATE 事件
Expand Down
56 changes: 28 additions & 28 deletions agentrun/server/invoker.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@
)
import uuid

from agentrun.utils.error_utils import build_error_event_data, is_model_error
from agentrun.utils.reasoning import get_reasoning_content

from .model import AgentEvent, AgentRequest, EventType
from .protocol import (
AsyncInvokeAgentHandler,
InvokeAgentHandler,
SyncInvokeAgentHandler,
)
from agentrun.utils.reasoning import get_reasoning_content


class AgentInvoker:
Expand Down Expand Up @@ -117,10 +119,7 @@ async def invoke_stream(
if isinstance(item, str):
if not item: # 跳过空字符串
continue
yield AgentEvent(
event=EventType.TEXT,
data={"delta": item},
)
yield self._wrap_text(item)

elif isinstance(item, AgentEvent):
# 处理用户返回的事件
Expand All @@ -142,7 +141,11 @@ async def invoke_stream(
logger.error(f"Agent 调用出错: {e}", exc_info=True)
yield AgentEvent(
event=EventType.ERROR,
data={"message": str(e), "code": type(e).__name__},
data=build_error_event_data(
e,
fallback_code=type(e).__name__,
fallback_message=str(e),
),
)

def _process_user_event(
Expand Down Expand Up @@ -227,12 +230,7 @@ def _wrap_non_stream(self, result: Any) -> List[AgentEvent]:
return results

if isinstance(result, str):
results.append(
AgentEvent(
event=EventType.TEXT,
data={"delta": result},
)
)
results.append(self._wrap_text(result))

elif isinstance(result, AgentEvent):
# 处理可能的 TOOL_CALL 展开
Expand All @@ -243,12 +241,7 @@ def _wrap_non_stream(self, result: Any) -> List[AgentEvent]:
if isinstance(item, AgentEvent):
results.extend(self._process_user_event(item))
elif isinstance(item, str) and item:
results.append(
AgentEvent(
event=EventType.TEXT,
data={"delta": item},
)
)
results.append(self._wrap_text(item))
else:
results.extend(self._wrap_model_chunk(item))

Expand All @@ -275,10 +268,7 @@ async def _wrap_stream(
if isinstance(item, str):
if not item:
continue
yield AgentEvent(
event=EventType.TEXT,
data={"delta": item},
)
yield self._wrap_text(item)

elif isinstance(item, AgentEvent):
for processed_event in self._process_user_event(item):
Expand Down Expand Up @@ -346,15 +336,25 @@ def _wrap_model_chunk(self, item: Any) -> List[AgentEvent]:

content = self._read_attr_or_key(item, "content")
if isinstance(content, str) and content:
events.append(
AgentEvent(
event=EventType.TEXT,
data={"delta": content},
)
)
events.append(self._wrap_text(content))

return events

def _wrap_text(self, text: str) -> AgentEvent:
if is_model_error(text):
return AgentEvent(
event=EventType.ERROR,
data=build_error_event_data(
text,
fallback_code=type(text).__name__,
fallback_message=text,
),
)
return AgentEvent(
event=EventType.TEXT,
data={"delta": text},
)

def _read_attr_or_key(self, obj: Any, key: str) -> Any:
if isinstance(obj, dict):
return obj.get(key)
Expand Down
Loading
Loading