Skip to content

Commit f9e41f9

Browse files
feat: improve error handling of Agent component, solves Empty ExceptionWithMessageError (#6097)
* Gracefully handle Errors * updates to Error handling * update in Error handling * update lint error similar to main * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * feat: add max retry and request timeout to open ai component, fixes remote protocol error caused by OpenAI LLM in Agents (#6118) * update to __str__ and fix lint errors * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 9264083 commit f9e41f9

22 files changed

+1127
-75
lines changed

src/backend/base/langflow/base/agents/agent.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from langflow.field_typing import Tool
1515
from langflow.inputs.inputs import InputTypes, MultilineInput
1616
from langflow.io import BoolInput, HandleInput, IntInput, MessageTextInput
17+
from langflow.logging import logger
1718
from langflow.memory import delete_message
1819
from langflow.schema import Data
1920
from langflow.schema.content_block import ContentBlock
@@ -171,8 +172,11 @@ async def run_agent(
171172
msg_id = e.agent_message.id
172173
await delete_message(id_=msg_id)
173174
await self._send_message_event(e.agent_message, category="remove_message")
175+
logger.error(f"ExceptionWithMessageError: {e}")
174176
raise
175-
except Exception:
177+
except Exception as e:
178+
# Log or handle any other exceptions
179+
logger.error(f"Error: {e}")
176180
raise
177181

178182
self.status = result
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from anthropic import BadRequestError as AnthropicBadRequestError
2+
from cohere import BadRequestError as CohereBadRequestError
3+
from httpx import HTTPStatusError
4+
5+
from langflow.schema.message import Message
6+
7+
8+
class CustomBadRequestError(AnthropicBadRequestError, CohereBadRequestError, HTTPStatusError):
9+
def __init__(self, agent_message: Message | None, message: str):
10+
super().__init__(message)
11+
self.message = message
12+
self.agent_message = agent_message
13+
14+
def __str__(self):
15+
return f"{self.message}"

src/backend/base/langflow/base/agents/events.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,17 @@
1414

1515

1616
class ExceptionWithMessageError(Exception):
17-
def __init__(self, agent_message: Message):
17+
def __init__(self, agent_message: Message, message: str):
1818
self.agent_message = agent_message
19-
super().__init__()
19+
super().__init__(message)
20+
self.message = message
21+
22+
def __str__(self):
23+
return (
24+
f"Agent message: {self.agent_message.text} \nError: {self.message}."
25+
if self.agent_message.error or self.agent_message.text
26+
else f"{self.message}."
27+
)
2028

2129

2230
class InputDict(TypedDict):
@@ -273,6 +281,5 @@ async def process_agent_events(
273281
agent_message, start_time = await chain_handler(event, agent_message, send_message_method, start_time)
274282
agent_message.properties.state = "complete"
275283
except Exception as e:
276-
raise ExceptionWithMessageError(agent_message) from e
277-
284+
raise ExceptionWithMessageError(agent_message, str(e)) from e
278285
return await Message.create(**agent_message.model_dump())

src/backend/base/langflow/components/agents/agent.py

+42-42
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from langchain_core.tools import StructuredTool
22

33
from langflow.base.agents.agent import LCToolsAgentComponent
4+
from langflow.base.agents.events import ExceptionWithMessageError
45
from langflow.base.models.model_input_constants import (
56
ALL_PROVIDER_FIELDS,
67
MODEL_DYNAMIC_UPDATE_FIELDS,
@@ -65,43 +66,32 @@ class AgentComponent(ToolCallingAgentComponent):
6566

6667
async def message_response(self) -> Message:
6768
try:
69+
# Get LLM model and validate
6870
llm_model, display_name = self.get_llm()
6971
if llm_model is None:
70-
msg = "No language model selected"
72+
msg = "No language model selected. Please choose a model to proceed."
7173
raise ValueError(msg)
7274
self.model_name = get_model_name(llm_model, display_name=display_name)
73-
except Exception as e:
74-
# Log the error for debugging purposes
75-
logger.error(f"Error retrieving language model: {e}")
76-
raise
7775

78-
try:
76+
# Get memory data
7977
self.chat_history = await self.get_memory_data()
80-
except Exception as e:
81-
logger.error(f"Error retrieving chat history: {e}")
82-
raise
8378

84-
if self.add_current_date_tool:
85-
try:
79+
# Add current date tool if enabled
80+
if self.add_current_date_tool:
8681
if not isinstance(self.tools, list): # type: ignore[has-type]
8782
self.tools = []
88-
# Convert CurrentDateComponent to a StructuredTool
8983
current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)
90-
if isinstance(current_date_tool, StructuredTool):
91-
self.tools.append(current_date_tool)
92-
else:
84+
if not isinstance(current_date_tool, StructuredTool):
9385
msg = "CurrentDateComponent must be converted to a StructuredTool"
9486
raise TypeError(msg)
95-
except Exception as e:
96-
logger.error(f"Error adding current date tool: {e}")
97-
raise
87+
self.tools.append(current_date_tool)
9888

99-
if not self.tools:
100-
msg = "Tools are required to run the agent."
101-
logger.error(msg)
102-
raise ValueError(msg)
89+
# Validate tools
90+
if not self.tools:
91+
msg = "Tools are required to run the agent. Please add at least one tool."
92+
raise ValueError(msg)
10393

104-
try:
94+
# Set up and run agent
10595
self.set(
10696
llm=llm_model,
10797
tools=self.tools,
@@ -110,12 +100,18 @@ async def message_response(self) -> Message:
110100
system_prompt=self.system_prompt,
111101
)
112102
agent = self.create_agent_runnable()
103+
return await self.run_agent(agent)
104+
105+
except (ValueError, TypeError, KeyError) as e:
106+
logger.error(f"{type(e).__name__}: {e!s}")
107+
raise
108+
except ExceptionWithMessageError as e:
109+
logger.error(f"ExceptionWithMessageError occurred: {e}")
110+
raise
113111
except Exception as e:
114-
logger.error(f"Error setting up the agent: {e}")
112+
logger.error(f"Unexpected error: {e!s}")
115113
raise
116114

117-
return await self.run_agent(agent)
118-
119115
async def get_memory_data(self):
120116
memory_kwargs = {
121117
component_input.name: getattr(self, f"{component_input.name}") for component_input in self.memory_inputs
@@ -126,22 +122,26 @@ async def get_memory_data(self):
126122
return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()
127123

128124
def get_llm(self):
129-
if isinstance(self.agent_llm, str):
130-
try:
131-
provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)
132-
if provider_info:
133-
component_class = provider_info.get("component_class")
134-
display_name = component_class.display_name
135-
inputs = provider_info.get("inputs")
136-
prefix = provider_info.get("prefix", "")
137-
return (
138-
self._build_llm_model(component_class, inputs, prefix),
139-
display_name,
140-
)
141-
except Exception as e:
142-
msg = f"Error building {self.agent_llm} language model"
143-
raise ValueError(msg) from e
144-
return self.agent_llm, None
125+
if not isinstance(self.agent_llm, str):
126+
return self.agent_llm, None
127+
128+
try:
129+
provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)
130+
if not provider_info:
131+
msg = f"Invalid model provider: {self.agent_llm}"
132+
raise ValueError(msg)
133+
134+
component_class = provider_info.get("component_class")
135+
display_name = component_class.display_name
136+
inputs = provider_info.get("inputs")
137+
prefix = provider_info.get("prefix", "")
138+
139+
return self._build_llm_model(component_class, inputs, prefix), display_name
140+
141+
except Exception as e:
142+
logger.error(f"Error building {self.agent_llm} language model: {e!s}")
143+
msg = f"Failed to initialize language model: {e!s}"
144+
raise ValueError(msg) from e
145145

146146
def _build_llm_model(self, component, inputs, prefix=""):
147147
model_kwargs = {input_.name: getattr(self, f"{prefix}{input_.name}") for input_ in inputs}

src/backend/base/langflow/components/models/openai.py

+18
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,20 @@ class OpenAIModelComponent(LCModelComponent):
6868
advanced=True,
6969
value=1,
7070
),
71+
IntInput(
72+
name="max_retries",
73+
display_name="Max Retries",
74+
info="The maximum number of retries to make when generating.",
75+
advanced=True,
76+
value=5,
77+
),
78+
IntInput(
79+
name="timeout",
80+
display_name="Timeout",
81+
info="The timeout for requests to OpenAI completion API.",
82+
advanced=True,
83+
value=700,
84+
),
7185
]
7286

7387
def build_model(self) -> LanguageModel: # type: ignore[type-var]
@@ -79,6 +93,8 @@ def build_model(self) -> LanguageModel: # type: ignore[type-var]
7993
openai_api_base = self.openai_api_base or "https://api.openai.com/v1"
8094
json_mode = self.json_mode
8195
seed = self.seed
96+
max_retries = self.max_retries
97+
timeout = self.timeout
8298

8399
api_key = SecretStr(openai_api_key).get_secret_value() if openai_api_key else None
84100
output = ChatOpenAI(
@@ -89,6 +105,8 @@ def build_model(self) -> LanguageModel: # type: ignore[type-var]
89105
api_key=api_key,
90106
temperature=temperature if temperature is not None else 0.1,
91107
seed=seed,
108+
max_retries=max_retries,
109+
request_timeout=timeout,
92110
)
93111
if json_mode:
94112
output = output.bind(response_format={"type": "json_object"})

0 commit comments

Comments
 (0)