aiqtoolkit 1.1.0a20250514__py3-none-any.whl → 1.1.0a20250516__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.
- aiq/builder/context.py +15 -0
- aiq/builder/intermediate_step_manager.py +73 -24
- aiq/front_ends/fastapi/step_adaptor.py +49 -44
- aiq/meta/pypi.md +14 -14
- aiq/observability/async_otel_listener.py +8 -5
- aiq/tool/mcp/mcp_tool.py +26 -7
- {aiqtoolkit-1.1.0a20250514.dist-info → aiqtoolkit-1.1.0a20250516.dist-info}/METADATA +16 -16
- {aiqtoolkit-1.1.0a20250514.dist-info → aiqtoolkit-1.1.0a20250516.dist-info}/RECORD +13 -13
- {aiqtoolkit-1.1.0a20250514.dist-info → aiqtoolkit-1.1.0a20250516.dist-info}/WHEEL +1 -1
- {aiqtoolkit-1.1.0a20250514.dist-info → aiqtoolkit-1.1.0a20250516.dist-info}/entry_points.txt +0 -0
- {aiqtoolkit-1.1.0a20250514.dist-info → aiqtoolkit-1.1.0a20250516.dist-info}/licenses/LICENSE-3rd-party.txt +0 -0
- {aiqtoolkit-1.1.0a20250514.dist-info → aiqtoolkit-1.1.0a20250516.dist-info}/licenses/LICENSE.md +0 -0
- {aiqtoolkit-1.1.0a20250514.dist-info → aiqtoolkit-1.1.0a20250516.dist-info}/top_level.txt +0 -0
aiq/builder/context.py
CHANGED
|
@@ -68,6 +68,8 @@ class AIQContextState(metaclass=Singleton):
|
|
|
68
68
|
self.active_function: ContextVar[InvocationNode] = ContextVar("active_function",
|
|
69
69
|
default=InvocationNode(function_id="root",
|
|
70
70
|
function_name="root"))
|
|
71
|
+
self.active_span_id_stack: ContextVar[list[str]] = ContextVar("active_span_id_stack", default=["root"])
|
|
72
|
+
|
|
71
73
|
# Default is a lambda no-op which returns NoneType
|
|
72
74
|
self.user_input_callback: ContextVar[Callable[[InteractionPrompt], Awaitable[HumanResponse | None]]
|
|
73
75
|
| None] = ContextVar(
|
|
@@ -198,6 +200,19 @@ class AIQContext:
|
|
|
198
200
|
"""
|
|
199
201
|
return self._context_state.active_function.get()
|
|
200
202
|
|
|
203
|
+
@property
|
|
204
|
+
def active_span_id(self) -> str:
|
|
205
|
+
"""
|
|
206
|
+
Retrieves the active span ID from the context state.
|
|
207
|
+
|
|
208
|
+
This property provides access to the active span ID stored in the context state. The active span ID represents
|
|
209
|
+
the currently running function/tool/llm/agent/etc and can be used to group telemetry data together.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
str: The active span ID.
|
|
213
|
+
"""
|
|
214
|
+
return self._context_state.active_span_id_stack.get()[-1]
|
|
215
|
+
|
|
201
216
|
@staticmethod
|
|
202
217
|
def get() -> "AIQContext":
|
|
203
218
|
"""
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
|
-
import contextvars
|
|
17
16
|
import dataclasses
|
|
18
17
|
import logging
|
|
18
|
+
import typing
|
|
19
19
|
|
|
20
20
|
from aiq.data_models.intermediate_step import IntermediateStep
|
|
21
21
|
from aiq.data_models.intermediate_step import IntermediateStepPayload
|
|
@@ -26,9 +26,10 @@ from aiq.utils.reactive.observable import OnError
|
|
|
26
26
|
from aiq.utils.reactive.observable import OnNext
|
|
27
27
|
from aiq.utils.reactive.subscription import Subscription
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
if typing.TYPE_CHECKING:
|
|
30
|
+
from aiq.builder.context import AIQContextState
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
@dataclasses.dataclass
|
|
@@ -37,8 +38,8 @@ class OpenStep:
|
|
|
37
38
|
step_name: str
|
|
38
39
|
step_type: str
|
|
39
40
|
step_parent_id: str | None
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
prev_stack: list[str]
|
|
42
|
+
active_stack: list[str]
|
|
42
43
|
|
|
43
44
|
|
|
44
45
|
class IntermediateStepManager:
|
|
@@ -59,18 +60,31 @@ class IntermediateStepManager:
|
|
|
59
60
|
if not isinstance(payload, IntermediateStepPayload):
|
|
60
61
|
raise TypeError(f"Payload must be of type IntermediateStepPayload, not {type(payload)}")
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
active_span_id_stack = self._context_state.active_span_id_stack.get()
|
|
63
64
|
|
|
64
65
|
if (payload.event_state == IntermediateStepState.START):
|
|
65
66
|
|
|
66
|
-
|
|
67
|
+
prev_stack = active_span_id_stack
|
|
68
|
+
|
|
69
|
+
parent_step_id = active_span_id_stack[-1]
|
|
70
|
+
|
|
71
|
+
# Note, this must not mutate the active_span_id_stack in place
|
|
72
|
+
active_span_id_stack = active_span_id_stack + [payload.UUID]
|
|
73
|
+
self._context_state.active_span_id_stack.set(active_span_id_stack)
|
|
67
74
|
|
|
68
75
|
self._outstanding_start_steps[payload.UUID] = OpenStep(step_id=payload.UUID,
|
|
69
|
-
step_name=payload.name,
|
|
76
|
+
step_name=payload.name or payload.UUID,
|
|
70
77
|
step_type=payload.event_type,
|
|
71
78
|
step_parent_id=parent_step_id,
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
prev_stack=prev_stack,
|
|
80
|
+
active_stack=active_span_id_stack)
|
|
81
|
+
|
|
82
|
+
logger.debug("Pushed start step %s, name %s, type %s, parent %s, stack id %s",
|
|
83
|
+
payload.UUID,
|
|
84
|
+
payload.name,
|
|
85
|
+
payload.event_type,
|
|
86
|
+
parent_step_id,
|
|
87
|
+
id(active_span_id_stack))
|
|
74
88
|
|
|
75
89
|
elif (payload.event_state == IntermediateStepState.END):
|
|
76
90
|
|
|
@@ -81,14 +95,49 @@ class IntermediateStepManager:
|
|
|
81
95
|
logger.warning("Step id %s not found in outstanding start steps", payload.UUID)
|
|
82
96
|
return
|
|
83
97
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
98
|
+
parent_step_id = open_step.step_parent_id
|
|
99
|
+
|
|
100
|
+
# Get the current and previous active span id stack.
|
|
101
|
+
curr_stack = open_step.active_stack
|
|
102
|
+
prev_stack = open_step.prev_stack
|
|
103
|
+
|
|
104
|
+
# To restore the stack, we need to handle two scenarios:
|
|
105
|
+
# 1. This function is called from a coroutine. In this case, the context variable will be the same as the
|
|
106
|
+
# one used in START. So we can just set the context variable to the previous stack.
|
|
107
|
+
# 2. This function is called from a task. In this case, the context variable will be separate from the one
|
|
108
|
+
# used in START so calling set() will have no effect. However, we still have a reference to the list used
|
|
109
|
+
# in START. So we update the reference to be equal to the old one.. So we need to update the current
|
|
110
|
+
# reference stack to be equal to the previous stack.
|
|
111
|
+
|
|
112
|
+
# Scenario 1: Restore the previous active span id stack in case we are in a coroutine. Dont use reset here
|
|
113
|
+
# since we can be in different contexts
|
|
114
|
+
self._context_state.active_span_id_stack.set(prev_stack)
|
|
115
|
+
|
|
116
|
+
pop_count = 0
|
|
117
|
+
|
|
118
|
+
# Scenario 2: Remove all steps from the current stack until we reach the parent step id to make it equal to
|
|
119
|
+
# the previous stack. In the coroutine case, this will not have any effect.
|
|
120
|
+
while (curr_stack[-1] != parent_step_id):
|
|
121
|
+
curr_stack.pop()
|
|
122
|
+
pop_count += 1
|
|
123
|
+
|
|
124
|
+
if (pop_count != 1):
|
|
125
|
+
logger.warning(
|
|
126
|
+
"Step id %s not the last step in the stack. "
|
|
127
|
+
"Removing it from the stack but this is likely an error",
|
|
128
|
+
payload.UUID)
|
|
129
|
+
|
|
130
|
+
# Verify that the stack is now equal to the previous stack
|
|
131
|
+
if (curr_stack != prev_stack):
|
|
132
|
+
logger.warning("Current span ID stack is not equal to the previous stack. "
|
|
133
|
+
"This is likely an error. Report this to the AIQ team.")
|
|
134
|
+
|
|
135
|
+
logger.debug("Popped end step %s, name %s, type %s, parent %s, stack id %s",
|
|
136
|
+
payload.UUID,
|
|
137
|
+
payload.name,
|
|
138
|
+
payload.event_type,
|
|
139
|
+
parent_step_id,
|
|
140
|
+
id(curr_stack))
|
|
92
141
|
|
|
93
142
|
elif (payload.event_state == IntermediateStepState.CHUNK):
|
|
94
143
|
|
|
@@ -103,14 +152,14 @@ class IntermediateStepManager:
|
|
|
103
152
|
payload.UUID)
|
|
104
153
|
return
|
|
105
154
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
155
|
+
parent_step_id = open_step.step_parent_id
|
|
156
|
+
|
|
157
|
+
active_function = self._context_state.active_function.get()
|
|
109
158
|
|
|
110
|
-
function_ancestry = InvocationNode(function_name=
|
|
111
|
-
function_id=
|
|
159
|
+
function_ancestry = InvocationNode(function_name=active_function.function_name,
|
|
160
|
+
function_id=active_function.function_id,
|
|
112
161
|
parent_id=parent_step_id,
|
|
113
|
-
parent_name=
|
|
162
|
+
parent_name=active_function.parent_name)
|
|
114
163
|
|
|
115
164
|
intermediate_step = IntermediateStep(function_ancestry=function_ancestry, payload=payload)
|
|
116
165
|
|
|
@@ -51,9 +51,9 @@ class StepAdaptor:
|
|
|
51
51
|
# default existing behavior: show LLM events + TOOL_END + FUNCTION events
|
|
52
52
|
if step.event_category == IntermediateStepCategory.LLM:
|
|
53
53
|
return True
|
|
54
|
-
if step.
|
|
54
|
+
if step.event_category == IntermediateStepCategory.TOOL:
|
|
55
55
|
return True
|
|
56
|
-
if step.
|
|
56
|
+
if step.event_category == IntermediateStepCategory.FUNCTION:
|
|
57
57
|
return True
|
|
58
58
|
return False
|
|
59
59
|
|
|
@@ -120,39 +120,57 @@ class StepAdaptor:
|
|
|
120
120
|
|
|
121
121
|
return event
|
|
122
122
|
|
|
123
|
-
def
|
|
124
|
-
ancestry: InvocationNode) -> AIQResponseSerializable | None:
|
|
123
|
+
def _handle_tool(self, step: IntermediateStepPayload, ancestry: InvocationNode) -> AIQResponseSerializable | None:
|
|
125
124
|
"""
|
|
126
|
-
Handles
|
|
125
|
+
Handles both TOOL_START and TOOL_END events
|
|
127
126
|
"""
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
input_str: str | None = None
|
|
128
|
+
output_str: str | None = None
|
|
130
129
|
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
# Find the start in the history with matching run_id
|
|
131
|
+
start_step = next(
|
|
132
|
+
(x for x in self._history if x.event_type == IntermediateStepType.TOOL_START and x.UUID == step.UUID), None)
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
if not start_step:
|
|
135
|
+
# If we don't have a start step, we can't do anything
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
input_str = str(start_step.data.input)
|
|
139
|
+
|
|
140
|
+
if step.event_type == IntermediateStepType.TOOL_END:
|
|
141
|
+
output_str = str(step.data.output)
|
|
142
|
+
|
|
143
|
+
if not input_str and not output_str:
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
escaped_input = html.escape(input_str, quote=False)
|
|
147
|
+
format_input_type = "json" if is_valid_json(escaped_input) else "python"
|
|
137
148
|
|
|
138
149
|
# Dont use f-strings here because the payload is markdown and screws up the dedent
|
|
139
|
-
|
|
150
|
+
payload = dedent("""
|
|
140
151
|
**Input:**
|
|
141
152
|
```{format_input_type}
|
|
142
153
|
{input_value}
|
|
143
154
|
```
|
|
144
|
-
|
|
145
|
-
```{format_output_type}
|
|
146
|
-
{output_value}
|
|
147
|
-
```
|
|
148
|
-
""").strip("\n").format(input_value=escaped_tool_input,
|
|
149
|
-
output_value=escaped_tool_output,
|
|
150
|
-
format_input_type=format_input_type,
|
|
151
|
-
format_output_type=format_output_type)
|
|
155
|
+
""").strip("\n").format(input_value=escaped_input, format_input_type=format_input_type)
|
|
152
156
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
157
|
+
if output_str:
|
|
158
|
+
escaped_output = html.escape(output_str, quote=False)
|
|
159
|
+
format_output_type = "json" if is_valid_json(escaped_output) else "python"
|
|
160
|
+
|
|
161
|
+
# Dont use f-strings here because the payload is markdown and screws up the dedent
|
|
162
|
+
payload = dedent("""
|
|
163
|
+
{payload}
|
|
164
|
+
|
|
165
|
+
**Output:**
|
|
166
|
+
```{format_output_type}
|
|
167
|
+
{output_value}
|
|
168
|
+
```
|
|
169
|
+
""").strip("\n").format(payload=payload, output_value=escaped_output, format_output_type=format_output_type)
|
|
170
|
+
|
|
171
|
+
event = AIQResponseIntermediateStep(id=step.UUID,
|
|
172
|
+
name=f"Tool: {step.name}",
|
|
173
|
+
payload=payload,
|
|
156
174
|
parent_id=ancestry.function_id)
|
|
157
175
|
|
|
158
176
|
return event
|
|
@@ -284,29 +302,16 @@ class StepAdaptor:
|
|
|
284
302
|
|
|
285
303
|
try:
|
|
286
304
|
|
|
287
|
-
if
|
|
288
|
-
|
|
289
|
-
if step.event_category == IntermediateStepCategory.LLM:
|
|
290
|
-
return self._handle_llm(payload, ancestry)
|
|
291
|
-
|
|
292
|
-
if step.event_type == IntermediateStepType.TOOL_END:
|
|
293
|
-
return self._handle_tool_end(payload, ancestry)
|
|
294
|
-
|
|
295
|
-
if step.event_type in [IntermediateStepType.FUNCTION_START, IntermediateStepType.FUNCTION_END]:
|
|
296
|
-
return self._handle_function(payload, ancestry)
|
|
297
|
-
|
|
298
|
-
if self.config.mode == StepAdaptorMode.CUSTOM:
|
|
299
|
-
# Now we're processing user defined custom types
|
|
300
|
-
|
|
301
|
-
if step.event_category == IntermediateStepCategory.LLM:
|
|
302
|
-
return self._handle_llm(payload, ancestry)
|
|
305
|
+
if step.event_category == IntermediateStepCategory.LLM:
|
|
306
|
+
return self._handle_llm(payload, ancestry)
|
|
303
307
|
|
|
304
|
-
|
|
305
|
-
|
|
308
|
+
if step.event_category == IntermediateStepCategory.TOOL:
|
|
309
|
+
return self._handle_tool(payload, ancestry)
|
|
306
310
|
|
|
307
|
-
|
|
308
|
-
|
|
311
|
+
if step.event_category == IntermediateStepCategory.FUNCTION:
|
|
312
|
+
return self._handle_function(payload, ancestry)
|
|
309
313
|
|
|
314
|
+
if step.event_category == IntermediateStepCategory.CUSTOM:
|
|
310
315
|
return self._handle_custom(payload, ancestry)
|
|
311
316
|
|
|
312
317
|
except Exception as e:
|
aiq/meta/pypi.md
CHANGED
|
@@ -15,30 +15,30 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
-->
|
|
17
17
|
|
|
18
|
-

|
|
19
19
|
|
|
20
20
|
# NVIDIA Agent Intelligence Toolkit
|
|
21
21
|
|
|
22
|
-
AIQ
|
|
22
|
+
AIQ toolkit is a flexible library designed to seamlessly integrate your enterprise agents—regardless of framework—with various data sources and tools. By treating agents, tools, and agentic workflows as simple function calls, AIQ toolkit enables true composability: build once and reuse anywhere.
|
|
23
23
|
|
|
24
24
|
## Key Features
|
|
25
25
|
|
|
26
|
-
- [**Framework Agnostic:**](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
27
|
-
- [**Reusability:**](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
28
|
-
- [**Rapid Development:**](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
29
|
-
- [**Profiling:**](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
30
|
-
- [**Observability:**](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
31
|
-
- [**Evaluation System:**](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
32
|
-
- [**User Interface:**](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
33
|
-
- [**MCP Compatibility**](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
26
|
+
- [**Framework Agnostic:**](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/extend/plugins.html) Works with any agentic framework, so you can use your current technology stack without replatforming.
|
|
27
|
+
- [**Reusability:**](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/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/aiqtoolkit/v1.1.0a20250516/tutorials/index.html) Start with a pre-built agent, tool, or workflow, and customize it to your needs.
|
|
29
|
+
- [**Profiling:**](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/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/aiqtoolkit/v1.1.0a20250516/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/aiqtoolkit/v1.1.0a20250516/workflows/observe/observe-workflow-with-phoenix.html) and [W&B Weave](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/workflows/observe/observe-workflow-with-weave.html).
|
|
31
|
+
- [**Evaluation System:**](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/workflows/evaluate.html) Validate and maintain accuracy of agentic workflows with built-in evaluation tools.
|
|
32
|
+
- [**User Interface:**](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/quick-start/launching-ui.html) Use the AIQ toolkit UI chat interface to interact with your agents, visualize output, and debug workflows.
|
|
33
|
+
- [**MCP Compatibility**](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/workflows/mcp/mcp-client.html) Compatible with Model Context Protocol (MCP), allowing tools served by MCP Servers to be used as AIQ toolkit functions.
|
|
34
34
|
|
|
35
|
-
With AIQ
|
|
35
|
+
With AIQ 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/aiqtoolkit/v1.1.
|
|
38
|
+
* [Documentation](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/index.html): Explore the full documentation for AIQ toolkit.
|
|
39
39
|
|
|
40
40
|
## First time user?
|
|
41
|
-
If this is your first time using AIQ
|
|
41
|
+
If this is your first time using AIQ toolkit, it is recommended to install the latest version from the [source repository](https://github.com/NVIDIA/AIQToolkit?tab=readme-ov-file#quick-start) on GitHub. This package is intended for users who are familiar with AIQ toolkit applications and need to add AIQ toolkit as a dependency to their project.
|
|
42
42
|
|
|
43
43
|
## Feedback
|
|
44
44
|
|
|
@@ -46,7 +46,7 @@ We would love to hear from you! Please file an issue on [GitHub](https://github.
|
|
|
46
46
|
|
|
47
47
|
## Acknowledgements
|
|
48
48
|
|
|
49
|
-
We would like to thank the following open source projects that made AIQ
|
|
49
|
+
We would like to thank the following open source projects that made AIQ toolkit possible:
|
|
50
50
|
|
|
51
51
|
- [CrewAI](https://github.com/crewAIInc/crewAI)
|
|
52
52
|
- [FastAPI](https://github.com/tiangolo/fastapi)
|
|
@@ -57,7 +57,8 @@ except TelemetryOptionalImportError:
|
|
|
57
57
|
from aiq.utils.optional_imports import DummyTrace # pylint: disable=ungrouped-imports
|
|
58
58
|
from aiq.utils.optional_imports import DummyTracerProvider # pylint: disable=ungrouped-imports
|
|
59
59
|
from aiq.utils.optional_imports import dummy_set_span_in_context # pylint: disable=ungrouped-imports
|
|
60
|
-
|
|
60
|
+
|
|
61
|
+
trace = DummyTrace # pylint: disable=invalid-name
|
|
61
62
|
TracerProvider = DummyTracerProvider
|
|
62
63
|
Span = DummySpan
|
|
63
64
|
set_span_in_context = dummy_set_span_in_context
|
|
@@ -290,6 +291,8 @@ class AsyncOtelSpanListener:
|
|
|
290
291
|
logger.warning("No subspan found for step %s", step.UUID)
|
|
291
292
|
return
|
|
292
293
|
|
|
294
|
+
self._span_stack.pop(step.UUID, None)
|
|
295
|
+
|
|
293
296
|
# Optionally add more attributes from usage_info or data
|
|
294
297
|
usage_info = step.payload.usage_info
|
|
295
298
|
if usage_info:
|
|
@@ -316,7 +319,7 @@ class AsyncOtelSpanListener:
|
|
|
316
319
|
|
|
317
320
|
# Finish corresponding Weave call if Weave is available and initialized
|
|
318
321
|
if self.gc is not None:
|
|
319
|
-
self._finish_weave_call(step
|
|
322
|
+
self._finish_weave_call(step)
|
|
320
323
|
|
|
321
324
|
@contextmanager
|
|
322
325
|
def parent_call(self, trace_id: str, parent_call_id: str):
|
|
@@ -342,13 +345,13 @@ class AsyncOtelSpanListener:
|
|
|
342
345
|
# use it as the parent
|
|
343
346
|
if existing_call is not None:
|
|
344
347
|
parent_call = existing_call
|
|
345
|
-
logger.debug(
|
|
348
|
+
logger.debug("Found existing Weave call: %s from trace: %s", existing_call.id, existing_call.trace_id)
|
|
346
349
|
# Otherwise, check our internal stack for parent relationships
|
|
347
350
|
elif len(self._weave_calls) > 0 and len(self._span_stack) > 1:
|
|
348
351
|
# Get the parent span using stack position (one level up)
|
|
349
352
|
parent_span_id = self._span_stack[-2].get_span_context().span_id
|
|
350
353
|
# Find the corresponding weave call for this parent span
|
|
351
|
-
for
|
|
354
|
+
for call in self._weave_calls.values():
|
|
352
355
|
if getattr(call, "span_id", None) == parent_span_id:
|
|
353
356
|
parent_call = call
|
|
354
357
|
break
|
|
@@ -387,7 +390,7 @@ class AsyncOtelSpanListener:
|
|
|
387
390
|
|
|
388
391
|
return call
|
|
389
392
|
|
|
390
|
-
def _finish_weave_call(self, step: IntermediateStep
|
|
393
|
+
def _finish_weave_call(self, step: IntermediateStep) -> None:
|
|
391
394
|
"""
|
|
392
395
|
Finish a previously created Weave call
|
|
393
396
|
"""
|
aiq/tool/mcp/mcp_tool.py
CHANGED
|
@@ -40,10 +40,15 @@ class MCPToolConfig(FunctionBaseConfig, name="mcp_tool_wrapper"):
|
|
|
40
40
|
Description for the tool that will override the description provided by the MCP server. Should only be used if
|
|
41
41
|
the description provided by the server is poor or nonexistent
|
|
42
42
|
""")
|
|
43
|
+
return_exception: bool = Field(default=True,
|
|
44
|
+
description="""
|
|
45
|
+
If true, the tool will return the exception message if the tool call fails.
|
|
46
|
+
If false, raise the exception.
|
|
47
|
+
""")
|
|
43
48
|
|
|
44
49
|
|
|
45
50
|
@register_function(config_type=MCPToolConfig)
|
|
46
|
-
async def mcp_tool(config: MCPToolConfig, builder: Builder):
|
|
51
|
+
async def mcp_tool(config: MCPToolConfig, builder: Builder): # pylint: disable=unused-argument
|
|
47
52
|
"""
|
|
48
53
|
Generate an AIQ Toolkit Function that wraps a tool provided by the MCP server.
|
|
49
54
|
"""
|
|
@@ -63,12 +68,26 @@ async def mcp_tool(config: MCPToolConfig, builder: Builder):
|
|
|
63
68
|
return tool.input_schema.model_validate_json(input_str)
|
|
64
69
|
|
|
65
70
|
async def _response_fn(tool_input: BaseModel | None = None, **kwargs) -> str:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
# Run the tool, catching any errors and sending to agent for correction
|
|
72
|
+
try:
|
|
73
|
+
if tool_input:
|
|
74
|
+
args = tool_input.model_dump()
|
|
75
|
+
return await tool.acall(args)
|
|
76
|
+
|
|
77
|
+
_ = tool.input_schema.model_validate(kwargs)
|
|
78
|
+
return await tool.acall(kwargs)
|
|
79
|
+
except Exception as e:
|
|
80
|
+
if config.return_exception:
|
|
81
|
+
if tool_input:
|
|
82
|
+
logger.warning("Error calling tool %s with serialized input: %s",
|
|
83
|
+
tool.name,
|
|
84
|
+
tool_input.model_dump(),
|
|
85
|
+
exc_info=True)
|
|
86
|
+
else:
|
|
87
|
+
logger.warning("Error calling tool %s with input: %s", tool.name, kwargs, exc_info=True)
|
|
88
|
+
return str(e)
|
|
89
|
+
# If the tool call fails, raise the exception.
|
|
90
|
+
raise
|
|
72
91
|
|
|
73
92
|
yield FunctionInfo.create(single_fn=_response_fn,
|
|
74
93
|
description=tool.description,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aiqtoolkit
|
|
3
|
-
Version: 1.1.
|
|
4
|
-
Summary: Agent Intelligence
|
|
3
|
+
Version: 1.1.0a20250516
|
|
4
|
+
Summary: NVIDIA Agent Intelligence toolkit
|
|
5
5
|
Author: NVIDIA Corporation
|
|
6
6
|
Maintainer: NVIDIA Corporation
|
|
7
7
|
License: Apache License
|
|
@@ -288,30 +288,30 @@ See the License for the specific language governing permissions and
|
|
|
288
288
|
limitations under the License.
|
|
289
289
|
-->
|
|
290
290
|
|
|
291
|
-

|
|
292
292
|
|
|
293
293
|
# NVIDIA Agent Intelligence Toolkit
|
|
294
294
|
|
|
295
|
-
AIQ
|
|
295
|
+
AIQ toolkit is a flexible library designed to seamlessly integrate your enterprise agents—regardless of framework—with various data sources and tools. By treating agents, tools, and agentic workflows as simple function calls, AIQ toolkit enables true composability: build once and reuse anywhere.
|
|
296
296
|
|
|
297
297
|
## Key Features
|
|
298
298
|
|
|
299
|
-
- [**Framework Agnostic:**](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
300
|
-
- [**Reusability:**](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
301
|
-
- [**Rapid Development:**](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
302
|
-
- [**Profiling:**](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
303
|
-
- [**Observability:**](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
304
|
-
- [**Evaluation System:**](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
305
|
-
- [**User Interface:**](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
306
|
-
- [**MCP Compatibility**](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
299
|
+
- [**Framework Agnostic:**](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/extend/plugins.html) Works with any agentic framework, so you can use your current technology stack without replatforming.
|
|
300
|
+
- [**Reusability:**](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/extend/sharing-components.html) Every agent, tool, or workflow can be combined and repurposed, allowing developers to leverage existing work in new scenarios.
|
|
301
|
+
- [**Rapid Development:**](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/tutorials/index.html) Start with a pre-built agent, tool, or workflow, and customize it to your needs.
|
|
302
|
+
- [**Profiling:**](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/workflows/profiler.html) Profile entire workflows down to the tool and agent level, track input/output tokens and timings, and identify bottlenecks.
|
|
303
|
+
- [**Observability:**](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/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/aiqtoolkit/v1.1.0a20250516/workflows/observe/observe-workflow-with-phoenix.html) and [W&B Weave](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/workflows/observe/observe-workflow-with-weave.html).
|
|
304
|
+
- [**Evaluation System:**](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/workflows/evaluate.html) Validate and maintain accuracy of agentic workflows with built-in evaluation tools.
|
|
305
|
+
- [**User Interface:**](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/quick-start/launching-ui.html) Use the AIQ toolkit UI chat interface to interact with your agents, visualize output, and debug workflows.
|
|
306
|
+
- [**MCP Compatibility**](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/workflows/mcp/mcp-client.html) Compatible with Model Context Protocol (MCP), allowing tools served by MCP Servers to be used as AIQ toolkit functions.
|
|
307
307
|
|
|
308
|
-
With AIQ
|
|
308
|
+
With AIQ toolkit, you can move quickly, experiment freely, and ensure reliability across all your agent-driven projects.
|
|
309
309
|
|
|
310
310
|
## Links
|
|
311
|
-
* [Documentation](https://docs.nvidia.com/aiqtoolkit/v1.1.
|
|
311
|
+
* [Documentation](https://docs.nvidia.com/aiqtoolkit/v1.1.0a20250516/index.html): Explore the full documentation for AIQ toolkit.
|
|
312
312
|
|
|
313
313
|
## First time user?
|
|
314
|
-
If this is your first time using AIQ
|
|
314
|
+
If this is your first time using AIQ toolkit, it is recommended to install the latest version from the [source repository](https://github.com/NVIDIA/AIQToolkit?tab=readme-ov-file#quick-start) on GitHub. This package is intended for users who are familiar with AIQ toolkit applications and need to add AIQ toolkit as a dependency to their project.
|
|
315
315
|
|
|
316
316
|
## Feedback
|
|
317
317
|
|
|
@@ -319,7 +319,7 @@ We would love to hear from you! Please file an issue on [GitHub](https://github.
|
|
|
319
319
|
|
|
320
320
|
## Acknowledgements
|
|
321
321
|
|
|
322
|
-
We would like to thank the following open source projects that made AIQ
|
|
322
|
+
We would like to thank the following open source projects that made AIQ toolkit possible:
|
|
323
323
|
|
|
324
324
|
- [CrewAI](https://github.com/crewAIInc/crewAI)
|
|
325
325
|
- [FastAPI](https://github.com/tiangolo/fastapi)
|
|
@@ -19,7 +19,7 @@ aiq/agent/tool_calling_agent/register.py,sha256=qWY1KmDhpG9AIwM3fO5nsF8zE7lWln5q
|
|
|
19
19
|
aiq/builder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
20
|
aiq/builder/builder.py,sha256=JE3uCw6qTmWX2akUfS-Ga5WSiJVTzBjDQPniiONMjy4,7448
|
|
21
21
|
aiq/builder/component_utils.py,sha256=2jIXWSLIlKxDKAO7kdXz_4BHqQNWw4t9GmcQfw0ER4g,12923
|
|
22
|
-
aiq/builder/context.py,sha256=
|
|
22
|
+
aiq/builder/context.py,sha256=f-kw7JfsIFW83V3ZJFv2OU8LcvNVAg-vRVZ9qtbVESo,9173
|
|
23
23
|
aiq/builder/embedder.py,sha256=M-n2oXSlwE7u-nmpzRbPq6UVWtFtMvrEdKqqsbKQZLk,965
|
|
24
24
|
aiq/builder/eval_builder.py,sha256=UnNgtQiDAUfT3yuwjZQVerenI09-4q0Cse9uwLjk3Fg,4657
|
|
25
25
|
aiq/builder/evaluator.py,sha256=O6Gu0cUwQkrPxPX29Vf_-RopgijxPnhy7mhg_j-9A84,1162
|
|
@@ -28,7 +28,7 @@ aiq/builder/front_end.py,sha256=Xhvfi4VcDh5EoCtLr6AlLQfbRm8_TyugUc_IRfirN6Y,2225
|
|
|
28
28
|
aiq/builder/function.py,sha256=Sh4LKgC-gipsMkNexUY4mw-Br4dWZxq6AHv-als0-e0,11430
|
|
29
29
|
aiq/builder/function_base.py,sha256=AF5a56y-Nw9OpWsP8IFukUKM2FtP8758qYQW6EfObO0,13109
|
|
30
30
|
aiq/builder/function_info.py,sha256=pGPIAL0tjVqLOJymIRB0boI9pzJGdXiPK3KiZvXQsqM,25266
|
|
31
|
-
aiq/builder/intermediate_step_manager.py,sha256=
|
|
31
|
+
aiq/builder/intermediate_step_manager.py,sha256=aKjOK7Gk9XbKhKvRMQTylRGDFZJU7rwqSuiZYaPfwjA,7830
|
|
32
32
|
aiq/builder/llm.py,sha256=DcoYCyschsRjkW_yGsa_Ci7ELSpk5KRbi9778Dm_B9c,951
|
|
33
33
|
aiq/builder/retriever.py,sha256=GM7L1T4NdNZKerFZiCfLcQOwsGoX0NRlF8my7SMq3l4,970
|
|
34
34
|
aiq/builder/user_interaction_manager.py,sha256=OXr-RxWf1sEZjzQH_jt0nmqrLBtYLHGEZEcfDYYFV88,2913
|
|
@@ -151,7 +151,7 @@ aiq/front_ends/fastapi/message_handler.py,sha256=3rFDXG633Upom1taW3ab_sC3KKxN8Y_
|
|
|
151
151
|
aiq/front_ends/fastapi/message_validator.py,sha256=NqjeIG0InGAS6yooEnTaYwjfy3qtQHNgmdJ4zZlxgSQ,17407
|
|
152
152
|
aiq/front_ends/fastapi/register.py,sha256=-Vr6HEDy7L1IIBQZy6VFKZWWKYNtSI-cxk3l4ZPPLko,1159
|
|
153
153
|
aiq/front_ends/fastapi/response_helpers.py,sha256=JnOOvurlkhh6akpzkKDNh1xCi5ClQTePyW_ScEY1pLo,9111
|
|
154
|
-
aiq/front_ends/fastapi/step_adaptor.py,sha256=
|
|
154
|
+
aiq/front_ends/fastapi/step_adaptor.py,sha256=2ps136GzZ7EFgNrN0rPCUSJllvO-GNZPtADrGYseCNc,12551
|
|
155
155
|
aiq/front_ends/fastapi/websocket.py,sha256=upRuFSceWRZcjBcjWG7l6Tl6fxY4NnMroSq372bdkpw,6569
|
|
156
156
|
aiq/front_ends/mcp/__init__.py,sha256=Xs1JQ16L9btwreh4pdGKwskffAw1YFO48jKrU4ib_7c,685
|
|
157
157
|
aiq/front_ends/mcp/mcp_front_end_config.py,sha256=Mp2mgCh1pJkegih5DEJ3t0OKEiCiCg8-rM5vnLpLS6U,1470
|
|
@@ -171,9 +171,9 @@ aiq/memory/__init__.py,sha256=sNqiLatqyTNSBUKKgmInOvCmebkuDHRTErZaeOaE8C8,844
|
|
|
171
171
|
aiq/memory/interfaces.py,sha256=lyj1TGr3Fhibul8Y64Emj-BUEqDotmmFoVCEMqTujUA,5531
|
|
172
172
|
aiq/memory/models.py,sha256=c5dA7nKHQ4AS1_ptQZcfC_oXO495-ehocnf_qXTE6c8,4319
|
|
173
173
|
aiq/meta/module_to_distro.json,sha256=1XV7edobFrdDKvsSoynfodXg_hczUWpDrQzGkW9qqEs,28
|
|
174
|
-
aiq/meta/pypi.md,sha256=
|
|
174
|
+
aiq/meta/pypi.md,sha256=uRioAvXPJX8FluYzqghmBJwRsv4hsXbH3AoeiTbX3G8,4472
|
|
175
175
|
aiq/observability/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
176
|
-
aiq/observability/async_otel_listener.py,sha256=
|
|
176
|
+
aiq/observability/async_otel_listener.py,sha256=oyDO_8XNzQqyiFe-8iJhZr3z9kWsEJEuKEoOPf7L-Bk,17667
|
|
177
177
|
aiq/observability/register.py,sha256=ZDQOaSuy9igc7nAKG7XWP2u6JanC2T8yufMWItNpPJI,4245
|
|
178
178
|
aiq/plugins/.namespace,sha256=Gace0pOC3ETEJf-TBVuNw0TQV6J_KtOPpEiSzMH-odo,215
|
|
179
179
|
aiq/profiler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -277,7 +277,7 @@ aiq/tool/github_tools/get_github_pr.py,sha256=b7eCOqrVoejGjRwmUVdU45uF07ihbY8lRa
|
|
|
277
277
|
aiq/tool/github_tools/update_github_issue.py,sha256=TUElxUuzjZr_QldL_48RcqSx0A9b23NB_lA82QwFjkM,4103
|
|
278
278
|
aiq/tool/mcp/__init__.py,sha256=GUJrgGtpvyMUCjUBvR3faAdv-tZzbU9W-izgx9aMEQg,680
|
|
279
279
|
aiq/tool/mcp/mcp_client.py,sha256=5TaYbYqvfswBzO9al8Ir89KZ3FhxJtzkJPHLBO_iNWY,7469
|
|
280
|
-
aiq/tool/mcp/mcp_tool.py,sha256=
|
|
280
|
+
aiq/tool/mcp/mcp_tool.py,sha256=rQQcaCT-GHQcDmG5weX-2Y-HxBPX-0cC73LjL1u0FUU,4009
|
|
281
281
|
aiq/tool/memory_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
282
282
|
aiq/tool/memory_tools/add_memory_tool.py,sha256=9EjB3DpYhxwasz7o3O8Rq__Ys5986fciv44ahC6mVCo,3349
|
|
283
283
|
aiq/tool/memory_tools/delete_memory_tool.py,sha256=wdB_I8y-1D1OpNtBi6ZOg36vvNkbaxp-yvdqFMc2Suk,2532
|
|
@@ -307,10 +307,10 @@ aiq/utils/reactive/base/observer_base.py,sha256=UAlyAY_ky4q2t0P81RVFo2Bs_R7z5Nde
|
|
|
307
307
|
aiq/utils/reactive/base/subject_base.py,sha256=Ed-AC6P7cT3qkW1EXjzbd5M9WpVoeN_9KCe3OM3FLU4,2521
|
|
308
308
|
aiq/utils/settings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
309
309
|
aiq/utils/settings/global_settings.py,sha256=U9TCLdoZsKq5qOVGjREipGVv9e-FlStzqy5zv82_VYk,7454
|
|
310
|
-
aiqtoolkit-1.1.
|
|
311
|
-
aiqtoolkit-1.1.
|
|
312
|
-
aiqtoolkit-1.1.
|
|
313
|
-
aiqtoolkit-1.1.
|
|
314
|
-
aiqtoolkit-1.1.
|
|
315
|
-
aiqtoolkit-1.1.
|
|
316
|
-
aiqtoolkit-1.1.
|
|
310
|
+
aiqtoolkit-1.1.0a20250516.dist-info/licenses/LICENSE-3rd-party.txt,sha256=8o7aySJa9CBvFshPcsRdJbczzdNyDGJ8b0J67WRUQ2k,183936
|
|
311
|
+
aiqtoolkit-1.1.0a20250516.dist-info/licenses/LICENSE.md,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
|
|
312
|
+
aiqtoolkit-1.1.0a20250516.dist-info/METADATA,sha256=PlFrenL9qp5NToG8vEnjtbvl7mjlM6edz1Z-rtg6rbg,20211
|
|
313
|
+
aiqtoolkit-1.1.0a20250516.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
|
314
|
+
aiqtoolkit-1.1.0a20250516.dist-info/entry_points.txt,sha256=gRlPfR5g21t328WNEQ4CcEz80S1sJNS8A7rMDYnzl4A,452
|
|
315
|
+
aiqtoolkit-1.1.0a20250516.dist-info/top_level.txt,sha256=fo7AzYcNhZ_tRWrhGumtxwnxMew4xrT1iwouDy_f0Kc,4
|
|
316
|
+
aiqtoolkit-1.1.0a20250516.dist-info/RECORD,,
|
{aiqtoolkit-1.1.0a20250514.dist-info → aiqtoolkit-1.1.0a20250516.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
{aiqtoolkit-1.1.0a20250514.dist-info → aiqtoolkit-1.1.0a20250516.dist-info}/licenses/LICENSE.md
RENAMED
|
File without changes
|
|
File without changes
|