agentx-python 0.8.25__tar.gz → 0.8.26__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentx_python-0.8.25 → agentx_python-0.8.26}/PKG-INFO +4 -1
- {agentx_python-0.8.25 → agentx_python-0.8.26}/README.md +1 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/integrations/__init__.py +1 -0
- agentx_python-0.8.26/agentx/integrations/nvidia_nim.py +70 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/integrations/openai.py +5 -1
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/version.py +2 -2
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx_python.egg-info/PKG-INFO +4 -1
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx_python.egg-info/SOURCES.txt +1 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx_python.egg-info/requires.txt +3 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/setup.py +2 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_integrations.py +179 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/LICENSE +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/__init__.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/agentx.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/cli.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/evaluations/__init__.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/evaluations/_term.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/evaluations/adapters/__init__.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/evaluations/adapters/http_endpoint.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/evaluations/adapters/precomputed.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/evaluations/adapters/raw.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/evaluations/client.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/evaluations/datasets.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/evaluations/evaluation_settings.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/evaluations/models.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/evaluations/prompts.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/evaluations/reporting.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/evaluations/results.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/evaluations/runner.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/evaluations/tool_schemas.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/evaluations/tracing.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/exceptions.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/export.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/feedback.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/integrations/_traced_call.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/integrations/anthropic.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/integrations/autogen.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/integrations/crewai.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/integrations/databricks.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/integrations/google_adk.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/integrations/google_genai.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/integrations/langchain.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/integrations/litellm.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/integrations/llamaindex.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/integrations/moveworks.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/integrations/openai_agents.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/monitor/__init__.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/monitor/_transport.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/monitor/agents.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/monitor/client.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/monitor/improvement_groups.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/monitor/judge_scorers.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/monitor/models.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/monitor/online_evaluators.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/monitor/patterns.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/monitor/profile.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/monitor/review_queue.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/monitor/rules.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/monitor/scorer_groups.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/monitor/scorers.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/monitor/sessions.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/monitor/signals.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/outcomes.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/projects.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/py.typed +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/resources/__init__.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/resources/agent.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/resources/conversation.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/resources/workforce.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/testing.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/traces.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/tracing/__init__.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/tracing/ci_types.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/tracing/eval_scope.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/tracing/framework_detect.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/tracing/ingest_client.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/tracing/tracer.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx/util.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx_python.egg-info/dependency_links.txt +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx_python.egg-info/entry_points.txt +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx_python.egg-info/not-zip-safe +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/agentx_python.egg-info/top_level.txt +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/setup.cfg +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_cli_launcher.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_deep_dive_fixes.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_docs_match_sdk.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_error_taxonomy.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_eval_scope.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_framework_detect.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_integration.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_judge_scorers.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_multi_judge.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_pairwise.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_pattern_update_merge.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_review_queue.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_runner_features.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_selfhost_analysis_fallback.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_selfhost_compat.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_span_tree.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_testing.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_wire_models.py +0 -0
- {agentx_python-0.8.25 → agentx_python-0.8.26}/tests/test_workforce_binding.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentx-python
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.26
|
|
4
4
|
Summary: Official Python SDK for AgentX (https://www.agentx.so/)
|
|
5
5
|
Home-page: https://github.com/AgentX-ai/AgentX-python
|
|
6
6
|
Author: Robin Wang and AgentX Team
|
|
@@ -23,6 +23,8 @@ Provides-Extra: openai-agents
|
|
|
23
23
|
Requires-Dist: openai-agents>=0.0.3; extra == "openai-agents"
|
|
24
24
|
Provides-Extra: openai
|
|
25
25
|
Requires-Dist: openai>=1.0.0; extra == "openai"
|
|
26
|
+
Provides-Extra: nvidia-nim
|
|
27
|
+
Requires-Dist: openai>=1.0.0; extra == "nvidia-nim"
|
|
26
28
|
Provides-Extra: anthropic
|
|
27
29
|
Requires-Dist: anthropic>=0.25.0; extra == "anthropic"
|
|
28
30
|
Provides-Extra: google-adk
|
|
@@ -250,6 +252,7 @@ extra:
|
|
|
250
252
|
| CrewAI | `pip install "agentx-python[crewai]"` | `AgentXCrewObserver` |
|
|
251
253
|
| OpenAI Agents SDK | `pip install "agentx-python[openai-agents]"` | `AgentXTracingProcessor` |
|
|
252
254
|
| OpenAI (raw client) | `pip install "agentx-python[openai]"` | `patch_openai_client` |
|
|
255
|
+
| NVIDIA NIM | `pip install "agentx-python[nvidia-nim]"` | `patch_nim_client` |
|
|
253
256
|
| Anthropic | `pip install "agentx-python[anthropic]"` | `patch_anthropic_client` |
|
|
254
257
|
| Google ADK | `pip install "agentx-python[google-adk]"` | `AgentXADKPlugin` |
|
|
255
258
|
| Google GenAI (Gemini) | `pip install "agentx-python[google-genai]"` | `patch_genai_client` |
|
|
@@ -185,6 +185,7 @@ extra:
|
|
|
185
185
|
| CrewAI | `pip install "agentx-python[crewai]"` | `AgentXCrewObserver` |
|
|
186
186
|
| OpenAI Agents SDK | `pip install "agentx-python[openai-agents]"` | `AgentXTracingProcessor` |
|
|
187
187
|
| OpenAI (raw client) | `pip install "agentx-python[openai]"` | `patch_openai_client` |
|
|
188
|
+
| NVIDIA NIM | `pip install "agentx-python[nvidia-nim]"` | `patch_nim_client` |
|
|
188
189
|
| Anthropic | `pip install "agentx-python[anthropic]"` | `patch_anthropic_client` |
|
|
189
190
|
| Google ADK | `pip install "agentx-python[google-adk]"` | `AgentXADKPlugin` |
|
|
190
191
|
| Google GenAI (Gemini) | `pip install "agentx-python[google-genai]"` | `patch_genai_client` |
|
|
@@ -7,4 +7,5 @@
|
|
|
7
7
|
# from agentx.integrations.anthropic import patch_anthropic_client
|
|
8
8
|
# from agentx.integrations.google_adk import AgentXADKPlugin
|
|
9
9
|
# from agentx.integrations.google_genai import patch_genai_client
|
|
10
|
+
# from agentx.integrations.nvidia_nim import patch_nim_client
|
|
10
11
|
# from agentx.integrations.moveworks import MoveworksImporter # Data API pull sync, not in-process
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
NVIDIA NIM integration for AgentX production tracing.
|
|
3
|
+
|
|
4
|
+
NIM (NVIDIA Inference Microservices) serves models behind an OpenAI-compatible
|
|
5
|
+
``/v1/chat/completions`` API, so the client you patch is the ordinary ``openai``
|
|
6
|
+
Python client pointed at a NIM endpoint - a local NIM container
|
|
7
|
+
(``http://localhost:8000/v1``) or NVIDIA's hosted API
|
|
8
|
+
(``https://integrate.api.nvidia.com/v1``). This module reuses the OpenAI patch
|
|
9
|
+
machinery verbatim and differs in exactly one way: traces are stamped
|
|
10
|
+
``framework="nvidia-nim"``, so NIM traffic gets its own row in Monitor's
|
|
11
|
+
Platforms chart and the framework filters instead of blending into "openai".
|
|
12
|
+
|
|
13
|
+
Usage::
|
|
14
|
+
|
|
15
|
+
from agentx.integrations.nvidia_nim import patch_nim_client
|
|
16
|
+
import openai
|
|
17
|
+
|
|
18
|
+
nim = openai.OpenAI(
|
|
19
|
+
base_url="http://localhost:8000/v1", # or https://integrate.api.nvidia.com/v1
|
|
20
|
+
api_key=os.environ.get("NVIDIA_API_KEY", "not-needed-for-local-nim"),
|
|
21
|
+
)
|
|
22
|
+
patch_nim_client(nim, agentx.tracer, name="nim-agent")
|
|
23
|
+
|
|
24
|
+
# All subsequent nim.chat.completions.create() calls are now traced.
|
|
25
|
+
|
|
26
|
+
Works with both ``openai.OpenAI`` and ``openai.AsyncOpenAI`` clients. Token
|
|
27
|
+
usage comes straight off the response's OpenAI-shaped ``usage`` block; NIM
|
|
28
|
+
reports no prompt-cache fields, so cache token counts stay unset.
|
|
29
|
+
|
|
30
|
+
Streaming calls (``stream=True``) are passed through untouched and are not
|
|
31
|
+
currently traced - same posture as ``patch_openai_client``, see its docstring.
|
|
32
|
+
|
|
33
|
+
Requires: ``pip install "agentx-python[nvidia-nim]"`` (installs the ``openai``
|
|
34
|
+
client package; there is no separate NIM SDK dependency).
|
|
35
|
+
"""
|
|
36
|
+
from __future__ import annotations
|
|
37
|
+
|
|
38
|
+
from typing import Any, Dict, Optional
|
|
39
|
+
|
|
40
|
+
from agentx.tracing.tracer import Tracer
|
|
41
|
+
from agentx.integrations.openai import _patch_chat_completions_create
|
|
42
|
+
|
|
43
|
+
NIM_FRAMEWORK = "nvidia-nim"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def patch_nim_client(
|
|
47
|
+
client: Any,
|
|
48
|
+
tracer: Tracer,
|
|
49
|
+
name: str = "nim-agent",
|
|
50
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
51
|
+
session_id: Optional[str] = None,
|
|
52
|
+
) -> None:
|
|
53
|
+
"""
|
|
54
|
+
Monkey-patch ``client.chat.completions.create`` on an OpenAI-compatible
|
|
55
|
+
client pointed at a NIM endpoint, sending a trace for every non-streaming
|
|
56
|
+
call with ``framework="nvidia-nim"``.
|
|
57
|
+
|
|
58
|
+
The original method is still called and its return value passed through
|
|
59
|
+
unchanged. Sync and async clients both work; ``stream=True`` calls pass
|
|
60
|
+
through untraced. Patching is idempotent - and because it shares the guard
|
|
61
|
+
with ``patch_openai_client``, whichever of the two patched a given client
|
|
62
|
+
first wins (patch each client with the integration that matches where its
|
|
63
|
+
``base_url`` actually points).
|
|
64
|
+
"""
|
|
65
|
+
chat = getattr(client, "chat", None)
|
|
66
|
+
completions = getattr(chat, "completions", None) if chat is not None else None
|
|
67
|
+
if completions is None:
|
|
68
|
+
raise ValueError("Provided client does not have a .chat.completions attribute")
|
|
69
|
+
|
|
70
|
+
_patch_chat_completions_create(completions, tracer, name, metadata, session_id, framework=NIM_FRAMEWORK)
|
|
@@ -113,7 +113,11 @@ def _patch_chat_completions_create(
|
|
|
113
113
|
name: str,
|
|
114
114
|
metadata: Optional[Dict[str, Any]],
|
|
115
115
|
session_id: Optional[str],
|
|
116
|
+
framework: str = "openai",
|
|
116
117
|
) -> None:
|
|
118
|
+
# `framework` exists for OpenAI-compatible endpoints served by other vendors
|
|
119
|
+
# (agentx.integrations.nvidia_nim stamps "nvidia-nim" through here) - the request/response
|
|
120
|
+
# shapes are identical, so they share this machinery instead of duplicating it.
|
|
117
121
|
original = completions_resource.create
|
|
118
122
|
if getattr(original, "_agentx_patched", False):
|
|
119
123
|
return # already patched
|
|
@@ -148,7 +152,7 @@ def _patch_chat_completions_create(
|
|
|
148
152
|
finish_llm_call(
|
|
149
153
|
tracer,
|
|
150
154
|
name=name,
|
|
151
|
-
framework=
|
|
155
|
+
framework=framework,
|
|
152
156
|
metadata=metadata,
|
|
153
157
|
session_id=session_id,
|
|
154
158
|
start_t=start_t,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
VERSION = "0.8.
|
|
1
|
+
VERSION = "0.8.26"
|
|
2
2
|
|
|
3
3
|
# The AgentX-trace-eval release this SDK version is tested against - what `agentx-trace-eval`
|
|
4
4
|
# installs and converges to (see agentx/cli.py). Bump together with VERSION when releasing, so
|
|
5
5
|
# every published SDK names a known-good engine+dashboard pair. Users can override with
|
|
6
6
|
# AGENTX_TRACE_EVAL_VERSION=<tag|latest>.
|
|
7
|
-
ENGINE_VERSION = "v0.3.
|
|
7
|
+
ENGINE_VERSION = "v0.3.29"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentx-python
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.26
|
|
4
4
|
Summary: Official Python SDK for AgentX (https://www.agentx.so/)
|
|
5
5
|
Home-page: https://github.com/AgentX-ai/AgentX-python
|
|
6
6
|
Author: Robin Wang and AgentX Team
|
|
@@ -23,6 +23,8 @@ Provides-Extra: openai-agents
|
|
|
23
23
|
Requires-Dist: openai-agents>=0.0.3; extra == "openai-agents"
|
|
24
24
|
Provides-Extra: openai
|
|
25
25
|
Requires-Dist: openai>=1.0.0; extra == "openai"
|
|
26
|
+
Provides-Extra: nvidia-nim
|
|
27
|
+
Requires-Dist: openai>=1.0.0; extra == "nvidia-nim"
|
|
26
28
|
Provides-Extra: anthropic
|
|
27
29
|
Requires-Dist: anthropic>=0.25.0; extra == "anthropic"
|
|
28
30
|
Provides-Extra: google-adk
|
|
@@ -250,6 +252,7 @@ extra:
|
|
|
250
252
|
| CrewAI | `pip install "agentx-python[crewai]"` | `AgentXCrewObserver` |
|
|
251
253
|
| OpenAI Agents SDK | `pip install "agentx-python[openai-agents]"` | `AgentXTracingProcessor` |
|
|
252
254
|
| OpenAI (raw client) | `pip install "agentx-python[openai]"` | `patch_openai_client` |
|
|
255
|
+
| NVIDIA NIM | `pip install "agentx-python[nvidia-nim]"` | `patch_nim_client` |
|
|
253
256
|
| Anthropic | `pip install "agentx-python[anthropic]"` | `patch_anthropic_client` |
|
|
254
257
|
| Google ADK | `pip install "agentx-python[google-adk]"` | `AgentXADKPlugin` |
|
|
255
258
|
| Google GenAI (Gemini) | `pip install "agentx-python[google-genai]"` | `patch_genai_client` |
|
|
@@ -42,6 +42,7 @@ agentx/integrations/langchain.py
|
|
|
42
42
|
agentx/integrations/litellm.py
|
|
43
43
|
agentx/integrations/llamaindex.py
|
|
44
44
|
agentx/integrations/moveworks.py
|
|
45
|
+
agentx/integrations/nvidia_nim.py
|
|
45
46
|
agentx/integrations/openai.py
|
|
46
47
|
agentx/integrations/openai_agents.py
|
|
47
48
|
agentx/monitor/__init__.py
|
|
@@ -51,6 +51,8 @@ setup(
|
|
|
51
51
|
"crewai": ["crewai>=0.80.0"],
|
|
52
52
|
"openai-agents": ["openai-agents>=0.0.3"],
|
|
53
53
|
"openai": ["openai>=1.0.0"],
|
|
54
|
+
# NIM endpoints speak the OpenAI-compatible API; the client package IS openai.
|
|
55
|
+
"nvidia-nim": ["openai>=1.0.0"],
|
|
54
56
|
"anthropic": ["anthropic>=0.25.0"],
|
|
55
57
|
"google-adk": ["google-adk>=1.0.0"],
|
|
56
58
|
"google-genai": ["google-genai>=1.0.0"],
|
|
@@ -513,6 +513,185 @@ def test_openai_sync_client_records_errors():
|
|
|
513
513
|
assert kwargs["error"] == "rate limited"
|
|
514
514
|
|
|
515
515
|
|
|
516
|
+
def test_openai_patch_stamps_openai_framework():
|
|
517
|
+
# Regression guard for the shared-machinery refactor: _patch_chat_completions_create
|
|
518
|
+
# grew a framework parameter for nvidia_nim.py, and the OpenAI default must stay "openai".
|
|
519
|
+
from agentx.integrations.openai import patch_openai_client
|
|
520
|
+
|
|
521
|
+
class FakeCompletions:
|
|
522
|
+
def create(self, **kwargs):
|
|
523
|
+
return _FakeOpenAIChatCompletion("hello")
|
|
524
|
+
|
|
525
|
+
client = _fake_openai_client(FakeCompletions())
|
|
526
|
+
tracer = make_tracer()
|
|
527
|
+
patch_openai_client(client, tracer, name="gpt-agent")
|
|
528
|
+
client.chat.completions.create(model="gpt-4o-mini", messages=[{"role": "user", "content": "hi"}])
|
|
529
|
+
|
|
530
|
+
_, kwargs = tracer._send.call_args
|
|
531
|
+
assert kwargs["framework"] == "openai"
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
# ---------------------------------------------------------------------------
|
|
535
|
+
# 6b. nvidia_nim.py — the OpenAI-compatible patch with the NIM framework label
|
|
536
|
+
# ---------------------------------------------------------------------------
|
|
537
|
+
|
|
538
|
+
def test_nim_sync_client_traces_call_with_nim_framework():
|
|
539
|
+
from agentx.integrations.nvidia_nim import patch_nim_client
|
|
540
|
+
|
|
541
|
+
response = _FakeOpenAIChatCompletion("hello from nim")
|
|
542
|
+
|
|
543
|
+
class FakeCompletions:
|
|
544
|
+
def create(self, **kwargs):
|
|
545
|
+
return response
|
|
546
|
+
|
|
547
|
+
client = _fake_openai_client(FakeCompletions())
|
|
548
|
+
tracer = make_tracer()
|
|
549
|
+
patch_nim_client(client, tracer, name="nim-agent")
|
|
550
|
+
|
|
551
|
+
result = client.chat.completions.create(
|
|
552
|
+
model="meta/llama-3.1-8b-instruct", messages=[{"role": "user", "content": "hi"}]
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
assert result is response
|
|
556
|
+
tracer._send.assert_called_once()
|
|
557
|
+
_, kwargs = tracer._send.call_args
|
|
558
|
+
assert kwargs["framework"] == "nvidia-nim"
|
|
559
|
+
assert kwargs["name"] == "nim-agent"
|
|
560
|
+
assert kwargs["output"] == "hello from nim"
|
|
561
|
+
assert kwargs["model"] == "meta/llama-3.1-8b-instruct"
|
|
562
|
+
assert kwargs["input_tokens"] == 12
|
|
563
|
+
assert kwargs["output_tokens"] == 6
|
|
564
|
+
# NIM reports no prompt-cache fields; the counts must stay unset, not become 0.
|
|
565
|
+
assert not kwargs.get("cache_read_tokens")
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
def test_nim_async_client_traces_the_real_response():
|
|
569
|
+
from agentx.integrations.nvidia_nim import patch_nim_client
|
|
570
|
+
|
|
571
|
+
response = _FakeOpenAIChatCompletion("hello from async nim")
|
|
572
|
+
|
|
573
|
+
class FakeAsyncCompletions:
|
|
574
|
+
async def create(self, **kwargs):
|
|
575
|
+
await asyncio.sleep(0.01)
|
|
576
|
+
return response
|
|
577
|
+
|
|
578
|
+
client = _fake_openai_client(FakeAsyncCompletions())
|
|
579
|
+
tracer = make_tracer()
|
|
580
|
+
patch_nim_client(client, tracer, name="nim-agent")
|
|
581
|
+
|
|
582
|
+
result = asyncio.run(
|
|
583
|
+
client.chat.completions.create(model="meta/llama-3.1-8b-instruct", messages=[{"role": "user", "content": "hi"}])
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
assert result is response
|
|
587
|
+
tracer._send.assert_called_once()
|
|
588
|
+
_, kwargs = tracer._send.call_args
|
|
589
|
+
assert kwargs["framework"] == "nvidia-nim"
|
|
590
|
+
assert kwargs["output"] == "hello from async nim"
|
|
591
|
+
assert kwargs["input_tokens"] == 12
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
def test_nim_streaming_calls_are_passed_through_untraced():
|
|
595
|
+
from agentx.integrations.nvidia_nim import patch_nim_client
|
|
596
|
+
|
|
597
|
+
sentinel_stream = object()
|
|
598
|
+
|
|
599
|
+
class FakeCompletions:
|
|
600
|
+
def create(self, **kwargs):
|
|
601
|
+
assert kwargs.get("stream") is True
|
|
602
|
+
return sentinel_stream
|
|
603
|
+
|
|
604
|
+
client = _fake_openai_client(FakeCompletions())
|
|
605
|
+
tracer = make_tracer()
|
|
606
|
+
patch_nim_client(client, tracer, name="nim-agent")
|
|
607
|
+
|
|
608
|
+
result = client.chat.completions.create(
|
|
609
|
+
model="meta/llama-3.1-8b-instruct", messages=[{"role": "user", "content": "hi"}], stream=True
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
assert result is sentinel_stream
|
|
613
|
+
tracer._send.assert_not_called()
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
def test_nim_sync_client_records_errors():
|
|
617
|
+
from agentx.integrations.nvidia_nim import patch_nim_client
|
|
618
|
+
|
|
619
|
+
class FakeCompletions:
|
|
620
|
+
def create(self, **kwargs):
|
|
621
|
+
raise ValueError("nim endpoint unavailable")
|
|
622
|
+
|
|
623
|
+
client = _fake_openai_client(FakeCompletions())
|
|
624
|
+
tracer = make_tracer()
|
|
625
|
+
patch_nim_client(client, tracer, name="nim-agent")
|
|
626
|
+
|
|
627
|
+
with pytest.raises(ValueError, match="nim endpoint unavailable"):
|
|
628
|
+
client.chat.completions.create(model="meta/llama-3.1-8b-instruct", messages=[{"role": "user", "content": "hi"}])
|
|
629
|
+
|
|
630
|
+
tracer._send.assert_called_once()
|
|
631
|
+
_, kwargs = tracer._send.call_args
|
|
632
|
+
assert kwargs["error"] == "nim endpoint unavailable"
|
|
633
|
+
assert kwargs["framework"] == "nvidia-nim"
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
def test_nim_patch_is_idempotent_and_first_patch_wins():
|
|
637
|
+
from agentx.integrations.nvidia_nim import patch_nim_client
|
|
638
|
+
from agentx.integrations.openai import patch_openai_client
|
|
639
|
+
|
|
640
|
+
class FakeCompletions:
|
|
641
|
+
def create(self, **kwargs):
|
|
642
|
+
return _FakeOpenAIChatCompletion("once")
|
|
643
|
+
|
|
644
|
+
client = _fake_openai_client(FakeCompletions())
|
|
645
|
+
tracer = make_tracer()
|
|
646
|
+
patch_nim_client(client, tracer, name="nim-agent")
|
|
647
|
+
# Double NIM patch and a later OpenAI patch are both no-ops (shared _agentx_patched guard):
|
|
648
|
+
# exactly one trace per call, and the first patch's framework label stays.
|
|
649
|
+
patch_nim_client(client, tracer, name="nim-agent")
|
|
650
|
+
patch_openai_client(client, tracer, name="gpt-agent")
|
|
651
|
+
|
|
652
|
+
client.chat.completions.create(model="meta/llama-3.1-8b-instruct", messages=[{"role": "user", "content": "hi"}])
|
|
653
|
+
|
|
654
|
+
tracer._send.assert_called_once()
|
|
655
|
+
_, kwargs = tracer._send.call_args
|
|
656
|
+
assert kwargs["framework"] == "nvidia-nim"
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
def test_nim_rejects_client_without_chat_completions():
|
|
660
|
+
from agentx.integrations.nvidia_nim import patch_nim_client
|
|
661
|
+
|
|
662
|
+
with pytest.raises(ValueError, match="chat.completions"):
|
|
663
|
+
patch_nim_client(object(), make_tracer())
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
def test_nim_request_tools_land_in_trace_metadata():
|
|
667
|
+
# The docs promise the request's tools=[...] definitions feed the unregistered-tool
|
|
668
|
+
# listing via metadata.tools - pin the shared capture path (openai.py machinery) here.
|
|
669
|
+
from agentx.integrations.nvidia_nim import patch_nim_client
|
|
670
|
+
|
|
671
|
+
class FakeCompletions:
|
|
672
|
+
def create(self, **kwargs):
|
|
673
|
+
return _FakeOpenAIChatCompletion("used a tool")
|
|
674
|
+
|
|
675
|
+
tool_def = {
|
|
676
|
+
"type": "function",
|
|
677
|
+
"function": {"name": "lookup_order", "parameters": {"type": "object", "properties": {}}},
|
|
678
|
+
}
|
|
679
|
+
client = _fake_openai_client(FakeCompletions())
|
|
680
|
+
tracer = make_tracer()
|
|
681
|
+
patch_nim_client(client, tracer, name="nim-agent", metadata={"env": "test"})
|
|
682
|
+
|
|
683
|
+
client.chat.completions.create(
|
|
684
|
+
model="meta/llama-3.1-8b-instruct",
|
|
685
|
+
messages=[{"role": "user", "content": "hi"}],
|
|
686
|
+
tools=[tool_def],
|
|
687
|
+
)
|
|
688
|
+
|
|
689
|
+
_, kwargs = tracer._send.call_args
|
|
690
|
+
assert kwargs["metadata"]["tools"] == [tool_def]
|
|
691
|
+
# The caller's own static metadata must survive the tools merge.
|
|
692
|
+
assert kwargs["metadata"]["env"] == "test"
|
|
693
|
+
|
|
694
|
+
|
|
516
695
|
# ---------------------------------------------------------------------------
|
|
517
696
|
# 7. langchain.py — nested-run state cleanup + TTL safety net
|
|
518
697
|
# ---------------------------------------------------------------------------
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|