nvidia-nat 1.3.0a20250910__py3-none-any.whl → 1.4.0a20251112__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/agent/base.py +13 -8
- nat/agent/prompt_optimizer/prompt.py +68 -0
- nat/agent/prompt_optimizer/register.py +149 -0
- nat/agent/react_agent/agent.py +6 -5
- nat/agent/react_agent/register.py +49 -39
- nat/agent/reasoning_agent/reasoning_agent.py +17 -15
- nat/agent/register.py +2 -0
- nat/agent/responses_api_agent/__init__.py +14 -0
- nat/agent/responses_api_agent/register.py +126 -0
- nat/agent/rewoo_agent/agent.py +304 -117
- nat/agent/rewoo_agent/prompt.py +19 -22
- nat/agent/rewoo_agent/register.py +51 -38
- nat/agent/tool_calling_agent/agent.py +75 -17
- nat/agent/tool_calling_agent/register.py +46 -23
- nat/authentication/api_key/api_key_auth_provider.py +6 -11
- nat/authentication/api_key/api_key_auth_provider_config.py +8 -5
- nat/authentication/credential_validator/__init__.py +14 -0
- nat/authentication/credential_validator/bearer_token_validator.py +557 -0
- nat/authentication/http_basic_auth/http_basic_auth_provider.py +1 -1
- nat/authentication/interfaces.py +5 -2
- nat/authentication/oauth2/oauth2_auth_code_flow_provider.py +69 -36
- nat/authentication/oauth2/oauth2_auth_code_flow_provider_config.py +2 -1
- nat/authentication/oauth2/oauth2_resource_server_config.py +125 -0
- nat/builder/builder.py +55 -23
- nat/builder/component_utils.py +9 -5
- nat/builder/context.py +54 -15
- nat/builder/eval_builder.py +14 -9
- nat/builder/framework_enum.py +1 -0
- nat/builder/front_end.py +1 -1
- nat/builder/function.py +370 -0
- nat/builder/function_info.py +1 -1
- nat/builder/intermediate_step_manager.py +38 -2
- nat/builder/workflow.py +5 -0
- nat/builder/workflow_builder.py +306 -54
- nat/cli/cli_utils/config_override.py +1 -1
- nat/cli/commands/info/info.py +16 -6
- nat/cli/commands/mcp/__init__.py +14 -0
- nat/cli/commands/mcp/mcp.py +986 -0
- nat/cli/commands/optimize.py +90 -0
- nat/cli/commands/start.py +1 -1
- nat/cli/commands/workflow/templates/config.yml.j2 +14 -13
- nat/cli/commands/workflow/templates/register.py.j2 +2 -2
- nat/cli/commands/workflow/templates/workflow.py.j2 +35 -21
- nat/cli/commands/workflow/workflow_commands.py +60 -18
- nat/cli/entrypoint.py +15 -11
- nat/cli/main.py +3 -0
- nat/cli/register_workflow.py +38 -4
- nat/cli/type_registry.py +72 -1
- nat/control_flow/__init__.py +0 -0
- nat/control_flow/register.py +20 -0
- nat/control_flow/router_agent/__init__.py +0 -0
- nat/control_flow/router_agent/agent.py +329 -0
- nat/control_flow/router_agent/prompt.py +48 -0
- nat/control_flow/router_agent/register.py +91 -0
- nat/control_flow/sequential_executor.py +166 -0
- nat/data_models/agent.py +34 -0
- nat/data_models/api_server.py +199 -69
- nat/data_models/authentication.py +23 -9
- nat/data_models/common.py +47 -0
- nat/data_models/component.py +2 -0
- nat/data_models/component_ref.py +11 -0
- nat/data_models/config.py +41 -17
- nat/data_models/dataset_handler.py +4 -3
- nat/data_models/function.py +34 -0
- nat/data_models/function_dependencies.py +8 -0
- nat/data_models/intermediate_step.py +9 -1
- nat/data_models/llm.py +15 -1
- nat/data_models/openai_mcp.py +46 -0
- nat/data_models/optimizable.py +208 -0
- nat/data_models/optimizer.py +161 -0
- nat/data_models/span.py +41 -3
- nat/data_models/thinking_mixin.py +2 -2
- nat/embedder/azure_openai_embedder.py +2 -1
- nat/embedder/nim_embedder.py +3 -2
- nat/embedder/openai_embedder.py +3 -2
- nat/eval/config.py +1 -1
- nat/eval/dataset_handler/dataset_downloader.py +3 -2
- nat/eval/dataset_handler/dataset_filter.py +34 -2
- nat/eval/evaluate.py +10 -3
- nat/eval/evaluator/base_evaluator.py +1 -1
- nat/eval/rag_evaluator/evaluate.py +7 -4
- nat/eval/register.py +4 -0
- nat/eval/runtime_evaluator/__init__.py +14 -0
- nat/eval/runtime_evaluator/evaluate.py +123 -0
- nat/eval/runtime_evaluator/register.py +100 -0
- nat/eval/swe_bench_evaluator/evaluate.py +1 -1
- nat/eval/trajectory_evaluator/register.py +1 -1
- nat/eval/tunable_rag_evaluator/evaluate.py +1 -1
- nat/eval/usage_stats.py +2 -0
- nat/eval/utils/output_uploader.py +3 -2
- nat/eval/utils/weave_eval.py +17 -3
- nat/experimental/decorators/experimental_warning_decorator.py +27 -7
- nat/experimental/test_time_compute/functions/execute_score_select_function.py +1 -1
- nat/experimental/test_time_compute/functions/plan_select_execute_function.py +7 -3
- nat/experimental/test_time_compute/functions/ttc_tool_orchestration_function.py +1 -1
- nat/experimental/test_time_compute/functions/ttc_tool_wrapper_function.py +3 -3
- nat/experimental/test_time_compute/models/strategy_base.py +2 -2
- nat/experimental/test_time_compute/selection/llm_based_output_merging_selector.py +1 -1
- nat/front_ends/console/authentication_flow_handler.py +82 -30
- nat/front_ends/console/console_front_end_plugin.py +19 -7
- nat/front_ends/fastapi/auth_flow_handlers/http_flow_handler.py +1 -1
- nat/front_ends/fastapi/auth_flow_handlers/websocket_flow_handler.py +52 -17
- nat/front_ends/fastapi/dask_client_mixin.py +65 -0
- nat/front_ends/fastapi/fastapi_front_end_config.py +25 -3
- nat/front_ends/fastapi/fastapi_front_end_plugin.py +140 -3
- nat/front_ends/fastapi/fastapi_front_end_plugin_worker.py +445 -265
- nat/front_ends/fastapi/job_store.py +518 -99
- nat/front_ends/fastapi/main.py +11 -19
- nat/front_ends/fastapi/message_handler.py +69 -44
- nat/front_ends/fastapi/message_validator.py +8 -7
- nat/front_ends/fastapi/utils.py +57 -0
- nat/front_ends/mcp/introspection_token_verifier.py +73 -0
- nat/front_ends/mcp/mcp_front_end_config.py +71 -3
- nat/front_ends/mcp/mcp_front_end_plugin.py +85 -21
- nat/front_ends/mcp/mcp_front_end_plugin_worker.py +248 -29
- nat/front_ends/mcp/memory_profiler.py +320 -0
- nat/front_ends/mcp/tool_converter.py +78 -25
- nat/front_ends/simple_base/simple_front_end_plugin_base.py +3 -1
- nat/llm/aws_bedrock_llm.py +21 -8
- nat/llm/azure_openai_llm.py +14 -5
- nat/llm/litellm_llm.py +80 -0
- nat/llm/nim_llm.py +23 -9
- nat/llm/openai_llm.py +19 -7
- nat/llm/register.py +4 -0
- nat/llm/utils/thinking.py +1 -1
- nat/observability/exporter/base_exporter.py +1 -1
- nat/observability/exporter/processing_exporter.py +29 -55
- nat/observability/exporter/span_exporter.py +43 -15
- nat/observability/exporter_manager.py +2 -2
- nat/observability/mixin/redaction_config_mixin.py +5 -4
- nat/observability/mixin/tagging_config_mixin.py +26 -14
- nat/observability/mixin/type_introspection_mixin.py +420 -107
- nat/observability/processor/batching_processor.py +1 -1
- nat/observability/processor/processor.py +3 -0
- nat/observability/processor/redaction/__init__.py +24 -0
- nat/observability/processor/redaction/contextual_redaction_processor.py +125 -0
- nat/observability/processor/redaction/contextual_span_redaction_processor.py +66 -0
- nat/observability/processor/redaction/redaction_processor.py +177 -0
- nat/observability/processor/redaction/span_header_redaction_processor.py +92 -0
- nat/observability/processor/span_tagging_processor.py +21 -14
- nat/observability/register.py +16 -0
- nat/profiler/callbacks/langchain_callback_handler.py +32 -7
- nat/profiler/callbacks/llama_index_callback_handler.py +36 -2
- nat/profiler/callbacks/token_usage_base_model.py +2 -0
- nat/profiler/decorators/framework_wrapper.py +61 -9
- nat/profiler/decorators/function_tracking.py +35 -3
- nat/profiler/forecasting/models/linear_model.py +1 -1
- nat/profiler/forecasting/models/random_forest_regressor.py +1 -1
- nat/profiler/inference_optimization/bottleneck_analysis/nested_stack_analysis.py +1 -1
- nat/profiler/inference_optimization/experimental/prefix_span_analysis.py +1 -1
- nat/profiler/parameter_optimization/__init__.py +0 -0
- nat/profiler/parameter_optimization/optimizable_utils.py +93 -0
- nat/profiler/parameter_optimization/optimizer_runtime.py +67 -0
- nat/profiler/parameter_optimization/parameter_optimizer.py +189 -0
- nat/profiler/parameter_optimization/parameter_selection.py +107 -0
- nat/profiler/parameter_optimization/pareto_visualizer.py +460 -0
- nat/profiler/parameter_optimization/prompt_optimizer.py +384 -0
- nat/profiler/parameter_optimization/update_helpers.py +66 -0
- nat/profiler/utils.py +3 -1
- nat/registry_handlers/pypi/register_pypi.py +5 -3
- nat/registry_handlers/rest/register_rest.py +5 -3
- nat/retriever/milvus/retriever.py +1 -1
- nat/retriever/nemo_retriever/register.py +2 -1
- nat/runtime/loader.py +1 -1
- nat/runtime/runner.py +111 -6
- nat/runtime/session.py +49 -3
- nat/settings/global_settings.py +2 -2
- nat/tool/chat_completion.py +4 -1
- nat/tool/code_execution/code_sandbox.py +3 -6
- nat/tool/code_execution/local_sandbox/Dockerfile.sandbox +19 -32
- nat/tool/code_execution/local_sandbox/local_sandbox_server.py +6 -1
- nat/tool/code_execution/local_sandbox/sandbox.requirements.txt +2 -0
- nat/tool/code_execution/local_sandbox/start_local_sandbox.sh +10 -4
- nat/tool/datetime_tools.py +1 -1
- nat/tool/github_tools.py +450 -0
- nat/tool/memory_tools/add_memory_tool.py +3 -3
- nat/tool/memory_tools/delete_memory_tool.py +3 -4
- nat/tool/memory_tools/get_memory_tool.py +4 -4
- nat/tool/register.py +2 -7
- nat/tool/server_tools.py +15 -2
- nat/utils/__init__.py +76 -0
- nat/utils/callable_utils.py +70 -0
- nat/utils/data_models/schema_validator.py +1 -1
- nat/utils/decorators.py +210 -0
- nat/utils/exception_handlers/automatic_retries.py +278 -72
- nat/utils/io/yaml_tools.py +73 -3
- nat/utils/log_levels.py +25 -0
- nat/utils/responses_api.py +26 -0
- nat/utils/string_utils.py +16 -0
- nat/utils/type_converter.py +12 -3
- nat/utils/type_utils.py +6 -2
- nvidia_nat-1.4.0a20251112.dist-info/METADATA +197 -0
- {nvidia_nat-1.3.0a20250910.dist-info → nvidia_nat-1.4.0a20251112.dist-info}/RECORD +199 -165
- {nvidia_nat-1.3.0a20250910.dist-info → nvidia_nat-1.4.0a20251112.dist-info}/entry_points.txt +1 -0
- nat/cli/commands/info/list_mcp.py +0 -461
- nat/data_models/temperature_mixin.py +0 -43
- nat/data_models/top_p_mixin.py +0 -43
- nat/observability/processor/header_redaction_processor.py +0 -123
- nat/observability/processor/redaction_processor.py +0 -77
- nat/tool/code_execution/test_code_execution_sandbox.py +0 -414
- nat/tool/github_tools/create_github_commit.py +0 -133
- nat/tool/github_tools/create_github_issue.py +0 -87
- nat/tool/github_tools/create_github_pr.py +0 -106
- nat/tool/github_tools/get_github_file.py +0 -106
- nat/tool/github_tools/get_github_issue.py +0 -166
- nat/tool/github_tools/get_github_pr.py +0 -256
- nat/tool/github_tools/update_github_issue.py +0 -100
- nvidia_nat-1.3.0a20250910.dist-info/METADATA +0 -373
- /nat/{tool/github_tools → agent/prompt_optimizer}/__init__.py +0 -0
- {nvidia_nat-1.3.0a20250910.dist-info → nvidia_nat-1.4.0a20251112.dist-info}/WHEEL +0 -0
- {nvidia_nat-1.3.0a20250910.dist-info → nvidia_nat-1.4.0a20251112.dist-info}/licenses/LICENSE-3rd-party.txt +0 -0
- {nvidia_nat-1.3.0a20250910.dist-info → nvidia_nat-1.4.0a20251112.dist-info}/licenses/LICENSE.md +0 -0
- {nvidia_nat-1.3.0a20250910.dist-info → nvidia_nat-1.4.0a20251112.dist-info}/top_level.txt +0 -0
nat/runtime/runner.py
CHANGED
|
@@ -15,11 +15,16 @@
|
|
|
15
15
|
|
|
16
16
|
import logging
|
|
17
17
|
import typing
|
|
18
|
+
import uuid
|
|
18
19
|
from enum import Enum
|
|
19
20
|
|
|
20
21
|
from nat.builder.context import Context
|
|
21
22
|
from nat.builder.context import ContextState
|
|
22
23
|
from nat.builder.function import Function
|
|
24
|
+
from nat.data_models.intermediate_step import IntermediateStepPayload
|
|
25
|
+
from nat.data_models.intermediate_step import IntermediateStepType
|
|
26
|
+
from nat.data_models.intermediate_step import StreamEventData
|
|
27
|
+
from nat.data_models.intermediate_step import TraceMetadata
|
|
23
28
|
from nat.data_models.invocation_node import InvocationNode
|
|
24
29
|
from nat.observability.exporter_manager import ExporterManager
|
|
25
30
|
from nat.utils.reactive.subject import Subject
|
|
@@ -130,17 +135,60 @@ class Runner:
|
|
|
130
135
|
if (self._state != RunnerState.INITIALIZED):
|
|
131
136
|
raise ValueError("Cannot run the workflow without entering the context")
|
|
132
137
|
|
|
138
|
+
token_run_id = None
|
|
139
|
+
token_trace_id = None
|
|
133
140
|
try:
|
|
134
141
|
self._state = RunnerState.RUNNING
|
|
135
142
|
|
|
136
143
|
if (not self._entry_fn.has_single_output):
|
|
137
144
|
raise ValueError("Workflow does not support single output")
|
|
138
145
|
|
|
146
|
+
# Establish workflow run and trace identifiers
|
|
147
|
+
existing_run_id = self._context_state.workflow_run_id.get()
|
|
148
|
+
existing_trace_id = self._context_state.workflow_trace_id.get()
|
|
149
|
+
|
|
150
|
+
workflow_run_id = existing_run_id or str(uuid.uuid4())
|
|
151
|
+
|
|
152
|
+
workflow_trace_id = existing_trace_id or uuid.uuid4().int
|
|
153
|
+
|
|
154
|
+
token_run_id = self._context_state.workflow_run_id.set(workflow_run_id)
|
|
155
|
+
token_trace_id = self._context_state.workflow_trace_id.set(workflow_trace_id)
|
|
156
|
+
|
|
157
|
+
# Prepare workflow-level intermediate step identifiers
|
|
158
|
+
workflow_step_uuid = str(uuid.uuid4())
|
|
159
|
+
workflow_name = getattr(self._entry_fn, 'instance_name', None) or "workflow"
|
|
160
|
+
|
|
139
161
|
async with self._exporter_manager.start(context_state=self._context_state):
|
|
140
|
-
#
|
|
141
|
-
|
|
162
|
+
# Emit WORKFLOW_START
|
|
163
|
+
start_metadata = TraceMetadata(
|
|
164
|
+
provided_metadata={
|
|
165
|
+
"workflow_run_id": workflow_run_id,
|
|
166
|
+
"workflow_trace_id": f"{workflow_trace_id:032x}",
|
|
167
|
+
"conversation_id": self._context_state.conversation_id.get(),
|
|
168
|
+
})
|
|
169
|
+
self._context.intermediate_step_manager.push_intermediate_step(
|
|
170
|
+
IntermediateStepPayload(UUID=workflow_step_uuid,
|
|
171
|
+
event_type=IntermediateStepType.WORKFLOW_START,
|
|
172
|
+
name=workflow_name,
|
|
173
|
+
metadata=start_metadata,
|
|
174
|
+
data=StreamEventData(input=self._input_message)))
|
|
175
|
+
|
|
176
|
+
result = await self._entry_fn.ainvoke(self._input_message, to_type=to_type) # type: ignore
|
|
177
|
+
|
|
178
|
+
# Emit WORKFLOW_END with output
|
|
179
|
+
end_metadata = TraceMetadata(
|
|
180
|
+
provided_metadata={
|
|
181
|
+
"workflow_run_id": workflow_run_id,
|
|
182
|
+
"workflow_trace_id": f"{workflow_trace_id:032x}",
|
|
183
|
+
"conversation_id": self._context_state.conversation_id.get(),
|
|
184
|
+
})
|
|
185
|
+
self._context.intermediate_step_manager.push_intermediate_step(
|
|
186
|
+
IntermediateStepPayload(UUID=workflow_step_uuid,
|
|
187
|
+
event_type=IntermediateStepType.WORKFLOW_END,
|
|
188
|
+
name=workflow_name,
|
|
189
|
+
metadata=end_metadata,
|
|
190
|
+
data=StreamEventData(output=result)))
|
|
142
191
|
|
|
143
|
-
# Close the intermediate stream
|
|
144
192
|
event_stream = self._context_state.event_stream.get()
|
|
145
193
|
if event_stream:
|
|
146
194
|
event_stream.on_complete()
|
|
@@ -154,25 +202,78 @@ class Runner:
|
|
|
154
202
|
if event_stream:
|
|
155
203
|
event_stream.on_complete()
|
|
156
204
|
self._state = RunnerState.FAILED
|
|
157
|
-
|
|
158
205
|
raise
|
|
206
|
+
finally:
|
|
207
|
+
if token_run_id is not None:
|
|
208
|
+
self._context_state.workflow_run_id.reset(token_run_id)
|
|
209
|
+
if token_trace_id is not None:
|
|
210
|
+
self._context_state.workflow_trace_id.reset(token_trace_id)
|
|
159
211
|
|
|
160
212
|
async def result_stream(self, to_type: type | None = None):
|
|
161
213
|
|
|
162
214
|
if (self._state != RunnerState.INITIALIZED):
|
|
163
215
|
raise ValueError("Cannot run the workflow without entering the context")
|
|
164
216
|
|
|
217
|
+
token_run_id = None
|
|
218
|
+
token_trace_id = None
|
|
165
219
|
try:
|
|
166
220
|
self._state = RunnerState.RUNNING
|
|
167
221
|
|
|
168
222
|
if (not self._entry_fn.has_streaming_output):
|
|
169
223
|
raise ValueError("Workflow does not support streaming output")
|
|
170
224
|
|
|
225
|
+
# Establish workflow run and trace identifiers
|
|
226
|
+
existing_run_id = self._context_state.workflow_run_id.get()
|
|
227
|
+
existing_trace_id = self._context_state.workflow_trace_id.get()
|
|
228
|
+
|
|
229
|
+
workflow_run_id = existing_run_id or str(uuid.uuid4())
|
|
230
|
+
|
|
231
|
+
workflow_trace_id = existing_trace_id or uuid.uuid4().int
|
|
232
|
+
|
|
233
|
+
token_run_id = self._context_state.workflow_run_id.set(workflow_run_id)
|
|
234
|
+
token_trace_id = self._context_state.workflow_trace_id.set(workflow_trace_id)
|
|
235
|
+
|
|
236
|
+
# Prepare workflow-level intermediate step identifiers
|
|
237
|
+
workflow_step_uuid = str(uuid.uuid4())
|
|
238
|
+
workflow_name = getattr(self._entry_fn, 'instance_name', None) or "workflow"
|
|
239
|
+
|
|
171
240
|
# Run the workflow
|
|
172
241
|
async with self._exporter_manager.start(context_state=self._context_state):
|
|
173
|
-
|
|
242
|
+
# Emit WORKFLOW_START
|
|
243
|
+
start_metadata = TraceMetadata(
|
|
244
|
+
provided_metadata={
|
|
245
|
+
"workflow_run_id": workflow_run_id,
|
|
246
|
+
"workflow_trace_id": f"{workflow_trace_id:032x}",
|
|
247
|
+
"conversation_id": self._context_state.conversation_id.get(),
|
|
248
|
+
})
|
|
249
|
+
self._context.intermediate_step_manager.push_intermediate_step(
|
|
250
|
+
IntermediateStepPayload(UUID=workflow_step_uuid,
|
|
251
|
+
event_type=IntermediateStepType.WORKFLOW_START,
|
|
252
|
+
name=workflow_name,
|
|
253
|
+
metadata=start_metadata,
|
|
254
|
+
data=StreamEventData(input=self._input_message)))
|
|
255
|
+
|
|
256
|
+
# Collect preview of streaming results for the WORKFLOW_END event
|
|
257
|
+
output_preview = []
|
|
258
|
+
|
|
259
|
+
async for m in self._entry_fn.astream(self._input_message, to_type=to_type): # type: ignore
|
|
260
|
+
if len(output_preview) < 50:
|
|
261
|
+
output_preview.append(m)
|
|
174
262
|
yield m
|
|
175
263
|
|
|
264
|
+
# Emit WORKFLOW_END
|
|
265
|
+
end_metadata = TraceMetadata(
|
|
266
|
+
provided_metadata={
|
|
267
|
+
"workflow_run_id": workflow_run_id,
|
|
268
|
+
"workflow_trace_id": f"{workflow_trace_id:032x}",
|
|
269
|
+
"conversation_id": self._context_state.conversation_id.get(),
|
|
270
|
+
})
|
|
271
|
+
self._context.intermediate_step_manager.push_intermediate_step(
|
|
272
|
+
IntermediateStepPayload(UUID=workflow_step_uuid,
|
|
273
|
+
event_type=IntermediateStepType.WORKFLOW_END,
|
|
274
|
+
name=workflow_name,
|
|
275
|
+
metadata=end_metadata,
|
|
276
|
+
data=StreamEventData(output=output_preview)))
|
|
176
277
|
self._state = RunnerState.COMPLETED
|
|
177
278
|
|
|
178
279
|
# Close the intermediate stream
|
|
@@ -186,8 +287,12 @@ class Runner:
|
|
|
186
287
|
if event_stream:
|
|
187
288
|
event_stream.on_complete()
|
|
188
289
|
self._state = RunnerState.FAILED
|
|
189
|
-
|
|
190
290
|
raise
|
|
291
|
+
finally:
|
|
292
|
+
if token_run_id is not None:
|
|
293
|
+
self._context_state.workflow_run_id.reset(token_run_id)
|
|
294
|
+
if token_trace_id is not None:
|
|
295
|
+
self._context_state.workflow_trace_id.reset(token_trace_id)
|
|
191
296
|
|
|
192
297
|
|
|
193
298
|
# Compatibility aliases with previous releases
|
nat/runtime/session.py
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import asyncio
|
|
17
17
|
import contextvars
|
|
18
18
|
import typing
|
|
19
|
+
import uuid
|
|
19
20
|
from collections.abc import Awaitable
|
|
20
21
|
from collections.abc import Callable
|
|
21
22
|
from contextlib import asynccontextmanager
|
|
@@ -111,7 +112,7 @@ class SessionManager:
|
|
|
111
112
|
token_user_authentication = self._context_state.user_auth_callback.set(user_authentication_callback)
|
|
112
113
|
|
|
113
114
|
if isinstance(http_connection, WebSocket):
|
|
114
|
-
self.set_metadata_from_websocket(user_message_id, conversation_id)
|
|
115
|
+
self.set_metadata_from_websocket(http_connection, user_message_id, conversation_id)
|
|
115
116
|
|
|
116
117
|
if isinstance(http_connection, Request):
|
|
117
118
|
self.set_metadata_from_http_request(http_connection)
|
|
@@ -161,11 +162,56 @@ class SessionManager:
|
|
|
161
162
|
if request.headers.get("user-message-id"):
|
|
162
163
|
self._context_state.user_message_id.set(request.headers["user-message-id"])
|
|
163
164
|
|
|
164
|
-
|
|
165
|
+
# W3C Trace Context header: traceparent: 00-<trace-id>-<span-id>-<flags>
|
|
166
|
+
traceparent = request.headers.get("traceparent")
|
|
167
|
+
if traceparent:
|
|
168
|
+
try:
|
|
169
|
+
parts = traceparent.split("-")
|
|
170
|
+
if len(parts) >= 4:
|
|
171
|
+
trace_id_hex = parts[1]
|
|
172
|
+
if len(trace_id_hex) == 32:
|
|
173
|
+
trace_id_int = uuid.UUID(trace_id_hex).int
|
|
174
|
+
self._context_state.workflow_trace_id.set(trace_id_int)
|
|
175
|
+
except Exception:
|
|
176
|
+
pass
|
|
177
|
+
|
|
178
|
+
if not self._context_state.workflow_trace_id.get():
|
|
179
|
+
workflow_trace_id = request.headers.get("workflow-trace-id")
|
|
180
|
+
if workflow_trace_id:
|
|
181
|
+
try:
|
|
182
|
+
self._context_state.workflow_trace_id.set(uuid.UUID(workflow_trace_id).int)
|
|
183
|
+
except Exception:
|
|
184
|
+
pass
|
|
185
|
+
|
|
186
|
+
workflow_run_id = request.headers.get("workflow-run-id")
|
|
187
|
+
if workflow_run_id:
|
|
188
|
+
self._context_state.workflow_run_id.set(workflow_run_id)
|
|
189
|
+
|
|
190
|
+
def set_metadata_from_websocket(self,
|
|
191
|
+
websocket: WebSocket,
|
|
192
|
+
user_message_id: str | None,
|
|
193
|
+
conversation_id: str | None) -> None:
|
|
165
194
|
"""
|
|
166
|
-
Extracts and sets user metadata for
|
|
195
|
+
Extracts and sets user metadata for WebSocket connections.
|
|
167
196
|
"""
|
|
168
197
|
|
|
198
|
+
# Extract cookies from WebSocket headers (similar to HTTP request)
|
|
199
|
+
if websocket and hasattr(websocket, 'scope') and 'headers' in websocket.scope:
|
|
200
|
+
cookies = {}
|
|
201
|
+
for header_name, header_value in websocket.scope.get('headers', []):
|
|
202
|
+
if header_name == b'cookie':
|
|
203
|
+
cookie_header = header_value.decode('utf-8')
|
|
204
|
+
# Parse cookie header: "name1=value1; name2=value2"
|
|
205
|
+
for cookie in cookie_header.split(';'):
|
|
206
|
+
cookie = cookie.strip()
|
|
207
|
+
if '=' in cookie:
|
|
208
|
+
name, value = cookie.split('=', 1)
|
|
209
|
+
cookies[name.strip()] = value.strip()
|
|
210
|
+
|
|
211
|
+
# Set cookies in metadata (same as HTTP request)
|
|
212
|
+
self._context.metadata._request.cookies = cookies
|
|
213
|
+
self._context_state.metadata.set(self._context.metadata)
|
|
214
|
+
|
|
169
215
|
if conversation_id is not None:
|
|
170
216
|
self._context_state.conversation_id.set(conversation_id)
|
|
171
217
|
|
nat/settings/global_settings.py
CHANGED
|
@@ -124,7 +124,7 @@ class Settings(HashableBaseModel):
|
|
|
124
124
|
if (short_names[key.local_name] == 1):
|
|
125
125
|
type_list.append((key.local_name, key.config_type))
|
|
126
126
|
|
|
127
|
-
return typing.Union[tuple(typing.Annotated[x_type, Tag(x_id)] for x_id, x_type in type_list)]
|
|
127
|
+
return typing.Union[*tuple(typing.Annotated[x_type, Tag(x_id)] for x_id, x_type in type_list)]
|
|
128
128
|
|
|
129
129
|
RegistryHandlerAnnotation = dict[
|
|
130
130
|
str,
|
|
@@ -169,7 +169,7 @@ class Settings(HashableBaseModel):
|
|
|
169
169
|
if (not os.path.exists(configuration_file)):
|
|
170
170
|
loaded_config = {}
|
|
171
171
|
else:
|
|
172
|
-
with open(file_path,
|
|
172
|
+
with open(file_path, encoding="utf-8") as f:
|
|
173
173
|
try:
|
|
174
174
|
loaded_config = json.load(f)
|
|
175
175
|
except Exception as e:
|
nat/tool/chat_completion.py
CHANGED
|
@@ -63,7 +63,10 @@ async def register_chat_completion(config: ChatCompletionConfig, builder: Builde
|
|
|
63
63
|
# Generate response using the LLM
|
|
64
64
|
response = await llm.ainvoke(prompt)
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
if isinstance(response, str):
|
|
67
|
+
return response
|
|
68
|
+
|
|
69
|
+
return response.text()
|
|
67
70
|
|
|
68
71
|
except Exception as e:
|
|
69
72
|
# Fallback response if LLM call fails
|
|
@@ -92,7 +92,9 @@ class Sandbox(abc.ABC):
|
|
|
92
92
|
raise ValueError(f"Language {language} not supported")
|
|
93
93
|
|
|
94
94
|
generated_code = generated_code.strip().strip("`")
|
|
95
|
-
|
|
95
|
+
# Use json.dumps to properly escape the generated_code instead of repr()
|
|
96
|
+
escaped_code = json.dumps(generated_code)
|
|
97
|
+
code_to_execute = textwrap.dedent(f"""
|
|
96
98
|
import traceback
|
|
97
99
|
import json
|
|
98
100
|
import os
|
|
@@ -101,11 +103,6 @@ class Sandbox(abc.ABC):
|
|
|
101
103
|
import io
|
|
102
104
|
warnings.filterwarnings('ignore')
|
|
103
105
|
os.environ['OPENBLAS_NUM_THREADS'] = '16'
|
|
104
|
-
""").strip()
|
|
105
|
-
|
|
106
|
-
# Use json.dumps to properly escape the generated_code instead of repr()
|
|
107
|
-
escaped_code = json.dumps(generated_code)
|
|
108
|
-
code_to_execute += textwrap.dedent(f"""
|
|
109
106
|
|
|
110
107
|
generated_code = {escaped_code}
|
|
111
108
|
|
|
@@ -12,43 +12,26 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
#
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
# Create Lean project directory and initialize a new Lean project with Mathlib4
|
|
30
|
-
RUN mkdir -p /lean4 && cd /lean4 && \
|
|
31
|
-
/root/.elan/bin/lake new my_project && \
|
|
32
|
-
cd my_project && \
|
|
33
|
-
echo 'leanprover/lean4:v4.12.0' > lean-toolchain && \
|
|
34
|
-
echo 'require mathlib from git "https://github.com/leanprover-community/mathlib4" @ "v4.12.0"' >> lakefile.lean
|
|
35
|
-
|
|
36
|
-
# Download and cache Mathlib4 to avoid recompiling, then build the project
|
|
37
|
-
RUN cd /lean4/my_project && \
|
|
38
|
-
/root/.elan/bin/lake exe cache get && \
|
|
39
|
-
/root/.elan/bin/lake build
|
|
40
|
-
|
|
41
|
-
# Set environment variables to include Lean project path
|
|
42
|
-
ENV LEAN_PATH="/lean4/my_project"
|
|
43
|
-
ENV PATH="/lean4/my_project:$PATH"
|
|
15
|
+
# UWSGI_CHEAPER sets the number of initial uWSGI worker processes
|
|
16
|
+
# UWSGI_PROCESSES sets the maximum number of uWSGI worker processes
|
|
17
|
+
ARG UWSGI_CHEAPER=5
|
|
18
|
+
ARG UWSGI_PROCESSES=10
|
|
19
|
+
|
|
20
|
+
# Use the base image with Python 3.13
|
|
21
|
+
FROM python:3.13-slim-bookworm
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
RUN apt update && \
|
|
25
|
+
apt upgrade && \
|
|
26
|
+
apt install -y --no-install-recommends libexpat1 && \
|
|
27
|
+
apt clean && \
|
|
28
|
+
rm -rf /var/lib/apt/lists/*
|
|
44
29
|
|
|
45
30
|
# Set up application code and install Python dependencies
|
|
46
31
|
COPY sandbox.requirements.txt /app/requirements.txt
|
|
47
32
|
RUN pip install --no-cache-dir -r /app/requirements.txt
|
|
48
33
|
COPY local_sandbox_server.py /app/main.py
|
|
49
|
-
|
|
50
|
-
# Set the working directory to /app
|
|
51
|
-
WORKDIR /app
|
|
34
|
+
RUN mkdir /workspace
|
|
52
35
|
|
|
53
36
|
# Set Flask app environment variables and ports
|
|
54
37
|
ARG UWSGI_CHEAPER
|
|
@@ -58,3 +41,7 @@ ARG UWSGI_PROCESSES
|
|
|
58
41
|
ENV UWSGI_PROCESSES=$UWSGI_PROCESSES
|
|
59
42
|
|
|
60
43
|
ENV LISTEN_PORT=6000
|
|
44
|
+
EXPOSE 6000
|
|
45
|
+
|
|
46
|
+
WORKDIR /app
|
|
47
|
+
CMD uwsgi --http 0.0.0.0:${LISTEN_PORT} --master -p ${UWSGI_PROCESSES} --force-cwd /workspace -w main:app
|
|
@@ -62,7 +62,7 @@ class CodeExecutionResponse(Response):
|
|
|
62
62
|
super().__init__(status=status_code, mimetype="application/json", response=result.model_dump_json())
|
|
63
63
|
|
|
64
64
|
@classmethod
|
|
65
|
-
def with_error(cls, status_code: int, error_message: str) ->
|
|
65
|
+
def with_error(cls, status_code: int, error_message: str) -> CodeExecutionResponse:
|
|
66
66
|
return cls(status_code,
|
|
67
67
|
CodeExecutionResult(process_status=CodeExecutionStatus.ERROR, stdout="", stderr=error_message))
|
|
68
68
|
|
|
@@ -194,5 +194,10 @@ def execute():
|
|
|
194
194
|
return do_execute(request)
|
|
195
195
|
|
|
196
196
|
|
|
197
|
+
@app.route("/", methods=["GET"])
|
|
198
|
+
def status() -> tuple[dict[str, str], int]:
|
|
199
|
+
return ({"status": "ok"}, 200)
|
|
200
|
+
|
|
201
|
+
|
|
197
202
|
if __name__ == '__main__':
|
|
198
203
|
app.run(port=6000)
|
|
@@ -19,7 +19,11 @@
|
|
|
19
19
|
|
|
20
20
|
DOCKER_COMMAND=${DOCKER_COMMAND:-"docker"}
|
|
21
21
|
SANDBOX_NAME=${1:-'local-sandbox'}
|
|
22
|
-
|
|
22
|
+
|
|
23
|
+
# UWSGI_CHEAPER sets the number of initial uWSGI worker processes
|
|
24
|
+
# UWSGI_PROCESSES sets the maximum number of uWSGI worker processes
|
|
25
|
+
UWSGI_CHEAPER=${UWSGI_CHEAPER:-5}
|
|
26
|
+
UWSGI_PROCESSES=${UWSGI_PROCESSES:-10}
|
|
23
27
|
|
|
24
28
|
# Get the output_data directory path for mounting
|
|
25
29
|
# Priority: command line argument > environment variable > default path (current directory)
|
|
@@ -37,14 +41,16 @@ fi
|
|
|
37
41
|
# Check if the Docker image already exists
|
|
38
42
|
if ! ${DOCKER_COMMAND} images ${SANDBOX_NAME} | grep -q "${SANDBOX_NAME}"; then
|
|
39
43
|
echo "Docker image not found locally. Building ${SANDBOX_NAME}..."
|
|
40
|
-
${DOCKER_COMMAND} build --tag=${SANDBOX_NAME}
|
|
44
|
+
${DOCKER_COMMAND} build --tag=${SANDBOX_NAME} \
|
|
45
|
+
--build-arg="UWSGI_PROCESSES=${UWSGI_PROCESSES}" \
|
|
46
|
+
--build-arg="UWSGI_CHEAPER=${UWSGI_CHEAPER}" \
|
|
47
|
+
-f Dockerfile.sandbox .
|
|
41
48
|
else
|
|
42
49
|
echo "Using existing Docker image: ${SANDBOX_NAME}"
|
|
43
50
|
fi
|
|
44
51
|
|
|
45
52
|
# Mount the output_data directory directly so files created in container appear in the local directory
|
|
46
|
-
${DOCKER_COMMAND} run --rm --name=local-sandbox \
|
|
53
|
+
${DOCKER_COMMAND} run --rm -ti --name=local-sandbox \
|
|
47
54
|
--network=host \
|
|
48
55
|
-v "${OUTPUT_DATA_PATH}:/workspace" \
|
|
49
|
-
-w /workspace \
|
|
50
56
|
${SANDBOX_NAME}
|
nat/tool/datetime_tools.py
CHANGED
|
@@ -72,7 +72,7 @@ async def current_datetime(_config: CurrentTimeToolConfig, _builder: Builder):
|
|
|
72
72
|
timezone_obj = _get_timezone_obj(headers)
|
|
73
73
|
|
|
74
74
|
now = datetime.datetime.now(timezone_obj)
|
|
75
|
-
now_machine_readable = now.strftime(
|
|
75
|
+
now_machine_readable = now.strftime("%Y-%m-%d %H:%M:%S %z")
|
|
76
76
|
|
|
77
77
|
# Returns the current time in machine readable format with timezone offset.
|
|
78
78
|
return f"The current time of day is {now_machine_readable}"
|