datarobot-genai 0.2.5__py3-none-any.whl → 0.2.6__py3-none-any.whl

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.
@@ -123,6 +123,8 @@ class NatAgent(BaseAgent[None]):
123
123
  model: str | None = None,
124
124
  verbose: bool | str | None = True,
125
125
  timeout: int | None = 90,
126
+ authorization_context: dict[str, Any] | None = None,
127
+ forwarded_headers: dict[str, str] | None = None,
126
128
  **kwargs: Any,
127
129
  ) -> None:
128
130
  super().__init__(
@@ -131,6 +133,8 @@ class NatAgent(BaseAgent[None]):
131
133
  model=model,
132
134
  verbose=verbose,
133
135
  timeout=timeout,
136
+ authorization_context=authorization_context,
137
+ forwarded_headers=forwarded_headers,
134
138
  **kwargs,
135
139
  )
136
140
  self.workflow_path = workflow_path
@@ -0,0 +1,53 @@
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
+ from datarobot.core.config import DataRobotAppFrameworkBaseSettings
15
+ from nat.authentication.api_key.api_key_auth_provider import APIKeyAuthProvider
16
+ from nat.authentication.api_key.api_key_auth_provider_config import APIKeyAuthProviderConfig
17
+ from nat.builder.builder import Builder
18
+ from nat.cli.register_workflow import register_auth_provider
19
+ from pydantic import Field
20
+
21
+
22
+ class Config(DataRobotAppFrameworkBaseSettings):
23
+ """
24
+ Finds variables in the priority order of: env
25
+ variables (including Runtime Parameters), .env, file_secrets, then
26
+ Pulumi output variables.
27
+ """
28
+
29
+ datarobot_api_token: str | None = None
30
+
31
+
32
+ config = Config()
33
+
34
+
35
+ class DataRobotAPIKeyAuthProviderConfig(APIKeyAuthProviderConfig, name="datarobot_api_key"): # type: ignore[call-arg]
36
+ raw_key: str = Field(
37
+ description=(
38
+ "Raw API token or credential to be injected into the request parameter. "
39
+ "Used for 'bearer','x-api-key','custom', and other schemes. "
40
+ ),
41
+ default=config.datarobot_api_token,
42
+ )
43
+ default_user_id: str | None = Field(default="default-user", description="Default user ID")
44
+ allow_default_user_id_for_tool_calls: bool = Field(
45
+ default=True, description="Allow default user ID for tool calls"
46
+ )
47
+
48
+
49
+ @register_auth_provider(config_type=DataRobotAPIKeyAuthProviderConfig)
50
+ async def datarobot_api_key_client(
51
+ config: DataRobotAPIKeyAuthProviderConfig, builder: Builder
52
+ ) -> APIKeyAuthProviderConfig:
53
+ yield APIKeyAuthProvider(config=config)
@@ -0,0 +1,181 @@
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 logging
16
+ from typing import Literal
17
+
18
+ from nat.builder.builder import Builder
19
+ from nat.cli.register_workflow import register_function_group
20
+ from nat.data_models.component_ref import AuthenticationRef
21
+ from nat.plugins.mcp.client_base import MCPSSEClient
22
+ from nat.plugins.mcp.client_base import MCPStdioClient
23
+ from nat.plugins.mcp.client_base import MCPStreamableHTTPClient
24
+ from nat.plugins.mcp.client_config import MCPServerConfig
25
+ from nat.plugins.mcp.client_impl import MCPClientConfig
26
+ from nat.plugins.mcp.client_impl import MCPFunctionGroup
27
+ from nat.plugins.mcp.client_impl import mcp_apply_tool_alias_and_description
28
+ from nat.plugins.mcp.client_impl import mcp_session_tool_function
29
+ from pydantic import Field
30
+ from pydantic import HttpUrl
31
+
32
+ from datarobot_genai.core.mcp.common import MCPConfig
33
+
34
+ logger = logging.getLogger(__name__)
35
+
36
+ config = MCPConfig().server_config
37
+
38
+
39
+ class DataRobotMCPServerConfig(MCPServerConfig):
40
+ transport: Literal["streamable-http", "sse", "stdio"] = Field(
41
+ default=config["transport"] if config else "stdio",
42
+ description="Transport type to connect to the MCP server (sse or streamable-http)",
43
+ )
44
+ url: HttpUrl | None = Field(
45
+ default=config["url"] if config else None,
46
+ description="URL of the MCP server (for sse or streamable-http transport)",
47
+ )
48
+ # Authentication configuration
49
+ auth_provider: str | AuthenticationRef | None = Field(
50
+ default="datarobot_api_key" if config else None,
51
+ description="Reference to authentication provider",
52
+ )
53
+ command: str | None = Field(
54
+ default=None if config else "docker",
55
+ description="Command to run for stdio transport (e.g. 'python' or 'docker')",
56
+ )
57
+
58
+
59
+ class DataRobotMCPClientConfig(MCPClientConfig, name="datarobot_mcp_client"): # type: ignore[call-arg]
60
+ server: DataRobotMCPServerConfig = Field(
61
+ default=DataRobotMCPServerConfig(), description="DataRobot MCP Server configuration"
62
+ )
63
+
64
+
65
+ @register_function_group(config_type=DataRobotMCPClientConfig)
66
+ async def datarobot_mcp_client_function_group(
67
+ config: DataRobotMCPClientConfig, _builder: Builder
68
+ ) -> MCPFunctionGroup:
69
+ """
70
+ Connect to an MCP server and expose tools as a function group.
71
+
72
+ Args:
73
+ config: The configuration for the MCP client
74
+ _builder: The builder
75
+ Returns:
76
+ The function group
77
+ """
78
+ # Resolve auth provider if specified
79
+ auth_provider = None
80
+ if config.server.auth_provider:
81
+ auth_provider = await _builder.get_auth_provider(config.server.auth_provider)
82
+
83
+ # Build the appropriate client
84
+ if config.server.transport == "stdio":
85
+ if not config.server.command:
86
+ raise ValueError("command is required for stdio transport")
87
+ client = MCPStdioClient(
88
+ config.server.command,
89
+ config.server.args,
90
+ config.server.env,
91
+ tool_call_timeout=config.tool_call_timeout,
92
+ auth_flow_timeout=config.auth_flow_timeout,
93
+ reconnect_enabled=config.reconnect_enabled,
94
+ reconnect_max_attempts=config.reconnect_max_attempts,
95
+ reconnect_initial_backoff=config.reconnect_initial_backoff,
96
+ reconnect_max_backoff=config.reconnect_max_backoff,
97
+ )
98
+ elif config.server.transport == "sse":
99
+ client = MCPSSEClient(
100
+ str(config.server.url),
101
+ tool_call_timeout=config.tool_call_timeout,
102
+ auth_flow_timeout=config.auth_flow_timeout,
103
+ reconnect_enabled=config.reconnect_enabled,
104
+ reconnect_max_attempts=config.reconnect_max_attempts,
105
+ reconnect_initial_backoff=config.reconnect_initial_backoff,
106
+ reconnect_max_backoff=config.reconnect_max_backoff,
107
+ )
108
+ elif config.server.transport == "streamable-http":
109
+ # Use default_user_id for the base client
110
+ base_user_id = auth_provider.config.default_user_id if auth_provider else None
111
+ client = MCPStreamableHTTPClient(
112
+ str(config.server.url),
113
+ auth_provider=auth_provider,
114
+ user_id=base_user_id,
115
+ tool_call_timeout=config.tool_call_timeout,
116
+ auth_flow_timeout=config.auth_flow_timeout,
117
+ reconnect_enabled=config.reconnect_enabled,
118
+ reconnect_max_attempts=config.reconnect_max_attempts,
119
+ reconnect_initial_backoff=config.reconnect_initial_backoff,
120
+ reconnect_max_backoff=config.reconnect_max_backoff,
121
+ )
122
+ else:
123
+ raise ValueError(f"Unsupported transport: {config.server.transport}")
124
+
125
+ logger.info("Configured to use MCP server at %s", client.server_name)
126
+
127
+ # Create the MCP function group
128
+ group = MCPFunctionGroup(config=config)
129
+
130
+ # Store shared components for session client creation
131
+ group._shared_auth_provider = auth_provider
132
+ group._client_config = config
133
+
134
+ async with client:
135
+ # Expose the live MCP client on the function group instance so other components
136
+ # (e.g., HTTP endpoints) can reuse the already-established session instead of creating a
137
+ # new client per request.
138
+ group.mcp_client = client
139
+ group.mcp_client_server_name = client.server_name
140
+ group.mcp_client_transport = client.transport
141
+
142
+ all_tools = await client.get_tools()
143
+ tool_overrides = mcp_apply_tool_alias_and_description(all_tools, config.tool_overrides)
144
+
145
+ # Add each tool as a function to the group
146
+ for tool_name, tool in all_tools.items():
147
+ # Get override if it exists
148
+ override = tool_overrides.get(tool_name)
149
+
150
+ # Use override values or defaults
151
+ function_name = override.alias if override and override.alias else tool_name
152
+ description = (
153
+ override.description if override and override.description else tool.description
154
+ )
155
+
156
+ # Create the tool function according to configuration
157
+ tool_fn = mcp_session_tool_function(tool, group)
158
+
159
+ # Normalize optional typing for linter/type-checker compatibility
160
+ single_fn = tool_fn.single_fn
161
+ if single_fn is None:
162
+ # Should not happen because FunctionInfo always sets a single_fn
163
+ logger.warning("Skipping tool %s because single_fn is None", function_name)
164
+ continue
165
+
166
+ input_schema = tool_fn.input_schema
167
+ # Convert NoneType sentinel to None for FunctionGroup.add_function signature
168
+ if input_schema is type(None): # noqa: E721
169
+ input_schema = None
170
+
171
+ # Add to group
172
+ logger.info("Adding tool %s to group", function_name)
173
+ group.add_function(
174
+ name=function_name,
175
+ description=description,
176
+ fn=single_fn,
177
+ input_schema=input_schema,
178
+ converters=tool_fn.converters,
179
+ )
180
+
181
+ yield group
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datarobot-genai
3
- Version: 0.2.5
3
+ Version: 0.2.6
4
4
  Summary: Generic helpers for GenAI
5
5
  Project-URL: Homepage, https://github.com/datarobot-oss/datarobot-genai
6
6
  Author: DataRobot, Inc.
@@ -63,6 +63,7 @@ Requires-Dist: anyio==4.11.0; extra == 'nat'
63
63
  Requires-Dist: crewai>=1.1.0; (python_version >= '3.11') and extra == 'nat'
64
64
  Requires-Dist: llama-index-llms-litellm<0.7.0,>=0.4.1; extra == 'nat'
65
65
  Requires-Dist: nvidia-nat-langchain==1.3.0; (python_version >= '3.11') and extra == 'nat'
66
+ Requires-Dist: nvidia-nat-mcp==1.3.0; (python_version >= '3.11') and extra == 'nat'
66
67
  Requires-Dist: nvidia-nat-opentelemetry==1.3.0; (python_version >= '3.11') and extra == 'nat'
67
68
  Requires-Dist: nvidia-nat==1.3.0; (python_version >= '3.11') and extra == 'nat'
68
69
  Requires-Dist: opentelemetry-instrumentation-crewai<1.0.0,>=0.40.5; extra == 'nat'
@@ -100,12 +100,14 @@ datarobot_genai/llama_index/agent.py,sha256=V6ZsD9GcBDJS-RJo1tJtIHhyW69_78gM6_fO
100
100
  datarobot_genai/llama_index/base.py,sha256=ovcQQtC-djD_hcLrWdn93jg23AmD6NBEj7xtw4a6K6c,14481
101
101
  datarobot_genai/llama_index/mcp.py,sha256=leXqF1C4zhuYEKFwNEfZHY4dsUuGZk3W7KArY-zxVL8,2645
102
102
  datarobot_genai/nat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
103
- datarobot_genai/nat/agent.py,sha256=siBLDWAff2-JwZ8Q3iNpM_e4_IoSwG9IvY0hyEjNenw,10292
103
+ datarobot_genai/nat/agent.py,sha256=jDeIS9f-8vGbeLy5gQkSjeuHINx5Fh_4BvXYERsgIIk,10516
104
+ datarobot_genai/nat/datarobot_auth_provider.py,sha256=5SBs0xBEZAlBvK-_zOR2cfE_rnn2CoEXeb-Du-rqotc,2117
104
105
  datarobot_genai/nat/datarobot_llm_clients.py,sha256=STzAZ4OF8U-Y_cUTywxmKBGVotwsnbGP6vTojnu6q0g,9921
105
106
  datarobot_genai/nat/datarobot_llm_providers.py,sha256=aDoQcTeGI-odqydPXEX9OGGNFbzAtpqzTvHHEkmJuEQ,4963
106
- datarobot_genai-0.2.5.dist-info/METADATA,sha256=ekA7W-PGh36MkW_Whpb4o7SP2ALvXk9-jzibzcT_Z-8,6088
107
- datarobot_genai-0.2.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
108
- datarobot_genai-0.2.5.dist-info/entry_points.txt,sha256=CZhmZcSyt_RBltgLN_b9xasJD6J5SaDc_z7K0wuOY9Y,150
109
- datarobot_genai-0.2.5.dist-info/licenses/AUTHORS,sha256=isJGUXdjq1U7XZ_B_9AH8Qf0u4eX0XyQifJZ_Sxm4sA,80
110
- datarobot_genai-0.2.5.dist-info/licenses/LICENSE,sha256=U2_VkLIktQoa60Nf6Tbt7E4RMlfhFSjWjcJJfVC-YCE,11341
111
- datarobot_genai-0.2.5.dist-info/RECORD,,
107
+ datarobot_genai/nat/datarobot_mcp_client.py,sha256=XK3-Tp4hdQmTdI-Zwrl3Xd81qH5RhFTw_UaLTqwnYn4,7531
108
+ datarobot_genai-0.2.6.dist-info/METADATA,sha256=2F0MD9IDjdYCmuhCO76dJHljxSk0cJP0rX17TJQoPaQ,6172
109
+ datarobot_genai-0.2.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
110
+ datarobot_genai-0.2.6.dist-info/entry_points.txt,sha256=jEW3WxDZ8XIK9-ISmTyt5DbmBb047rFlzQuhY09rGrM,284
111
+ datarobot_genai-0.2.6.dist-info/licenses/AUTHORS,sha256=isJGUXdjq1U7XZ_B_9AH8Qf0u4eX0XyQifJZ_Sxm4sA,80
112
+ datarobot_genai-0.2.6.dist-info/licenses/LICENSE,sha256=U2_VkLIktQoa60Nf6Tbt7E4RMlfhFSjWjcJJfVC-YCE,11341
113
+ datarobot_genai-0.2.6.dist-info/RECORD,,
@@ -1,3 +1,5 @@
1
1
  [nat.plugins]
2
+ datarobot_auth_provider = datarobot_genai.nat.datarobot_auth_provider
2
3
  datarobot_llm_clients = datarobot_genai.nat.datarobot_llm_clients
3
4
  datarobot_llm_providers = datarobot_genai.nat.datarobot_llm_providers
5
+ datarobot_mcp_client = datarobot_genai.nat.datarobot_mcp_client