datarobot-genai 0.1.55__tar.gz → 0.1.64__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.
Files changed (106) hide show
  1. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/PKG-INFO +47 -47
  2. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/pyproject.toml +47 -47
  3. datarobot_genai-0.1.64/src/datarobot_genai/core/mcp/common.py +161 -0
  4. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/core/telemetry_agent.py +14 -1
  5. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/core/utils/auth.py +64 -0
  6. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/crewai/base.py +0 -2
  7. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/crewai/mcp.py +2 -9
  8. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/auth.py +28 -25
  9. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/clients.py +67 -3
  10. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/config.py +12 -8
  11. datarobot_genai-0.1.64/src/datarobot_genai/drmcp/core/dynamic_prompts/controllers.py +85 -0
  12. datarobot_genai-0.1.64/src/datarobot_genai/drmcp/core/dynamic_prompts/dr_lib.py +128 -0
  13. datarobot_genai-0.1.64/src/datarobot_genai/drmcp/core/dynamic_prompts/register.py +206 -0
  14. datarobot_genai-0.1.64/src/datarobot_genai/drmcp/core/dynamic_prompts/utils.py +33 -0
  15. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/mcp_instance.py +85 -3
  16. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/routes.py +112 -28
  17. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/langgraph/agent.py +3 -6
  18. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/langgraph/mcp.py +1 -9
  19. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/llama_index/base.py +0 -2
  20. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/llama_index/mcp.py +1 -7
  21. datarobot_genai-0.1.64/src/datarobot_genai/nat/agent.py +258 -0
  22. datarobot_genai-0.1.55/src/datarobot_genai/core/mcp/common.py +0 -107
  23. datarobot_genai-0.1.55/src/datarobot_genai/drmcp/core/dynamic_prompts/dr_lib.py +0 -91
  24. datarobot_genai-0.1.55/src/datarobot_genai/drmcp/core/dynamic_prompts/register.py +0 -121
  25. datarobot_genai-0.1.55/src/datarobot_genai/drmcp/test_utils/prompt_management.py +0 -84
  26. datarobot_genai-0.1.55/src/datarobot_genai/nat/agent.py +0 -137
  27. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/.gitignore +0 -0
  28. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/AUTHORS +0 -0
  29. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/LICENSE +0 -0
  30. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/README.md +0 -0
  31. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/__init__.py +0 -0
  32. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/core/__init__.py +0 -0
  33. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/core/agents/__init__.py +0 -0
  34. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/core/agents/base.py +0 -0
  35. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/core/chat/__init__.py +0 -0
  36. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/core/chat/auth.py +0 -0
  37. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/core/chat/client.py +0 -0
  38. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/core/chat/responses.py +0 -0
  39. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/core/cli/__init__.py +0 -0
  40. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/core/cli/agent_environment.py +0 -0
  41. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/core/cli/agent_kernel.py +0 -0
  42. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/core/custom_model.py +0 -0
  43. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/core/mcp/__init__.py +0 -0
  44. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/core/utils/__init__.py +0 -0
  45. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/core/utils/urls.py +0 -0
  46. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/crewai/__init__.py +0 -0
  47. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/crewai/agent.py +0 -0
  48. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/crewai/events.py +0 -0
  49. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/__init__.py +0 -0
  50. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/__init__.py +0 -0
  51. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/config_utils.py +0 -0
  52. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/constants.py +0 -0
  53. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/credentials.py +0 -0
  54. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dr_mcp_server.py +0 -0
  55. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dr_mcp_server_logo.py +0 -0
  56. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dynamic_prompts/__init__.py +0 -0
  57. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dynamic_tools/__init__.py +0 -0
  58. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/__init__.py +0 -0
  59. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/adapters/__init__.py +0 -0
  60. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/adapters/base.py +0 -0
  61. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/adapters/default.py +0 -0
  62. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/adapters/drum.py +0 -0
  63. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/config.py +0 -0
  64. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/controllers.py +0 -0
  65. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/metadata.py +0 -0
  66. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/register.py +0 -0
  67. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/schemas/drum_agentic_fallback_schema.json +0 -0
  68. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/schemas/drum_prediction_fallback_schema.json +0 -0
  69. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dynamic_tools/register.py +0 -0
  70. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/dynamic_tools/schema.py +0 -0
  71. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/exceptions.py +0 -0
  72. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/logging.py +0 -0
  73. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/mcp_server_tools.py +0 -0
  74. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/memory_management/__init__.py +0 -0
  75. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/memory_management/manager.py +0 -0
  76. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/memory_management/memory_tools.py +0 -0
  77. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/routes_utils.py +0 -0
  78. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/server_life_cycle.py +0 -0
  79. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/telemetry.py +0 -0
  80. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/tool_filter.py +0 -0
  81. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/core/utils.py +0 -0
  82. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/server.py +0 -0
  83. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/test_utils/__init__.py +0 -0
  84. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/test_utils/integration_mcp_server.py +0 -0
  85. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/test_utils/mcp_utils_ete.py +0 -0
  86. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/test_utils/mcp_utils_integration.py +0 -0
  87. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/test_utils/openai_llm_mcp_client.py +0 -0
  88. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/test_utils/tool_base_ete.py +0 -0
  89. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/test_utils/utils.py +0 -0
  90. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/tools/__init__.py +0 -0
  91. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/tools/predictive/__init__.py +0 -0
  92. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/tools/predictive/data.py +0 -0
  93. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/tools/predictive/deployment.py +0 -0
  94. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/tools/predictive/deployment_info.py +0 -0
  95. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/tools/predictive/model.py +0 -0
  96. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/tools/predictive/predict.py +0 -0
  97. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/tools/predictive/predict_realtime.py +0 -0
  98. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/tools/predictive/project.py +0 -0
  99. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/drmcp/tools/predictive/training.py +0 -0
  100. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/langgraph/__init__.py +0 -0
  101. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/llama_index/__init__.py +0 -0
  102. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/llama_index/agent.py +0 -0
  103. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/nat/__init__.py +0 -0
  104. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/nat/datarobot_llm_clients.py +0 -0
  105. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/nat/datarobot_llm_providers.py +0 -0
  106. {datarobot_genai-0.1.55 → datarobot_genai-0.1.64}/src/datarobot_genai/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datarobot-genai
3
- Version: 0.1.55
3
+ Version: 0.1.64
4
4
  Summary: Generic helpers for GenAI
5
5
  Project-URL: Homepage, https://github.com/datarobot-oss/datarobot-genai
6
6
  Author: DataRobot, Inc.
@@ -8,65 +8,65 @@ License: Apache-2.0
8
8
  License-File: AUTHORS
9
9
  License-File: LICENSE
10
10
  Requires-Python: <3.13,>=3.10
11
- Requires-Dist: datarobot-drum>=1.17.5
12
- Requires-Dist: datarobot-predict>=1.13.2
13
- Requires-Dist: datarobot>=3.9.1
14
- Requires-Dist: openai>=1.76.2
15
- Requires-Dist: opentelemetry-instrumentation-aiohttp-client>=0.43b0
16
- Requires-Dist: opentelemetry-instrumentation-httpx>=0.43b0
17
- Requires-Dist: opentelemetry-instrumentation-openai>=0.40.5
18
- Requires-Dist: opentelemetry-instrumentation-requests>=0.43b0
19
- Requires-Dist: pandas>=2.2.3
20
- Requires-Dist: pyjwt>=2.10.1
21
- Requires-Dist: pypdf>=6.1.3
22
- Requires-Dist: ragas>=0.3.8
23
- Requires-Dist: requests>=2.32.4
11
+ Requires-Dist: datarobot-drum<2.0.0,>=1.17.5
12
+ Requires-Dist: datarobot-predict<2.0.0,>=1.13.2
13
+ Requires-Dist: datarobot<4.0.0,>=3.9.1
14
+ Requires-Dist: openai<2.0.0,>=1.76.2
15
+ Requires-Dist: opentelemetry-instrumentation-aiohttp-client<1.0.0,>=0.43b0
16
+ Requires-Dist: opentelemetry-instrumentation-httpx<1.0.0,>=0.43b0
17
+ Requires-Dist: opentelemetry-instrumentation-openai<1.0.0,>=0.40.5
18
+ Requires-Dist: opentelemetry-instrumentation-requests<1.0.0,>=0.43b0
19
+ Requires-Dist: pandas<3.0.0,>=2.2.3
20
+ Requires-Dist: pyjwt<3.0.0,>=2.10.1
21
+ Requires-Dist: pypdf<7.0.0,>=6.1.3
22
+ Requires-Dist: ragas<0.4.0,>=0.3.8
23
+ Requires-Dist: requests<3.0.0,>=2.32.4
24
24
  Provides-Extra: crewai
25
- Requires-Dist: crewai-tools[mcp]>=0.69.0; extra == 'crewai'
26
- Requires-Dist: crewai>=0.193.2; extra == 'crewai'
27
- Requires-Dist: opentelemetry-instrumentation-crewai>=0.40.5; extra == 'crewai'
28
- Requires-Dist: pybase64>=1.4.2; extra == 'crewai'
25
+ Requires-Dist: crewai-tools[mcp]<0.77.0,>=0.69.0; extra == 'crewai'
26
+ Requires-Dist: crewai<1.0.0,>=0.193.2; extra == 'crewai'
27
+ Requires-Dist: opentelemetry-instrumentation-crewai<1.0.0,>=0.40.5; extra == 'crewai'
28
+ Requires-Dist: pybase64<2.0.0,>=1.4.2; extra == 'crewai'
29
29
  Provides-Extra: drmcp
30
- Requires-Dist: aiohttp-retry>=2.8.3; extra == 'drmcp'
31
- Requires-Dist: aiohttp>=3.9.0; extra == 'drmcp'
32
- Requires-Dist: aiosignal>=1.3.1; extra == 'drmcp'
33
- Requires-Dist: boto3>=1.34.0; extra == 'drmcp'
34
- Requires-Dist: datarobot-asgi-middleware>=0.2.0; extra == 'drmcp'
30
+ Requires-Dist: aiohttp-retry<3.0.0,>=2.8.3; extra == 'drmcp'
31
+ Requires-Dist: aiohttp<4.0.0,>=3.9.0; extra == 'drmcp'
32
+ Requires-Dist: aiosignal<2.0.0,>=1.3.1; extra == 'drmcp'
33
+ Requires-Dist: boto3<2.0.0,>=1.34.0; extra == 'drmcp'
34
+ Requires-Dist: datarobot-asgi-middleware<1.0.0,>=0.2.0; extra == 'drmcp'
35
35
  Requires-Dist: fastmcp==2.13.0.2; extra == 'drmcp'
36
- Requires-Dist: httpx>=0.28.1; extra == 'drmcp'
37
- Requires-Dist: opentelemetry-api>=1.22.0; extra == 'drmcp'
38
- Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.22.0; extra == 'drmcp'
39
- Requires-Dist: opentelemetry-exporter-otlp>=1.22.0; extra == 'drmcp'
40
- Requires-Dist: opentelemetry-sdk>=1.22.0; extra == 'drmcp'
41
- Requires-Dist: pydantic-settings>=2.1.0; extra == 'drmcp'
42
- Requires-Dist: pydantic>=2.6.1; extra == 'drmcp'
43
- Requires-Dist: python-dotenv>=1.1.0; extra == 'drmcp'
36
+ Requires-Dist: httpx<1.0.0,>=0.28.1; extra == 'drmcp'
37
+ Requires-Dist: opentelemetry-api<2.0.0,>=1.22.0; extra == 'drmcp'
38
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http<2.0.0,>=1.22.0; extra == 'drmcp'
39
+ Requires-Dist: opentelemetry-exporter-otlp<2.0.0,>=1.22.0; extra == 'drmcp'
40
+ Requires-Dist: opentelemetry-sdk<2.0.0,>=1.22.0; extra == 'drmcp'
41
+ Requires-Dist: pydantic-settings<3.0.0,>=2.1.0; extra == 'drmcp'
42
+ Requires-Dist: pydantic<3.0.0,>=2.6.1; extra == 'drmcp'
43
+ Requires-Dist: python-dotenv<2.0.0,>=1.1.0; extra == 'drmcp'
44
44
  Provides-Extra: langgraph
45
- Requires-Dist: langchain-mcp-adapters>=0.1.12; extra == 'langgraph'
46
- Requires-Dist: langgraph-prebuilt>=0.2.3; extra == 'langgraph'
47
- Requires-Dist: langgraph>=0.4.10; extra == 'langgraph'
48
- Requires-Dist: opentelemetry-instrumentation-langchain>=0.40.5; extra == 'langgraph'
45
+ Requires-Dist: langchain-mcp-adapters<0.2.0,>=0.1.12; extra == 'langgraph'
46
+ Requires-Dist: langgraph-prebuilt<0.7.0,>=0.2.3; extra == 'langgraph'
47
+ Requires-Dist: langgraph<0.7.0,>=0.4.10; extra == 'langgraph'
48
+ Requires-Dist: opentelemetry-instrumentation-langchain<1.0.0,>=0.40.5; extra == 'langgraph'
49
49
  Provides-Extra: llamaindex
50
50
  Requires-Dist: llama-index-core<0.14.0,>=0.13.6; extra == 'llamaindex'
51
- Requires-Dist: llama-index-llms-langchain>=0.6.1; extra == 'llamaindex'
52
- Requires-Dist: llama-index-llms-litellm>=0.4.1; extra == 'llamaindex'
53
- Requires-Dist: llama-index-llms-openai>=0.3.38; extra == 'llamaindex'
54
- Requires-Dist: llama-index-tools-mcp>=0.1.0; extra == 'llamaindex'
51
+ Requires-Dist: llama-index-llms-langchain<0.8.0,>=0.6.1; extra == 'llamaindex'
52
+ Requires-Dist: llama-index-llms-litellm<0.7.0,>=0.4.1; extra == 'llamaindex'
53
+ Requires-Dist: llama-index-llms-openai<0.6.0,>=0.3.38; extra == 'llamaindex'
54
+ Requires-Dist: llama-index-tools-mcp<0.5.0,>=0.1.0; extra == 'llamaindex'
55
55
  Requires-Dist: llama-index<0.14.0,>=0.13.6; extra == 'llamaindex'
56
- Requires-Dist: opentelemetry-instrumentation-llamaindex>=0.40.5; extra == 'llamaindex'
57
- Requires-Dist: pypdf>=6.0.0; extra == 'llamaindex'
56
+ Requires-Dist: opentelemetry-instrumentation-llamaindex<1.0.0,>=0.40.5; extra == 'llamaindex'
57
+ Requires-Dist: pypdf<7.0.0,>=6.0.0; extra == 'llamaindex'
58
58
  Provides-Extra: nat
59
- Requires-Dist: llama-index-llms-litellm>=0.4.1; extra == 'nat'
59
+ Requires-Dist: llama-index-llms-litellm<0.7.0,>=0.4.1; extra == 'nat'
60
60
  Requires-Dist: nvidia-nat-crewai==1.3.0; (python_version >= '3.11') and extra == 'nat'
61
61
  Requires-Dist: nvidia-nat-langchain==1.3.0; (python_version >= '3.11') and extra == 'nat'
62
62
  Requires-Dist: nvidia-nat-opentelemetry==1.3.0; (python_version >= '3.11') and extra == 'nat'
63
63
  Requires-Dist: nvidia-nat==1.3.0; (python_version >= '3.11') and extra == 'nat'
64
- Requires-Dist: opentelemetry-instrumentation-crewai>=0.40.5; extra == 'nat'
65
- Requires-Dist: opentelemetry-instrumentation-langchain>=0.40.5; extra == 'nat'
66
- Requires-Dist: opentelemetry-instrumentation-llamaindex>=0.40.5; extra == 'nat'
64
+ Requires-Dist: opentelemetry-instrumentation-crewai<1.0.0,>=0.40.5; extra == 'nat'
65
+ Requires-Dist: opentelemetry-instrumentation-langchain<1.0.0,>=0.40.5; extra == 'nat'
66
+ Requires-Dist: opentelemetry-instrumentation-llamaindex<1.0.0,>=0.40.5; extra == 'nat'
67
67
  Provides-Extra: pydanticai
68
- Requires-Dist: logfire>=4.6.0; extra == 'pydanticai'
69
- Requires-Dist: pydantic-ai>=1.0.5; extra == 'pydanticai'
68
+ Requires-Dist: logfire<5.0.0,>=4.6.0; extra == 'pydanticai'
69
+ Requires-Dist: pydantic-ai<1.9.0,>=1.0.5; extra == 'pydanticai'
70
70
  Description-Content-Type: text/markdown
71
71
 
72
72
  <p align="center">
@@ -4,26 +4,26 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "datarobot-genai"
7
- version = "0.1.55"
7
+ version = "0.1.64"
8
8
  description = "Generic helpers for GenAI"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10, <3.13"
11
11
  license = { text = "Apache-2.0" }
12
12
  authors = [{ name = "DataRobot, Inc." }]
13
13
  dependencies = [
14
- "requests>=2.32.4",
15
- "datarobot>=3.9.1",
16
- "datarobot-predict>=1.13.2",
17
- "openai>=1.76.2",
18
- "pandas>=2.2.3",
19
- "ragas>=0.3.8",
20
- "pyjwt>=2.10.1",
21
- "pypdf>=6.1.3", # CVE BUZZOK-28182
22
- "datarobot-drum>=1.17.5",
23
- "opentelemetry-instrumentation-requests>=0.43b0",
24
- "opentelemetry-instrumentation-aiohttp-client>=0.43b0",
25
- "opentelemetry-instrumentation-httpx>=0.43b0",
26
- "opentelemetry-instrumentation-openai>=0.40.5",
14
+ "requests>=2.32.4,<3.0.0",
15
+ "datarobot>=3.9.1,<4.0.0",
16
+ "datarobot-predict>=1.13.2,<2.0.0",
17
+ "openai>=1.76.2,<2.0.0",
18
+ "pandas>=2.2.3,<3.0.0",
19
+ "ragas>=0.3.8,<0.4.0",
20
+ "pyjwt>=2.10.1,<3.0.0",
21
+ "pypdf>=6.1.3,<7.0.0", # CVE BUZZOK-28182
22
+ "datarobot-drum>=1.17.5,<2.0.0",
23
+ "opentelemetry-instrumentation-requests>=0.43b0,<1.0.0",
24
+ "opentelemetry-instrumentation-aiohttp-client>=0.43b0,<1.0.0",
25
+ "opentelemetry-instrumentation-httpx>=0.43b0,<1.0.0",
26
+ "opentelemetry-instrumentation-openai>=0.40.5,<1.0.0",
27
27
  ]
28
28
 
29
29
  [project.urls]
@@ -35,55 +35,55 @@ datarobot_llm_clients = "datarobot_genai.nat.datarobot_llm_clients"
35
35
 
36
36
  [project.optional-dependencies]
37
37
  crewai = [
38
- "crewai>=0.193.2",
39
- "crewai-tools[mcp]>=0.69.0",
40
- "opentelemetry-instrumentation-crewai>=0.40.5",
41
- "pybase64>=1.4.2",
38
+ "crewai>=0.193.2,<1.0.0",
39
+ "crewai-tools[mcp]>=0.69.0,<0.77.0",
40
+ "opentelemetry-instrumentation-crewai>=0.40.5,<1.0.0",
41
+ "pybase64>=1.4.2,<2.0.0",
42
42
  ]
43
43
  langgraph = [
44
- "langchain-mcp-adapters>=0.1.12",
45
- "langgraph>=0.4.10",
46
- "langgraph-prebuilt>=0.2.3",
47
- "opentelemetry-instrumentation-langchain>=0.40.5",
44
+ "langchain-mcp-adapters>=0.1.12,<0.2.0",
45
+ "langgraph>=0.4.10,<0.7.0",
46
+ "langgraph-prebuilt>=0.2.3,<0.7.0",
47
+ "opentelemetry-instrumentation-langchain>=0.40.5,<1.0.0",
48
48
  ]
49
49
  llamaindex = [
50
50
  "llama-index>=0.13.6,<0.14.0",
51
51
  "llama-index-core>=0.13.6,<0.14.0",
52
- "llama-index-llms-langchain>=0.6.1",
53
- "llama-index-llms-litellm>=0.4.1", # Sync nat dependency if possible too
54
- "llama-index-llms-openai>=0.3.38",
55
- "llama-index-tools-mcp>=0.1.0",
56
- "opentelemetry-instrumentation-llamaindex>=0.40.5",
57
- "pypdf>=6.0.0",
52
+ "llama-index-llms-langchain>=0.6.1,<0.8.0",
53
+ "llama-index-llms-litellm>=0.4.1,<0.7.0", # Sync nat dependency if possible too
54
+ "llama-index-llms-openai>=0.3.38,<0.6.0",
55
+ "llama-index-tools-mcp>=0.1.0,<0.5.0",
56
+ "opentelemetry-instrumentation-llamaindex>=0.40.5,<1.0.0",
57
+ "pypdf>=6.0.0,<7.0.0",
58
58
  ]
59
59
  nat = [
60
60
  "nvidia-nat==1.3.0; python_version >= '3.11'",
61
61
  "nvidia-nat-opentelemetry==1.3.0; python_version >= '3.11'",
62
62
  "nvidia-nat-crewai==1.3.0; python_version >= '3.11'",
63
63
  "nvidia-nat-langchain==1.3.0; python_version >= '3.11'",
64
- "llama-index-llms-litellm>=0.4.1", # Need this to support datarobot-llm plugin
65
- "opentelemetry-instrumentation-crewai>=0.40.5",
66
- "opentelemetry-instrumentation-llamaindex>=0.40.5",
67
- "opentelemetry-instrumentation-langchain>=0.40.5",
64
+ "llama-index-llms-litellm>=0.4.1,<0.7.0", # Need this to support datarobot-llm plugin
65
+ "opentelemetry-instrumentation-crewai>=0.40.5,<1.0.0",
66
+ "opentelemetry-instrumentation-llamaindex>=0.40.5,<1.0.0",
67
+ "opentelemetry-instrumentation-langchain>=0.40.5,<1.0.0",
68
68
  ]
69
69
  pydanticai = [
70
- "logfire>=4.6.0",
71
- "pydantic-ai>=1.0.5",
70
+ "logfire>=4.6.0,<5.0.0",
71
+ "pydantic-ai>=1.0.5,<1.9.0",
72
72
  ]
73
73
  drmcp = [
74
- "datarobot-asgi-middleware>=0.2.0",
75
- "python-dotenv>=1.1.0",
76
- "boto3>=1.34.0",
77
- "httpx>=0.28.1",
78
- "pydantic>=2.6.1",
79
- "pydantic-settings>=2.1.0",
80
- "opentelemetry-api>=1.22.0",
81
- "opentelemetry-sdk>=1.22.0",
82
- "opentelemetry-exporter-otlp>=1.22.0",
83
- "opentelemetry-exporter-otlp-proto-http>=1.22.0",
84
- "aiohttp>=3.9.0",
85
- "aiohttp-retry>=2.8.3",
86
- "aiosignal>=1.3.1",
74
+ "datarobot-asgi-middleware>=0.2.0,<1.0.0",
75
+ "python-dotenv>=1.1.0,<2.0.0",
76
+ "boto3>=1.34.0,<2.0.0",
77
+ "httpx>=0.28.1,<1.0.0",
78
+ "pydantic>=2.6.1,<3.0.0",
79
+ "pydantic-settings>=2.1.0,<3.0.0",
80
+ "opentelemetry-api>=1.22.0,<2.0.0",
81
+ "opentelemetry-sdk>=1.22.0,<2.0.0",
82
+ "opentelemetry-exporter-otlp>=1.22.0,<2.0.0",
83
+ "opentelemetry-exporter-otlp-proto-http>=1.22.0,<2.0.0",
84
+ "aiohttp>=3.9.0,<4.0.0",
85
+ "aiohttp-retry>=2.8.3,<3.0.0",
86
+ "aiosignal>=1.3.1,<2.0.0",
87
87
  "fastmcp==2.13.0.2",
88
88
  ]
89
89
 
@@ -0,0 +1,161 @@
1
+ # Copyright 2025 DataRobot, Inc. and its affiliates.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import json
16
+ import re
17
+ from typing import Any
18
+ from typing import Literal
19
+
20
+ from datarobot.core.config import DataRobotAppFrameworkBaseSettings
21
+ from pydantic import field_validator
22
+
23
+ from datarobot_genai.core.utils.auth import AuthContextHeaderHandler
24
+
25
+
26
+ class MCPConfig(DataRobotAppFrameworkBaseSettings):
27
+ """Configuration for MCP server connection.
28
+
29
+ Derived values are exposed as properties rather than stored, avoiding
30
+ Pydantic field validation/serialization concerns for internal helpers.
31
+ """
32
+
33
+ external_mcp_url: str | None = None
34
+ external_mcp_headers: str | None = None
35
+ external_mcp_transport: Literal["sse", "streamable-http"] = "streamable-http"
36
+ mcp_deployment_id: str | None = None
37
+ datarobot_endpoint: str | None = None
38
+ datarobot_api_token: str | None = None
39
+ authorization_context: dict[str, Any] | None = None
40
+
41
+ _auth_context_handler: AuthContextHeaderHandler | None = None
42
+ _server_config: dict[str, Any] | None = None
43
+
44
+ @field_validator("external_mcp_headers", mode="before")
45
+ @classmethod
46
+ def validate_external_mcp_headers(cls, value: str | None) -> str | None:
47
+ if value is None:
48
+ return None
49
+
50
+ if not isinstance(value, str):
51
+ msg = "external_mcp_headers must be a JSON string"
52
+ raise TypeError(msg)
53
+
54
+ candidate = value.strip()
55
+
56
+ try:
57
+ json.loads(candidate)
58
+ except json.JSONDecodeError as exc:
59
+ msg = "external_mcp_headers must be valid JSON"
60
+ raise ValueError(msg) from exc
61
+
62
+ return candidate
63
+
64
+ @field_validator("mcp_deployment_id", mode="before")
65
+ @classmethod
66
+ def validate_mcp_deployment_id(cls, value: str | None) -> str | None:
67
+ if value is None:
68
+ return None
69
+
70
+ if not isinstance(value, str):
71
+ msg = "mcp_deployment_id must be a string"
72
+ raise TypeError(msg)
73
+
74
+ candidate = value.strip()
75
+
76
+ if not re.fullmatch(r"[0-9a-fA-F]{24}", candidate):
77
+ msg = "mcp_deployment_id must be a valid 24-character hex ID"
78
+ raise ValueError(msg)
79
+
80
+ return candidate
81
+
82
+ def _authorization_bearer_header(self) -> dict[str, str]:
83
+ """Return Authorization header with Bearer token or empty dict."""
84
+ if not self.datarobot_api_token:
85
+ return {}
86
+ auth = (
87
+ self.datarobot_api_token
88
+ if self.datarobot_api_token.startswith("Bearer ")
89
+ else f"Bearer {self.datarobot_api_token}"
90
+ )
91
+ return {"Authorization": auth}
92
+
93
+ @property
94
+ def auth_context_handler(self) -> AuthContextHeaderHandler:
95
+ if self._auth_context_handler is None:
96
+ self._auth_context_handler = AuthContextHeaderHandler()
97
+ return self._auth_context_handler
98
+
99
+ @property
100
+ def server_config(self) -> dict[str, Any] | None:
101
+ if self._server_config is None:
102
+ self._server_config = self._build_server_config()
103
+ return self._server_config
104
+
105
+ def _authorization_context_header(self) -> dict[str, str]:
106
+ """Return X-DataRobot-Authorization-Context header or empty dict."""
107
+ try:
108
+ return self.auth_context_handler.get_header(self.authorization_context)
109
+ except (LookupError, RuntimeError):
110
+ # Authorization context not available (e.g., in tests)
111
+ return {}
112
+
113
+ def _build_server_config(self) -> dict[str, Any] | None:
114
+ """
115
+ Get MCP server configuration.
116
+
117
+ Returns
118
+ -------
119
+ Server configuration dict with url, transport, and optional headers,
120
+ or None if not configured.
121
+ """
122
+ if self.external_mcp_url:
123
+ # External MCP URL - no authentication needed
124
+ if self.external_mcp_headers:
125
+ headers = json.loads(self.external_mcp_headers)
126
+ else:
127
+ headers = {}
128
+
129
+ config = {
130
+ "url": self.external_mcp_url.rstrip("/"),
131
+ "transport": self.external_mcp_transport,
132
+ "headers": headers,
133
+ }
134
+ return config
135
+ elif self.mcp_deployment_id:
136
+ # DataRobot deployment ID - requires authentication
137
+ if self.datarobot_endpoint is None:
138
+ raise ValueError(
139
+ "When using a DataRobot hosted MCP deployment, datarobot_endpoint must be set."
140
+ )
141
+ if self.datarobot_api_token is None:
142
+ raise ValueError(
143
+ "When using a DataRobot hosted MCP deployment, datarobot_api_token must be set."
144
+ )
145
+ base_url = self.datarobot_endpoint.rstrip("/")
146
+ if not base_url.endswith("/api/v2"):
147
+ base_url = base_url + "/api/v2"
148
+ url = f"{base_url}/deployments/{self.mcp_deployment_id}/directAccess/mcp"
149
+
150
+ headers = {
151
+ **self._authorization_bearer_header(),
152
+ **self._authorization_context_header(),
153
+ }
154
+
155
+ return {
156
+ "url": url,
157
+ "transport": "streamable-http",
158
+ "headers": headers,
159
+ }
160
+
161
+ return None
@@ -28,10 +28,22 @@ logging.getLogger("opentelemetry.instrumentation.instrumentor").setLevel(logging
28
28
  logger = logging.getLogger(__name__)
29
29
 
30
30
  # Internal instrumentation state to avoid 'global' mutation warnings
31
- _INSTRUMENTATION_STATE = {"http": False, "openai": False}
31
+ _INSTRUMENTATION_STATE = {"http": False, "openai": False, "threading": False}
32
32
  _INSTRUMENTED_FRAMEWORKS: set[str] = set()
33
33
 
34
34
 
35
+ def _instrument_threading() -> None:
36
+ if _INSTRUMENTATION_STATE["threading"]:
37
+ return
38
+ try:
39
+ threading_module = importlib.import_module("opentelemetry.instrumentation.threading")
40
+ threading_instrumentor = getattr(threading_module, "ThreadingInstrumentor")
41
+ threading_instrumentor().instrument()
42
+ _INSTRUMENTATION_STATE["threading"] = True
43
+ except Exception as e:
44
+ logger.debug(f"threading instrumentation skipped: {e}")
45
+
46
+
35
47
  def _instrument_http_clients() -> None:
36
48
  if _INSTRUMENTATION_STATE["http"]:
37
49
  return
@@ -107,6 +119,7 @@ def instrument(
107
119
  os.environ.setdefault("RAGAS_DO_NOT_TRACK", "true")
108
120
  os.environ.setdefault("DEEPEVAL_TELEMETRY_OPT_OUT", "YES")
109
121
 
122
+ _instrument_threading()
110
123
  _instrument_http_clients()
111
124
  _instrument_openai()
112
125
  if framework:
@@ -16,9 +16,14 @@ import warnings
16
16
  from typing import Any
17
17
 
18
18
  import jwt
19
+ from datarobot.auth.datarobot.oauth import AsyncOAuth as DatarobotAsyncOAuthClient
20
+ from datarobot.auth.identity import Identity
21
+ from datarobot.auth.oauth import AsyncOAuthComponent
19
22
  from datarobot.auth.session import AuthCtx
20
23
  from datarobot.core.config import DataRobotAppFrameworkBaseSettings
24
+ from datarobot.models.genai.agent.auth import ToolAuth
21
25
  from datarobot.models.genai.agent.auth import get_authorization_context
26
+ from pydantic import BaseModel
22
27
 
23
28
  logger = logging.getLogger(__name__)
24
29
 
@@ -27,6 +32,13 @@ class AuthContextConfig(DataRobotAppFrameworkBaseSettings):
27
32
  session_secret_key: str = ""
28
33
 
29
34
 
35
+ class DRAppCtx(BaseModel):
36
+ """DataRobot application context from authorization metadata."""
37
+
38
+ email: str | None = None
39
+ api_key: str | None = None
40
+
41
+
30
42
  class AuthContextHeaderHandler:
31
43
  """Manages encoding and decoding of authorization context into JWT tokens.
32
44
 
@@ -146,6 +158,7 @@ class AuthContextHeaderHandler:
146
158
 
147
159
  auth_ctx_dict = self.decode(token)
148
160
  if not auth_ctx_dict:
161
+ logger.debug("Failed to decode auth context from token")
149
162
  return None
150
163
 
151
164
  try:
@@ -153,3 +166,54 @@ class AuthContextHeaderHandler:
153
166
  except Exception as e:
154
167
  logger.error(f"Failed to create AuthCtx from decoded token: {e}", exc_info=True)
155
168
  return None
169
+
170
+
171
+ class AsyncOAuthTokenProvider:
172
+ """Manages OAuth access tokens using generic OAuth client."""
173
+
174
+ def __init__(self, auth_ctx: AuthCtx) -> None:
175
+ self.auth_ctx = auth_ctx
176
+ self.oauth_client = self._create_oauth_client()
177
+
178
+ def _get_identity(self, provider_type: str | None) -> Identity:
179
+ """Retrieve the appropriate identity from the authentication context."""
180
+ identities = [x for x in self.auth_ctx.identities if x.provider_identity_id is not None]
181
+
182
+ if not identities:
183
+ raise ValueError("No identities found in authorization context.")
184
+
185
+ if provider_type is None:
186
+ if len(identities) > 1:
187
+ raise ValueError(
188
+ "Multiple identities found. Please specify 'provider_type' parameter."
189
+ )
190
+ return identities[0]
191
+
192
+ identity = next((id for id in identities if id.provider_type == provider_type), None)
193
+
194
+ if identity is None:
195
+ raise ValueError(f"No identity found for provider '{provider_type}'.")
196
+
197
+ return identity
198
+
199
+ async def get_token(self, auth_type: ToolAuth, provider_type: str | None = None) -> str:
200
+ """Get OAuth access token using the specified method."""
201
+ if auth_type != ToolAuth.OBO:
202
+ raise ValueError(
203
+ f"Unsupported auth type: {auth_type}. Only {ToolAuth.OBO} is supported."
204
+ )
205
+
206
+ identity = self._get_identity(provider_type)
207
+ token_data = await self.oauth_client.refresh_access_token(
208
+ identity_id=identity.provider_identity_id
209
+ )
210
+ return token_data.access_token
211
+
212
+ def _create_oauth_client(self) -> AsyncOAuthComponent:
213
+ """Create either DataRobot or Authlib OAuth client based on
214
+ authorization context.
215
+
216
+ Note: at the moment, only DataRobot OAuth client is supported.
217
+ """
218
+ logger.debug("Using DataRobot OAuth client")
219
+ return DatarobotAsyncOAuthClient()
@@ -92,8 +92,6 @@ class CrewAIAgent(BaseAgent[BaseTool], abc.ABC):
92
92
 
93
93
  # Use MCP context manager to handle connection lifecycle
94
94
  with mcp_tools_context(
95
- api_base=self.api_base,
96
- api_key=self.api_key,
97
95
  authorization_context=self._authorization_context,
98
96
  ) as mcp_tools:
99
97
  # Set MCP tools for all agents if MCP is not configured this is effectively a no-op
@@ -29,15 +29,10 @@ from datarobot_genai.core.mcp.common import MCPConfig
29
29
 
30
30
  @contextmanager
31
31
  def mcp_tools_context(
32
- api_base: str | None = None,
33
- api_key: str | None = None,
34
32
  authorization_context: dict[str, Any] | None = None,
35
33
  ) -> Generator[list[Any], None, None]:
36
34
  """Context manager for MCP tools that handles connection lifecycle."""
37
- config = MCPConfig(
38
- api_base=api_base, api_key=api_key, authorization_context=authorization_context
39
- )
40
-
35
+ config = MCPConfig(authorization_context=authorization_context)
41
36
  # If no MCP server configured, return empty tools list
42
37
  if not config.server_config:
43
38
  print("No MCP server configured, using empty tools list", flush=True)
@@ -47,10 +42,8 @@ def mcp_tools_context(
47
42
  print(f"Connecting to MCP server: {config.server_config['url']}", flush=True)
48
43
 
49
44
  # Use MCPServerAdapter as context manager with the server config
50
- adapter_setting = config.server_config.copy()
51
- adapter_setting["transport"] = "streamable-http"
52
45
  try:
53
- with MCPServerAdapter(adapter_setting) as tools:
46
+ with MCPServerAdapter(config.server_config) as tools:
54
47
  print(
55
48
  f"Successfully connected to MCP server, got {len(tools)} tools",
56
49
  flush=True,