mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
Fix SambaNova context length exception handling (#9252)
Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
parent
1e33624951
commit
9b4ad4e6e3
@ -821,6 +821,11 @@ class AgentController:
|
||||
or 'input length and `max_tokens` exceed context limit' in error_str
|
||||
or 'please reduce the length of either one'
|
||||
in error_str # For OpenRouter context window errors
|
||||
or (
|
||||
'sambanovaexception' in error_str
|
||||
and 'maximum context length' in error_str
|
||||
)
|
||||
# For SambaNova context window errors - only match when both patterns are present
|
||||
or isinstance(e, ContextWindowExceededError)
|
||||
):
|
||||
if self.agent.config.enable_history_truncation:
|
||||
|
||||
@ -1682,3 +1682,138 @@ async def test_openrouter_context_window_exceeded_error(
|
||||
)
|
||||
|
||||
await controller.close()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sambanova_context_window_exceeded_error(
|
||||
mock_agent, test_event_stream, mock_status_callback
|
||||
):
|
||||
"""Test that SambaNova context window exceeded errors are properly detected and handled."""
|
||||
max_iterations = 5
|
||||
error_after = 2
|
||||
|
||||
class StepState:
|
||||
def __init__(self):
|
||||
self.has_errored = False
|
||||
self.index = 0
|
||||
self.views = []
|
||||
|
||||
def step(self, state: State):
|
||||
# Store the view for later inspection
|
||||
self.views.append(state.view)
|
||||
# only throw it once.
|
||||
if self.index < error_after or self.has_errored:
|
||||
self.index += 1
|
||||
return MessageAction(content=f'Test message {self.index}')
|
||||
|
||||
# Create a BadRequestError with the SambaNova context window exceeded message pattern
|
||||
error = BadRequestError(
|
||||
message='litellm.BadRequestError: SambanovaException - The maximum context length of DeepSeek-V3-0324 is 32768. However, answering your request will take 39732 tokens. Please reduce the length of the messages or the specified max_completion_tokens value.',
|
||||
model='sambanova/deepseek-v3-0324',
|
||||
llm_provider='sambanova',
|
||||
)
|
||||
self.has_errored = True
|
||||
raise error
|
||||
|
||||
step_state = StepState()
|
||||
mock_agent.step = step_state.step
|
||||
mock_agent.config = AgentConfig(enable_history_truncation=True)
|
||||
|
||||
controller = AgentController(
|
||||
agent=mock_agent,
|
||||
event_stream=test_event_stream,
|
||||
iteration_delta=max_iterations,
|
||||
sid='test',
|
||||
confirmation_mode=False,
|
||||
headless_mode=True,
|
||||
status_callback=mock_status_callback,
|
||||
)
|
||||
|
||||
# Set the agent state to RUNNING
|
||||
controller.state.agent_state = AgentState.RUNNING
|
||||
|
||||
# Run the controller until it hits the error
|
||||
for _ in range(error_after + 2): # +2 to ensure we go past the error
|
||||
await controller._step()
|
||||
if step_state.has_errored:
|
||||
break
|
||||
|
||||
# Verify that the error was handled as a context window exceeded error
|
||||
# by checking that _handle_long_context_error was called (which adds a CondensationAction)
|
||||
events = list(test_event_stream.get_events())
|
||||
condensation_actions = [e for e in events if isinstance(e, CondensationAction)]
|
||||
|
||||
# There should be at least one CondensationAction if the error was handled correctly
|
||||
assert len(condensation_actions) > 0, (
|
||||
'SambaNova context window exceeded error was not handled correctly'
|
||||
)
|
||||
|
||||
await controller.close()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sambanova_generic_exception_not_handled_as_context_error(
|
||||
mock_agent, test_event_stream, mock_status_callback
|
||||
):
|
||||
"""Test that generic SambaNova exceptions (without context length pattern) are NOT handled as context window errors."""
|
||||
max_iterations = 5
|
||||
error_after = 2
|
||||
|
||||
class StepState:
|
||||
def __init__(self):
|
||||
self.has_errored = False
|
||||
self.index = 0
|
||||
self.views = []
|
||||
|
||||
def step(self, state: State):
|
||||
# Store the view for later inspection
|
||||
self.views.append(state.view)
|
||||
# only throw it once.
|
||||
if self.index < error_after or self.has_errored:
|
||||
self.index += 1
|
||||
return MessageAction(content=f'Test message {self.index}')
|
||||
|
||||
# Create a BadRequestError with a generic SambaNova error (no context length pattern)
|
||||
error = BadRequestError(
|
||||
message='litellm.BadRequestError: SambanovaException - Some other error occurred',
|
||||
model='sambanova/deepseek-v3-0324',
|
||||
llm_provider='sambanova',
|
||||
)
|
||||
self.has_errored = True
|
||||
raise error
|
||||
|
||||
step_state = StepState()
|
||||
mock_agent.step = step_state.step
|
||||
mock_agent.config = AgentConfig(enable_history_truncation=True)
|
||||
|
||||
controller = AgentController(
|
||||
agent=mock_agent,
|
||||
event_stream=test_event_stream,
|
||||
iteration_delta=max_iterations,
|
||||
sid='test',
|
||||
confirmation_mode=False,
|
||||
headless_mode=True,
|
||||
status_callback=mock_status_callback,
|
||||
)
|
||||
|
||||
# Set the agent state to RUNNING
|
||||
controller.state.agent_state = AgentState.RUNNING
|
||||
|
||||
# Run the controller until it hits the error
|
||||
with pytest.raises(BadRequestError):
|
||||
for _ in range(error_after + 2): # +2 to ensure we go past the error
|
||||
await controller._step()
|
||||
if step_state.has_errored:
|
||||
break
|
||||
|
||||
# Verify that the error was NOT handled as a context window exceeded error
|
||||
# by checking that _handle_long_context_error was NOT called (no CondensationAction should be added)
|
||||
events = list(test_event_stream.get_events())
|
||||
condensation_actions = [e for e in events if isinstance(e, CondensationAction)]
|
||||
|
||||
# There should be NO CondensationAction if the error was correctly NOT handled as context window error
|
||||
assert len(condensation_actions) == 0, (
|
||||
'Generic SambaNova exception was incorrectly handled as context window error'
|
||||
)
|
||||
|
||||
await controller.close()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user