nvidia-nat 1.4.0a20251120__py3-none-any.whl → 1.4.0a20260113__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.
Files changed (492) hide show
  1. aiq/__init__.py +1 -1
  2. nat/{front_ends/mcp → agent/auto_memory_wrapper}/__init__.py +1 -1
  3. nat/agent/auto_memory_wrapper/agent.py +278 -0
  4. nat/agent/auto_memory_wrapper/register.py +227 -0
  5. nat/agent/auto_memory_wrapper/state.py +30 -0
  6. nat/agent/base.py +1 -1
  7. nat/agent/dual_node.py +1 -1
  8. nat/agent/prompt_optimizer/prompt.py +1 -1
  9. nat/agent/prompt_optimizer/register.py +1 -1
  10. nat/agent/react_agent/agent.py +16 -9
  11. nat/agent/react_agent/output_parser.py +2 -2
  12. nat/agent/react_agent/prompt.py +3 -2
  13. nat/agent/react_agent/register.py +2 -2
  14. nat/agent/react_agent/register_per_user_agent.py +104 -0
  15. nat/agent/reasoning_agent/reasoning_agent.py +1 -1
  16. nat/agent/register.py +3 -1
  17. nat/agent/responses_api_agent/__init__.py +1 -1
  18. nat/agent/responses_api_agent/register.py +1 -1
  19. nat/agent/rewoo_agent/agent.py +9 -4
  20. nat/agent/rewoo_agent/prompt.py +1 -1
  21. nat/agent/rewoo_agent/register.py +1 -1
  22. nat/agent/tool_calling_agent/agent.py +5 -4
  23. nat/agent/tool_calling_agent/register.py +1 -1
  24. nat/authentication/__init__.py +1 -1
  25. nat/authentication/api_key/__init__.py +1 -1
  26. nat/authentication/api_key/api_key_auth_provider.py +1 -1
  27. nat/authentication/api_key/api_key_auth_provider_config.py +22 -7
  28. nat/authentication/api_key/register.py +1 -1
  29. nat/authentication/credential_validator/__init__.py +1 -1
  30. nat/authentication/credential_validator/bearer_token_validator.py +1 -1
  31. nat/authentication/exceptions/__init__.py +1 -1
  32. nat/authentication/exceptions/api_key_exceptions.py +1 -1
  33. nat/authentication/http_basic_auth/http_basic_auth_provider.py +1 -1
  34. nat/authentication/http_basic_auth/register.py +1 -1
  35. nat/authentication/interfaces.py +1 -1
  36. nat/authentication/oauth2/__init__.py +1 -1
  37. nat/authentication/oauth2/oauth2_auth_code_flow_provider.py +1 -1
  38. nat/authentication/oauth2/oauth2_auth_code_flow_provider_config.py +1 -1
  39. nat/authentication/oauth2/oauth2_resource_server_config.py +1 -1
  40. nat/authentication/oauth2/register.py +1 -1
  41. nat/authentication/register.py +1 -1
  42. nat/builder/builder.py +511 -1
  43. nat/builder/child_builder.py +385 -0
  44. nat/builder/component_utils.py +28 -4
  45. nat/builder/context.py +17 -1
  46. nat/builder/embedder.py +1 -1
  47. nat/builder/eval_builder.py +19 -7
  48. nat/builder/evaluator.py +1 -1
  49. nat/builder/framework_enum.py +2 -1
  50. nat/builder/front_end.py +1 -1
  51. nat/builder/function.py +40 -3
  52. nat/builder/function_base.py +1 -1
  53. nat/builder/function_info.py +1 -1
  54. nat/builder/intermediate_step_manager.py +1 -1
  55. nat/builder/llm.py +1 -1
  56. nat/builder/per_user_workflow_builder.py +843 -0
  57. nat/builder/retriever.py +1 -1
  58. nat/builder/sync_builder.py +571 -0
  59. nat/builder/user_interaction_manager.py +1 -1
  60. nat/builder/workflow.py +1 -1
  61. nat/builder/workflow_builder.py +536 -424
  62. nat/cli/__init__.py +1 -1
  63. nat/cli/cli_utils/config_override.py +1 -1
  64. nat/cli/cli_utils/validation.py +32 -1
  65. nat/cli/commands/configure/channel/add.py +1 -1
  66. nat/cli/commands/configure/channel/channel.py +1 -1
  67. nat/cli/commands/configure/channel/remove.py +1 -1
  68. nat/cli/commands/configure/channel/update.py +1 -1
  69. nat/cli/commands/configure/configure.py +1 -1
  70. nat/cli/commands/evaluate.py +87 -13
  71. nat/cli/commands/finetune.py +132 -0
  72. nat/cli/commands/info/__init__.py +1 -1
  73. nat/cli/commands/info/info.py +1 -1
  74. nat/cli/commands/info/list_channels.py +1 -1
  75. nat/cli/commands/info/list_components.py +1 -1
  76. nat/cli/commands/object_store/__init__.py +1 -1
  77. nat/cli/commands/object_store/object_store.py +1 -1
  78. nat/cli/commands/optimize.py +1 -1
  79. nat/cli/commands/{mcp → red_teaming}/__init__.py +1 -1
  80. nat/cli/commands/red_teaming/red_teaming.py +138 -0
  81. nat/cli/commands/red_teaming/red_teaming_utils.py +73 -0
  82. nat/cli/commands/registry/__init__.py +1 -1
  83. nat/cli/commands/registry/publish.py +1 -1
  84. nat/cli/commands/registry/pull.py +1 -1
  85. nat/cli/commands/registry/registry.py +1 -1
  86. nat/cli/commands/registry/remove.py +1 -1
  87. nat/cli/commands/registry/search.py +1 -1
  88. nat/cli/commands/sizing/__init__.py +1 -1
  89. nat/cli/commands/sizing/calc.py +1 -1
  90. nat/cli/commands/sizing/sizing.py +1 -1
  91. nat/cli/commands/start.py +1 -1
  92. nat/cli/commands/uninstall.py +1 -1
  93. nat/cli/commands/validate.py +1 -1
  94. nat/cli/commands/workflow/__init__.py +1 -1
  95. nat/cli/commands/workflow/workflow.py +1 -1
  96. nat/cli/commands/workflow/workflow_commands.py +3 -2
  97. nat/cli/entrypoint.py +15 -37
  98. nat/cli/main.py +2 -2
  99. nat/cli/plugin_loader.py +69 -0
  100. nat/cli/register_workflow.py +183 -5
  101. nat/cli/type_registry.py +169 -3
  102. nat/control_flow/register.py +1 -1
  103. nat/control_flow/router_agent/agent.py +1 -1
  104. nat/control_flow/router_agent/prompt.py +1 -1
  105. nat/control_flow/router_agent/register.py +1 -1
  106. nat/control_flow/sequential_executor.py +28 -7
  107. nat/data_models/__init__.py +1 -1
  108. nat/data_models/agent.py +1 -1
  109. nat/data_models/api_server.py +38 -3
  110. nat/data_models/authentication.py +1 -1
  111. nat/data_models/common.py +1 -1
  112. nat/data_models/component.py +7 -1
  113. nat/data_models/component_ref.py +34 -1
  114. nat/data_models/config.py +62 -1
  115. nat/data_models/dataset_handler.py +15 -2
  116. nat/data_models/discovery_metadata.py +1 -1
  117. nat/data_models/embedder.py +1 -1
  118. nat/data_models/evaluate.py +6 -1
  119. nat/data_models/evaluator.py +1 -1
  120. nat/data_models/finetuning.py +260 -0
  121. nat/data_models/front_end.py +1 -1
  122. nat/data_models/function.py +1 -1
  123. nat/data_models/function_dependencies.py +1 -1
  124. nat/data_models/gated_field_mixin.py +1 -1
  125. nat/data_models/interactive.py +1 -1
  126. nat/data_models/intermediate_step.py +29 -2
  127. nat/data_models/invocation_node.py +1 -1
  128. nat/data_models/llm.py +1 -1
  129. nat/data_models/logging.py +1 -1
  130. nat/data_models/memory.py +1 -1
  131. nat/data_models/middleware.py +3 -1
  132. nat/data_models/object_store.py +1 -1
  133. nat/data_models/openai_mcp.py +1 -1
  134. nat/data_models/optimizable.py +1 -1
  135. nat/data_models/optimizer.py +1 -1
  136. nat/data_models/profiler.py +1 -1
  137. nat/data_models/registry_handler.py +1 -1
  138. nat/data_models/retriever.py +1 -1
  139. nat/data_models/retry_mixin.py +1 -1
  140. nat/data_models/runtime_enum.py +1 -1
  141. nat/data_models/span.py +1 -1
  142. nat/data_models/step_adaptor.py +1 -1
  143. nat/data_models/streaming.py +1 -1
  144. nat/data_models/swe_bench_model.py +1 -1
  145. nat/data_models/telemetry_exporter.py +1 -1
  146. nat/data_models/thinking_mixin.py +1 -1
  147. nat/data_models/ttc_strategy.py +1 -1
  148. nat/embedder/azure_openai_embedder.py +1 -1
  149. nat/embedder/nim_embedder.py +1 -1
  150. nat/embedder/openai_embedder.py +1 -1
  151. nat/embedder/register.py +1 -1
  152. nat/eval/__init__.py +1 -1
  153. nat/eval/config.py +8 -1
  154. nat/eval/dataset_handler/dataset_downloader.py +1 -1
  155. nat/eval/dataset_handler/dataset_filter.py +1 -1
  156. nat/eval/dataset_handler/dataset_handler.py +4 -2
  157. nat/eval/evaluate.py +217 -80
  158. nat/eval/evaluator/__init__.py +1 -1
  159. nat/eval/evaluator/base_evaluator.py +2 -2
  160. nat/eval/evaluator/evaluator_model.py +3 -2
  161. nat/eval/intermediate_step_adapter.py +1 -1
  162. nat/eval/llm_validator.py +336 -0
  163. nat/eval/rag_evaluator/evaluate.py +17 -10
  164. nat/eval/rag_evaluator/register.py +1 -1
  165. nat/eval/red_teaming_evaluator/__init__.py +14 -0
  166. nat/eval/red_teaming_evaluator/data_models.py +66 -0
  167. nat/eval/red_teaming_evaluator/evaluate.py +327 -0
  168. nat/eval/red_teaming_evaluator/filter_conditions.py +75 -0
  169. nat/eval/red_teaming_evaluator/register.py +55 -0
  170. nat/eval/register.py +2 -1
  171. nat/eval/remote_workflow.py +1 -1
  172. nat/eval/runners/__init__.py +1 -1
  173. nat/eval/runners/config.py +1 -1
  174. nat/eval/runners/multi_eval_runner.py +1 -1
  175. nat/eval/runners/red_teaming_runner/__init__.py +24 -0
  176. nat/eval/runners/red_teaming_runner/config.py +282 -0
  177. nat/eval/runners/red_teaming_runner/report_utils.py +707 -0
  178. nat/eval/runners/red_teaming_runner/runner.py +867 -0
  179. nat/eval/runtime_evaluator/__init__.py +1 -1
  180. nat/eval/runtime_evaluator/evaluate.py +1 -1
  181. nat/eval/runtime_evaluator/register.py +1 -1
  182. nat/eval/runtime_event_subscriber.py +1 -1
  183. nat/eval/swe_bench_evaluator/evaluate.py +1 -1
  184. nat/eval/swe_bench_evaluator/register.py +1 -1
  185. nat/eval/trajectory_evaluator/evaluate.py +2 -2
  186. nat/eval/trajectory_evaluator/register.py +1 -1
  187. nat/eval/tunable_rag_evaluator/evaluate.py +5 -5
  188. nat/eval/tunable_rag_evaluator/register.py +1 -1
  189. nat/eval/usage_stats.py +1 -1
  190. nat/eval/utils/eval_trace_ctx.py +1 -1
  191. nat/eval/utils/output_uploader.py +1 -1
  192. nat/eval/utils/tqdm_position_registry.py +1 -1
  193. nat/eval/utils/weave_eval.py +1 -1
  194. nat/experimental/decorators/experimental_warning_decorator.py +1 -1
  195. nat/experimental/test_time_compute/editing/iterative_plan_refinement_editor.py +1 -1
  196. nat/experimental/test_time_compute/editing/llm_as_a_judge_editor.py +1 -1
  197. nat/experimental/test_time_compute/editing/motivation_aware_summarization.py +1 -1
  198. nat/experimental/test_time_compute/functions/execute_score_select_function.py +1 -1
  199. nat/experimental/test_time_compute/functions/multi_llm_judge_function.py +88 -0
  200. nat/experimental/test_time_compute/functions/plan_select_execute_function.py +1 -1
  201. nat/experimental/test_time_compute/functions/ttc_tool_orchestration_function.py +1 -1
  202. nat/experimental/test_time_compute/functions/ttc_tool_wrapper_function.py +1 -1
  203. nat/experimental/test_time_compute/models/editor_config.py +1 -1
  204. nat/experimental/test_time_compute/models/scoring_config.py +1 -1
  205. nat/experimental/test_time_compute/models/search_config.py +20 -2
  206. nat/experimental/test_time_compute/models/selection_config.py +33 -2
  207. nat/experimental/test_time_compute/models/stage_enums.py +1 -1
  208. nat/experimental/test_time_compute/models/strategy_base.py +1 -1
  209. nat/experimental/test_time_compute/models/tool_use_config.py +1 -1
  210. nat/experimental/test_time_compute/models/ttc_item.py +1 -1
  211. nat/experimental/test_time_compute/register.py +4 -1
  212. nat/experimental/test_time_compute/scoring/llm_based_agent_scorer.py +1 -1
  213. nat/experimental/test_time_compute/scoring/llm_based_plan_scorer.py +1 -1
  214. nat/experimental/test_time_compute/scoring/motivation_aware_scorer.py +1 -1
  215. nat/experimental/test_time_compute/search/multi_llm_generation.py +115 -0
  216. nat/experimental/test_time_compute/search/multi_llm_planner.py +1 -1
  217. nat/experimental/test_time_compute/search/multi_query_retrieval_search.py +1 -1
  218. nat/experimental/test_time_compute/search/single_shot_multi_plan_planner.py +1 -1
  219. nat/experimental/test_time_compute/selection/best_of_n_selector.py +1 -1
  220. nat/experimental/test_time_compute/selection/llm_based_agent_output_selector.py +1 -1
  221. nat/experimental/test_time_compute/selection/llm_based_output_merging_selector.py +1 -1
  222. nat/experimental/test_time_compute/selection/llm_based_plan_selector.py +1 -1
  223. nat/experimental/test_time_compute/selection/llm_judge_selection.py +127 -0
  224. nat/experimental/test_time_compute/selection/threshold_selector.py +1 -1
  225. nat/finetuning/__init__.py +24 -0
  226. nat/finetuning/finetuning_runtime.py +143 -0
  227. nat/finetuning/interfaces/__init__.py +24 -0
  228. nat/finetuning/interfaces/finetuning_runner.py +261 -0
  229. nat/finetuning/interfaces/trainer_adapter.py +103 -0
  230. nat/finetuning/interfaces/trajectory_builder.py +115 -0
  231. nat/finetuning/utils/__init__.py +15 -0
  232. nat/finetuning/utils/parsers/__init__.py +15 -0
  233. nat/finetuning/utils/parsers/adk_parser.py +141 -0
  234. nat/finetuning/utils/parsers/base_parser.py +238 -0
  235. nat/finetuning/utils/parsers/common.py +91 -0
  236. nat/finetuning/utils/parsers/langchain_parser.py +267 -0
  237. nat/finetuning/utils/parsers/llama_index_parser.py +218 -0
  238. nat/front_ends/__init__.py +1 -1
  239. nat/front_ends/console/__init__.py +1 -1
  240. nat/front_ends/console/authentication_flow_handler.py +1 -1
  241. nat/front_ends/console/console_front_end_config.py +4 -1
  242. nat/front_ends/console/console_front_end_plugin.py +5 -4
  243. nat/front_ends/console/register.py +1 -1
  244. nat/front_ends/cron/__init__.py +1 -1
  245. nat/front_ends/fastapi/__init__.py +1 -1
  246. nat/front_ends/fastapi/async_job.py +128 -0
  247. nat/front_ends/fastapi/auth_flow_handlers/http_flow_handler.py +1 -1
  248. nat/front_ends/fastapi/auth_flow_handlers/websocket_flow_handler.py +13 -9
  249. nat/front_ends/fastapi/dask_client_mixin.py +1 -1
  250. nat/front_ends/fastapi/fastapi_front_end_config.py +1 -1
  251. nat/front_ends/fastapi/fastapi_front_end_controller.py +1 -1
  252. nat/front_ends/fastapi/fastapi_front_end_plugin.py +25 -30
  253. nat/front_ends/fastapi/fastapi_front_end_plugin_worker.py +195 -60
  254. nat/front_ends/fastapi/html_snippets/__init__.py +1 -1
  255. nat/front_ends/fastapi/html_snippets/auth_code_grant_success.py +1 -1
  256. nat/front_ends/fastapi/intermediate_steps_subscriber.py +12 -1
  257. nat/front_ends/fastapi/job_store.py +23 -11
  258. nat/front_ends/fastapi/main.py +1 -1
  259. nat/front_ends/fastapi/message_handler.py +27 -4
  260. nat/front_ends/fastapi/message_validator.py +54 -2
  261. nat/front_ends/fastapi/register.py +1 -1
  262. nat/front_ends/fastapi/response_helpers.py +16 -15
  263. nat/front_ends/fastapi/step_adaptor.py +1 -1
  264. nat/front_ends/fastapi/utils.py +1 -1
  265. nat/front_ends/register.py +1 -2
  266. nat/front_ends/simple_base/__init__.py +1 -1
  267. nat/front_ends/simple_base/simple_front_end_plugin_base.py +6 -4
  268. nat/llm/aws_bedrock_llm.py +1 -1
  269. nat/llm/azure_openai_llm.py +10 -1
  270. nat/llm/dynamo_llm.py +363 -0
  271. nat/llm/huggingface_llm.py +177 -0
  272. nat/llm/litellm_llm.py +1 -1
  273. nat/llm/nim_llm.py +1 -1
  274. nat/llm/openai_llm.py +1 -1
  275. nat/llm/register.py +3 -1
  276. nat/llm/utils/__init__.py +1 -1
  277. nat/llm/utils/env_config_value.py +1 -1
  278. nat/llm/utils/error.py +1 -1
  279. nat/llm/utils/thinking.py +1 -1
  280. nat/memory/__init__.py +1 -1
  281. nat/memory/interfaces.py +1 -1
  282. nat/memory/models.py +1 -1
  283. nat/meta/pypi.md +1 -1
  284. nat/middleware/__init__.py +5 -5
  285. nat/middleware/cache/__init__.py +14 -0
  286. nat/middleware/{cache_middleware.py → cache/cache_middleware.py} +39 -42
  287. nat/middleware/cache/cache_middleware_config.py +44 -0
  288. nat/middleware/cache/register.py +33 -0
  289. nat/middleware/defense/__init__.py +14 -0
  290. nat/middleware/defense/defense_middleware.py +362 -0
  291. nat/middleware/defense/defense_middleware_content_guard.py +455 -0
  292. nat/middleware/defense/defense_middleware_data_models.py +91 -0
  293. nat/middleware/defense/defense_middleware_output_verifier.py +440 -0
  294. nat/middleware/defense/defense_middleware_pii.py +356 -0
  295. nat/middleware/defense/register.py +82 -0
  296. nat/middleware/dynamic/__init__.py +14 -0
  297. nat/middleware/dynamic/dynamic_function_middleware.py +962 -0
  298. nat/middleware/dynamic/dynamic_middleware_config.py +132 -0
  299. nat/middleware/dynamic/register.py +34 -0
  300. nat/middleware/function_middleware.py +236 -52
  301. nat/middleware/logging/__init__.py +14 -0
  302. nat/middleware/logging/logging_middleware.py +67 -0
  303. nat/middleware/logging/logging_middleware_config.py +28 -0
  304. nat/middleware/logging/register.py +33 -0
  305. nat/middleware/middleware.py +142 -28
  306. nat/middleware/red_teaming/__init__.py +14 -0
  307. nat/middleware/red_teaming/red_teaming_middleware.py +344 -0
  308. nat/middleware/red_teaming/red_teaming_middleware_config.py +112 -0
  309. nat/middleware/red_teaming/register.py +47 -0
  310. nat/middleware/register.py +7 -20
  311. nat/middleware/utils/__init__.py +14 -0
  312. nat/middleware/utils/workflow_inventory.py +155 -0
  313. nat/object_store/__init__.py +1 -1
  314. nat/object_store/in_memory_object_store.py +1 -1
  315. nat/object_store/interfaces.py +1 -1
  316. nat/object_store/models.py +1 -1
  317. nat/object_store/register.py +1 -1
  318. nat/observability/__init__.py +1 -1
  319. nat/observability/exporter/__init__.py +1 -1
  320. nat/observability/exporter/base_exporter.py +1 -1
  321. nat/observability/exporter/exporter.py +1 -1
  322. nat/observability/exporter/file_exporter.py +1 -1
  323. nat/observability/exporter/processing_exporter.py +1 -1
  324. nat/observability/exporter/raw_exporter.py +1 -1
  325. nat/observability/exporter/span_exporter.py +7 -1
  326. nat/observability/exporter_manager.py +1 -1
  327. nat/observability/mixin/__init__.py +1 -1
  328. nat/observability/mixin/batch_config_mixin.py +1 -1
  329. nat/observability/mixin/collector_config_mixin.py +1 -1
  330. nat/observability/mixin/file_mixin.py +1 -1
  331. nat/observability/mixin/file_mode.py +1 -1
  332. nat/observability/mixin/redaction_config_mixin.py +1 -1
  333. nat/observability/mixin/resource_conflict_mixin.py +1 -1
  334. nat/observability/mixin/serialize_mixin.py +1 -1
  335. nat/observability/mixin/tagging_config_mixin.py +1 -1
  336. nat/observability/mixin/type_introspection_mixin.py +1 -1
  337. nat/observability/processor/__init__.py +1 -1
  338. nat/observability/processor/batching_processor.py +1 -1
  339. nat/observability/processor/callback_processor.py +1 -1
  340. nat/observability/processor/falsy_batch_filter_processor.py +1 -1
  341. nat/observability/processor/intermediate_step_serializer.py +1 -1
  342. nat/observability/processor/processor.py +1 -1
  343. nat/observability/processor/processor_factory.py +1 -1
  344. nat/observability/processor/redaction/__init__.py +1 -1
  345. nat/observability/processor/redaction/contextual_redaction_processor.py +1 -1
  346. nat/observability/processor/redaction/contextual_span_redaction_processor.py +1 -1
  347. nat/observability/processor/redaction/redaction_processor.py +1 -1
  348. nat/observability/processor/redaction/span_header_redaction_processor.py +1 -1
  349. nat/observability/processor/span_tagging_processor.py +1 -1
  350. nat/observability/register.py +1 -1
  351. nat/observability/utils/__init__.py +1 -1
  352. nat/observability/utils/dict_utils.py +1 -1
  353. nat/observability/utils/time_utils.py +1 -1
  354. nat/profiler/calc/__init__.py +1 -1
  355. nat/profiler/calc/calc_runner.py +3 -3
  356. nat/profiler/calc/calculations.py +1 -1
  357. nat/profiler/calc/data_models.py +1 -1
  358. nat/profiler/calc/plot.py +30 -3
  359. nat/profiler/callbacks/agno_callback_handler.py +1 -1
  360. nat/profiler/callbacks/base_callback_class.py +1 -1
  361. nat/profiler/callbacks/langchain_callback_handler.py +33 -3
  362. nat/profiler/callbacks/llama_index_callback_handler.py +13 -10
  363. nat/profiler/callbacks/semantic_kernel_callback_handler.py +1 -1
  364. nat/profiler/callbacks/token_usage_base_model.py +1 -1
  365. nat/profiler/data_frame_row.py +1 -1
  366. nat/profiler/data_models.py +1 -1
  367. nat/profiler/decorators/framework_wrapper.py +16 -1
  368. nat/profiler/decorators/function_tracking.py +1 -1
  369. nat/profiler/forecasting/config.py +1 -1
  370. nat/profiler/forecasting/model_trainer.py +1 -1
  371. nat/profiler/forecasting/models/__init__.py +1 -1
  372. nat/profiler/forecasting/models/forecasting_base_model.py +1 -1
  373. nat/profiler/forecasting/models/linear_model.py +1 -1
  374. nat/profiler/forecasting/models/random_forest_regressor.py +1 -1
  375. nat/profiler/inference_metrics_model.py +1 -1
  376. nat/profiler/inference_optimization/bottleneck_analysis/nested_stack_analysis.py +1 -1
  377. nat/profiler/inference_optimization/bottleneck_analysis/simple_stack_analysis.py +1 -1
  378. nat/profiler/inference_optimization/data_models.py +1 -1
  379. nat/profiler/inference_optimization/experimental/concurrency_spike_analysis.py +1 -1
  380. nat/profiler/inference_optimization/experimental/prefix_span_analysis.py +1 -1
  381. nat/profiler/inference_optimization/llm_metrics.py +1 -1
  382. nat/profiler/inference_optimization/prompt_caching.py +1 -1
  383. nat/profiler/inference_optimization/token_uniqueness.py +1 -1
  384. nat/profiler/inference_optimization/workflow_runtimes.py +1 -1
  385. nat/profiler/intermediate_property_adapter.py +1 -1
  386. nat/profiler/parameter_optimization/optimizable_utils.py +1 -1
  387. nat/profiler/parameter_optimization/optimizer_runtime.py +1 -1
  388. nat/profiler/parameter_optimization/parameter_optimizer.py +1 -1
  389. nat/profiler/parameter_optimization/parameter_selection.py +1 -1
  390. nat/profiler/parameter_optimization/pareto_visualizer.py +1 -1
  391. nat/profiler/parameter_optimization/prompt_optimizer.py +1 -1
  392. nat/profiler/parameter_optimization/update_helpers.py +1 -1
  393. nat/profiler/profile_runner.py +1 -1
  394. nat/profiler/utils.py +1 -1
  395. nat/registry_handlers/local/local_handler.py +1 -1
  396. nat/registry_handlers/local/register_local.py +1 -1
  397. nat/registry_handlers/metadata_factory.py +1 -1
  398. nat/registry_handlers/package_utils.py +1 -1
  399. nat/registry_handlers/pypi/pypi_handler.py +1 -1
  400. nat/registry_handlers/pypi/register_pypi.py +1 -1
  401. nat/registry_handlers/register.py +1 -1
  402. nat/registry_handlers/registry_handler_base.py +1 -1
  403. nat/registry_handlers/rest/register_rest.py +1 -1
  404. nat/registry_handlers/rest/rest_handler.py +1 -1
  405. nat/registry_handlers/schemas/headers.py +1 -1
  406. nat/registry_handlers/schemas/package.py +1 -1
  407. nat/registry_handlers/schemas/publish.py +1 -1
  408. nat/registry_handlers/schemas/pull.py +1 -1
  409. nat/registry_handlers/schemas/remove.py +1 -1
  410. nat/registry_handlers/schemas/search.py +1 -1
  411. nat/registry_handlers/schemas/status.py +1 -1
  412. nat/retriever/interface.py +1 -1
  413. nat/retriever/milvus/__init__.py +1 -1
  414. nat/retriever/milvus/register.py +1 -1
  415. nat/retriever/milvus/retriever.py +1 -1
  416. nat/retriever/models.py +1 -1
  417. nat/retriever/nemo_retriever/__init__.py +1 -1
  418. nat/retriever/nemo_retriever/register.py +1 -1
  419. nat/retriever/nemo_retriever/retriever.py +5 -5
  420. nat/retriever/register.py +1 -1
  421. nat/runtime/__init__.py +1 -1
  422. nat/runtime/loader.py +10 -3
  423. nat/runtime/metrics.py +180 -0
  424. nat/runtime/runner.py +1 -5
  425. nat/runtime/session.py +451 -32
  426. nat/runtime/user_metadata.py +1 -1
  427. nat/settings/global_settings.py +1 -1
  428. nat/tool/chat_completion.py +1 -1
  429. nat/tool/code_execution/README.md +1 -1
  430. nat/tool/code_execution/code_sandbox.py +1 -1
  431. nat/tool/code_execution/local_sandbox/Dockerfile.sandbox +1 -1
  432. nat/tool/code_execution/local_sandbox/__init__.py +1 -1
  433. nat/tool/code_execution/local_sandbox/local_sandbox_server.py +1 -1
  434. nat/tool/code_execution/local_sandbox/start_local_sandbox.sh +1 -1
  435. nat/tool/code_execution/register.py +1 -1
  436. nat/tool/code_execution/utils.py +1 -1
  437. nat/tool/datetime_tools.py +1 -1
  438. nat/tool/document_search.py +1 -1
  439. nat/tool/github_tools.py +1 -1
  440. nat/tool/memory_tools/add_memory_tool.py +1 -1
  441. nat/tool/memory_tools/delete_memory_tool.py +1 -1
  442. nat/tool/memory_tools/get_memory_tool.py +1 -1
  443. nat/tool/nvidia_rag.py +2 -2
  444. nat/tool/register.py +1 -1
  445. nat/tool/retriever.py +1 -1
  446. nat/tool/server_tools.py +1 -1
  447. nat/utils/__init__.py +8 -5
  448. nat/utils/callable_utils.py +1 -1
  449. nat/utils/data_models/schema_validator.py +1 -1
  450. nat/utils/debugging_utils.py +1 -1
  451. nat/utils/decorators.py +1 -1
  452. nat/utils/dump_distro_mapping.py +1 -1
  453. nat/utils/exception_handlers/automatic_retries.py +3 -3
  454. nat/utils/exception_handlers/schemas.py +1 -1
  455. nat/utils/io/model_processing.py +1 -1
  456. nat/utils/io/supress_logs.py +33 -0
  457. nat/utils/io/yaml_tools.py +1 -1
  458. nat/utils/log_levels.py +1 -1
  459. nat/utils/log_utils.py +13 -1
  460. nat/utils/metadata_utils.py +1 -1
  461. nat/utils/optional_imports.py +1 -1
  462. nat/utils/producer_consumer_queue.py +1 -1
  463. nat/utils/reactive/base/observable_base.py +1 -1
  464. nat/utils/reactive/base/observer_base.py +1 -1
  465. nat/utils/reactive/base/subject_base.py +1 -1
  466. nat/utils/reactive/observable.py +1 -1
  467. nat/utils/reactive/observer.py +1 -1
  468. nat/utils/reactive/subject.py +1 -1
  469. nat/utils/reactive/subscription.py +1 -1
  470. nat/utils/responses_api.py +1 -1
  471. nat/utils/settings/global_settings.py +1 -1
  472. nat/utils/string_utils.py +1 -1
  473. nat/utils/type_converter.py +18 -5
  474. nat/utils/type_utils.py +1 -1
  475. nat/utils/url_utils.py +1 -1
  476. {nvidia_nat-1.4.0a20251120.dist-info → nvidia_nat-1.4.0a20260113.dist-info}/METADATA +39 -14
  477. nvidia_nat-1.4.0a20260113.dist-info/RECORD +547 -0
  478. nvidia_nat-1.4.0a20260113.dist-info/entry_points.txt +38 -0
  479. nat/cli/commands/mcp/mcp.py +0 -986
  480. nat/front_ends/mcp/introspection_token_verifier.py +0 -73
  481. nat/front_ends/mcp/mcp_front_end_config.py +0 -109
  482. nat/front_ends/mcp/mcp_front_end_plugin.py +0 -155
  483. nat/front_ends/mcp/mcp_front_end_plugin_worker.py +0 -388
  484. nat/front_ends/mcp/memory_profiler.py +0 -320
  485. nat/front_ends/mcp/register.py +0 -27
  486. nat/front_ends/mcp/tool_converter.py +0 -321
  487. nvidia_nat-1.4.0a20251120.dist-info/RECORD +0 -488
  488. nvidia_nat-1.4.0a20251120.dist-info/entry_points.txt +0 -23
  489. {nvidia_nat-1.4.0a20251120.dist-info → nvidia_nat-1.4.0a20260113.dist-info}/WHEEL +0 -0
  490. {nvidia_nat-1.4.0a20251120.dist-info → nvidia_nat-1.4.0a20260113.dist-info}/licenses/LICENSE-3rd-party.txt +0 -0
  491. {nvidia_nat-1.4.0a20251120.dist-info → nvidia_nat-1.4.0a20260113.dist-info}/licenses/LICENSE.md +0 -0
  492. {nvidia_nat-1.4.0a20251120.dist-info → nvidia_nat-1.4.0a20260113.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,440 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025-2026, 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
+ Output Verifier Defense Middleware.
17
+
18
+ This middleware uses an LLM to verify function outputs for correctness and security.
19
+ It can detect incorrect results, malicious content, and provide corrections automatically.
20
+ """
21
+
22
+ import json
23
+ import logging
24
+ import re
25
+ from collections.abc import AsyncIterator
26
+ from typing import Any
27
+
28
+ from pydantic import Field
29
+
30
+ from nat.middleware.defense.defense_middleware import DefenseMiddleware
31
+ from nat.middleware.defense.defense_middleware import DefenseMiddlewareConfig
32
+ from nat.middleware.defense.defense_middleware_data_models import OutputVerificationResult
33
+ from nat.middleware.function_middleware import CallNext
34
+ from nat.middleware.function_middleware import CallNextStream
35
+ from nat.middleware.middleware import FunctionMiddlewareContext
36
+
37
+ logger = logging.getLogger(__name__)
38
+
39
+
40
+ class OutputVerifierMiddlewareConfig(DefenseMiddlewareConfig, name="output_verifier"):
41
+ """Configuration for Output Verifier middleware.
42
+
43
+ This middleware analyzes function outputs using an LLM to verify correctness,
44
+ detect security threats, and provide corrections when needed.
45
+
46
+ Actions:
47
+ - 'partial_compliance': Detect and log threats, but allow content to pass through
48
+ - 'refusal': Block output if threat detected (hard stop)
49
+ - 'redirection': Replace incorrect output with correct answer from LLM
50
+
51
+ Note: Only output analysis is currently supported (target_location='output').
52
+ """
53
+
54
+ llm_name: str = Field(description="Name of the LLM to use for verification (must be defined in llms section)")
55
+
56
+ threshold: float = Field(default=0.7, description="Confidence threshold for threat detection (0.0-1.0)")
57
+
58
+ tool_description: str | None = Field(
59
+ default=None, description="Description of what the tool/function does (optional, helps LLM verify correctness)")
60
+
61
+
62
+ class OutputVerifierMiddleware(DefenseMiddleware):
63
+ """Verification middleware using an LLM for correctness and security.
64
+
65
+ This middleware uses NAT's LLM system to verify function outputs for:
66
+
67
+ * Correctness and reasonableness
68
+ * Security validation (detecting malicious content and manipulated values)
69
+ * Providing automatic corrections when errors are detected
70
+
71
+ Only output analysis is currently supported (``target_location='output'``).
72
+
73
+ Streaming Behavior:
74
+ For 'refusal' and 'redirection' actions, chunks are buffered and checked
75
+ before yielding to prevent incorrect content from being streamed to clients.
76
+ For 'partial_compliance' action, chunks are yielded immediately; violations
77
+ are logged but content passes through.
78
+ """
79
+
80
+ def __init__(self, config: OutputVerifierMiddlewareConfig, builder):
81
+ """Initialize output verifier middleware.
82
+
83
+ Args:
84
+ config: Configuration for output verifier middleware
85
+ builder: Builder instance for loading LLMs
86
+ """
87
+ super().__init__(config, builder)
88
+ # Store config with correct type for linter
89
+ self.config: OutputVerifierMiddlewareConfig = config
90
+
91
+ # Output Verifier only supports output analysis
92
+ if config.target_location == "input":
93
+ raise ValueError("OutputVerifierMiddleware only supports target_location='output'. "
94
+ "Input analysis is not yet supported.")
95
+
96
+ self._llm = None # Lazy loaded LLM
97
+
98
+ async def _get_llm(self):
99
+ """Lazy load the LLM when first needed."""
100
+ if self._llm is None:
101
+ self._llm = await self._get_llm_for_defense(self.config.llm_name)
102
+ return self._llm
103
+
104
+ def _extract_json_from_response(self, response_text: str) -> str:
105
+ """Extract JSON from LLM response, handling markdown code blocks.
106
+
107
+ Args:
108
+ response_text: Raw response from LLM
109
+
110
+ Returns:
111
+ Extracted JSON string
112
+ """
113
+ # Remove markdown code blocks
114
+ if "```json" in response_text:
115
+ response_text = response_text.split("```json")[1].split("```")[0].strip()
116
+ elif "```" in response_text:
117
+ response_text = response_text.split("```")[1].split("```")[0].strip()
118
+
119
+ # Extract JSON object (handles nested braces)
120
+ json_match = re.search(r'\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}', response_text, re.DOTALL)
121
+ if json_match:
122
+ return json_match.group(0)
123
+
124
+ return response_text
125
+
126
+ async def _analyze_content(self,
127
+ content: Any,
128
+ content_type: str,
129
+ inputs: Any = None,
130
+ function_name: str | None = None) -> OutputVerificationResult:
131
+ """Check content for threats using the configured LLM.
132
+
133
+ Args:
134
+ content: The content to analyze
135
+ content_type: Either 'input' or 'output' (for logging only)
136
+ inputs: Optional function inputs for context (helps LLM calculate correct answers)
137
+ function_name: Name of the function being verified (for context)
138
+
139
+ Returns:
140
+ OutputVerificationResult with threat detection info and should_refuse flag.
141
+ """
142
+ content_str = str(content)
143
+
144
+ # Build structured system prompt
145
+ system_prompt = """You are a function output verifier that validates correctness and detects security threats.
146
+
147
+ Your task:
148
+ 1. Verify if the output is correct and reasonable given the function name and inputs
149
+ 2. Detect suspicious or manipulated values (extreme values, unexpected types, malicious content)
150
+ 3. If incorrect, provide the correct output
151
+ 4. Only report high confidence when certain
152
+
153
+ Respond ONLY with valid JSON in this exact format:
154
+ {"threat_detected": true/false, "confidence": 0.0-1.0, "reason": "brief explanation",
155
+ "correct_answer": "correct value if wrong, null if correct"}"""
156
+
157
+ # Build user prompt with function context
158
+ user_prompt_parts = []
159
+
160
+ if function_name:
161
+ user_prompt_parts.append(f"Function: {function_name}")
162
+
163
+ if self.config.tool_description:
164
+ user_prompt_parts.append(f"Description: {self.config.tool_description}")
165
+
166
+ if inputs is not None:
167
+ user_prompt_parts.append(f"Inputs: {inputs}")
168
+
169
+ user_prompt_parts.append(f"{content_type.capitalize()}: {content_str}")
170
+
171
+ prompt = "\n".join(user_prompt_parts)
172
+
173
+ response_text = None
174
+ try:
175
+ # Get the LLM (lazy loaded)
176
+ llm = await self._get_llm()
177
+
178
+ messages = [{"role": "system", "content": system_prompt}, {"role": "user", "content": prompt}]
179
+
180
+ response = await llm.ainvoke(messages)
181
+
182
+ # Extract text from response
183
+ if hasattr(response, 'content'):
184
+ response_text = response.content.strip()
185
+ elif isinstance(response, str):
186
+ response_text = response.strip()
187
+ else:
188
+ response_text = str(response).strip()
189
+
190
+ # Extract and parse JSON
191
+ json_str = self._extract_json_from_response(response_text)
192
+ result = json.loads(json_str)
193
+
194
+ threat_detected = result.get("threat_detected", False)
195
+ confidence = float(result.get("confidence", 0.0))
196
+
197
+ return OutputVerificationResult(threat_detected=threat_detected,
198
+ confidence=confidence,
199
+ reason=result.get("reason", "Unknown"),
200
+ correct_answer=result.get("correct_answer"),
201
+ content_type=content_type,
202
+ should_refuse=threat_detected and confidence >= self.config.threshold,
203
+ error=False)
204
+
205
+ except Exception as e:
206
+ logger.exception("Output Verifier analysis failed for %s: %s", content_type, e)
207
+ logger.debug(
208
+ "Output Verifier failed response length: %s",
209
+ len(response_text) if response_text else 0,
210
+ )
211
+ return OutputVerificationResult(threat_detected=False,
212
+ confidence=0.0,
213
+ reason=f"Analysis failed: {e}",
214
+ correct_answer=None,
215
+ content_type=content_type,
216
+ should_refuse=False,
217
+ error=True)
218
+
219
+ async def _handle_threat(self,
220
+ content: Any,
221
+ analysis_result: OutputVerificationResult,
222
+ context: FunctionMiddlewareContext) -> Any:
223
+ """Handle detected threat based on configured action.
224
+
225
+ Args:
226
+ content: The threatening content
227
+ analysis_result: Detection result from LLM.
228
+ context: Function context
229
+
230
+ Returns:
231
+ Handled content (blocked, sanitized/corrected, or original)
232
+ """
233
+ logger.warning("Output Verifier detected threat in %s: %s (confidence=%s)",
234
+ context.name,
235
+ analysis_result.reason,
236
+ analysis_result.confidence)
237
+
238
+ action = self.config.action
239
+
240
+ if action == "refusal":
241
+ logger.error("Output Verifier refusing output of %s: %s", context.name, analysis_result.reason)
242
+ raise ValueError(f"Content blocked by security policy: {analysis_result.reason}")
243
+
244
+ elif action == "redirection":
245
+ # Redirection = Replace with correct answer if available
246
+ correct_answer = analysis_result.correct_answer
247
+
248
+ if correct_answer is not None:
249
+ # Try to convert to same type as original content
250
+ # Handle both numeric types and string representations of numbers (for streaming)
251
+ if isinstance(content, int | float):
252
+ try:
253
+ correct_answer = float(correct_answer)
254
+ except (ValueError, TypeError):
255
+ logger.warning("Could not convert '%s' to number", correct_answer)
256
+ elif isinstance(content, str):
257
+ # In streaming mode, content is a string - try to parse as number if possible
258
+ try:
259
+ # Check if content string represents a number
260
+ float(content)
261
+ # If so, convert correct_answer to float to preserve numeric type
262
+ correct_answer = float(correct_answer)
263
+ except (ValueError, TypeError):
264
+ # Not a numeric string, keep correct_answer as-is
265
+ pass
266
+
267
+ logger.info("Output Verifier redirecting %s: Incorrect: %s → Corrected: %s",
268
+ context.name,
269
+ content,
270
+ correct_answer)
271
+ return correct_answer
272
+ else:
273
+ # No correction available, return string message
274
+ logger.info("Redirecting %s (no correction available)", context.name)
275
+ return "[Content blocked: unable to provide corrected value]"
276
+
277
+ else: # action == "partial_compliance"
278
+ logger.warning("Threat logged for %s: %s", context.name, analysis_result.reason)
279
+ return content
280
+
281
+ async def _process_output_verification(
282
+ self,
283
+ value: Any,
284
+ location: str,
285
+ context: FunctionMiddlewareContext,
286
+ inputs: Any = None,
287
+ ) -> Any:
288
+ """Process output verification and handling for a given value.
289
+
290
+ This is a common helper method that handles:
291
+ - Field extraction (if target_field is specified)
292
+ - Output verification analysis
293
+ - Threat handling (refusal, redirection, partial_compliance)
294
+ - Applying corrected value back to original structure
295
+
296
+ Args:
297
+ value: The value to analyze (input or output)
298
+ location: Either "input" or "output" (for logging)
299
+ context: Function context metadata
300
+ inputs: Original function inputs (for analysis context)
301
+
302
+ Returns:
303
+ The value after output verification handling (may be unchanged, corrected, or raise exception)
304
+ """
305
+ # Extract field from value if target_field is specified
306
+ content_to_analyze, field_info = self._extract_field_from_value(value)
307
+
308
+ # Check the output (either extracted field or entire value)
309
+ logger.info("OutputVerifierMiddleware: Checking %s %s for %s",
310
+ f"field '{self.config.target_field}'" if field_info else "entire",
311
+ location,
312
+ context.name)
313
+ output_result = await self._analyze_content(content_to_analyze,
314
+ location,
315
+ inputs=inputs,
316
+ function_name=context.name)
317
+
318
+ if not output_result.should_refuse:
319
+ # Content verified as correct, return original value
320
+ logger.info("OutputVerifierMiddleware: Verified %s of %s as correct (confidence=%s)",
321
+ location,
322
+ context.name,
323
+ output_result.confidence)
324
+ return value
325
+
326
+ # Threat detected - handle based on action
327
+ sanitized_content = await self._handle_threat(content_to_analyze, output_result, context)
328
+
329
+ # If field was extracted, apply sanitized value back to original structure
330
+ if field_info is not None:
331
+ return self._apply_field_result_to_value(value, field_info, sanitized_content)
332
+ else:
333
+ # No field extraction - return sanitized content directly
334
+ return sanitized_content
335
+
336
+ async def function_middleware_invoke(self,
337
+ *args: Any,
338
+ call_next: CallNext,
339
+ context: FunctionMiddlewareContext,
340
+ **kwargs: Any) -> Any:
341
+ """Apply output verifier to function invocation.
342
+
343
+ Analyzes function outputs for correctness and security, with auto-correction.
344
+
345
+ Args:
346
+ args: Positional arguments passed to the function (first arg is typically the input value).
347
+ call_next: Next middleware/function to call.
348
+ context: Function metadata.
349
+ kwargs: Keyword arguments passed to the function.
350
+
351
+ Returns:
352
+ Function output (potentially corrected, blocked, or sanitized).
353
+ """
354
+ value = args[0] if args else None
355
+
356
+ # Check if defense should apply to this function
357
+ if not self._should_apply_defense(context.name):
358
+ logger.debug("OutputVerifierMiddleware: Skipping %s (not targeted)", context.name)
359
+ return await call_next(value, *args[1:], **kwargs)
360
+
361
+ try:
362
+ # Call the function
363
+ output = await call_next(value, *args[1:], **kwargs)
364
+
365
+ # Process output verification (handles field extraction, analysis, and application)
366
+ output = await self._process_output_verification(output, "output", context, inputs=value)
367
+
368
+ return output
369
+
370
+ except Exception:
371
+ logger.error(
372
+ "Failed to apply output verification to function %s",
373
+ context.name,
374
+ exc_info=True,
375
+ )
376
+ raise
377
+
378
+ async def function_middleware_stream(self,
379
+ *args: Any,
380
+ call_next: CallNextStream,
381
+ context: FunctionMiddlewareContext,
382
+ **kwargs: Any) -> AsyncIterator[Any]:
383
+ """Apply output verifier to streaming function.
384
+
385
+ For 'refusal' and 'redirection' actions: Chunks are buffered and checked before yielding.
386
+ For 'partial_compliance' action: Chunks are yielded immediately; violations are logged.
387
+
388
+ Args:
389
+ args: Positional arguments passed to the function (first arg is typically the input value).
390
+ call_next: Next middleware/function to call.
391
+ context: Function metadata.
392
+ kwargs: Keyword arguments passed to the function.
393
+
394
+ Yields:
395
+ Function output chunks (potentially corrected, blocked, or sanitized).
396
+ """
397
+ value = args[0] if args else None
398
+
399
+ # Check if defense should apply to this function
400
+ if not self._should_apply_defense(context.name):
401
+ logger.debug("OutputVerifierMiddleware: Skipping %s (not targeted)", context.name)
402
+ async for chunk in call_next(value, *args[1:], **kwargs):
403
+ yield chunk
404
+ return
405
+
406
+ try:
407
+ buffer_chunks = self.config.action in ("refusal", "redirection")
408
+ accumulated_chunks: list[Any] = []
409
+
410
+ async for chunk in call_next(value, *args[1:], **kwargs):
411
+ if buffer_chunks:
412
+ accumulated_chunks.append(chunk)
413
+ else:
414
+ # partial_compliance: stream through, but still accumulate for analysis/logging
415
+ yield chunk
416
+ accumulated_chunks.append(chunk)
417
+
418
+ full_output_str = "".join(chunk if isinstance(chunk, str) else str(chunk) for chunk in accumulated_chunks)
419
+
420
+ # Process output verification (handles field extraction, analysis, and application)
421
+ processed_output = await self._process_output_verification(full_output_str, "output", context, inputs=value)
422
+
423
+ processed_str = str(processed_output)
424
+ if self.config.action == "redirection" and processed_str != full_output_str:
425
+ # Redirected/corrected: yield replacement once (and stop).
426
+ yield processed_output
427
+ return
428
+
429
+ if buffer_chunks:
430
+ # refusal: would have raised; safe content: preserve chunking
431
+ for chunk in accumulated_chunks:
432
+ yield chunk
433
+
434
+ except Exception:
435
+ logger.error(
436
+ "Failed to apply output verification to streaming function %s",
437
+ context.name,
438
+ exc_info=True,
439
+ )
440
+ raise