datarobot-genai 0.1.62__py3-none-any.whl → 0.1.64__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.
- datarobot_genai/drmcp/core/dynamic_prompts/dr_lib.py +17 -7
- datarobot_genai/drmcp/core/dynamic_prompts/register.py +36 -4
- datarobot_genai/langgraph/agent.py +3 -2
- datarobot_genai/nat/agent.py +45 -0
- {datarobot_genai-0.1.62.dist-info → datarobot_genai-0.1.64.dist-info}/METADATA +1 -1
- {datarobot_genai-0.1.62.dist-info → datarobot_genai-0.1.64.dist-info}/RECORD +10 -10
- {datarobot_genai-0.1.62.dist-info → datarobot_genai-0.1.64.dist-info}/WHEEL +1 -1
- {datarobot_genai-0.1.62.dist-info → datarobot_genai-0.1.64.dist-info}/entry_points.txt +0 -0
- {datarobot_genai-0.1.62.dist-info → datarobot_genai-0.1.64.dist-info}/licenses/AUTHORS +0 -0
- {datarobot_genai-0.1.62.dist-info → datarobot_genai-0.1.64.dist-info}/licenses/LICENSE +0 -0
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
-
|
|
14
|
+
from collections import defaultdict
|
|
15
15
|
from dataclasses import dataclass
|
|
16
16
|
|
|
17
17
|
import datarobot as dr
|
|
@@ -34,6 +34,7 @@ class DrVariable:
|
|
|
34
34
|
@dataclass
|
|
35
35
|
class DrPromptVersion:
|
|
36
36
|
id: str
|
|
37
|
+
prompt_template_id: str
|
|
37
38
|
version: int
|
|
38
39
|
prompt_text: str
|
|
39
40
|
variables: list[DrVariable]
|
|
@@ -45,6 +46,7 @@ class DrPromptVersion:
|
|
|
45
46
|
]
|
|
46
47
|
return cls(
|
|
47
48
|
id=d["id"],
|
|
49
|
+
prompt_template_id=d["promptTemplateId"],
|
|
48
50
|
version=d["version"],
|
|
49
51
|
prompt_text=d["promptText"],
|
|
50
52
|
variables=variables,
|
|
@@ -58,7 +60,9 @@ class DrPrompt:
|
|
|
58
60
|
description: str
|
|
59
61
|
|
|
60
62
|
def get_latest_version(self) -> DrPromptVersion | None:
|
|
61
|
-
|
|
63
|
+
all_prompt_template_versions = get_datarobot_prompt_template_versions([self.id])
|
|
64
|
+
prompt_template_versions = all_prompt_template_versions.get(self.id)
|
|
65
|
+
|
|
62
66
|
if not prompt_template_versions:
|
|
63
67
|
return None
|
|
64
68
|
latest_version = max(prompt_template_versions, key=lambda v: v.version)
|
|
@@ -77,15 +81,21 @@ def get_datarobot_prompt_templates() -> list[DrPrompt]:
|
|
|
77
81
|
return [DrPrompt.from_dict(prompt_template) for prompt_template in prompt_templates_data]
|
|
78
82
|
|
|
79
83
|
|
|
80
|
-
def get_datarobot_prompt_template_versions(
|
|
84
|
+
def get_datarobot_prompt_template_versions(
|
|
85
|
+
prompt_template_ids: list[str],
|
|
86
|
+
) -> dict[str, list[DrPromptVersion]]:
|
|
81
87
|
prompt_template_versions_data = dr.utils.pagination.unpaginate(
|
|
82
|
-
initial_url=
|
|
83
|
-
initial_params={
|
|
88
|
+
initial_url="genai/promptTemplates/versions/",
|
|
89
|
+
initial_params={
|
|
90
|
+
"promptTemplateIds": prompt_template_ids,
|
|
91
|
+
},
|
|
84
92
|
client=get_api_client(),
|
|
85
93
|
)
|
|
86
|
-
prompt_template_versions =
|
|
94
|
+
prompt_template_versions = defaultdict(list)
|
|
87
95
|
for prompt_template_version in prompt_template_versions_data:
|
|
88
|
-
prompt_template_versions.append(
|
|
96
|
+
prompt_template_versions[prompt_template_version["promptTemplateId"]].append(
|
|
97
|
+
DrPromptVersion.from_dict(prompt_template_version)
|
|
98
|
+
)
|
|
89
99
|
return prompt_template_versions
|
|
90
100
|
|
|
91
101
|
|
|
@@ -27,6 +27,7 @@ from datarobot_genai.drmcp.core.mcp_instance import register_prompt
|
|
|
27
27
|
from .dr_lib import DrPrompt
|
|
28
28
|
from .dr_lib import DrPromptVersion
|
|
29
29
|
from .dr_lib import DrVariable
|
|
30
|
+
from .dr_lib import get_datarobot_prompt_template_versions
|
|
30
31
|
from .dr_lib import get_datarobot_prompt_templates
|
|
31
32
|
|
|
32
33
|
logger = logging.getLogger(__name__)
|
|
@@ -36,11 +37,21 @@ async def register_prompts_from_datarobot_prompt_management() -> None:
|
|
|
36
37
|
"""Register prompts from DataRobot Prompt Management."""
|
|
37
38
|
prompts = get_datarobot_prompt_templates()
|
|
38
39
|
logger.info(f"Found {len(prompts)} prompts in Prompts Management.")
|
|
40
|
+
all_prompts_versions = get_datarobot_prompt_template_versions(
|
|
41
|
+
prompt_template_ids=list({prompt.id for prompt in prompts})
|
|
42
|
+
)
|
|
39
43
|
|
|
40
44
|
# Try to register each prompt, continue on failure
|
|
41
45
|
for prompt in prompts:
|
|
46
|
+
prompt_versions = all_prompts_versions.get(prompt.id)
|
|
47
|
+
if not prompt_versions:
|
|
48
|
+
logger.warning(f"Prompt template id {prompt.id} has no versions.")
|
|
49
|
+
continue
|
|
50
|
+
|
|
51
|
+
latest_version = max(prompt_versions, key=lambda v: v.version)
|
|
52
|
+
|
|
42
53
|
try:
|
|
43
|
-
await register_prompt_from_datarobot_prompt_management(prompt)
|
|
54
|
+
await register_prompt_from_datarobot_prompt_management(prompt, latest_version)
|
|
44
55
|
except DynamicPromptRegistrationError:
|
|
45
56
|
pass
|
|
46
57
|
|
|
@@ -114,15 +125,36 @@ async def register_prompt_from_datarobot_prompt_management(
|
|
|
114
125
|
) from exc
|
|
115
126
|
|
|
116
127
|
|
|
128
|
+
def _escape_non_ascii(s: str) -> str:
|
|
129
|
+
out = []
|
|
130
|
+
for ch in s:
|
|
131
|
+
# If its space -> change to underscore
|
|
132
|
+
if ch.isspace():
|
|
133
|
+
out.append("_")
|
|
134
|
+
# ASCII letter, digit or underscore -> keep
|
|
135
|
+
elif ch.isascii() and (ch.isalnum() or ch == "_"):
|
|
136
|
+
out.append(ch)
|
|
137
|
+
# Everything else -> encode as 'xHEX'
|
|
138
|
+
else:
|
|
139
|
+
out.append(f"x{ord(ch):x}")
|
|
140
|
+
return "".join(out)
|
|
141
|
+
|
|
142
|
+
|
|
117
143
|
def to_valid_mcp_prompt_name(s: str) -> str:
|
|
118
144
|
"""Convert an arbitrary string into a valid MCP prompt name."""
|
|
119
|
-
# Replace any sequence of invalid characters with '_'
|
|
120
|
-
s = re.sub(r"[^0-9a-zA-Z_]+", "_", s)
|
|
121
|
-
|
|
122
145
|
# If its ONLY numbers return "prompt_[number]"
|
|
123
146
|
if s.isdigit():
|
|
124
147
|
return f"prompt_{s}"
|
|
125
148
|
|
|
149
|
+
# First, ASCII-transliterate using hex escape for non-ASCII
|
|
150
|
+
if not s.isascii():
|
|
151
|
+
# whole string non-ascii? -> escape and prefix with prompt_
|
|
152
|
+
encoded = _escape_non_ascii(s)
|
|
153
|
+
return f"prompt_{encoded}"
|
|
154
|
+
|
|
155
|
+
# Replace any sequence of invalid characters with '_'
|
|
156
|
+
s = re.sub(r"[^0-9a-zA-Z_]+", "_", s)
|
|
157
|
+
|
|
126
158
|
# Remove leading characters that are not letters or underscores (can't start with a digit or _)
|
|
127
159
|
s = re.sub(r"^[^a-zA-Z]+", "", s)
|
|
128
160
|
|
|
@@ -32,6 +32,7 @@ from datarobot_genai.core.agents.base import BaseAgent
|
|
|
32
32
|
from datarobot_genai.core.agents.base import InvokeReturn
|
|
33
33
|
from datarobot_genai.core.agents.base import UsageMetrics
|
|
34
34
|
from datarobot_genai.core.agents.base import extract_user_prompt_content
|
|
35
|
+
from datarobot_genai.core.agents.base import is_streaming
|
|
35
36
|
from datarobot_genai.langgraph.mcp import mcp_tools_context
|
|
36
37
|
|
|
37
38
|
logger = logging.getLogger(__name__)
|
|
@@ -136,10 +137,10 @@ class LangGraphAgent(BaseAgent[BaseTool], abc.ABC):
|
|
|
136
137
|
# The following code demonstrate both a synchronous and streaming response.
|
|
137
138
|
# You can choose one or the other based on your use case, they function the same.
|
|
138
139
|
# The main difference is returning a generator for streaming or a final response for sync.
|
|
139
|
-
if completion_create_params
|
|
140
|
+
if is_streaming(completion_create_params):
|
|
140
141
|
# Streaming response: yield each message as it is generated
|
|
141
142
|
async def stream_generator() -> AsyncGenerator[
|
|
142
|
-
tuple[str,
|
|
143
|
+
tuple[str, MultiTurnSample | None, UsageMetrics], None
|
|
143
144
|
]:
|
|
144
145
|
# Iterate over the graph stream. For message events, yield the content.
|
|
145
146
|
# For update events, accumulate the usage metrics.
|
datarobot_genai/nat/agent.py
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
import asyncio
|
|
15
15
|
import logging
|
|
16
|
+
from collections.abc import AsyncGenerator
|
|
16
17
|
from typing import Any
|
|
17
18
|
|
|
18
19
|
from nat.builder.context import Context
|
|
@@ -32,6 +33,7 @@ from datarobot_genai.core.agents.base import BaseAgent
|
|
|
32
33
|
from datarobot_genai.core.agents.base import InvokeReturn
|
|
33
34
|
from datarobot_genai.core.agents.base import UsageMetrics
|
|
34
35
|
from datarobot_genai.core.agents.base import extract_user_prompt_content
|
|
36
|
+
from datarobot_genai.core.agents.base import is_streaming
|
|
35
37
|
|
|
36
38
|
logger = logging.getLogger(__name__)
|
|
37
39
|
|
|
@@ -160,6 +162,49 @@ class NatAgent(BaseAgent[None]):
|
|
|
160
162
|
# Print commands may need flush=True to ensure they are displayed in real-time.
|
|
161
163
|
print("Running agent with user prompt:", chat_request.messages[0].content, flush=True)
|
|
162
164
|
|
|
165
|
+
if is_streaming(completion_create_params):
|
|
166
|
+
|
|
167
|
+
async def stream_generator() -> AsyncGenerator[
|
|
168
|
+
tuple[str, MultiTurnSample | None, UsageMetrics], None
|
|
169
|
+
]:
|
|
170
|
+
usage_metrics: UsageMetrics = {
|
|
171
|
+
"completion_tokens": 0,
|
|
172
|
+
"prompt_tokens": 0,
|
|
173
|
+
"total_tokens": 0,
|
|
174
|
+
}
|
|
175
|
+
async with load_workflow(self.workflow_path) as workflow:
|
|
176
|
+
async with workflow.run(chat_request) as runner:
|
|
177
|
+
intermediate_future = pull_intermediate_structured()
|
|
178
|
+
async for result in runner.result_stream():
|
|
179
|
+
if isinstance(result, ChatResponse):
|
|
180
|
+
result_text = result.choices[0].message.content
|
|
181
|
+
else:
|
|
182
|
+
result_text = str(result)
|
|
183
|
+
|
|
184
|
+
yield (
|
|
185
|
+
result_text,
|
|
186
|
+
None,
|
|
187
|
+
usage_metrics,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
steps = await intermediate_future
|
|
191
|
+
llm_end_steps = [
|
|
192
|
+
step
|
|
193
|
+
for step in steps
|
|
194
|
+
if step.event_type == IntermediateStepType.LLM_END
|
|
195
|
+
]
|
|
196
|
+
for step in llm_end_steps:
|
|
197
|
+
if step.usage_info:
|
|
198
|
+
token_usage = step.usage_info.token_usage
|
|
199
|
+
usage_metrics["total_tokens"] += token_usage.total_tokens
|
|
200
|
+
usage_metrics["prompt_tokens"] += token_usage.prompt_tokens
|
|
201
|
+
usage_metrics["completion_tokens"] += token_usage.completion_tokens
|
|
202
|
+
|
|
203
|
+
pipeline_interactions = create_pipeline_interactions_from_steps(steps)
|
|
204
|
+
yield "", pipeline_interactions, usage_metrics
|
|
205
|
+
|
|
206
|
+
return stream_generator()
|
|
207
|
+
|
|
163
208
|
# Create and invoke the NAT (Nemo Agent Toolkit) Agentic Workflow with the inputs
|
|
164
209
|
result, steps = await self.run_nat_workflow(self.workflow_path, chat_request)
|
|
165
210
|
|
|
@@ -45,8 +45,8 @@ datarobot_genai/drmcp/core/tool_filter.py,sha256=tLOcG50QBvS48cOVHM6OqoODYiiS6Ke
|
|
|
45
45
|
datarobot_genai/drmcp/core/utils.py,sha256=dSjrayWVcnC5GxQcvOIOSHaoEymPIVtG_s2ZBMlmSOw,4336
|
|
46
46
|
datarobot_genai/drmcp/core/dynamic_prompts/__init__.py,sha256=y4yapzp3KnFMzSR6HlNDS4uSuyNT7I1iPBvaCLsS0sU,577
|
|
47
47
|
datarobot_genai/drmcp/core/dynamic_prompts/controllers.py,sha256=vCMYxwYjNDadRxSlRk6p8pHK6h_2K-PkbBTTW_lqBJ0,3318
|
|
48
|
-
datarobot_genai/drmcp/core/dynamic_prompts/dr_lib.py,sha256=
|
|
49
|
-
datarobot_genai/drmcp/core/dynamic_prompts/register.py,sha256=
|
|
48
|
+
datarobot_genai/drmcp/core/dynamic_prompts/dr_lib.py,sha256=IEdD2Gqm4SfUdiXJB99RiWxkN6frGaxJ2SfATetMM3c,4243
|
|
49
|
+
datarobot_genai/drmcp/core/dynamic_prompts/register.py,sha256=5AEh1m8GX-gPZHUdiE1VATt7IKJQk-eThcxh01sWn0I,7204
|
|
50
50
|
datarobot_genai/drmcp/core/dynamic_prompts/utils.py,sha256=BZ3792AgfvYlwL0_J0MzQfGecyEA5_OKUMynEZYzCds,1136
|
|
51
51
|
datarobot_genai/drmcp/core/dynamic_tools/__init__.py,sha256=0kq9vMkF7EBsS6lkEdiLibmUrghTQqosHbZ5k-V9a5g,578
|
|
52
52
|
datarobot_genai/drmcp/core/dynamic_tools/register.py,sha256=3M5-F0mhUYTZJWmFDmqzsj3QAd7ut7b0kPv-JZyaTzg,9204
|
|
@@ -83,19 +83,19 @@ datarobot_genai/drmcp/tools/predictive/predict_realtime.py,sha256=t7f28y_ealZoA6
|
|
|
83
83
|
datarobot_genai/drmcp/tools/predictive/project.py,sha256=KaMDAvJY4s12j_4ybA7-KcCS1yMOj-KPIKNBgCSE2iM,2536
|
|
84
84
|
datarobot_genai/drmcp/tools/predictive/training.py,sha256=kxeDVLqUh9ajDk8wK7CZRRydDK8UNuTVZCB3huUihF8,23660
|
|
85
85
|
datarobot_genai/langgraph/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
86
|
-
datarobot_genai/langgraph/agent.py,sha256=
|
|
86
|
+
datarobot_genai/langgraph/agent.py,sha256=us-DXSgmI2271tsbzOOtDbRHdStCsOro-YRQ30ePpkA,9739
|
|
87
87
|
datarobot_genai/langgraph/mcp.py,sha256=_ggxlRFkydhJgJVcAdwDWZL0WWCejctNC5X9ycAWeUM,2610
|
|
88
88
|
datarobot_genai/llama_index/__init__.py,sha256=JEMkLQLuP8n14kNE3bZ2j08NdajnkJMfYjDQYqj7C0c,407
|
|
89
89
|
datarobot_genai/llama_index/agent.py,sha256=V6ZsD9GcBDJS-RJo1tJtIHhyW69_78gM6_fOHFV-Piw,1829
|
|
90
90
|
datarobot_genai/llama_index/base.py,sha256=MwhSlRCwsP0Z9IxaTJ4tMZO2mCMX3pvqNFl3s9aj1P8,14427
|
|
91
91
|
datarobot_genai/llama_index/mcp.py,sha256=3XULVxtLBV_ItM491zWRg2KMHGszy6OTyPzHW08zO2k,2439
|
|
92
92
|
datarobot_genai/nat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
93
|
-
datarobot_genai/nat/agent.py,sha256=
|
|
93
|
+
datarobot_genai/nat/agent.py,sha256=siBLDWAff2-JwZ8Q3iNpM_e4_IoSwG9IvY0hyEjNenw,10292
|
|
94
94
|
datarobot_genai/nat/datarobot_llm_clients.py,sha256=IZq_kooUL8QyDTkpEreszLQk9vCzg6-FbTjIkXR9wc0,7203
|
|
95
95
|
datarobot_genai/nat/datarobot_llm_providers.py,sha256=lOVaL_0Fl6-7GFYl3HmfqttqKpKt-2w8o92P3T7B6cU,3683
|
|
96
|
-
datarobot_genai-0.1.
|
|
97
|
-
datarobot_genai-0.1.
|
|
98
|
-
datarobot_genai-0.1.
|
|
99
|
-
datarobot_genai-0.1.
|
|
100
|
-
datarobot_genai-0.1.
|
|
101
|
-
datarobot_genai-0.1.
|
|
96
|
+
datarobot_genai-0.1.64.dist-info/METADATA,sha256=xx80UKcDU-NjYz1wE6vHRUx_nJpEhX01MUi7tLU5wNs,5911
|
|
97
|
+
datarobot_genai-0.1.64.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
98
|
+
datarobot_genai-0.1.64.dist-info/entry_points.txt,sha256=CZhmZcSyt_RBltgLN_b9xasJD6J5SaDc_z7K0wuOY9Y,150
|
|
99
|
+
datarobot_genai-0.1.64.dist-info/licenses/AUTHORS,sha256=isJGUXdjq1U7XZ_B_9AH8Qf0u4eX0XyQifJZ_Sxm4sA,80
|
|
100
|
+
datarobot_genai-0.1.64.dist-info/licenses/LICENSE,sha256=U2_VkLIktQoa60Nf6Tbt7E4RMlfhFSjWjcJJfVC-YCE,11341
|
|
101
|
+
datarobot_genai-0.1.64.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|