aiqtoolkit 1.1.0rc5__py3-none-any.whl → 1.2.0__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.
Potentially problematic release.
This version of aiqtoolkit might be problematic. Click here for more details.
- aiqtoolkit-1.2.0.dist-info/METADATA +29 -0
- aiqtoolkit-1.2.0.dist-info/RECORD +4 -0
- {aiqtoolkit-1.1.0rc5.dist-info → aiqtoolkit-1.2.0.dist-info}/WHEEL +1 -1
- aiqtoolkit-1.2.0.dist-info/top_level.txt +1 -0
- aiq/agent/__init__.py +0 -0
- aiq/agent/base.py +0 -76
- aiq/agent/dual_node.py +0 -67
- aiq/agent/react_agent/__init__.py +0 -0
- aiq/agent/react_agent/agent.py +0 -322
- aiq/agent/react_agent/output_parser.py +0 -104
- aiq/agent/react_agent/prompt.py +0 -46
- aiq/agent/react_agent/register.py +0 -148
- aiq/agent/reasoning_agent/__init__.py +0 -0
- aiq/agent/reasoning_agent/reasoning_agent.py +0 -224
- aiq/agent/register.py +0 -23
- aiq/agent/rewoo_agent/__init__.py +0 -0
- aiq/agent/rewoo_agent/agent.py +0 -410
- aiq/agent/rewoo_agent/prompt.py +0 -108
- aiq/agent/rewoo_agent/register.py +0 -158
- aiq/agent/tool_calling_agent/__init__.py +0 -0
- aiq/agent/tool_calling_agent/agent.py +0 -123
- aiq/agent/tool_calling_agent/register.py +0 -105
- aiq/builder/__init__.py +0 -0
- aiq/builder/builder.py +0 -223
- aiq/builder/component_utils.py +0 -303
- aiq/builder/context.py +0 -227
- aiq/builder/embedder.py +0 -24
- aiq/builder/eval_builder.py +0 -120
- aiq/builder/evaluator.py +0 -29
- aiq/builder/framework_enum.py +0 -24
- aiq/builder/front_end.py +0 -73
- aiq/builder/function.py +0 -297
- aiq/builder/function_base.py +0 -376
- aiq/builder/function_info.py +0 -627
- aiq/builder/intermediate_step_manager.py +0 -135
- aiq/builder/llm.py +0 -25
- aiq/builder/retriever.py +0 -25
- aiq/builder/user_interaction_manager.py +0 -71
- aiq/builder/workflow.py +0 -143
- aiq/builder/workflow_builder.py +0 -757
- aiq/cli/__init__.py +0 -14
- aiq/cli/cli_utils/__init__.py +0 -0
- aiq/cli/cli_utils/config_override.py +0 -231
- aiq/cli/cli_utils/validation.py +0 -37
- aiq/cli/commands/__init__.py +0 -0
- aiq/cli/commands/configure/__init__.py +0 -0
- aiq/cli/commands/configure/channel/__init__.py +0 -0
- aiq/cli/commands/configure/channel/add.py +0 -28
- aiq/cli/commands/configure/channel/channel.py +0 -36
- aiq/cli/commands/configure/channel/remove.py +0 -30
- aiq/cli/commands/configure/channel/update.py +0 -30
- aiq/cli/commands/configure/configure.py +0 -33
- aiq/cli/commands/evaluate.py +0 -139
- aiq/cli/commands/info/__init__.py +0 -14
- aiq/cli/commands/info/info.py +0 -39
- aiq/cli/commands/info/list_channels.py +0 -32
- aiq/cli/commands/info/list_components.py +0 -129
- aiq/cli/commands/info/list_mcp.py +0 -126
- aiq/cli/commands/registry/__init__.py +0 -14
- aiq/cli/commands/registry/publish.py +0 -88
- aiq/cli/commands/registry/pull.py +0 -118
- aiq/cli/commands/registry/registry.py +0 -38
- aiq/cli/commands/registry/remove.py +0 -108
- aiq/cli/commands/registry/search.py +0 -155
- aiq/cli/commands/start.py +0 -250
- aiq/cli/commands/uninstall.py +0 -83
- aiq/cli/commands/validate.py +0 -47
- aiq/cli/commands/workflow/__init__.py +0 -14
- aiq/cli/commands/workflow/templates/__init__.py.j2 +0 -0
- aiq/cli/commands/workflow/templates/config.yml.j2 +0 -16
- aiq/cli/commands/workflow/templates/pyproject.toml.j2 +0 -22
- aiq/cli/commands/workflow/templates/register.py.j2 +0 -5
- aiq/cli/commands/workflow/templates/workflow.py.j2 +0 -36
- aiq/cli/commands/workflow/workflow.py +0 -37
- aiq/cli/commands/workflow/workflow_commands.py +0 -313
- aiq/cli/entrypoint.py +0 -133
- aiq/cli/main.py +0 -44
- aiq/cli/register_workflow.py +0 -408
- aiq/cli/type_registry.py +0 -879
- aiq/data_models/__init__.py +0 -14
- aiq/data_models/api_server.py +0 -588
- aiq/data_models/common.py +0 -143
- aiq/data_models/component.py +0 -46
- aiq/data_models/component_ref.py +0 -135
- aiq/data_models/config.py +0 -349
- aiq/data_models/dataset_handler.py +0 -122
- aiq/data_models/discovery_metadata.py +0 -286
- aiq/data_models/embedder.py +0 -26
- aiq/data_models/evaluate.py +0 -104
- aiq/data_models/evaluator.py +0 -26
- aiq/data_models/front_end.py +0 -26
- aiq/data_models/function.py +0 -30
- aiq/data_models/function_dependencies.py +0 -64
- aiq/data_models/interactive.py +0 -237
- aiq/data_models/intermediate_step.py +0 -269
- aiq/data_models/invocation_node.py +0 -38
- aiq/data_models/llm.py +0 -26
- aiq/data_models/logging.py +0 -26
- aiq/data_models/memory.py +0 -26
- aiq/data_models/profiler.py +0 -53
- aiq/data_models/registry_handler.py +0 -26
- aiq/data_models/retriever.py +0 -30
- aiq/data_models/step_adaptor.py +0 -64
- aiq/data_models/streaming.py +0 -33
- aiq/data_models/swe_bench_model.py +0 -54
- aiq/data_models/telemetry_exporter.py +0 -26
- aiq/embedder/__init__.py +0 -0
- aiq/embedder/langchain_client.py +0 -41
- aiq/embedder/nim_embedder.py +0 -58
- aiq/embedder/openai_embedder.py +0 -42
- aiq/embedder/register.py +0 -24
- aiq/eval/__init__.py +0 -14
- aiq/eval/config.py +0 -42
- aiq/eval/dataset_handler/__init__.py +0 -0
- aiq/eval/dataset_handler/dataset_downloader.py +0 -106
- aiq/eval/dataset_handler/dataset_filter.py +0 -52
- aiq/eval/dataset_handler/dataset_handler.py +0 -169
- aiq/eval/evaluate.py +0 -325
- aiq/eval/evaluator/__init__.py +0 -14
- aiq/eval/evaluator/evaluator_model.py +0 -44
- aiq/eval/intermediate_step_adapter.py +0 -93
- aiq/eval/rag_evaluator/__init__.py +0 -0
- aiq/eval/rag_evaluator/evaluate.py +0 -138
- aiq/eval/rag_evaluator/register.py +0 -138
- aiq/eval/register.py +0 -23
- aiq/eval/remote_workflow.py +0 -128
- aiq/eval/runtime_event_subscriber.py +0 -52
- aiq/eval/swe_bench_evaluator/__init__.py +0 -0
- aiq/eval/swe_bench_evaluator/evaluate.py +0 -215
- aiq/eval/swe_bench_evaluator/register.py +0 -36
- aiq/eval/trajectory_evaluator/__init__.py +0 -0
- aiq/eval/trajectory_evaluator/evaluate.py +0 -118
- aiq/eval/trajectory_evaluator/register.py +0 -40
- aiq/eval/tunable_rag_evaluator/__init__.py +0 -0
- aiq/eval/tunable_rag_evaluator/evaluate.py +0 -263
- aiq/eval/tunable_rag_evaluator/register.py +0 -50
- aiq/eval/utils/__init__.py +0 -0
- aiq/eval/utils/output_uploader.py +0 -131
- aiq/eval/utils/tqdm_position_registry.py +0 -40
- aiq/front_ends/__init__.py +0 -14
- aiq/front_ends/console/__init__.py +0 -14
- aiq/front_ends/console/console_front_end_config.py +0 -32
- aiq/front_ends/console/console_front_end_plugin.py +0 -107
- aiq/front_ends/console/register.py +0 -25
- aiq/front_ends/cron/__init__.py +0 -14
- aiq/front_ends/fastapi/__init__.py +0 -14
- aiq/front_ends/fastapi/fastapi_front_end_config.py +0 -150
- aiq/front_ends/fastapi/fastapi_front_end_plugin.py +0 -103
- aiq/front_ends/fastapi/fastapi_front_end_plugin_worker.py +0 -607
- aiq/front_ends/fastapi/intermediate_steps_subscriber.py +0 -80
- aiq/front_ends/fastapi/job_store.py +0 -161
- aiq/front_ends/fastapi/main.py +0 -70
- aiq/front_ends/fastapi/message_handler.py +0 -279
- aiq/front_ends/fastapi/message_validator.py +0 -345
- aiq/front_ends/fastapi/register.py +0 -25
- aiq/front_ends/fastapi/response_helpers.py +0 -195
- aiq/front_ends/fastapi/step_adaptor.py +0 -320
- aiq/front_ends/fastapi/websocket.py +0 -148
- aiq/front_ends/mcp/__init__.py +0 -14
- aiq/front_ends/mcp/mcp_front_end_config.py +0 -32
- aiq/front_ends/mcp/mcp_front_end_plugin.py +0 -93
- aiq/front_ends/mcp/register.py +0 -27
- aiq/front_ends/mcp/tool_converter.py +0 -242
- aiq/front_ends/register.py +0 -22
- aiq/front_ends/simple_base/__init__.py +0 -14
- aiq/front_ends/simple_base/simple_front_end_plugin_base.py +0 -52
- aiq/llm/__init__.py +0 -0
- aiq/llm/nim_llm.py +0 -45
- aiq/llm/openai_llm.py +0 -45
- aiq/llm/register.py +0 -22
- aiq/llm/utils/__init__.py +0 -14
- aiq/llm/utils/env_config_value.py +0 -94
- aiq/llm/utils/error.py +0 -17
- aiq/memory/__init__.py +0 -20
- aiq/memory/interfaces.py +0 -183
- aiq/memory/models.py +0 -112
- aiq/meta/module_to_distro.json +0 -3
- aiq/meta/pypi.md +0 -58
- aiq/observability/__init__.py +0 -0
- aiq/observability/async_otel_listener.py +0 -429
- aiq/observability/register.py +0 -99
- aiq/plugins/.namespace +0 -1
- aiq/profiler/__init__.py +0 -0
- aiq/profiler/callbacks/__init__.py +0 -0
- aiq/profiler/callbacks/agno_callback_handler.py +0 -295
- aiq/profiler/callbacks/base_callback_class.py +0 -20
- aiq/profiler/callbacks/langchain_callback_handler.py +0 -278
- aiq/profiler/callbacks/llama_index_callback_handler.py +0 -205
- aiq/profiler/callbacks/semantic_kernel_callback_handler.py +0 -238
- aiq/profiler/callbacks/token_usage_base_model.py +0 -27
- aiq/profiler/data_frame_row.py +0 -51
- aiq/profiler/decorators/__init__.py +0 -0
- aiq/profiler/decorators/framework_wrapper.py +0 -131
- aiq/profiler/decorators/function_tracking.py +0 -254
- aiq/profiler/forecasting/__init__.py +0 -0
- aiq/profiler/forecasting/config.py +0 -18
- aiq/profiler/forecasting/model_trainer.py +0 -75
- aiq/profiler/forecasting/models/__init__.py +0 -22
- aiq/profiler/forecasting/models/forecasting_base_model.py +0 -40
- aiq/profiler/forecasting/models/linear_model.py +0 -196
- aiq/profiler/forecasting/models/random_forest_regressor.py +0 -268
- aiq/profiler/inference_metrics_model.py +0 -25
- aiq/profiler/inference_optimization/__init__.py +0 -0
- aiq/profiler/inference_optimization/bottleneck_analysis/__init__.py +0 -0
- aiq/profiler/inference_optimization/bottleneck_analysis/nested_stack_analysis.py +0 -452
- aiq/profiler/inference_optimization/bottleneck_analysis/simple_stack_analysis.py +0 -258
- aiq/profiler/inference_optimization/data_models.py +0 -386
- aiq/profiler/inference_optimization/experimental/__init__.py +0 -0
- aiq/profiler/inference_optimization/experimental/concurrency_spike_analysis.py +0 -468
- aiq/profiler/inference_optimization/experimental/prefix_span_analysis.py +0 -405
- aiq/profiler/inference_optimization/llm_metrics.py +0 -212
- aiq/profiler/inference_optimization/prompt_caching.py +0 -163
- aiq/profiler/inference_optimization/token_uniqueness.py +0 -107
- aiq/profiler/inference_optimization/workflow_runtimes.py +0 -72
- aiq/profiler/intermediate_property_adapter.py +0 -102
- aiq/profiler/profile_runner.py +0 -433
- aiq/profiler/utils.py +0 -184
- aiq/registry_handlers/__init__.py +0 -0
- aiq/registry_handlers/local/__init__.py +0 -0
- aiq/registry_handlers/local/local_handler.py +0 -176
- aiq/registry_handlers/local/register_local.py +0 -37
- aiq/registry_handlers/metadata_factory.py +0 -60
- aiq/registry_handlers/package_utils.py +0 -198
- aiq/registry_handlers/pypi/__init__.py +0 -0
- aiq/registry_handlers/pypi/pypi_handler.py +0 -251
- aiq/registry_handlers/pypi/register_pypi.py +0 -40
- aiq/registry_handlers/register.py +0 -21
- aiq/registry_handlers/registry_handler_base.py +0 -157
- aiq/registry_handlers/rest/__init__.py +0 -0
- aiq/registry_handlers/rest/register_rest.py +0 -56
- aiq/registry_handlers/rest/rest_handler.py +0 -237
- aiq/registry_handlers/schemas/__init__.py +0 -0
- aiq/registry_handlers/schemas/headers.py +0 -42
- aiq/registry_handlers/schemas/package.py +0 -68
- aiq/registry_handlers/schemas/publish.py +0 -63
- aiq/registry_handlers/schemas/pull.py +0 -82
- aiq/registry_handlers/schemas/remove.py +0 -36
- aiq/registry_handlers/schemas/search.py +0 -91
- aiq/registry_handlers/schemas/status.py +0 -47
- aiq/retriever/__init__.py +0 -0
- aiq/retriever/interface.py +0 -37
- aiq/retriever/milvus/__init__.py +0 -14
- aiq/retriever/milvus/register.py +0 -81
- aiq/retriever/milvus/retriever.py +0 -228
- aiq/retriever/models.py +0 -74
- aiq/retriever/nemo_retriever/__init__.py +0 -14
- aiq/retriever/nemo_retriever/register.py +0 -60
- aiq/retriever/nemo_retriever/retriever.py +0 -190
- aiq/retriever/register.py +0 -22
- aiq/runtime/__init__.py +0 -14
- aiq/runtime/loader.py +0 -188
- aiq/runtime/runner.py +0 -176
- aiq/runtime/session.py +0 -140
- aiq/runtime/user_metadata.py +0 -131
- aiq/settings/__init__.py +0 -0
- aiq/settings/global_settings.py +0 -318
- aiq/test/.namespace +0 -1
- aiq/tool/__init__.py +0 -0
- aiq/tool/code_execution/__init__.py +0 -0
- aiq/tool/code_execution/code_sandbox.py +0 -188
- aiq/tool/code_execution/local_sandbox/Dockerfile.sandbox +0 -60
- aiq/tool/code_execution/local_sandbox/__init__.py +0 -13
- aiq/tool/code_execution/local_sandbox/local_sandbox_server.py +0 -83
- aiq/tool/code_execution/local_sandbox/sandbox.requirements.txt +0 -4
- aiq/tool/code_execution/local_sandbox/start_local_sandbox.sh +0 -25
- aiq/tool/code_execution/register.py +0 -70
- aiq/tool/code_execution/utils.py +0 -100
- aiq/tool/datetime_tools.py +0 -42
- aiq/tool/document_search.py +0 -141
- aiq/tool/github_tools/__init__.py +0 -0
- aiq/tool/github_tools/create_github_commit.py +0 -133
- aiq/tool/github_tools/create_github_issue.py +0 -87
- aiq/tool/github_tools/create_github_pr.py +0 -106
- aiq/tool/github_tools/get_github_file.py +0 -106
- aiq/tool/github_tools/get_github_issue.py +0 -166
- aiq/tool/github_tools/get_github_pr.py +0 -256
- aiq/tool/github_tools/update_github_issue.py +0 -100
- aiq/tool/mcp/__init__.py +0 -14
- aiq/tool/mcp/mcp_client.py +0 -220
- aiq/tool/mcp/mcp_tool.py +0 -95
- aiq/tool/memory_tools/__init__.py +0 -0
- aiq/tool/memory_tools/add_memory_tool.py +0 -79
- aiq/tool/memory_tools/delete_memory_tool.py +0 -67
- aiq/tool/memory_tools/get_memory_tool.py +0 -72
- aiq/tool/nvidia_rag.py +0 -95
- aiq/tool/register.py +0 -37
- aiq/tool/retriever.py +0 -89
- aiq/tool/server_tools.py +0 -63
- aiq/utils/__init__.py +0 -0
- aiq/utils/data_models/__init__.py +0 -0
- aiq/utils/data_models/schema_validator.py +0 -58
- aiq/utils/debugging_utils.py +0 -43
- aiq/utils/exception_handlers/__init__.py +0 -0
- aiq/utils/exception_handlers/schemas.py +0 -114
- aiq/utils/io/__init__.py +0 -0
- aiq/utils/io/yaml_tools.py +0 -119
- aiq/utils/metadata_utils.py +0 -74
- aiq/utils/optional_imports.py +0 -142
- aiq/utils/producer_consumer_queue.py +0 -178
- aiq/utils/reactive/__init__.py +0 -0
- aiq/utils/reactive/base/__init__.py +0 -0
- aiq/utils/reactive/base/observable_base.py +0 -65
- aiq/utils/reactive/base/observer_base.py +0 -55
- aiq/utils/reactive/base/subject_base.py +0 -79
- aiq/utils/reactive/observable.py +0 -59
- aiq/utils/reactive/observer.py +0 -76
- aiq/utils/reactive/subject.py +0 -131
- aiq/utils/reactive/subscription.py +0 -49
- aiq/utils/settings/__init__.py +0 -0
- aiq/utils/settings/global_settings.py +0 -197
- aiq/utils/type_converter.py +0 -232
- aiq/utils/type_utils.py +0 -397
- aiq/utils/url_utils.py +0 -27
- aiqtoolkit-1.1.0rc5.dist-info/METADATA +0 -331
- aiqtoolkit-1.1.0rc5.dist-info/RECORD +0 -316
- aiqtoolkit-1.1.0rc5.dist-info/entry_points.txt +0 -17
- aiqtoolkit-1.1.0rc5.dist-info/licenses/LICENSE-3rd-party.txt +0 -3686
- aiqtoolkit-1.1.0rc5.dist-info/licenses/LICENSE.md +0 -201
- aiqtoolkit-1.1.0rc5.dist-info/top_level.txt +0 -1
|
@@ -1,123 +0,0 @@
|
|
|
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
|
-
# pylint: disable=R0917
|
|
17
|
-
import logging
|
|
18
|
-
|
|
19
|
-
from langchain_core.callbacks.base import AsyncCallbackHandler
|
|
20
|
-
from langchain_core.language_models import BaseChatModel
|
|
21
|
-
from langchain_core.messages.base import BaseMessage
|
|
22
|
-
from langchain_core.runnables import RunnableConfig
|
|
23
|
-
from langchain_core.tools import BaseTool
|
|
24
|
-
from langgraph.prebuilt import ToolNode
|
|
25
|
-
from pydantic import BaseModel
|
|
26
|
-
from pydantic import Field
|
|
27
|
-
|
|
28
|
-
from aiq.agent.base import AGENT_LOG_PREFIX
|
|
29
|
-
from aiq.agent.base import AGENT_RESPONSE_LOG_MESSAGE
|
|
30
|
-
from aiq.agent.base import TOOL_RESPONSE_LOG_MESSAGE
|
|
31
|
-
from aiq.agent.base import AgentDecision
|
|
32
|
-
from aiq.agent.dual_node import DualNodeAgent
|
|
33
|
-
|
|
34
|
-
logger = logging.getLogger(__name__)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class ToolCallAgentGraphState(BaseModel):
|
|
38
|
-
"""State schema for the Tool Calling Agent Graph"""
|
|
39
|
-
messages: list[BaseMessage] = Field(default_factory=list) # input and output of the Agent
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
class ToolCallAgentGraph(DualNodeAgent):
|
|
43
|
-
"""Configurable LangGraph Tool Calling Agent. A Tool Calling Agent requires an LLM which supports tool calling.
|
|
44
|
-
A tool Calling Agent utilizes the tool input parameters to select the optimal tool. Supports handling tool errors.
|
|
45
|
-
Argument "detailed_logs" toggles logging of inputs, outputs, and intermediate steps."""
|
|
46
|
-
|
|
47
|
-
def __init__(self,
|
|
48
|
-
llm: BaseChatModel,
|
|
49
|
-
tools: list[BaseTool],
|
|
50
|
-
callbacks: list[AsyncCallbackHandler] = None,
|
|
51
|
-
detailed_logs: bool = False,
|
|
52
|
-
handle_tool_errors: bool = True):
|
|
53
|
-
super().__init__(llm=llm, tools=tools, callbacks=callbacks, detailed_logs=detailed_logs)
|
|
54
|
-
self.tool_caller = ToolNode(tools, handle_tool_errors=handle_tool_errors)
|
|
55
|
-
logger.debug("%s Initialized Tool Calling Agent Graph", AGENT_LOG_PREFIX)
|
|
56
|
-
|
|
57
|
-
async def agent_node(self, state: ToolCallAgentGraphState):
|
|
58
|
-
try:
|
|
59
|
-
logger.debug('%s Starting the Tool Calling Agent Node', AGENT_LOG_PREFIX)
|
|
60
|
-
if len(state.messages) == 0:
|
|
61
|
-
raise RuntimeError('No input received in state: "messages"')
|
|
62
|
-
response = await self.llm.ainvoke(state.messages, config=RunnableConfig(callbacks=self.callbacks))
|
|
63
|
-
if self.detailed_logs:
|
|
64
|
-
agent_input = "\n".join(str(message.content) for message in state.messages)
|
|
65
|
-
logger.info(AGENT_RESPONSE_LOG_MESSAGE, agent_input, response)
|
|
66
|
-
|
|
67
|
-
state.messages += [response]
|
|
68
|
-
return state
|
|
69
|
-
except Exception as ex:
|
|
70
|
-
logger.exception("%s Failed to call agent_node: %s", AGENT_LOG_PREFIX, ex, exc_info=True)
|
|
71
|
-
raise ex
|
|
72
|
-
|
|
73
|
-
async def conditional_edge(self, state: ToolCallAgentGraphState):
|
|
74
|
-
try:
|
|
75
|
-
logger.debug("%s Starting the Tool Calling Conditional Edge", AGENT_LOG_PREFIX)
|
|
76
|
-
last_message = state.messages[-1]
|
|
77
|
-
if last_message.tool_calls:
|
|
78
|
-
# the agent wants to call a tool
|
|
79
|
-
logger.debug('%s Agent is calling a tool', AGENT_LOG_PREFIX)
|
|
80
|
-
return AgentDecision.TOOL
|
|
81
|
-
if self.detailed_logs:
|
|
82
|
-
logger.debug("%s Final answer:\n%s", AGENT_LOG_PREFIX, state.messages[-1].content)
|
|
83
|
-
return AgentDecision.END
|
|
84
|
-
except Exception as ex:
|
|
85
|
-
logger.exception("%s Failed to determine whether agent is calling a tool: %s",
|
|
86
|
-
AGENT_LOG_PREFIX,
|
|
87
|
-
ex,
|
|
88
|
-
exc_info=True)
|
|
89
|
-
logger.warning("%s Ending graph traversal", AGENT_LOG_PREFIX)
|
|
90
|
-
return AgentDecision.END
|
|
91
|
-
|
|
92
|
-
async def tool_node(self, state: ToolCallAgentGraphState):
|
|
93
|
-
try:
|
|
94
|
-
logger.debug("%s Starting Tool Node", AGENT_LOG_PREFIX)
|
|
95
|
-
tool_calls = state.messages[-1].tool_calls
|
|
96
|
-
tools = [tool.get('name') for tool in tool_calls]
|
|
97
|
-
tool_input = state.messages[-1]
|
|
98
|
-
tool_response = await self.tool_caller.ainvoke(input={"messages": [tool_input]},
|
|
99
|
-
config=RunnableConfig(callbacks=self.callbacks,
|
|
100
|
-
configurable={}))
|
|
101
|
-
# this configurable = {} argument is needed due to a bug in LangGraph PreBuilt ToolNode ^
|
|
102
|
-
|
|
103
|
-
for response in tool_response.get('messages'):
|
|
104
|
-
if self.detailed_logs:
|
|
105
|
-
# The tool response can be very large, so we log only the first 1000 characters
|
|
106
|
-
response.content = response.content[:1000] + "..." if len(
|
|
107
|
-
response.content) > 1000 else response.content
|
|
108
|
-
logger.info(TOOL_RESPONSE_LOG_MESSAGE, tools, tool_input, response.content)
|
|
109
|
-
state.messages += [response]
|
|
110
|
-
|
|
111
|
-
return state
|
|
112
|
-
except Exception as ex:
|
|
113
|
-
logger.exception("%s Failed to call tool_node: %s", AGENT_LOG_PREFIX, ex, exc_info=ex)
|
|
114
|
-
raise ex
|
|
115
|
-
|
|
116
|
-
async def build_graph(self):
|
|
117
|
-
try:
|
|
118
|
-
await super()._build_graph(state_schema=ToolCallAgentGraphState)
|
|
119
|
-
logger.debug("%s Tool Calling Agent Graph built and compiled successfully", AGENT_LOG_PREFIX)
|
|
120
|
-
return self.graph
|
|
121
|
-
except Exception as ex:
|
|
122
|
-
logger.exception("%s Failed to build Tool Calling Agent Graph: %s", AGENT_LOG_PREFIX, ex, exc_info=ex)
|
|
123
|
-
raise ex
|
|
@@ -1,105 +0,0 @@
|
|
|
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
|
-
import logging
|
|
17
|
-
|
|
18
|
-
from pydantic import Field
|
|
19
|
-
|
|
20
|
-
from aiq.agent.base import AGENT_LOG_PREFIX
|
|
21
|
-
from aiq.builder.builder import Builder
|
|
22
|
-
from aiq.builder.framework_enum import LLMFrameworkEnum
|
|
23
|
-
from aiq.builder.function_info import FunctionInfo
|
|
24
|
-
from aiq.cli.register_workflow import register_function
|
|
25
|
-
from aiq.data_models.component_ref import FunctionRef
|
|
26
|
-
from aiq.data_models.component_ref import LLMRef
|
|
27
|
-
from aiq.data_models.function import FunctionBaseConfig
|
|
28
|
-
|
|
29
|
-
logger = logging.getLogger(__name__)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class ToolCallAgentWorkflowConfig(FunctionBaseConfig, name="tool_calling_agent"):
|
|
33
|
-
"""
|
|
34
|
-
A Tool Calling Agent requires an LLM which supports tool calling. A tool Calling Agent utilizes the tool
|
|
35
|
-
input parameters to select the optimal tool. Supports handling tool errors.
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
tool_names: list[FunctionRef] = Field(default_factory=list,
|
|
39
|
-
description="The list of tools to provide to the tool calling agent.")
|
|
40
|
-
llm_name: LLMRef = Field(description="The LLM model to use with the tool calling agent.")
|
|
41
|
-
verbose: bool = Field(default=False, description="Set the verbosity of the react agent's logging.")
|
|
42
|
-
handle_tool_errors: bool = Field(default=True, description="Specify ability to handle tool calling errors.")
|
|
43
|
-
description: str = Field(default="Tool Calling Agent Workflow", description="Description of this functions use.")
|
|
44
|
-
max_iterations: int = Field(default=15, description="Number of tool calls before stoping the tool calling agent.")
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
@register_function(config_type=ToolCallAgentWorkflowConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN])
|
|
48
|
-
async def tool_calling_agent_workflow(config: ToolCallAgentWorkflowConfig, builder: Builder):
|
|
49
|
-
from langchain_core.messages.human import HumanMessage
|
|
50
|
-
from langgraph.graph.graph import CompiledGraph
|
|
51
|
-
|
|
52
|
-
from .agent import ToolCallAgentGraph
|
|
53
|
-
from .agent import ToolCallAgentGraphState
|
|
54
|
-
|
|
55
|
-
# we can choose an LLM for the ReAct agent in the config file
|
|
56
|
-
llm = await builder.get_llm(config.llm_name, wrapper_type=LLMFrameworkEnum.LANGCHAIN)
|
|
57
|
-
# the agent can run any installed tool, simply install the tool and add it to the config file
|
|
58
|
-
# the sample tools provided can easily be copied or changed
|
|
59
|
-
tools = builder.get_tools(tool_names=config.tool_names, wrapper_type=LLMFrameworkEnum.LANGCHAIN)
|
|
60
|
-
if not tools:
|
|
61
|
-
raise ValueError(f"No tools specified for Tool Calling Agent '{config.llm_name}'")
|
|
62
|
-
|
|
63
|
-
# some LLMs support tool calling
|
|
64
|
-
# these models accept the tool's input schema and decide when to use a tool based on the input's relevance
|
|
65
|
-
try:
|
|
66
|
-
# in tool calling agents, we bind the tools to the LLM, to pass the tools' input schemas at runtime
|
|
67
|
-
llm = llm.bind_tools(tools)
|
|
68
|
-
except NotImplementedError as ex:
|
|
69
|
-
logger.error("%s Failed to bind tools: %s", AGENT_LOG_PREFIX, ex, exc_info=True)
|
|
70
|
-
raise ex
|
|
71
|
-
|
|
72
|
-
# construct the Tool Calling Agent Graph from the configured llm, and tools
|
|
73
|
-
graph: CompiledGraph = await ToolCallAgentGraph(llm=llm,
|
|
74
|
-
tools=tools,
|
|
75
|
-
detailed_logs=config.verbose,
|
|
76
|
-
handle_tool_errors=config.handle_tool_errors).build_graph()
|
|
77
|
-
|
|
78
|
-
async def _response_fn(input_message: str) -> str:
|
|
79
|
-
try:
|
|
80
|
-
# initialize the starting state with the user query
|
|
81
|
-
input_message = HumanMessage(content=input_message)
|
|
82
|
-
state = ToolCallAgentGraphState(messages=[input_message])
|
|
83
|
-
|
|
84
|
-
# run the Tool Calling Agent Graph
|
|
85
|
-
state = await graph.ainvoke(state, config={'recursion_limit': (config.max_iterations + 1) * 2})
|
|
86
|
-
# setting recursion_limit: 4 allows 1 tool call
|
|
87
|
-
# - allows the Tool Calling Agent to perform 1 cycle / call 1 single tool,
|
|
88
|
-
# - but stops the agent when it tries to call a tool a second time
|
|
89
|
-
|
|
90
|
-
# get and return the output from the state
|
|
91
|
-
state = ToolCallAgentGraphState(**state)
|
|
92
|
-
output_message = state.messages[-1] # pylint: disable=E1136
|
|
93
|
-
return output_message.content
|
|
94
|
-
except Exception as ex:
|
|
95
|
-
logger.exception("%s Tool Calling Agent failed with exception: %s", AGENT_LOG_PREFIX, ex, exc_info=ex)
|
|
96
|
-
if config.verbose:
|
|
97
|
-
return str(ex)
|
|
98
|
-
return "I seem to be having a problem."
|
|
99
|
-
|
|
100
|
-
try:
|
|
101
|
-
yield FunctionInfo.from_fn(_response_fn, description=config.description)
|
|
102
|
-
except GeneratorExit:
|
|
103
|
-
logger.exception("%s Workflow exited early!", AGENT_LOG_PREFIX, exc_info=True)
|
|
104
|
-
finally:
|
|
105
|
-
logger.debug("%s Cleaning up react_agent workflow.", AGENT_LOG_PREFIX)
|
aiq/builder/__init__.py
DELETED
|
File without changes
|
aiq/builder/builder.py
DELETED
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: Copyright (c) 2024-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
|
-
import asyncio
|
|
17
|
-
import typing
|
|
18
|
-
from abc import ABC
|
|
19
|
-
from abc import abstractmethod
|
|
20
|
-
from collections.abc import Sequence
|
|
21
|
-
from pathlib import Path
|
|
22
|
-
|
|
23
|
-
from aiq.builder.context import AIQContext
|
|
24
|
-
from aiq.builder.framework_enum import LLMFrameworkEnum
|
|
25
|
-
from aiq.builder.function import Function
|
|
26
|
-
from aiq.data_models.component_ref import EmbedderRef
|
|
27
|
-
from aiq.data_models.component_ref import FunctionRef
|
|
28
|
-
from aiq.data_models.component_ref import LLMRef
|
|
29
|
-
from aiq.data_models.component_ref import MemoryRef
|
|
30
|
-
from aiq.data_models.component_ref import RetrieverRef
|
|
31
|
-
from aiq.data_models.embedder import EmbedderBaseConfig
|
|
32
|
-
from aiq.data_models.evaluator import EvaluatorBaseConfig
|
|
33
|
-
from aiq.data_models.function import FunctionBaseConfig
|
|
34
|
-
from aiq.data_models.function_dependencies import FunctionDependencies
|
|
35
|
-
from aiq.data_models.llm import LLMBaseConfig
|
|
36
|
-
from aiq.data_models.memory import MemoryBaseConfig
|
|
37
|
-
from aiq.data_models.retriever import RetrieverBaseConfig
|
|
38
|
-
from aiq.memory.interfaces import MemoryEditor
|
|
39
|
-
from aiq.retriever.interface import AIQRetriever
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
class UserManagerHolder():
|
|
43
|
-
|
|
44
|
-
def __init__(self, context: AIQContext) -> None:
|
|
45
|
-
self._context = context
|
|
46
|
-
|
|
47
|
-
def get_id(self):
|
|
48
|
-
return self._context.user_manager.get_id()
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class Builder(ABC): # pylint: disable=too-many-public-methods
|
|
52
|
-
|
|
53
|
-
@abstractmethod
|
|
54
|
-
async def add_function(self, name: str | FunctionRef, config: FunctionBaseConfig) -> Function:
|
|
55
|
-
pass
|
|
56
|
-
|
|
57
|
-
@abstractmethod
|
|
58
|
-
def get_function(self, name: str | FunctionRef) -> Function:
|
|
59
|
-
pass
|
|
60
|
-
|
|
61
|
-
def get_functions(self, function_names: Sequence[str | FunctionRef]) -> list[Function]:
|
|
62
|
-
|
|
63
|
-
return [self.get_function(name) for name in function_names]
|
|
64
|
-
|
|
65
|
-
@abstractmethod
|
|
66
|
-
def get_function_config(self, name: str | FunctionRef) -> FunctionBaseConfig:
|
|
67
|
-
pass
|
|
68
|
-
|
|
69
|
-
@abstractmethod
|
|
70
|
-
async def set_workflow(self, config: FunctionBaseConfig) -> Function:
|
|
71
|
-
pass
|
|
72
|
-
|
|
73
|
-
@abstractmethod
|
|
74
|
-
def get_workflow(self) -> Function:
|
|
75
|
-
pass
|
|
76
|
-
|
|
77
|
-
@abstractmethod
|
|
78
|
-
def get_workflow_config(self) -> FunctionBaseConfig:
|
|
79
|
-
pass
|
|
80
|
-
|
|
81
|
-
def get_tools(self, tool_names: Sequence[str | FunctionRef],
|
|
82
|
-
wrapper_type: LLMFrameworkEnum | str) -> list[typing.Any]:
|
|
83
|
-
|
|
84
|
-
return [self.get_tool(fn_name=n, wrapper_type=wrapper_type) for n in tool_names]
|
|
85
|
-
|
|
86
|
-
@abstractmethod
|
|
87
|
-
def get_tool(self, fn_name: str | FunctionRef, wrapper_type: LLMFrameworkEnum | str) -> typing.Any:
|
|
88
|
-
pass
|
|
89
|
-
|
|
90
|
-
@abstractmethod
|
|
91
|
-
async def add_llm(self, name: str | LLMRef, config: LLMBaseConfig):
|
|
92
|
-
pass
|
|
93
|
-
|
|
94
|
-
async def get_llms(self, llm_names: Sequence[str | LLMRef],
|
|
95
|
-
wrapper_type: LLMFrameworkEnum | str) -> list[typing.Any]:
|
|
96
|
-
|
|
97
|
-
coros = [self.get_llm(llm_name=n, wrapper_type=wrapper_type) for n in llm_names]
|
|
98
|
-
|
|
99
|
-
llms = await asyncio.gather(*coros, return_exceptions=False)
|
|
100
|
-
|
|
101
|
-
return list(llms)
|
|
102
|
-
|
|
103
|
-
@abstractmethod
|
|
104
|
-
async def get_llm(self, llm_name: str | LLMRef, wrapper_type: LLMFrameworkEnum | str) -> typing.Any:
|
|
105
|
-
pass
|
|
106
|
-
|
|
107
|
-
@abstractmethod
|
|
108
|
-
def get_llm_config(self, llm_name: str | LLMRef) -> LLMBaseConfig:
|
|
109
|
-
pass
|
|
110
|
-
|
|
111
|
-
@abstractmethod
|
|
112
|
-
async def add_embedder(self, name: str | EmbedderRef, config: EmbedderBaseConfig):
|
|
113
|
-
pass
|
|
114
|
-
|
|
115
|
-
async def get_embedders(self, embedder_names: Sequence[str | EmbedderRef],
|
|
116
|
-
wrapper_type: LLMFrameworkEnum | str) -> list[typing.Any]:
|
|
117
|
-
|
|
118
|
-
coros = [self.get_embedder(embedder_name=n, wrapper_type=wrapper_type) for n in embedder_names]
|
|
119
|
-
|
|
120
|
-
embedders = await asyncio.gather(*coros, return_exceptions=False)
|
|
121
|
-
|
|
122
|
-
return list(embedders)
|
|
123
|
-
|
|
124
|
-
@abstractmethod
|
|
125
|
-
async def get_embedder(self, embedder_name: str | EmbedderRef, wrapper_type: LLMFrameworkEnum | str) -> typing.Any:
|
|
126
|
-
pass
|
|
127
|
-
|
|
128
|
-
@abstractmethod
|
|
129
|
-
def get_embedder_config(self, embedder_name: str | EmbedderRef) -> EmbedderBaseConfig:
|
|
130
|
-
pass
|
|
131
|
-
|
|
132
|
-
@abstractmethod
|
|
133
|
-
async def add_memory_client(self, name: str | MemoryRef, config: MemoryBaseConfig):
|
|
134
|
-
pass
|
|
135
|
-
|
|
136
|
-
def get_memory_clients(self, memory_names: Sequence[str | MemoryRef]) -> list[MemoryEditor]:
|
|
137
|
-
"""
|
|
138
|
-
Return a list of memory clients for the specified names.
|
|
139
|
-
"""
|
|
140
|
-
return [self.get_memory_client(n) for n in memory_names]
|
|
141
|
-
|
|
142
|
-
@abstractmethod
|
|
143
|
-
def get_memory_client(self, memory_name: str | MemoryRef) -> MemoryEditor:
|
|
144
|
-
"""
|
|
145
|
-
Return the instantiated memory client for the given name.
|
|
146
|
-
"""
|
|
147
|
-
pass
|
|
148
|
-
|
|
149
|
-
@abstractmethod
|
|
150
|
-
def get_memory_client_config(self, memory_name: str | MemoryRef) -> MemoryBaseConfig:
|
|
151
|
-
pass
|
|
152
|
-
|
|
153
|
-
@abstractmethod
|
|
154
|
-
async def add_retriever(self, name: str | RetrieverRef, config: RetrieverBaseConfig):
|
|
155
|
-
pass
|
|
156
|
-
|
|
157
|
-
async def get_retrievers(self,
|
|
158
|
-
retriever_names: Sequence[str | RetrieverRef],
|
|
159
|
-
wrapper_type: LLMFrameworkEnum | str | None = None):
|
|
160
|
-
|
|
161
|
-
tasks = [self.get_retriever(n, wrapper_type=wrapper_type) for n in retriever_names]
|
|
162
|
-
|
|
163
|
-
retrievers = await asyncio.gather(*tasks, return_exceptions=False)
|
|
164
|
-
|
|
165
|
-
return list(retrievers)
|
|
166
|
-
|
|
167
|
-
@typing.overload
|
|
168
|
-
async def get_retriever(self, retriever_name: str | RetrieverRef,
|
|
169
|
-
wrapper_type: LLMFrameworkEnum | str) -> typing.Any:
|
|
170
|
-
...
|
|
171
|
-
|
|
172
|
-
@typing.overload
|
|
173
|
-
async def get_retriever(self, retriever_name: str | RetrieverRef, wrapper_type: None) -> AIQRetriever:
|
|
174
|
-
...
|
|
175
|
-
|
|
176
|
-
@typing.overload
|
|
177
|
-
async def get_retriever(self, retriever_name: str | RetrieverRef) -> AIQRetriever:
|
|
178
|
-
...
|
|
179
|
-
|
|
180
|
-
@abstractmethod
|
|
181
|
-
async def get_retriever(self,
|
|
182
|
-
retriever_name: str | RetrieverRef,
|
|
183
|
-
wrapper_type: LLMFrameworkEnum | str | None = None) -> typing.Any:
|
|
184
|
-
pass
|
|
185
|
-
|
|
186
|
-
@abstractmethod
|
|
187
|
-
async def get_retriever_config(self, retriever_name: str | RetrieverRef) -> RetrieverBaseConfig:
|
|
188
|
-
pass
|
|
189
|
-
|
|
190
|
-
@abstractmethod
|
|
191
|
-
def get_user_manager(self) -> UserManagerHolder:
|
|
192
|
-
pass
|
|
193
|
-
|
|
194
|
-
@abstractmethod
|
|
195
|
-
def get_function_dependencies(self, fn_name: str) -> FunctionDependencies:
|
|
196
|
-
pass
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
class EvalBuilder(Builder):
|
|
200
|
-
|
|
201
|
-
@abstractmethod
|
|
202
|
-
async def add_evaluator(self, name: str, config: EvaluatorBaseConfig):
|
|
203
|
-
pass
|
|
204
|
-
|
|
205
|
-
@abstractmethod
|
|
206
|
-
def get_evaluator(self, evaluator_name: str) -> typing.Any:
|
|
207
|
-
pass
|
|
208
|
-
|
|
209
|
-
@abstractmethod
|
|
210
|
-
def get_evaluator_config(self, evaluator_name: str) -> EvaluatorBaseConfig:
|
|
211
|
-
pass
|
|
212
|
-
|
|
213
|
-
@abstractmethod
|
|
214
|
-
def get_max_concurrency(self) -> int:
|
|
215
|
-
pass
|
|
216
|
-
|
|
217
|
-
@abstractmethod
|
|
218
|
-
def get_output_dir(self) -> Path:
|
|
219
|
-
pass
|
|
220
|
-
|
|
221
|
-
@abstractmethod
|
|
222
|
-
def get_all_tools(self, wrapper_type: LLMFrameworkEnum | str) -> list[typing.Any]:
|
|
223
|
-
pass
|