nvidia-nat-weave 1.1.0a20251020__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.
nat/meta/pypi.md ADDED
@@ -0,0 +1,23 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ SPDX-License-Identifier: Apache-2.0
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ -->
17
+
18
+ ![NVIDIA NeMo Agent Toolkit](https://media.githubusercontent.com/media/NVIDIA/NeMo-Agent-Toolkit/refs/heads/main/docs/source/_static/banner.png "NeMo Agent toolkit banner image")
19
+
20
+ # NVIDIA NeMo Agent Toolkit Subpackage
21
+ This is a subpackage for Weights and Biases Weave integration for observability.
22
+
23
+ For more information about the NVIDIA NeMo Agent toolkit, please visit the [NeMo Agent toolkit GitHub Repo](https://github.com/NVIDIA/NeMo-Agent-Toolkit).
File without changes
@@ -0,0 +1,70 @@
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 nat.builder.builder import Builder
21
+ from nat.cli.register_workflow import register_telemetry_exporter
22
+ from nat.data_models.telemetry_exporter import TelemetryExporterBaseConfig
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ class WeaveTelemetryExporter(TelemetryExporterBaseConfig, name="weave"):
28
+ """A telemetry exporter to transmit traces to Weights & Biases Weave using OpenTelemetry."""
29
+ project: str = Field(description="The W&B project name.")
30
+ entity: str | None = Field(default=None, description="The W&B username or team name.")
31
+ redact_pii: bool = Field(default=False, description="Whether to redact PII from the traces.")
32
+ redact_pii_fields: list[str] | None = Field(
33
+ default=None,
34
+ description="Custom list of PII entity types to redact. Only used when redact_pii=True. "
35
+ "Examples: CREDIT_CARD, EMAIL_ADDRESS, PHONE_NUMBER, etc.")
36
+ redact_keys: list[str] | None = Field(
37
+ default=None,
38
+ description="Additional keys to redact from traces beyond the default (api_key, auth_headers, authorization).")
39
+ verbose: bool = Field(default=False, description="Whether to enable verbose logging.")
40
+
41
+
42
+ @register_telemetry_exporter(config_type=WeaveTelemetryExporter)
43
+ async def weave_telemetry_exporter(config: WeaveTelemetryExporter, builder: Builder):
44
+ import weave
45
+ from nat.plugins.weave.weave_exporter import WeaveExporter
46
+
47
+ weave_settings = {}
48
+
49
+ if config.redact_pii:
50
+ weave_settings["redact_pii"] = True
51
+
52
+ # Add custom fields if specified
53
+ if config.redact_pii_fields:
54
+ weave_settings["redact_pii_fields"] = config.redact_pii_fields
55
+
56
+ project_name = f"{config.entity}/{config.project}" if config.entity else config.project
57
+
58
+ if weave_settings:
59
+ _ = weave.init(project_name=project_name, settings=weave_settings)
60
+ else:
61
+ _ = weave.init(project_name=project_name)
62
+
63
+ # Handle custom redact keys if specified
64
+ if config.redact_keys and config.redact_pii:
65
+ from weave.utils import sanitize
66
+
67
+ for key in config.redact_keys:
68
+ sanitize.add_redact_key(key)
69
+
70
+ yield WeaveExporter(project=config.project, entity=config.entity, verbose=config.verbose)
@@ -0,0 +1,232 @@
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
+ from collections.abc import Generator
18
+ from contextlib import contextmanager
19
+
20
+ from nat.data_models.intermediate_step import IntermediateStep
21
+ from nat.data_models.span import Span
22
+ from nat.observability.exporter.base_exporter import IsolatedAttribute
23
+ from nat.observability.exporter.span_exporter import SpanExporter
24
+ from nat.utils.log_utils import LogFilter
25
+ from nat.utils.type_utils import override
26
+ from weave.trace.context import weave_client_context
27
+ from weave.trace.context.call_context import get_current_call
28
+ from weave.trace.context.call_context import set_call_stack
29
+ from weave.trace.weave_client import Call
30
+
31
+ logger = logging.getLogger(__name__)
32
+
33
+ # Use LogFilter to filter out specific message patterns
34
+ presidio_filter = LogFilter([
35
+ "nlp_engine not provided",
36
+ "Created NLP engine",
37
+ "registry not provided",
38
+ "Loaded recognizer",
39
+ "Recognizer not added to registry"
40
+ ])
41
+
42
+
43
+ class WeaveExporter(SpanExporter[Span, Span]):
44
+ """A Weave exporter that exports telemetry traces to Weights & Biases Weave using OpenTelemetry."""
45
+
46
+ _weave_calls: IsolatedAttribute[dict[str, Call]] = IsolatedAttribute(dict)
47
+
48
+ def __init__(self,
49
+ context_state=None,
50
+ entity: str | None = None,
51
+ project: str | None = None,
52
+ verbose: bool = False):
53
+ super().__init__(context_state=context_state)
54
+ self._entity = entity
55
+ self._project = project
56
+ self._gc = weave_client_context.require_weave_client()
57
+
58
+ # Optionally, set log filtering for presidio-analyzer to reduce verbosity
59
+ if not verbose:
60
+ presidio_logger = logging.getLogger('presidio-analyzer')
61
+ presidio_logger.addFilter(presidio_filter)
62
+
63
+ @override
64
+ async def export_processed(self, item: Span | list[Span]) -> None:
65
+ """Dummy implementation of export_processed.
66
+
67
+ Args:
68
+ item (Span | list[Span]): The span or list of spans to export.
69
+ """
70
+ pass
71
+
72
+ def _process_start_event(self, event: IntermediateStep):
73
+ """Process the start event for a Weave call.
74
+
75
+ Args:
76
+ event (IntermediateStep): The intermediate step event.
77
+ """
78
+ super()._process_start_event(event)
79
+ span = self._span_stack.get(event.UUID, None)
80
+ if span is None:
81
+ logger.warning("No span found for event %s", event.UUID)
82
+ return
83
+ self._create_weave_call(event, span)
84
+
85
+ def _process_end_event(self, event: IntermediateStep):
86
+ """Process the end event for a Weave call.
87
+
88
+ Args:
89
+ event (IntermediateStep): The intermediate step event.
90
+ """
91
+ super()._process_end_event(event)
92
+ self._finish_weave_call(event)
93
+
94
+ @contextmanager
95
+ def parent_call(self, trace_id: str, parent_call_id: str) -> Generator[None]:
96
+ """Create a dummy Weave call for the parent span.
97
+
98
+ Args:
99
+ trace_id (str): The trace ID of the parent span.
100
+ parent_call_id (str): The ID of the parent call.
101
+
102
+ Yields:
103
+ None: The dummy Weave call.
104
+ """
105
+ dummy_call = Call(trace_id=trace_id, id=parent_call_id, _op_name="", project_id="", parent_id=None, inputs={})
106
+ with set_call_stack([dummy_call]):
107
+ yield
108
+
109
+ def _create_weave_call(self, step: IntermediateStep, span: Span) -> Call:
110
+ """
111
+ Create a Weave call directly from the span and step data,
112
+ connecting to existing framework traces if available.
113
+
114
+ Args:
115
+ step (IntermediateStep): The intermediate step event.
116
+ span (Span): The span associated with the intermediate step.
117
+
118
+ Returns:
119
+ Call: The Weave call created from the span and step data.
120
+ """
121
+ # Check for existing Weave trace/call
122
+ existing_call = get_current_call()
123
+
124
+ # Extract parent call if applicable
125
+ parent_call = None
126
+
127
+ # If we have an existing Weave call from another framework (e.g., LangChain/LangGraph),
128
+ # use it as the parent
129
+ if existing_call is not None:
130
+ parent_call = existing_call
131
+ logger.debug("Found existing Weave call: %s from trace: %s", existing_call.id, existing_call.trace_id)
132
+ # Otherwise, check our internal stack for parent relationships
133
+ elif len(self._weave_calls) > 0 and len(self._span_stack) > 1:
134
+ # Get the parent span using stack position (one level up)
135
+ parent_span_id = self._span_stack[-2].context.span_id
136
+ # Find the corresponding weave call for this parent span
137
+ for call in self._weave_calls.values():
138
+ if getattr(call, "span_id", None) == parent_span_id:
139
+ parent_call = call
140
+ break
141
+
142
+ # Generate a meaningful operation name based on event type
143
+ event_type = step.payload.event_type.split(".")[-1]
144
+ if step.payload.name:
145
+ op_name = f"aiq.{event_type}.{step.payload.name}"
146
+ else:
147
+ op_name = f"aiq.{event_type}"
148
+
149
+ # Create input dictionary
150
+ inputs = {}
151
+ if step.payload.data and step.payload.data.input is not None:
152
+ try:
153
+ # Add the input to the Weave call
154
+ inputs["input"] = step.payload.data.input
155
+ except Exception:
156
+ # If serialization fails, use string representation
157
+ inputs["input"] = str(step.payload.data.input)
158
+
159
+ # Create the Weave call
160
+ call = self._gc.create_call(
161
+ op_name,
162
+ inputs=inputs,
163
+ parent=parent_call,
164
+ attributes=span.attributes,
165
+ display_name=op_name,
166
+ )
167
+
168
+ # Store the call with step UUID as key
169
+ self._weave_calls[step.UUID] = call
170
+
171
+ # Store span ID for parent reference
172
+ if span.context is not None:
173
+ setattr(call, "span_id", span.context.span_id)
174
+ else:
175
+ logger.warning("Span has no context, skipping span_id setting")
176
+
177
+ return call
178
+
179
+ def _finish_weave_call(self, step: IntermediateStep) -> None:
180
+ """
181
+ Finish a previously created Weave call.
182
+
183
+ Args:
184
+ step (IntermediateStep): The intermediate step event.
185
+ """
186
+ # Find the call for this step
187
+ call = self._weave_calls.pop(step.UUID, None)
188
+
189
+ if call is None:
190
+ logger.warning("No Weave call found for step %s", step.UUID)
191
+ return
192
+
193
+ # Create output dictionary
194
+ outputs = {}
195
+ if step.payload.data and step.payload.data.output is not None:
196
+ try:
197
+ # Add the output to the Weave call
198
+ outputs["output"] = step.payload.data.output
199
+ except Exception:
200
+ # If serialization fails, use string representation
201
+ outputs["output"] = str(step.payload.data.output)
202
+
203
+ # Add usage information if available
204
+ usage_info = step.payload.usage_info
205
+ if usage_info:
206
+ if usage_info.token_usage:
207
+ outputs["prompt_tokens"] = usage_info.token_usage.prompt_tokens
208
+ outputs["completion_tokens"] = usage_info.token_usage.completion_tokens
209
+ outputs["total_tokens"] = usage_info.token_usage.total_tokens
210
+
211
+ if usage_info.num_llm_calls:
212
+ outputs["num_llm_calls"] = usage_info.num_llm_calls
213
+
214
+ if usage_info.seconds_between_calls:
215
+ outputs["seconds_between_calls"] = usage_info.seconds_between_calls
216
+
217
+ # Finish the call with outputs
218
+ self._gc.finish_call(call, outputs)
219
+
220
+ async def _cleanup_weave_calls(self) -> None:
221
+ """
222
+ Clean up any lingering Weave calls.
223
+ """
224
+ if self._weave_calls:
225
+ for _, call in list(self._weave_calls.items()):
226
+ self._gc.finish_call(call, {"status": "incomplete"})
227
+ self._weave_calls.clear()
228
+
229
+ async def _cleanup(self) -> None:
230
+ """Perform cleanup once the exporter is stopped."""
231
+ await self._cleanup_weave_calls()
232
+ await super()._cleanup()
@@ -0,0 +1,47 @@
1
+ Metadata-Version: 2.4
2
+ Name: nvidia-nat-weave
3
+ Version: 1.1.0a20251020
4
+ Summary: Subpackage for Weave integration in NeMo Agent toolkit
5
+ Author: NVIDIA Corporation
6
+ Maintainer: NVIDIA Corporation
7
+ License: Apache-2.0
8
+ Project-URL: documentation, https://docs.nvidia.com/nemo/agent-toolkit/latest/
9
+ Project-URL: source, https://github.com/NVIDIA/NeMo-Agent-Toolkit
10
+ Keywords: ai,observability,wandb,pii
11
+ Classifier: Programming Language :: Python
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Requires-Python: <3.14,>=3.11
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE-3rd-party.txt
18
+ License-File: LICENSE.md
19
+ Requires-Dist: nvidia-nat==v1.1.0a20251020
20
+ Requires-Dist: presidio-analyzer~=2.2
21
+ Requires-Dist: presidio-anonymizer~=2.2
22
+ Requires-Dist: weave==0.52.6
23
+ Dynamic: license-file
24
+
25
+ <!--
26
+ SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
27
+ SPDX-License-Identifier: Apache-2.0
28
+
29
+ Licensed under the Apache License, Version 2.0 (the "License");
30
+ you may not use this file except in compliance with the License.
31
+ You may obtain a copy of the License at
32
+
33
+ http://www.apache.org/licenses/LICENSE-2.0
34
+
35
+ Unless required by applicable law or agreed to in writing, software
36
+ distributed under the License is distributed on an "AS IS" BASIS,
37
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
38
+ See the License for the specific language governing permissions and
39
+ limitations under the License.
40
+ -->
41
+
42
+ ![NVIDIA NeMo Agent Toolkit](https://media.githubusercontent.com/media/NVIDIA/NeMo-Agent-Toolkit/refs/heads/main/docs/source/_static/banner.png "NeMo Agent toolkit banner image")
43
+
44
+ # NVIDIA NeMo Agent Toolkit Subpackage
45
+ This is a subpackage for Weights and Biases Weave integration for observability.
46
+
47
+ For more information about the NVIDIA NeMo Agent toolkit, please visit the [NeMo Agent toolkit GitHub Repo](https://github.com/NVIDIA/NeMo-Agent-Toolkit).
@@ -0,0 +1,11 @@
1
+ nat/meta/pypi.md,sha256=FVQR5lfZjqZHm4VWMmQJYgZbwJJjrfQZgEqHscDuMR8,1121
2
+ nat/plugins/weave/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ nat/plugins/weave/register.py,sha256=NvK8roew0XjgrhVVw7sDKqZcjpy-LvNIv3UYEFCElB0,2927
4
+ nat/plugins/weave/weave_exporter.py,sha256=5JygAVkNKDl_uj-YRTIrN8w4Si_H1vOVBh7OCRuCzf4,8798
5
+ nvidia_nat_weave-1.1.0a20251020.dist-info/licenses/LICENSE-3rd-party.txt,sha256=fOk5jMmCX9YoKWyYzTtfgl-SUy477audFC5hNY4oP7Q,284609
6
+ nvidia_nat_weave-1.1.0a20251020.dist-info/licenses/LICENSE.md,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
7
+ nvidia_nat_weave-1.1.0a20251020.dist-info/METADATA,sha256=_HTuHalHEychKwMiFB15-U5JzEzQqcjhn2htDvbza88,2014
8
+ nvidia_nat_weave-1.1.0a20251020.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
+ nvidia_nat_weave-1.1.0a20251020.dist-info/entry_points.txt,sha256=xg4vW3wKsOLfHa-QR6JqWnq3DmdfI_z9IZfg4I9thTY,56
10
+ nvidia_nat_weave-1.1.0a20251020.dist-info/top_level.txt,sha256=8-CJ2cP6-f0ZReXe5Hzqp-5pvzzHz-5Ds5H2bGqh1-U,4
11
+ nvidia_nat_weave-1.1.0a20251020.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [nat.components]
2
+ nat_weave = nat.plugins.weave.register