|
32 | 32 | from newrelic.common.object_names import callable_name |
33 | 33 | from newrelic.common.object_wrapper import transient_function_wrapper |
34 | 34 |
|
35 | | -from ._test_tools import add_exclamation, tool_method_name, tool_type |
| 35 | +from ._test_tools import ( |
| 36 | + add_exclamation, |
| 37 | + add_exclamation_async, |
| 38 | + add_exclamation_sync, |
| 39 | + remote_add_exclamation, |
| 40 | + remote_add_exclamation_async, |
| 41 | + remote_add_exclamation_sync, |
| 42 | + tool_method_name, |
| 43 | + tool_type, |
| 44 | +) |
36 | 45 |
|
37 | 46 | PROMPT = { |
38 | 47 | "messages": [ |
@@ -155,6 +164,38 @@ def _test(): |
155 | 164 | _test() |
156 | 165 |
|
157 | 166 |
|
| 167 | +@dt_enabled |
| 168 | +@reset_core_stats_engine() |
| 169 | +def test_tool_remote_no_subcomponent( |
| 170 | + exercise_agent, set_trace_info, create_agent_runnable, remote_add_exclamation, tool_method_name |
| 171 | +): |
| 172 | + @validate_custom_events(tool_recorded_event) |
| 173 | + @validate_custom_event_count(count=exercise_agent._expected_event_count) |
| 174 | + @validate_transaction_metrics( |
| 175 | + "test_tool_remote_no_subcomponent", |
| 176 | + scoped_metrics=[(f"Llm/tool/LangChain/{tool_method_name}/add_exclamation", 1)], |
| 177 | + rollup_metrics=[(f"Llm/tool/LangChain/{tool_method_name}/add_exclamation", 1)], |
| 178 | + background_task=True, |
| 179 | + ) |
| 180 | + # The agent span still has a subcomponent attribute |
| 181 | + @validate_span_events(count=1, exact_agents={"subcomponent": '{"type": "APM-AI_AGENT", "name": "my_agent"}'}) |
| 182 | + # Tool span must NOT have a subcomponent attribute |
| 183 | + @validate_span_events( |
| 184 | + count=1, |
| 185 | + exact_intrinsics={"name": f"Llm/tool/LangChain/{tool_method_name}/add_exclamation"}, |
| 186 | + unexpected_agents=["subcomponent"], |
| 187 | + ) |
| 188 | + @background_task(name="test_tool_remote_no_subcomponent") |
| 189 | + def _test(): |
| 190 | + set_trace_info() |
| 191 | + my_agent = create_agent_runnable( |
| 192 | + tools=[remote_add_exclamation], system_prompt="You are a text manipulation algorithm." |
| 193 | + ) |
| 194 | + exercise_agent(my_agent, PROMPT) |
| 195 | + |
| 196 | + _test() |
| 197 | + |
| 198 | + |
158 | 199 | @dt_enabled |
159 | 200 | @reset_core_stats_engine() |
160 | 201 | def test_tool_execution_error(exercise_agent, set_trace_info, create_agent_runnable, add_exclamation, tool_method_name): |
@@ -219,3 +260,23 @@ def _test(): |
219 | 260 | exercise_agent(my_agent, PROMPT) |
220 | 261 |
|
221 | 262 | _test() |
| 263 | + |
| 264 | + |
| 265 | +def test_is_local_tool_helper(): |
| 266 | + from newrelic.hooks.mlmodel_langchain import _is_local_tool |
| 267 | + |
| 268 | + # Local tool functions |
| 269 | + assert _is_local_tool(add_exclamation_sync) is True |
| 270 | + assert _is_local_tool(add_exclamation_async) is True |
| 271 | + |
| 272 | + # Tools whose __module__ reads as a collection of remote tools |
| 273 | + assert _is_local_tool(remote_add_exclamation_sync) is False |
| 274 | + assert _is_local_tool(remote_add_exclamation_async) is False |
| 275 | + |
| 276 | + # A tool instance that raises an exception when trying to access its underlying callable |
| 277 | + class BrokenTool: |
| 278 | + @property |
| 279 | + def func(self): |
| 280 | + raise RuntimeError("Oops") |
| 281 | + |
| 282 | + assert _is_local_tool(BrokenTool()) is True |
0 commit comments