nvidia-nat 1.3a20250819__py3-none-any.whl → 1.3.0a20250823__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.
- aiq/__init__.py +66 -0
- nat/agent/base.py +16 -0
- nat/agent/react_agent/agent.py +38 -13
- nat/agent/react_agent/prompt.py +4 -1
- nat/agent/react_agent/register.py +1 -1
- nat/agent/register.py +0 -1
- nat/agent/rewoo_agent/agent.py +6 -3
- nat/agent/rewoo_agent/prompt.py +3 -0
- nat/agent/rewoo_agent/register.py +4 -3
- nat/agent/tool_calling_agent/agent.py +92 -22
- nat/agent/tool_calling_agent/register.py +9 -13
- nat/authentication/api_key/api_key_auth_provider.py +1 -1
- nat/authentication/register.py +0 -1
- nat/builder/builder.py +1 -1
- nat/builder/context.py +9 -1
- nat/builder/function_base.py +3 -3
- nat/builder/function_info.py +5 -7
- nat/builder/user_interaction_manager.py +2 -2
- nat/builder/workflow.py +3 -0
- nat/builder/workflow_builder.py +0 -1
- nat/cli/commands/evaluate.py +1 -1
- nat/cli/commands/info/list_components.py +7 -8
- nat/cli/commands/info/list_mcp.py +3 -4
- nat/cli/commands/registry/search.py +14 -16
- nat/cli/commands/start.py +0 -1
- nat/cli/commands/workflow/templates/pyproject.toml.j2 +3 -0
- nat/cli/commands/workflow/templates/register.py.j2 +0 -1
- nat/cli/commands/workflow/workflow_commands.py +0 -1
- nat/cli/type_registry.py +7 -9
- nat/data_models/config.py +1 -1
- nat/data_models/evaluate.py +1 -1
- nat/data_models/function_dependencies.py +6 -6
- nat/data_models/intermediate_step.py +3 -3
- nat/data_models/model_gated_field_mixin.py +125 -0
- nat/data_models/swe_bench_model.py +1 -1
- nat/data_models/temperature_mixin.py +36 -0
- nat/data_models/top_p_mixin.py +36 -0
- nat/embedder/azure_openai_embedder.py +46 -0
- nat/embedder/openai_embedder.py +1 -2
- nat/embedder/register.py +1 -1
- nat/eval/config.py +2 -0
- nat/eval/dataset_handler/dataset_handler.py +5 -6
- nat/eval/evaluate.py +64 -20
- nat/eval/rag_evaluator/register.py +2 -2
- nat/eval/register.py +0 -1
- nat/eval/tunable_rag_evaluator/evaluate.py +0 -3
- nat/eval/utils/eval_trace_ctx.py +89 -0
- nat/eval/utils/weave_eval.py +14 -7
- nat/experimental/test_time_compute/models/strategy_base.py +3 -2
- nat/experimental/test_time_compute/register.py +0 -1
- nat/experimental/test_time_compute/selection/llm_based_output_merging_selector.py +0 -2
- nat/front_ends/fastapi/fastapi_front_end_plugin_worker.py +48 -49
- nat/front_ends/fastapi/message_handler.py +13 -14
- nat/front_ends/fastapi/message_validator.py +4 -4
- nat/front_ends/fastapi/step_adaptor.py +1 -1
- nat/front_ends/register.py +0 -1
- nat/llm/aws_bedrock_llm.py +3 -3
- nat/llm/azure_openai_llm.py +49 -0
- nat/llm/nim_llm.py +4 -4
- nat/llm/openai_llm.py +4 -4
- nat/llm/register.py +1 -1
- nat/llm/utils/env_config_value.py +2 -3
- nat/meta/pypi.md +9 -9
- nat/object_store/models.py +2 -0
- nat/object_store/register.py +0 -1
- nat/observability/exporter/base_exporter.py +1 -1
- nat/observability/exporter/file_exporter.py +1 -1
- nat/observability/register.py +3 -3
- nat/profiler/callbacks/langchain_callback_handler.py +9 -2
- nat/profiler/callbacks/semantic_kernel_callback_handler.py +1 -1
- nat/profiler/data_frame_row.py +1 -1
- nat/profiler/decorators/framework_wrapper.py +1 -4
- nat/profiler/forecasting/models/forecasting_base_model.py +3 -1
- nat/profiler/inference_optimization/bottleneck_analysis/simple_stack_analysis.py +1 -1
- nat/profiler/inference_optimization/data_models.py +3 -3
- nat/profiler/inference_optimization/experimental/prefix_span_analysis.py +7 -8
- nat/profiler/inference_optimization/token_uniqueness.py +1 -1
- nat/profiler/profile_runner.py +13 -8
- nat/registry_handlers/package_utils.py +0 -1
- nat/registry_handlers/pypi/pypi_handler.py +20 -23
- nat/registry_handlers/register.py +3 -4
- nat/registry_handlers/rest/rest_handler.py +8 -9
- nat/retriever/register.py +0 -1
- nat/runtime/session.py +23 -8
- nat/settings/global_settings.py +13 -2
- nat/tool/code_execution/local_sandbox/local_sandbox_server.py +1 -1
- nat/tool/datetime_tools.py +49 -9
- nat/tool/document_search.py +1 -1
- nat/tool/mcp/mcp_tool.py +1 -1
- nat/tool/register.py +0 -1
- nat/utils/data_models/schema_validator.py +2 -2
- nat/utils/exception_handlers/automatic_retries.py +0 -2
- nat/utils/exception_handlers/schemas.py +1 -1
- nat/utils/reactive/base/observable_base.py +2 -2
- nat/utils/reactive/base/observer_base.py +1 -1
- nat/utils/reactive/observable.py +2 -2
- nat/utils/reactive/observer.py +2 -2
- nat/utils/reactive/subscription.py +1 -1
- nat/utils/settings/global_settings.py +4 -6
- nat/utils/type_utils.py +4 -4
- {nvidia_nat-1.3a20250819.dist-info → nvidia_nat-1.3.0a20250823.dist-info}/METADATA +17 -15
- {nvidia_nat-1.3a20250819.dist-info → nvidia_nat-1.3.0a20250823.dist-info}/RECORD +107 -100
- nvidia_nat-1.3.0a20250823.dist-info/licenses/LICENSE-3rd-party.txt +5478 -0
- {nvidia_nat-1.3a20250819.dist-info → nvidia_nat-1.3.0a20250823.dist-info}/top_level.txt +1 -0
- nvidia_nat-1.3a20250819.dist-info/licenses/LICENSE-3rd-party.txt +0 -3686
- {nvidia_nat-1.3a20250819.dist-info → nvidia_nat-1.3.0a20250823.dist-info}/WHEEL +0 -0
- {nvidia_nat-1.3a20250819.dist-info → nvidia_nat-1.3.0a20250823.dist-info}/entry_points.txt +0 -0
- {nvidia_nat-1.3a20250819.dist-info → nvidia_nat-1.3.0a20250823.dist-info}/licenses/LICENSE.md +0 -0
|
@@ -232,7 +232,7 @@ class MessageValidator:
|
|
|
232
232
|
"""
|
|
233
233
|
return data_model.parent_id or "root"
|
|
234
234
|
|
|
235
|
-
async def create_system_response_token_message(
|
|
235
|
+
async def create_system_response_token_message(
|
|
236
236
|
self,
|
|
237
237
|
message_type: Literal[WebSocketMessageType.RESPONSE_MESSAGE,
|
|
238
238
|
WebSocketMessageType.ERROR_MESSAGE] = WebSocketMessageType.RESPONSE_MESSAGE,
|
|
@@ -272,7 +272,7 @@ class MessageValidator:
|
|
|
272
272
|
logger.error("Error creating system response token message: %s", str(e), exc_info=True)
|
|
273
273
|
return None
|
|
274
274
|
|
|
275
|
-
async def create_system_intermediate_step_message(
|
|
275
|
+
async def create_system_intermediate_step_message(
|
|
276
276
|
self,
|
|
277
277
|
message_type: Literal[WebSocketMessageType.INTERMEDIATE_STEP_MESSAGE] = (
|
|
278
278
|
WebSocketMessageType.INTERMEDIATE_STEP_MESSAGE),
|
|
@@ -311,7 +311,7 @@ class MessageValidator:
|
|
|
311
311
|
logger.error("Error creating system intermediate step message: %s", str(e), exc_info=True)
|
|
312
312
|
return None
|
|
313
313
|
|
|
314
|
-
async def create_system_interaction_message(
|
|
314
|
+
async def create_system_interaction_message(
|
|
315
315
|
self,
|
|
316
316
|
*,
|
|
317
317
|
message_type: Literal[WebSocketMessageType.SYSTEM_INTERACTION_MESSAGE] = (
|
|
@@ -323,7 +323,7 @@ class MessageValidator:
|
|
|
323
323
|
content: HumanPrompt,
|
|
324
324
|
status: WebSocketMessageStatus = WebSocketMessageStatus.IN_PROGRESS,
|
|
325
325
|
timestamp: str = str(datetime.datetime.now(datetime.timezone.utc))
|
|
326
|
-
) -> WebSocketSystemInteractionMessage | None:
|
|
326
|
+
) -> WebSocketSystemInteractionMessage | None:
|
|
327
327
|
"""
|
|
328
328
|
Creates a system interaction message with default values.
|
|
329
329
|
|
|
@@ -289,7 +289,7 @@ class StepAdaptor:
|
|
|
289
289
|
|
|
290
290
|
return event
|
|
291
291
|
|
|
292
|
-
def process(self, step: IntermediateStep) -> ResponseSerializable | None:
|
|
292
|
+
def process(self, step: IntermediateStep) -> ResponseSerializable | None:
|
|
293
293
|
|
|
294
294
|
# Track the chunk
|
|
295
295
|
self._history.append(step)
|
nat/front_ends/register.py
CHANGED
nat/llm/aws_bedrock_llm.py
CHANGED
|
@@ -22,9 +22,10 @@ from nat.builder.llm import LLMProviderInfo
|
|
|
22
22
|
from nat.cli.register_workflow import register_llm_provider
|
|
23
23
|
from nat.data_models.llm import LLMBaseConfig
|
|
24
24
|
from nat.data_models.retry_mixin import RetryMixin
|
|
25
|
+
from nat.data_models.temperature_mixin import TemperatureMixin
|
|
25
26
|
|
|
26
27
|
|
|
27
|
-
class AWSBedrockModelConfig(LLMBaseConfig, RetryMixin, name="aws_bedrock"):
|
|
28
|
+
class AWSBedrockModelConfig(LLMBaseConfig, RetryMixin, TemperatureMixin, name="aws_bedrock"):
|
|
28
29
|
"""An AWS Bedrock llm provider to be used with an LLM client."""
|
|
29
30
|
|
|
30
31
|
model_config = ConfigDict(protected_namespaces=())
|
|
@@ -33,7 +34,6 @@ class AWSBedrockModelConfig(LLMBaseConfig, RetryMixin, name="aws_bedrock"):
|
|
|
33
34
|
model_name: str = Field(validation_alias=AliasChoices("model_name", "model"),
|
|
34
35
|
serialization_alias="model",
|
|
35
36
|
description="The model name for the hosted AWS Bedrock.")
|
|
36
|
-
temperature: float = Field(default=0.0, ge=0.0, le=1.0, description="Sampling temperature in [0, 1].")
|
|
37
37
|
max_tokens: int | None = Field(default=1024,
|
|
38
38
|
gt=0,
|
|
39
39
|
description="Maximum number of tokens to generate."
|
|
@@ -52,6 +52,6 @@ class AWSBedrockModelConfig(LLMBaseConfig, RetryMixin, name="aws_bedrock"):
|
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
@register_llm_provider(config_type=AWSBedrockModelConfig)
|
|
55
|
-
async def aws_bedrock_model(llm_config: AWSBedrockModelConfig,
|
|
55
|
+
async def aws_bedrock_model(llm_config: AWSBedrockModelConfig, _builder: Builder):
|
|
56
56
|
|
|
57
57
|
yield LLMProviderInfo(config=llm_config, description="A AWS Bedrock model for use with an LLM client.")
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
from pydantic import AliasChoices
|
|
17
|
+
from pydantic import ConfigDict
|
|
18
|
+
from pydantic import Field
|
|
19
|
+
|
|
20
|
+
from nat.builder.builder import Builder
|
|
21
|
+
from nat.builder.llm import LLMProviderInfo
|
|
22
|
+
from nat.cli.register_workflow import register_llm_provider
|
|
23
|
+
from nat.data_models.llm import LLMBaseConfig
|
|
24
|
+
from nat.data_models.retry_mixin import RetryMixin
|
|
25
|
+
from nat.data_models.temperature_mixin import TemperatureMixin
|
|
26
|
+
from nat.data_models.top_p_mixin import TopPMixin
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AzureOpenAIModelConfig(LLMBaseConfig, RetryMixin, TemperatureMixin, TopPMixin, name="azure_openai"):
|
|
30
|
+
"""An Azure OpenAI LLM provider to be used with an LLM client."""
|
|
31
|
+
|
|
32
|
+
model_config = ConfigDict(protected_namespaces=(), extra="allow")
|
|
33
|
+
|
|
34
|
+
api_key: str | None = Field(default=None, description="Azure OpenAI API key to interact with hosted model.")
|
|
35
|
+
api_version: str = Field(default="2025-04-01-preview", description="Azure OpenAI API version.")
|
|
36
|
+
azure_endpoint: str | None = Field(validation_alias=AliasChoices("azure_endpoint", "base_url"),
|
|
37
|
+
serialization_alias="azure_endpoint",
|
|
38
|
+
default=None,
|
|
39
|
+
description="Base URL for the hosted model.")
|
|
40
|
+
azure_deployment: str = Field(validation_alias=AliasChoices("azure_deployment", "model_name", "model"),
|
|
41
|
+
serialization_alias="azure_deployment",
|
|
42
|
+
description="The Azure OpenAI hosted model/deployment name.")
|
|
43
|
+
seed: int | None = Field(default=None, description="Random seed to set for generation.")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@register_llm_provider(config_type=AzureOpenAIModelConfig)
|
|
47
|
+
async def azure_openai_llm(config: AzureOpenAIModelConfig, _builder: Builder):
|
|
48
|
+
|
|
49
|
+
yield LLMProviderInfo(config=config, description="An Azure OpenAI model for use with an LLM client.")
|
nat/llm/nim_llm.py
CHANGED
|
@@ -23,9 +23,11 @@ from nat.builder.llm import LLMProviderInfo
|
|
|
23
23
|
from nat.cli.register_workflow import register_llm_provider
|
|
24
24
|
from nat.data_models.llm import LLMBaseConfig
|
|
25
25
|
from nat.data_models.retry_mixin import RetryMixin
|
|
26
|
+
from nat.data_models.temperature_mixin import TemperatureMixin
|
|
27
|
+
from nat.data_models.top_p_mixin import TopPMixin
|
|
26
28
|
|
|
27
29
|
|
|
28
|
-
class NIMModelConfig(LLMBaseConfig, RetryMixin, name="nim"):
|
|
30
|
+
class NIMModelConfig(LLMBaseConfig, RetryMixin, TemperatureMixin, TopPMixin, name="nim"):
|
|
29
31
|
"""An NVIDIA Inference Microservice (NIM) llm provider to be used with an LLM client."""
|
|
30
32
|
|
|
31
33
|
model_config = ConfigDict(protected_namespaces=())
|
|
@@ -35,12 +37,10 @@ class NIMModelConfig(LLMBaseConfig, RetryMixin, name="nim"):
|
|
|
35
37
|
model_name: str = Field(validation_alias=AliasChoices("model_name", "model"),
|
|
36
38
|
serialization_alias="model",
|
|
37
39
|
description="The model name for the hosted NIM.")
|
|
38
|
-
temperature: float = Field(default=0.0, description="Sampling temperature in [0, 1].")
|
|
39
|
-
top_p: float = Field(default=1.0, description="Top-p for distribution sampling.")
|
|
40
40
|
max_tokens: PositiveInt = Field(default=300, description="Maximum number of tokens to generate.")
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
@register_llm_provider(config_type=NIMModelConfig)
|
|
44
|
-
async def nim_model(llm_config: NIMModelConfig,
|
|
44
|
+
async def nim_model(llm_config: NIMModelConfig, _builder: Builder):
|
|
45
45
|
|
|
46
46
|
yield LLMProviderInfo(config=llm_config, description="A NIM model for use with an LLM client.")
|
nat/llm/openai_llm.py
CHANGED
|
@@ -22,9 +22,11 @@ from nat.builder.llm import LLMProviderInfo
|
|
|
22
22
|
from nat.cli.register_workflow import register_llm_provider
|
|
23
23
|
from nat.data_models.llm import LLMBaseConfig
|
|
24
24
|
from nat.data_models.retry_mixin import RetryMixin
|
|
25
|
+
from nat.data_models.temperature_mixin import TemperatureMixin
|
|
26
|
+
from nat.data_models.top_p_mixin import TopPMixin
|
|
25
27
|
|
|
26
28
|
|
|
27
|
-
class OpenAIModelConfig(LLMBaseConfig, RetryMixin, name="openai"):
|
|
29
|
+
class OpenAIModelConfig(LLMBaseConfig, RetryMixin, TemperatureMixin, TopPMixin, name="openai"):
|
|
28
30
|
"""An OpenAI LLM provider to be used with an LLM client."""
|
|
29
31
|
|
|
30
32
|
model_config = ConfigDict(protected_namespaces=(), extra="allow")
|
|
@@ -34,13 +36,11 @@ class OpenAIModelConfig(LLMBaseConfig, RetryMixin, name="openai"):
|
|
|
34
36
|
model_name: str = Field(validation_alias=AliasChoices("model_name", "model"),
|
|
35
37
|
serialization_alias="model",
|
|
36
38
|
description="The OpenAI hosted model name.")
|
|
37
|
-
temperature: float = Field(default=0.0, description="Sampling temperature in [0, 1].")
|
|
38
|
-
top_p: float = Field(default=1.0, description="Top-p for distribution sampling.")
|
|
39
39
|
seed: int | None = Field(default=None, description="Random seed to set for generation.")
|
|
40
40
|
max_retries: int = Field(default=10, description="The max number of retries for the request.")
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
@register_llm_provider(config_type=OpenAIModelConfig)
|
|
44
|
-
async def openai_llm(config: OpenAIModelConfig,
|
|
44
|
+
async def openai_llm(config: OpenAIModelConfig, _builder: Builder):
|
|
45
45
|
|
|
46
46
|
yield LLMProviderInfo(config=config, description="An OpenAI model for use with an LLM client.")
|
nat/llm/register.py
CHANGED
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
|
-
# pylint: disable=unused-import
|
|
17
16
|
# flake8: noqa
|
|
18
17
|
# isort:skip_file
|
|
19
18
|
|
|
20
19
|
# Import any providers which need to be automatically registered here
|
|
21
20
|
from . import aws_bedrock_llm
|
|
21
|
+
from . import azure_openai_llm
|
|
22
22
|
from . import nim_llm
|
|
23
23
|
from . import openai_llm
|
|
@@ -72,9 +72,8 @@ class EnvConfigValue(ABC):
|
|
|
72
72
|
f"{message} Try passing a value to the constructor, or setting the `{self.__class__._ENV_KEY}` "
|
|
73
73
|
"environment variable.")
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
raise ValueError("value must not be none")
|
|
75
|
+
elif not self.__class__._ALLOW_NONE and value is None:
|
|
76
|
+
raise ValueError("value must not be none")
|
|
78
77
|
|
|
79
78
|
assert isinstance(value, str) or value is None
|
|
80
79
|
|
nat/meta/pypi.md
CHANGED
|
@@ -23,19 +23,19 @@ NeMo Agent toolkit is a flexible library designed to seamlessly integrate your e
|
|
|
23
23
|
|
|
24
24
|
## Key Features
|
|
25
25
|
|
|
26
|
-
- [**Framework Agnostic:**](https://docs.nvidia.com/nemo/agent-toolkit/1.
|
|
27
|
-
- [**Reusability:**](https://docs.nvidia.com/nemo/agent-toolkit/1.
|
|
28
|
-
- [**Rapid Development:**](https://docs.nvidia.com/nemo/agent-toolkit/1.
|
|
29
|
-
- [**Profiling:**](https://docs.nvidia.com/nemo/agent-toolkit/1.
|
|
30
|
-
- [**Observability:**](https://docs.nvidia.com/nemo/agent-toolkit/1.
|
|
31
|
-
- [**Evaluation System:**](https://docs.nvidia.com/nemo/agent-toolkit/1.
|
|
32
|
-
- [**User Interface:**](https://docs.nvidia.com/nemo/agent-toolkit/1.
|
|
33
|
-
- [**MCP Compatibility**](https://docs.nvidia.com/nemo/agent-toolkit/1.
|
|
26
|
+
- [**Framework Agnostic:**](https://docs.nvidia.com/nemo/agent-toolkit/1.3/extend/plugins.html) Works with any agentic framework, so you can use your current technology stack without replatforming.
|
|
27
|
+
- [**Reusability:**](https://docs.nvidia.com/nemo/agent-toolkit/1.3/extend/sharing-components.html) Every agent, tool, or workflow can be combined and repurposed, allowing developers to leverage existing work in new scenarios.
|
|
28
|
+
- [**Rapid Development:**](https://docs.nvidia.com/nemo/agent-toolkit/1.3/tutorials/index.html) Start with a pre-built agent, tool, or workflow, and customize it to your needs.
|
|
29
|
+
- [**Profiling:**](https://docs.nvidia.com/nemo/agent-toolkit/1.3/workflows/profiler.html) Profile entire workflows down to the tool and agent level, track input/output tokens and timings, and identify bottlenecks.
|
|
30
|
+
- [**Observability:**](https://docs.nvidia.com/nemo/agent-toolkit/1.3/workflows/observe/observe-workflow-with-phoenix.html) Monitor and debug your workflows with any OpenTelemetry-compatible observability tool, with examples using [Phoenix](https://docs.nvidia.com/nemo/agent-toolkit/1.3/workflows/observe/observe-workflow-with-phoenix.html) and [W&B Weave](https://docs.nvidia.com/nemo/agent-toolkit/1.3/workflows/observe/observe-workflow-with-weave.html).
|
|
31
|
+
- [**Evaluation System:**](https://docs.nvidia.com/nemo/agent-toolkit/1.3/workflows/evaluate.html) Validate and maintain accuracy of agentic workflows with built-in evaluation tools.
|
|
32
|
+
- [**User Interface:**](https://docs.nvidia.com/nemo/agent-toolkit/1.3/quick-start/launching-ui.html) Use the NeMo Agent toolkit UI chat interface to interact with your agents, visualize output, and debug workflows.
|
|
33
|
+
- [**MCP Compatibility**](https://docs.nvidia.com/nemo/agent-toolkit/1.3/workflows/mcp/mcp-client.html) Compatible with Model Context Protocol (MCP), allowing tools served by MCP Servers to be used as NeMo Agent toolkit functions.
|
|
34
34
|
|
|
35
35
|
With NeMo Agent toolkit, you can move quickly, experiment freely, and ensure reliability across all your agent-driven projects.
|
|
36
36
|
|
|
37
37
|
## Links
|
|
38
|
-
* [Documentation](https://docs.nvidia.com/nemo/agent-toolkit/1.
|
|
38
|
+
* [Documentation](https://docs.nvidia.com/nemo/agent-toolkit/1.3/index.html): Explore the full documentation for NeMo Agent toolkit.
|
|
39
39
|
|
|
40
40
|
## First time user?
|
|
41
41
|
If this is your first time using NeMo Agent toolkit, it is recommended to install the latest version from the [source repository](https://github.com/NVIDIA/NeMo-Agent-Toolkit?tab=readme-ov-file#quick-start) on GitHub. This package is intended for users who are familiar with NeMo Agent toolkit applications and need to add NeMo Agent toolkit as a dependency to their project.
|
nat/object_store/models.py
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
16
|
from pydantic import BaseModel
|
|
17
|
+
from pydantic import ConfigDict
|
|
17
18
|
from pydantic import Field
|
|
18
19
|
|
|
19
20
|
|
|
@@ -30,6 +31,7 @@ class ObjectStoreItem(BaseModel):
|
|
|
30
31
|
metadata : dict[str, str] | None
|
|
31
32
|
Metadata providing context and utility for management operations.
|
|
32
33
|
"""
|
|
34
|
+
model_config = ConfigDict(ser_json_bytes="base64", val_json_bytes="base64")
|
|
33
35
|
|
|
34
36
|
data: bytes = Field(description="The data to store in the object store.")
|
|
35
37
|
content_type: str | None = Field(description="The content type of the data.", default=None)
|
nat/object_store/register.py
CHANGED
|
@@ -357,7 +357,7 @@ class BaseExporter(Exporter):
|
|
|
357
357
|
except Exception as e:
|
|
358
358
|
logger.warning("Error while canceling task %s: %s", task.get_name(), e)
|
|
359
359
|
|
|
360
|
-
async def
|
|
360
|
+
async def wait_for_tasks(self, timeout: float = 5.0):
|
|
361
361
|
"""Wait for all tracked tasks to complete with a timeout.
|
|
362
362
|
|
|
363
363
|
Note: This method is NOT called during normal stop() operation for performance.
|
|
@@ -24,7 +24,7 @@ from nat.observability.processor.intermediate_step_serializer import Intermediat
|
|
|
24
24
|
logger = logging.getLogger(__name__)
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
class FileExporter(FileExportMixin, RawExporter[IntermediateStep, str]):
|
|
27
|
+
class FileExporter(FileExportMixin, RawExporter[IntermediateStep, str]):
|
|
28
28
|
"""A File exporter that exports telemetry traces to a local file."""
|
|
29
29
|
|
|
30
30
|
def __init__(self, context_state: ContextState | None = None, **file_kwargs):
|
nat/observability/register.py
CHANGED
|
@@ -45,7 +45,7 @@ class FileTelemetryExporterConfig(TelemetryExporterBaseConfig, name="file"):
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
@register_telemetry_exporter(config_type=FileTelemetryExporterConfig)
|
|
48
|
-
async def file_telemetry_exporter(config: FileTelemetryExporterConfig, builder: Builder):
|
|
48
|
+
async def file_telemetry_exporter(config: FileTelemetryExporterConfig, builder: Builder):
|
|
49
49
|
"""
|
|
50
50
|
Build and return a FileExporter for file-based telemetry export with optional rolling.
|
|
51
51
|
"""
|
|
@@ -68,7 +68,7 @@ class ConsoleLoggingMethodConfig(LoggingBaseConfig, name="console"):
|
|
|
68
68
|
|
|
69
69
|
|
|
70
70
|
@register_logging_method(config_type=ConsoleLoggingMethodConfig)
|
|
71
|
-
async def console_logging_method(config: ConsoleLoggingMethodConfig, builder: Builder):
|
|
71
|
+
async def console_logging_method(config: ConsoleLoggingMethodConfig, builder: Builder):
|
|
72
72
|
"""
|
|
73
73
|
Build and return a StreamHandler for console-based logging.
|
|
74
74
|
"""
|
|
@@ -86,7 +86,7 @@ class FileLoggingMethod(LoggingBaseConfig, name="file"):
|
|
|
86
86
|
|
|
87
87
|
|
|
88
88
|
@register_logging_method(config_type=FileLoggingMethod)
|
|
89
|
-
async def file_logging_method(config: FileLoggingMethod, builder: Builder):
|
|
89
|
+
async def file_logging_method(config: FileLoggingMethod, builder: Builder):
|
|
90
90
|
"""
|
|
91
91
|
Build and return a FileHandler for file-based logging.
|
|
92
92
|
"""
|
|
@@ -53,7 +53,7 @@ def _extract_tools_schema(invocation_params: dict) -> list:
|
|
|
53
53
|
return tools_schema
|
|
54
54
|
|
|
55
55
|
|
|
56
|
-
class LangchainProfilerHandler(AsyncCallbackHandler, BaseProfilerCallback):
|
|
56
|
+
class LangchainProfilerHandler(AsyncCallbackHandler, BaseProfilerCallback):
|
|
57
57
|
"""Callback Handler that tracks NIM info."""
|
|
58
58
|
|
|
59
59
|
total_tokens: int = 0
|
|
@@ -223,7 +223,14 @@ class LangchainProfilerHandler(AsyncCallbackHandler, BaseProfilerCallback): # p
|
|
|
223
223
|
except AttributeError:
|
|
224
224
|
usage_metadata = {}
|
|
225
225
|
|
|
226
|
-
|
|
226
|
+
if generation:
|
|
227
|
+
llm_text_output = generation.message.content
|
|
228
|
+
if "tool_calls" in generation.message.additional_kwargs:
|
|
229
|
+
# add tool calls if included in the output
|
|
230
|
+
tool_calls = generation.message.additional_kwargs['tool_calls']
|
|
231
|
+
llm_text_output = f"{llm_text_output}\n\nTool calls: {tool_calls}"
|
|
232
|
+
else:
|
|
233
|
+
llm_text_output = ""
|
|
227
234
|
|
|
228
235
|
# update shared state behind lock
|
|
229
236
|
with self._lock:
|
|
@@ -86,7 +86,7 @@ class SemanticKernelProfilerHandler(BaseProfilerCallback):
|
|
|
86
86
|
|
|
87
87
|
# Gather the appropriate modules/functions based on your builder config
|
|
88
88
|
for llm in self._builder_llms:
|
|
89
|
-
if self._builder_llms[llm].provider_type == 'openai':
|
|
89
|
+
if self._builder_llms[llm].provider_type == 'openai':
|
|
90
90
|
functions_to_patch.extend(["openai_non_streaming", "openai_streaming"])
|
|
91
91
|
|
|
92
92
|
# Grab original reference for the tool call
|
nat/profiler/data_frame_row.py
CHANGED
|
@@ -42,7 +42,7 @@ class DataFrameRow(BaseModel):
|
|
|
42
42
|
framework: str | None
|
|
43
43
|
|
|
44
44
|
@field_validator('llm_text_input', 'llm_text_output', 'llm_new_token', mode='before')
|
|
45
|
-
def cast_to_str(cls, v):
|
|
45
|
+
def cast_to_str(cls, v):
|
|
46
46
|
if v is None:
|
|
47
47
|
return v
|
|
48
48
|
try:
|
|
@@ -13,8 +13,6 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
|
-
# pylint disable=ungrouped-imports
|
|
17
|
-
|
|
18
16
|
from __future__ import annotations
|
|
19
17
|
|
|
20
18
|
import functools
|
|
@@ -75,8 +73,7 @@ def set_framework_profiler_handler(
|
|
|
75
73
|
logger.debug("LlamaIndex callback handler registered")
|
|
76
74
|
|
|
77
75
|
if LLMFrameworkEnum.CREWAI in frameworks and not _library_instrumented["crewai"]:
|
|
78
|
-
from nat.plugins.crewai.crewai_callback_handler import
|
|
79
|
-
CrewAIProfilerHandler # pylint: disable=ungrouped-imports,line-too-long # noqa E501
|
|
76
|
+
from nat.plugins.crewai.crewai_callback_handler import CrewAIProfilerHandler
|
|
80
77
|
|
|
81
78
|
handler = CrewAIProfilerHandler()
|
|
82
79
|
handler.instrument()
|
|
@@ -195,7 +195,7 @@ def profile_workflow_bottlenecks(all_steps: list[list[IntermediateStep]]) -> Sim
|
|
|
195
195
|
c_max = 0
|
|
196
196
|
for ts, delta in events_sub:
|
|
197
197
|
c_curr += delta
|
|
198
|
-
if c_curr > c_max: #
|
|
198
|
+
if c_curr > c_max: # noqa: PLR1730 - don't use max built-in
|
|
199
199
|
c_max = c_curr
|
|
200
200
|
max_concurrency_by_name[op_name] = c_max
|
|
201
201
|
|
|
@@ -172,7 +172,7 @@ class CallNode(BaseModel):
|
|
|
172
172
|
if not self.children:
|
|
173
173
|
return self.duration
|
|
174
174
|
|
|
175
|
-
intervals = [(c.start_time, c.end_time) for c in self.children]
|
|
175
|
+
intervals = [(c.start_time, c.end_time) for c in self.children]
|
|
176
176
|
# Sort by start time
|
|
177
177
|
intervals.sort(key=lambda x: x[0])
|
|
178
178
|
|
|
@@ -204,7 +204,7 @@ class CallNode(BaseModel):
|
|
|
204
204
|
This ensures no overlap double-counting among children.
|
|
205
205
|
"""
|
|
206
206
|
total = self.compute_self_time()
|
|
207
|
-
for c in self.children:
|
|
207
|
+
for c in self.children:
|
|
208
208
|
total += c.compute_subtree_time()
|
|
209
209
|
return total
|
|
210
210
|
|
|
@@ -216,7 +216,7 @@ class CallNode(BaseModel):
|
|
|
216
216
|
info = (f"{indent}- {self.operation_type} '{self.operation_name}' "
|
|
217
217
|
f"(uuid={self.uuid}, start={self.start_time:.2f}, "
|
|
218
218
|
f"end={self.end_time:.2f}, dur={self.duration:.2f})")
|
|
219
|
-
child_strs = [child._repr(level + 1) for child in self.children]
|
|
219
|
+
child_strs = [child._repr(level + 1) for child in self.children]
|
|
220
220
|
return "\n".join([info] + child_strs)
|
|
221
221
|
|
|
222
222
|
|
|
@@ -228,7 +228,7 @@ def run_prefixspan(sequences_map: dict[int, list[PrefixCallNode]],
|
|
|
228
228
|
else:
|
|
229
229
|
abs_min_support = min_support
|
|
230
230
|
|
|
231
|
-
freq_patterns = ps.frequent(abs_min_support)
|
|
231
|
+
freq_patterns = ps.frequent(abs_min_support)
|
|
232
232
|
# freq_patterns => [(count, [item1, item2, ...])]
|
|
233
233
|
|
|
234
234
|
results = []
|
|
@@ -321,13 +321,12 @@ def compute_coverage_and_duration(sequences_map: dict[int, list[PrefixCallNode]]
|
|
|
321
321
|
# --------------------------------------------------------------------------------
|
|
322
322
|
|
|
323
323
|
|
|
324
|
-
def prefixspan_subworkflow_with_text(
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
prefix_list: list[str] = None) -> PrefixSpanSubworkflowResult:
|
|
324
|
+
def prefixspan_subworkflow_with_text(all_steps: list[list[IntermediateStep]],
|
|
325
|
+
min_support: int | float = 2,
|
|
326
|
+
top_k: int = 10,
|
|
327
|
+
min_coverage: float = 0.0,
|
|
328
|
+
max_text_len: int = 700,
|
|
329
|
+
prefix_list: list[str] = None) -> PrefixSpanSubworkflowResult:
|
|
331
330
|
"""
|
|
332
331
|
1) Build sequences of calls for each example (with llm_text_input).
|
|
333
332
|
2) Convert to token lists, run PrefixSpan with min_support.
|
|
@@ -66,7 +66,7 @@ def compute_inter_query_token_uniqueness_by_llm(all_steps: list[list[Intermediat
|
|
|
66
66
|
# 2) Group by (llm_name, example_number), then sort each group
|
|
67
67
|
grouped = cdf.groupby(['llm_name', 'example_number'], as_index=False, group_keys=True)
|
|
68
68
|
|
|
69
|
-
for (llm, ex_num), group_df in grouped:
|
|
69
|
+
for (llm, ex_num), group_df in grouped:
|
|
70
70
|
# Sort by event_timestamp
|
|
71
71
|
group_df = group_df.sort_values('event_timestamp', ascending=True)
|
|
72
72
|
|
nat/profiler/profile_runner.py
CHANGED
|
@@ -88,14 +88,19 @@ class ProfilerRunner:
|
|
|
88
88
|
writes out combined requests JSON, then computes and saves additional metrics,
|
|
89
89
|
and optionally fits a forecasting model.
|
|
90
90
|
"""
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
from nat.profiler.inference_optimization.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
91
|
+
# Yapf and ruff disagree on how to format long imports, disable yapf go with ruff
|
|
92
|
+
from nat.profiler.inference_optimization.bottleneck_analysis.nested_stack_analysis import (
|
|
93
|
+
multi_example_call_profiling,
|
|
94
|
+
) # yapf: disable
|
|
95
|
+
from nat.profiler.inference_optimization.bottleneck_analysis.simple_stack_analysis import (
|
|
96
|
+
profile_workflow_bottlenecks,
|
|
97
|
+
) # yapf: disable
|
|
98
|
+
from nat.profiler.inference_optimization.experimental.concurrency_spike_analysis import (
|
|
99
|
+
concurrency_spike_analysis,
|
|
100
|
+
) # yapf: disable
|
|
101
|
+
from nat.profiler.inference_optimization.experimental.prefix_span_analysis import (
|
|
102
|
+
prefixspan_subworkflow_with_text,
|
|
103
|
+
) # yapf: disable
|
|
99
104
|
from nat.profiler.inference_optimization.llm_metrics import LLMMetrics
|
|
100
105
|
from nat.profiler.inference_optimization.prompt_caching import get_common_prefixes
|
|
101
106
|
from nat.profiler.inference_optimization.token_uniqueness import compute_inter_query_token_uniqueness_by_llm
|
|
@@ -44,13 +44,12 @@ class PypiRegistryHandler(AbstractRegistryHandler):
|
|
|
44
44
|
https://github.com/pypiserver/pypiserver
|
|
45
45
|
"""
|
|
46
46
|
|
|
47
|
-
def __init__(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
search_route: str = ""):
|
|
47
|
+
def __init__(self,
|
|
48
|
+
endpoint: str,
|
|
49
|
+
token: str | None = None,
|
|
50
|
+
publish_route: str = "",
|
|
51
|
+
pull_route: str = "",
|
|
52
|
+
search_route: str = ""):
|
|
54
53
|
super().__init__()
|
|
55
54
|
self._endpoint = endpoint.rstrip("/")
|
|
56
55
|
self._token = token
|
|
@@ -126,17 +125,16 @@ class PypiRegistryHandler(AbstractRegistryHandler):
|
|
|
126
125
|
|
|
127
126
|
versioned_packages_str = " ".join(versioned_packages)
|
|
128
127
|
|
|
129
|
-
result = subprocess.run(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
check=True)
|
|
128
|
+
result = subprocess.run([
|
|
129
|
+
"uv",
|
|
130
|
+
"pip",
|
|
131
|
+
"install",
|
|
132
|
+
"--prerelease=allow",
|
|
133
|
+
"--index-url",
|
|
134
|
+
f"{self._endpoint}/{self._pull_route}/",
|
|
135
|
+
versioned_packages_str
|
|
136
|
+
],
|
|
137
|
+
check=True)
|
|
140
138
|
|
|
141
139
|
result.check_returncode()
|
|
142
140
|
|
|
@@ -171,11 +169,10 @@ class PypiRegistryHandler(AbstractRegistryHandler):
|
|
|
171
169
|
"""
|
|
172
170
|
|
|
173
171
|
try:
|
|
174
|
-
completed_process = subprocess.run(
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
check=True)
|
|
172
|
+
completed_process = subprocess.run(["pip", "search", "--index", f"{self._endpoint}", query.query],
|
|
173
|
+
text=True,
|
|
174
|
+
capture_output=True,
|
|
175
|
+
check=True)
|
|
179
176
|
search_response_list = []
|
|
180
177
|
search_results = completed_process.stdout
|
|
181
178
|
package_results = search_results.split("\n")
|
|
@@ -13,9 +13,8 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
|
-
# pylint: disable=unused-import
|
|
17
16
|
# flake8: noqa
|
|
18
17
|
|
|
19
|
-
from .local import register_local
|
|
20
|
-
from .pypi import register_pypi
|
|
21
|
-
from .rest import register_rest
|
|
18
|
+
from .local import register_local
|
|
19
|
+
from .pypi import register_pypi
|
|
20
|
+
from .rest import register_rest
|
|
@@ -42,15 +42,14 @@ logger = logging.getLogger(__name__)
|
|
|
42
42
|
class RestRegistryHandler(AbstractRegistryHandler):
|
|
43
43
|
"""A registry handler for interactions with a remote REST registry."""
|
|
44
44
|
|
|
45
|
-
def __init__(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
remove_route: str = ""):
|
|
45
|
+
def __init__(self,
|
|
46
|
+
endpoint: str,
|
|
47
|
+
token: str,
|
|
48
|
+
timeout: int = 30,
|
|
49
|
+
publish_route: str = "",
|
|
50
|
+
pull_route: str = "",
|
|
51
|
+
search_route: str = "",
|
|
52
|
+
remove_route: str = ""):
|
|
54
53
|
super().__init__()
|
|
55
54
|
self._endpoint = endpoint.rstrip("/")
|
|
56
55
|
self._timeout = timeout
|