|
51 | 51 | ) |
52 | 52 | ] |
53 | 53 |
|
| 54 | +tool_recorded_event_forced_internal_error = [ |
| 55 | + ( |
| 56 | + {"type": "LlmTool"}, |
| 57 | + { |
| 58 | + "id": None, |
| 59 | + "run_id": "123", |
| 60 | + "name": "add_exclamation", |
| 61 | + "agent_name": "my_agent", |
| 62 | + "span_id": None, |
| 63 | + "trace_id": "trace-id", |
| 64 | + "input": "{'message': 'Hello'}", |
| 65 | + "vendor": "strands", |
| 66 | + "ingest_source": "Python", |
| 67 | + "duration": None, |
| 68 | + "error": True, |
| 69 | + }, |
| 70 | + ) |
| 71 | +] |
54 | 72 |
|
55 | 73 | tool_recorded_event_error_coro = [ |
56 | 74 | ( |
@@ -362,6 +380,43 @@ def test_agent_invoke_tool_agen_runtime_error(set_trace_info, single_tool_model_ |
362 | 380 | assert response.metrics.tool_metrics["throw_exception_agen"].error_count == 1 |
363 | 381 |
|
364 | 382 |
|
| 383 | +@reset_core_stats_engine() |
| 384 | +@validate_transaction_error_event_count(1) |
| 385 | +@validate_error_trace_attributes(callable_name(ValueError), exact_attrs={"agent": {}, "intrinsic": {}, "user": {}}) |
| 386 | +@validate_custom_events(agent_recorded_event) |
| 387 | +@validate_custom_events(tool_recorded_event_forced_internal_error) |
| 388 | +@validate_custom_event_count(count=2) |
| 389 | +@validate_transaction_metrics( |
| 390 | + "test_agent:test_agent_tool_forced_exception", |
| 391 | + scoped_metrics=[ |
| 392 | + ("Llm/agent/Strands/strands.agent.agent:Agent.stream_async/my_agent", 1), |
| 393 | + ("Llm/tool/Strands/strands.tools.executors._executor:ToolExecutor._stream/add_exclamation", 1), |
| 394 | + ], |
| 395 | + rollup_metrics=[ |
| 396 | + ("Llm/agent/Strands/strands.agent.agent:Agent.stream_async/my_agent", 1), |
| 397 | + ("Llm/tool/Strands/strands.tools.executors._executor:ToolExecutor._stream/add_exclamation", 1), |
| 398 | + ], |
| 399 | + background_task=True, |
| 400 | +) |
| 401 | +@validate_attributes("agent", ["llm"]) |
| 402 | +@background_task() |
| 403 | +def test_agent_tool_forced_exception(set_trace_info, single_tool_model): |
| 404 | + # Add a wrapper to intentionally force an error in the ToolExecutor._stream code to hit the exception path in |
| 405 | + # the AsyncGeneratorProxy |
| 406 | + @transient_function_wrapper("strands.hooks.events", "BeforeToolCallEvent.__init__") |
| 407 | + def _wrap_BeforeToolCallEvent_init(wrapped, instance, args, kwargs): |
| 408 | + raise ValueError("Oops") |
| 409 | + |
| 410 | + @_wrap_BeforeToolCallEvent_init |
| 411 | + def _test(): |
| 412 | + set_trace_info() |
| 413 | + my_agent = Agent(name="my_agent", model=single_tool_model, tools=[add_exclamation]) |
| 414 | + my_agent('Add an exclamation to the word "Hello"') |
| 415 | + |
| 416 | + # This will not explicitly raise a ValueError when running the test but we are still able to capture it in the error trace |
| 417 | + _test() |
| 418 | + |
| 419 | + |
365 | 420 | @reset_core_stats_engine() |
366 | 421 | @validate_custom_event_count(count=0) |
367 | 422 | def test_agent_invoke_outside_txn(single_tool_model): |
|
0 commit comments