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/data_models/api_server.py
CHANGED
|
@@ -28,14 +28,25 @@ from pydantic import HttpUrl
|
|
|
28
28
|
from pydantic import conlist
|
|
29
29
|
from pydantic import field_serializer
|
|
30
30
|
from pydantic import field_validator
|
|
31
|
+
from pydantic import model_validator
|
|
31
32
|
from pydantic_core.core_schema import ValidationInfo
|
|
32
33
|
|
|
34
|
+
from nat.data_models.common import SerializableSecretStr
|
|
33
35
|
from nat.data_models.interactive import HumanPrompt
|
|
34
36
|
from nat.utils.type_converter import GlobalTypeConverter
|
|
35
37
|
|
|
36
38
|
FINISH_REASONS = frozenset({'stop', 'length', 'tool_calls', 'content_filter', 'function_call'})
|
|
37
39
|
|
|
38
40
|
|
|
41
|
+
class UserMessageContentRoleType(str, Enum):
|
|
42
|
+
"""
|
|
43
|
+
Enum representing chat message roles in API requests and responses.
|
|
44
|
+
"""
|
|
45
|
+
USER = "user"
|
|
46
|
+
ASSISTANT = "assistant"
|
|
47
|
+
SYSTEM = "system"
|
|
48
|
+
|
|
49
|
+
|
|
39
50
|
class Request(BaseModel):
|
|
40
51
|
"""
|
|
41
52
|
Request is a data model that represents HTTP request attributes.
|
|
@@ -99,8 +110,8 @@ class TextContent(BaseModel):
|
|
|
99
110
|
class Security(BaseModel):
|
|
100
111
|
model_config = ConfigDict(extra="forbid")
|
|
101
112
|
|
|
102
|
-
api_key:
|
|
103
|
-
token:
|
|
113
|
+
api_key: SerializableSecretStr = Field(default="default")
|
|
114
|
+
token: SerializableSecretStr = Field(default="default")
|
|
104
115
|
|
|
105
116
|
|
|
106
117
|
UserContent = typing.Annotated[TextContent | ImageContent | AudioContent, Discriminator("type")]
|
|
@@ -108,7 +119,7 @@ UserContent = typing.Annotated[TextContent | ImageContent | AudioContent, Discri
|
|
|
108
119
|
|
|
109
120
|
class Message(BaseModel):
|
|
110
121
|
content: str | list[UserContent]
|
|
111
|
-
role:
|
|
122
|
+
role: UserMessageContentRoleType
|
|
112
123
|
|
|
113
124
|
|
|
114
125
|
class ChatRequest(BaseModel):
|
|
@@ -143,7 +154,6 @@ class ChatRequest(BaseModel):
|
|
|
143
154
|
tool_choice: str | dict[str, typing.Any] | None = Field(default=None, description="Controls which tool is called")
|
|
144
155
|
parallel_tool_calls: bool | None = Field(default=True, description="Whether to enable parallel function calling")
|
|
145
156
|
user: str | None = Field(default=None, description="Unique identifier representing end-user")
|
|
146
|
-
|
|
147
157
|
model_config = ConfigDict(extra="allow",
|
|
148
158
|
json_schema_extra={
|
|
149
159
|
"example": {
|
|
@@ -164,7 +174,7 @@ class ChatRequest(BaseModel):
|
|
|
164
174
|
max_tokens: int | None = None,
|
|
165
175
|
top_p: float | None = None) -> "ChatRequest":
|
|
166
176
|
|
|
167
|
-
return ChatRequest(messages=[Message(content=data, role=
|
|
177
|
+
return ChatRequest(messages=[Message(content=data, role=UserMessageContentRoleType.USER)],
|
|
168
178
|
model=model,
|
|
169
179
|
temperature=temperature,
|
|
170
180
|
max_tokens=max_tokens,
|
|
@@ -178,38 +188,128 @@ class ChatRequest(BaseModel):
|
|
|
178
188
|
max_tokens: int | None = None,
|
|
179
189
|
top_p: float | None = None) -> "ChatRequest":
|
|
180
190
|
|
|
181
|
-
return ChatRequest(messages=[Message(content=content, role=
|
|
191
|
+
return ChatRequest(messages=[Message(content=content, role=UserMessageContentRoleType.USER)],
|
|
182
192
|
model=model,
|
|
183
193
|
temperature=temperature,
|
|
184
194
|
max_tokens=max_tokens,
|
|
185
195
|
top_p=top_p)
|
|
186
196
|
|
|
187
197
|
|
|
198
|
+
class ChatRequestOrMessage(BaseModel):
|
|
199
|
+
"""
|
|
200
|
+
`ChatRequestOrMessage` is a data model that represents either a conversation or a string input.
|
|
201
|
+
This is useful for functions that can handle either type of input.
|
|
202
|
+
|
|
203
|
+
- `messages` is compatible with the OpenAI Chat Completions API specification.
|
|
204
|
+
- `input_message` is a string input that can be used for functions that do not require a conversation.
|
|
205
|
+
|
|
206
|
+
Note: When `messages` is provided, extra fields are allowed to enable lossless round-trip
|
|
207
|
+
conversion with ChatRequest. When `input_message` is provided, no extra fields are permitted.
|
|
208
|
+
"""
|
|
209
|
+
model_config = ConfigDict(
|
|
210
|
+
extra="allow",
|
|
211
|
+
json_schema_extra={
|
|
212
|
+
"examples": [
|
|
213
|
+
{
|
|
214
|
+
"input_message": "What can you do?"
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"messages": [{
|
|
218
|
+
"role": "user", "content": "What can you do?"
|
|
219
|
+
}],
|
|
220
|
+
"model": "nvidia/nemotron",
|
|
221
|
+
"temperature": 0.7
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
"oneOf": [
|
|
225
|
+
{
|
|
226
|
+
"required": ["input_message"],
|
|
227
|
+
"properties": {
|
|
228
|
+
"input_message": {
|
|
229
|
+
"type": "string"
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
"additionalProperties": {
|
|
233
|
+
"not": True, "errorMessage": 'remove additional property ${0#}'
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"required": ["messages"],
|
|
238
|
+
"properties": {
|
|
239
|
+
"messages": {
|
|
240
|
+
"type": "array"
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
"additionalProperties": True
|
|
244
|
+
},
|
|
245
|
+
]
|
|
246
|
+
},
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
messages: typing.Annotated[list[Message] | None, conlist(Message, min_length=1)] = Field(
|
|
250
|
+
default=None, description="A non-empty conversation of messages to process.")
|
|
251
|
+
|
|
252
|
+
input_message: str | None = Field(
|
|
253
|
+
default=None,
|
|
254
|
+
description="A single input message to process. Useful for functions that do not require a conversation")
|
|
255
|
+
|
|
256
|
+
@property
|
|
257
|
+
def is_string(self) -> bool:
|
|
258
|
+
return self.input_message is not None
|
|
259
|
+
|
|
260
|
+
@property
|
|
261
|
+
def is_conversation(self) -> bool:
|
|
262
|
+
return self.messages is not None
|
|
263
|
+
|
|
264
|
+
@model_validator(mode="after")
|
|
265
|
+
def validate_model(self):
|
|
266
|
+
if self.messages is not None and self.input_message is not None:
|
|
267
|
+
raise ValueError("Either messages or input_message must be provided, not both")
|
|
268
|
+
if self.messages is None and self.input_message is None:
|
|
269
|
+
raise ValueError("Either messages or input_message must be provided")
|
|
270
|
+
if self.input_message is not None:
|
|
271
|
+
extra_fields = self.model_dump(exclude={"input_message"}, exclude_none=True, exclude_unset=True)
|
|
272
|
+
if len(extra_fields) > 0:
|
|
273
|
+
raise ValueError("no extra fields are permitted when input_message is provided")
|
|
274
|
+
return self
|
|
275
|
+
|
|
276
|
+
|
|
188
277
|
class ChoiceMessage(BaseModel):
|
|
189
278
|
content: str | None = None
|
|
190
|
-
role:
|
|
279
|
+
role: UserMessageContentRoleType | None = None
|
|
191
280
|
|
|
192
281
|
|
|
193
282
|
class ChoiceDelta(BaseModel):
|
|
194
283
|
"""Delta object for streaming responses (OpenAI-compatible)"""
|
|
195
284
|
content: str | None = None
|
|
196
|
-
role:
|
|
285
|
+
role: UserMessageContentRoleType | None = None
|
|
197
286
|
|
|
198
287
|
|
|
199
|
-
class
|
|
288
|
+
class ChoiceBase(BaseModel):
|
|
289
|
+
"""Base choice model with common fields for both streaming and non-streaming responses"""
|
|
200
290
|
model_config = ConfigDict(extra="allow")
|
|
201
|
-
|
|
202
|
-
message: ChoiceMessage | None = None
|
|
203
|
-
delta: ChoiceDelta | None = None
|
|
204
291
|
finish_reason: typing.Literal['stop', 'length', 'tool_calls', 'content_filter', 'function_call'] | None = None
|
|
205
292
|
index: int
|
|
206
|
-
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
class ChatResponseChoice(ChoiceBase):
|
|
296
|
+
"""Choice model for non-streaming responses - contains message field"""
|
|
297
|
+
message: ChoiceMessage
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class ChatResponseChunkChoice(ChoiceBase):
|
|
301
|
+
"""Choice model for streaming responses - contains delta field"""
|
|
302
|
+
delta: ChoiceDelta
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
# Backward compatibility alias
|
|
306
|
+
Choice = ChatResponseChoice
|
|
207
307
|
|
|
208
308
|
|
|
209
309
|
class Usage(BaseModel):
|
|
210
|
-
prompt_tokens: int
|
|
211
|
-
completion_tokens: int
|
|
212
|
-
total_tokens: int
|
|
310
|
+
prompt_tokens: int | None = None
|
|
311
|
+
completion_tokens: int | None = None
|
|
312
|
+
total_tokens: int | None = None
|
|
213
313
|
|
|
214
314
|
|
|
215
315
|
class ResponseSerializable(abc.ABC):
|
|
@@ -245,10 +345,10 @@ class ChatResponse(ResponseBaseModelOutput):
|
|
|
245
345
|
model_config = ConfigDict(extra="allow")
|
|
246
346
|
id: str
|
|
247
347
|
object: str = "chat.completion"
|
|
248
|
-
model: str = ""
|
|
348
|
+
model: str = "unknown-model"
|
|
249
349
|
created: datetime.datetime
|
|
250
|
-
choices: list[
|
|
251
|
-
usage: Usage
|
|
350
|
+
choices: list[ChatResponseChoice]
|
|
351
|
+
usage: Usage
|
|
252
352
|
system_fingerprint: str | None = None
|
|
253
353
|
service_tier: typing.Literal["scale", "default"] | None = None
|
|
254
354
|
|
|
@@ -264,22 +364,27 @@ class ChatResponse(ResponseBaseModelOutput):
|
|
|
264
364
|
object_: str | None = None,
|
|
265
365
|
model: str | None = None,
|
|
266
366
|
created: datetime.datetime | None = None,
|
|
267
|
-
usage: Usage
|
|
367
|
+
usage: Usage) -> "ChatResponse":
|
|
268
368
|
|
|
269
369
|
if id_ is None:
|
|
270
370
|
id_ = str(uuid.uuid4())
|
|
271
371
|
if object_ is None:
|
|
272
372
|
object_ = "chat.completion"
|
|
273
373
|
if model is None:
|
|
274
|
-
model = ""
|
|
374
|
+
model = "unknown-model"
|
|
275
375
|
if created is None:
|
|
276
|
-
created = datetime.datetime.now(datetime.
|
|
376
|
+
created = datetime.datetime.now(datetime.UTC)
|
|
277
377
|
|
|
278
378
|
return ChatResponse(id=id_,
|
|
279
379
|
object=object_,
|
|
280
380
|
model=model,
|
|
281
381
|
created=created,
|
|
282
|
-
choices=[
|
|
382
|
+
choices=[
|
|
383
|
+
ChatResponseChoice(index=0,
|
|
384
|
+
message=ChoiceMessage(content=data,
|
|
385
|
+
role=UserMessageContentRoleType.ASSISTANT),
|
|
386
|
+
finish_reason="stop")
|
|
387
|
+
],
|
|
283
388
|
usage=usage)
|
|
284
389
|
|
|
285
390
|
|
|
@@ -293,9 +398,9 @@ class ChatResponseChunk(ResponseBaseModelOutput):
|
|
|
293
398
|
model_config = ConfigDict(extra="allow")
|
|
294
399
|
|
|
295
400
|
id: str
|
|
296
|
-
choices: list[
|
|
401
|
+
choices: list[ChatResponseChunkChoice]
|
|
297
402
|
created: datetime.datetime
|
|
298
|
-
model: str = ""
|
|
403
|
+
model: str = "unknown-model"
|
|
299
404
|
object: str = "chat.completion.chunk"
|
|
300
405
|
system_fingerprint: str | None = None
|
|
301
406
|
service_tier: typing.Literal["scale", "default"] | None = None
|
|
@@ -317,14 +422,20 @@ class ChatResponseChunk(ResponseBaseModelOutput):
|
|
|
317
422
|
if id_ is None:
|
|
318
423
|
id_ = str(uuid.uuid4())
|
|
319
424
|
if created is None:
|
|
320
|
-
created = datetime.datetime.now(datetime.
|
|
425
|
+
created = datetime.datetime.now(datetime.UTC)
|
|
321
426
|
if model is None:
|
|
322
|
-
model = ""
|
|
427
|
+
model = "unknown-model"
|
|
323
428
|
if object_ is None:
|
|
324
429
|
object_ = "chat.completion.chunk"
|
|
325
430
|
|
|
326
431
|
return ChatResponseChunk(id=id_,
|
|
327
|
-
choices=[
|
|
432
|
+
choices=[
|
|
433
|
+
ChatResponseChunkChoice(index=0,
|
|
434
|
+
delta=ChoiceDelta(
|
|
435
|
+
content=data,
|
|
436
|
+
role=UserMessageContentRoleType.ASSISTANT),
|
|
437
|
+
finish_reason="stop")
|
|
438
|
+
],
|
|
328
439
|
created=created,
|
|
329
440
|
model=model,
|
|
330
441
|
object=object_)
|
|
@@ -335,7 +446,7 @@ class ChatResponseChunk(ResponseBaseModelOutput):
|
|
|
335
446
|
id_: str | None = None,
|
|
336
447
|
created: datetime.datetime | None = None,
|
|
337
448
|
model: str | None = None,
|
|
338
|
-
role:
|
|
449
|
+
role: UserMessageContentRoleType | None = None,
|
|
339
450
|
finish_reason: str | None = None,
|
|
340
451
|
usage: Usage | None = None,
|
|
341
452
|
system_fingerprint: str | None = None) -> "ChatResponseChunk":
|
|
@@ -343,9 +454,9 @@ class ChatResponseChunk(ResponseBaseModelOutput):
|
|
|
343
454
|
if id_ is None:
|
|
344
455
|
id_ = str(uuid.uuid4())
|
|
345
456
|
if created is None:
|
|
346
|
-
created = datetime.datetime.now(datetime.
|
|
457
|
+
created = datetime.datetime.now(datetime.UTC)
|
|
347
458
|
if model is None:
|
|
348
|
-
model = ""
|
|
459
|
+
model = "unknown-model"
|
|
349
460
|
|
|
350
461
|
delta = ChoiceDelta(content=content, role=role) if content is not None or role is not None else ChoiceDelta()
|
|
351
462
|
|
|
@@ -353,7 +464,14 @@ class ChatResponseChunk(ResponseBaseModelOutput):
|
|
|
353
464
|
|
|
354
465
|
return ChatResponseChunk(
|
|
355
466
|
id=id_,
|
|
356
|
-
choices=[
|
|
467
|
+
choices=[
|
|
468
|
+
ChatResponseChunkChoice(
|
|
469
|
+
index=0,
|
|
470
|
+
delta=delta,
|
|
471
|
+
finish_reason=typing.cast(
|
|
472
|
+
typing.Literal['stop', 'length', 'tool_calls', 'content_filter', 'function_call'] | None,
|
|
473
|
+
final_finish_reason))
|
|
474
|
+
],
|
|
357
475
|
created=created,
|
|
358
476
|
model=model,
|
|
359
477
|
object="chat.completion.chunk",
|
|
@@ -398,11 +516,6 @@ class GenerateResponse(BaseModel):
|
|
|
398
516
|
value: str | None = "default"
|
|
399
517
|
|
|
400
518
|
|
|
401
|
-
class UserMessageContentRoleType(str, Enum):
|
|
402
|
-
USER = "user"
|
|
403
|
-
ASSISTANT = "assistant"
|
|
404
|
-
|
|
405
|
-
|
|
406
519
|
class WebSocketMessageType(str, Enum):
|
|
407
520
|
"""
|
|
408
521
|
WebSocketMessageType is an Enum that represents WebSocket Message types.
|
|
@@ -485,7 +598,7 @@ class WebSocketUserMessage(BaseModel):
|
|
|
485
598
|
security: Security = Security()
|
|
486
599
|
error: Error = Error()
|
|
487
600
|
schema_version: str = "1.0.0"
|
|
488
|
-
timestamp: str = str(datetime.datetime.now(datetime.
|
|
601
|
+
timestamp: str = str(datetime.datetime.now(datetime.UTC))
|
|
489
602
|
|
|
490
603
|
|
|
491
604
|
class WebSocketUserInteractionResponseMessage(BaseModel):
|
|
@@ -496,12 +609,14 @@ class WebSocketUserInteractionResponseMessage(BaseModel):
|
|
|
496
609
|
type: typing.Literal[WebSocketMessageType.USER_INTERACTION_MESSAGE]
|
|
497
610
|
id: str = "default"
|
|
498
611
|
thread_id: str = "default"
|
|
612
|
+
parent_id: str = "default"
|
|
613
|
+
conversation_id: str | None = None
|
|
499
614
|
content: UserMessageContent
|
|
500
615
|
user: User = User()
|
|
501
616
|
security: Security = Security()
|
|
502
617
|
error: Error = Error()
|
|
503
618
|
schema_version: str = "1.0.0"
|
|
504
|
-
timestamp: str = str(datetime.datetime.now(datetime.
|
|
619
|
+
timestamp: str = str(datetime.datetime.now(datetime.UTC))
|
|
505
620
|
|
|
506
621
|
|
|
507
622
|
class SystemIntermediateStepContent(BaseModel):
|
|
@@ -527,7 +642,7 @@ class WebSocketSystemIntermediateStepMessage(BaseModel):
|
|
|
527
642
|
conversation_id: str | None = None
|
|
528
643
|
content: SystemIntermediateStepContent
|
|
529
644
|
status: WebSocketMessageStatus
|
|
530
|
-
timestamp: str = str(datetime.datetime.now(datetime.
|
|
645
|
+
timestamp: str = str(datetime.datetime.now(datetime.UTC))
|
|
531
646
|
|
|
532
647
|
|
|
533
648
|
class SystemResponseContent(BaseModel):
|
|
@@ -551,7 +666,7 @@ class WebSocketSystemResponseTokenMessage(BaseModel):
|
|
|
551
666
|
conversation_id: str | None = None
|
|
552
667
|
content: SystemResponseContent | Error | GenerateResponse
|
|
553
668
|
status: WebSocketMessageStatus
|
|
554
|
-
timestamp: str = str(datetime.datetime.now(datetime.
|
|
669
|
+
timestamp: str = str(datetime.datetime.now(datetime.UTC))
|
|
555
670
|
|
|
556
671
|
@field_validator("content")
|
|
557
672
|
@classmethod
|
|
@@ -560,7 +675,7 @@ class WebSocketSystemResponseTokenMessage(BaseModel):
|
|
|
560
675
|
raise ValueError(f"Field: content must be 'Error' when type is {WebSocketMessageType.ERROR_MESSAGE}")
|
|
561
676
|
|
|
562
677
|
if info.data.get("type") == WebSocketMessageType.RESPONSE_MESSAGE and not isinstance(
|
|
563
|
-
value,
|
|
678
|
+
value, SystemResponseContent | GenerateResponse):
|
|
564
679
|
raise ValueError(
|
|
565
680
|
f"Field: content must be 'SystemResponseContent' when type is {WebSocketMessageType.RESPONSE_MESSAGE}")
|
|
566
681
|
return value
|
|
@@ -582,7 +697,7 @@ class WebSocketSystemInteractionMessage(BaseModel):
|
|
|
582
697
|
conversation_id: str | None = None
|
|
583
698
|
content: HumanPrompt
|
|
584
699
|
status: WebSocketMessageStatus
|
|
585
|
-
timestamp: str = str(datetime.datetime.now(datetime.
|
|
700
|
+
timestamp: str = str(datetime.datetime.now(datetime.UTC))
|
|
586
701
|
|
|
587
702
|
|
|
588
703
|
# ======== GenerateResponse Converters ========
|
|
@@ -622,12 +737,52 @@ GlobalTypeConverter.register_converter(_nat_chat_request_to_string)
|
|
|
622
737
|
|
|
623
738
|
|
|
624
739
|
def _string_to_nat_chat_request(data: str) -> ChatRequest:
|
|
625
|
-
return ChatRequest.from_string(data, model="")
|
|
740
|
+
return ChatRequest.from_string(data, model="unknown-model")
|
|
626
741
|
|
|
627
742
|
|
|
628
743
|
GlobalTypeConverter.register_converter(_string_to_nat_chat_request)
|
|
629
744
|
|
|
630
745
|
|
|
746
|
+
def _chat_request_or_message_to_chat_request(data: ChatRequestOrMessage) -> ChatRequest:
|
|
747
|
+
if data.input_message is not None:
|
|
748
|
+
return _string_to_nat_chat_request(data.input_message)
|
|
749
|
+
return ChatRequest(**data.model_dump(exclude={"input_message"}))
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
GlobalTypeConverter.register_converter(_chat_request_or_message_to_chat_request)
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
def _chat_request_to_chat_request_or_message(data: ChatRequest) -> ChatRequestOrMessage:
|
|
756
|
+
return ChatRequestOrMessage(**data.model_dump(by_alias=True))
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
GlobalTypeConverter.register_converter(_chat_request_to_chat_request_or_message)
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
def _chat_request_or_message_to_string(data: ChatRequestOrMessage) -> str:
|
|
763
|
+
if data.input_message is not None:
|
|
764
|
+
return data.input_message
|
|
765
|
+
# Extract content from last message in conversation
|
|
766
|
+
if data.messages is None:
|
|
767
|
+
return ""
|
|
768
|
+
content = data.messages[-1].content
|
|
769
|
+
if content is None:
|
|
770
|
+
return ""
|
|
771
|
+
if isinstance(content, str):
|
|
772
|
+
return content
|
|
773
|
+
return str(content)
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
GlobalTypeConverter.register_converter(_chat_request_or_message_to_string)
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
def _string_to_chat_request_or_message(data: str) -> ChatRequestOrMessage:
|
|
780
|
+
return ChatRequestOrMessage(input_message=data)
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
GlobalTypeConverter.register_converter(_string_to_chat_request_or_message)
|
|
784
|
+
|
|
785
|
+
|
|
631
786
|
# ======== ChatResponse Converters ========
|
|
632
787
|
def _nat_chat_response_to_string(data: ChatResponse) -> str:
|
|
633
788
|
if data.choices and data.choices[0].message:
|
|
@@ -654,22 +809,12 @@ def _string_to_nat_chat_response(data: str) -> ChatResponse:
|
|
|
654
809
|
GlobalTypeConverter.register_converter(_string_to_nat_chat_response)
|
|
655
810
|
|
|
656
811
|
|
|
657
|
-
def _chat_response_to_chat_response_chunk(data: ChatResponse) -> ChatResponseChunk:
|
|
658
|
-
# Preserve original message structure for backward compatibility
|
|
659
|
-
return ChatResponseChunk(id=data.id, choices=data.choices, created=data.created, model=data.model)
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
GlobalTypeConverter.register_converter(_chat_response_to_chat_response_chunk)
|
|
663
|
-
|
|
664
|
-
|
|
665
812
|
# ======== ChatResponseChunk Converters ========
|
|
666
813
|
def _chat_response_chunk_to_string(data: ChatResponseChunk) -> str:
|
|
667
814
|
if data.choices and len(data.choices) > 0:
|
|
668
815
|
choice = data.choices[0]
|
|
669
816
|
if choice.delta and choice.delta.content:
|
|
670
817
|
return choice.delta.content
|
|
671
|
-
if choice.message and choice.message.content:
|
|
672
|
-
return choice.message.content
|
|
673
818
|
return ""
|
|
674
819
|
|
|
675
820
|
|
|
@@ -685,21 +830,6 @@ def _string_to_nat_chat_response_chunk(data: str) -> ChatResponseChunk:
|
|
|
685
830
|
|
|
686
831
|
GlobalTypeConverter.register_converter(_string_to_nat_chat_response_chunk)
|
|
687
832
|
|
|
688
|
-
|
|
689
|
-
# ======== AINodeMessageChunk Converters ========
|
|
690
|
-
def _ai_message_chunk_to_nat_chat_response_chunk(data) -> ChatResponseChunk:
|
|
691
|
-
'''Converts LangChain/LangGraph AINodeMessageChunk to ChatResponseChunk'''
|
|
692
|
-
content = ""
|
|
693
|
-
if hasattr(data, 'content') and data.content is not None:
|
|
694
|
-
content = str(data.content)
|
|
695
|
-
elif hasattr(data, 'text') and data.text is not None:
|
|
696
|
-
content = str(data.text)
|
|
697
|
-
elif hasattr(data, 'message') and data.message is not None:
|
|
698
|
-
content = str(data.message)
|
|
699
|
-
|
|
700
|
-
return ChatResponseChunk.create_streaming_chunk(content=content, role="assistant", finish_reason=None)
|
|
701
|
-
|
|
702
|
-
|
|
703
833
|
# Compatibility aliases with previous releases
|
|
704
834
|
AIQChatRequest = ChatRequest
|
|
705
835
|
AIQChoiceMessage = ChoiceMessage
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
16
|
import typing
|
|
17
|
+
from datetime import UTC
|
|
17
18
|
from datetime import datetime
|
|
18
|
-
from datetime import timezone
|
|
19
19
|
from enum import Enum
|
|
20
20
|
|
|
21
21
|
import httpx
|
|
@@ -166,17 +166,31 @@ class BearerTokenCred(_CredBase):
|
|
|
166
166
|
|
|
167
167
|
|
|
168
168
|
Credential = typing.Annotated[
|
|
169
|
-
|
|
170
|
-
HeaderCred,
|
|
171
|
-
QueryCred,
|
|
172
|
-
CookieCred,
|
|
173
|
-
BasicAuthCred,
|
|
174
|
-
BearerTokenCred,
|
|
175
|
-
],
|
|
169
|
+
HeaderCred | QueryCred | CookieCred | BasicAuthCred | BearerTokenCred,
|
|
176
170
|
Field(discriminator="kind"),
|
|
177
171
|
]
|
|
178
172
|
|
|
179
173
|
|
|
174
|
+
class TokenValidationResult(BaseModel):
|
|
175
|
+
"""
|
|
176
|
+
Standard result for Bearer Token Validation.
|
|
177
|
+
"""
|
|
178
|
+
model_config = ConfigDict(extra="forbid")
|
|
179
|
+
|
|
180
|
+
client_id: str | None = Field(description="OAuth2 client identifier")
|
|
181
|
+
scopes: list[str] | None = Field(default=None, description="List of granted scopes (introspection only)")
|
|
182
|
+
expires_at: int | None = Field(default=None, description="Token expiration time (Unix timestamp)")
|
|
183
|
+
audience: list[str] | None = Field(default=None, description="Token audiences (aud claim)")
|
|
184
|
+
subject: str | None = Field(default=None, description="Token subject (sub claim)")
|
|
185
|
+
issuer: str | None = Field(default=None, description="Token issuer (iss claim)")
|
|
186
|
+
token_type: str = Field(description="Token type")
|
|
187
|
+
active: bool | None = Field(default=True, description="Token active status")
|
|
188
|
+
nbf: int | None = Field(default=None, description="Not before time (Unix timestamp)")
|
|
189
|
+
iat: int | None = Field(default=None, description="Issued at time (Unix timestamp)")
|
|
190
|
+
jti: str | None = Field(default=None, description="JWT ID")
|
|
191
|
+
username: str | None = Field(default=None, description="Username (introspection only)")
|
|
192
|
+
|
|
193
|
+
|
|
180
194
|
class AuthResult(BaseModel):
|
|
181
195
|
"""
|
|
182
196
|
Represents the result of an authentication process.
|
|
@@ -193,7 +207,7 @@ class AuthResult(BaseModel):
|
|
|
193
207
|
"""
|
|
194
208
|
Checks if the authentication token has expired.
|
|
195
209
|
"""
|
|
196
|
-
return bool(self.token_expires_at and datetime.now(
|
|
210
|
+
return bool(self.token_expires_at and datetime.now(UTC) >= self.token_expires_at)
|
|
197
211
|
|
|
198
212
|
def as_requests_kwargs(self) -> dict[str, typing.Any]:
|
|
199
213
|
"""
|
nat/data_models/common.py
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
16
|
import inspect
|
|
17
|
+
import os
|
|
17
18
|
import sys
|
|
18
19
|
import typing
|
|
19
20
|
from hashlib import sha512
|
|
@@ -21,6 +22,8 @@ from hashlib import sha512
|
|
|
21
22
|
from pydantic import AliasChoices
|
|
22
23
|
from pydantic import BaseModel
|
|
23
24
|
from pydantic import Field
|
|
25
|
+
from pydantic import PlainSerializer
|
|
26
|
+
from pydantic import SecretStr
|
|
24
27
|
from pydantic.json_schema import GenerateJsonSchema
|
|
25
28
|
from pydantic.json_schema import JsonSchemaMode
|
|
26
29
|
|
|
@@ -169,3 +172,47 @@ class TypedBaseModel(BaseModel):
|
|
|
169
172
|
|
|
170
173
|
|
|
171
174
|
TypedBaseModelT = typing.TypeVar("TypedBaseModelT", bound=TypedBaseModel)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def get_secret_value(v: SecretStr | None) -> str | None:
|
|
178
|
+
"""
|
|
179
|
+
Extract the secret value from a SecretStr or return None.
|
|
180
|
+
|
|
181
|
+
Parameters
|
|
182
|
+
----------
|
|
183
|
+
v: SecretStr or None.
|
|
184
|
+
A field defined as OptionalSecretStr, which is either a SecretStr or None.
|
|
185
|
+
|
|
186
|
+
Returns
|
|
187
|
+
-------
|
|
188
|
+
str | None
|
|
189
|
+
The secret value as a plain string, or None if v is None.
|
|
190
|
+
"""
|
|
191
|
+
if v is None:
|
|
192
|
+
return None
|
|
193
|
+
return v.get_secret_value()
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def set_secret_from_env(model: BaseModel, field_name: str, env_var: str):
|
|
197
|
+
"""
|
|
198
|
+
Set a SecretStr field in a Pydantic model from an environment variable, but only if the environment variable is set.
|
|
199
|
+
|
|
200
|
+
Parameters
|
|
201
|
+
----------
|
|
202
|
+
model: BaseModel
|
|
203
|
+
The Pydantic model instance containing the field to set.
|
|
204
|
+
field_name: str
|
|
205
|
+
The name of the field in the model to set.
|
|
206
|
+
env_var: str
|
|
207
|
+
The name of the environment variable to read the secret value from.
|
|
208
|
+
"""
|
|
209
|
+
env_value = os.getenv(env_var)
|
|
210
|
+
if env_value is not None:
|
|
211
|
+
setattr(model, field_name, SecretStr(env_value))
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
# A SecretStr that serializes to plain string
|
|
215
|
+
SerializableSecretStr = typing.Annotated[SecretStr, PlainSerializer(get_secret_value)]
|
|
216
|
+
|
|
217
|
+
# A SecretStr or None that serializes to plain string
|
|
218
|
+
OptionalSecretStr = typing.Annotated[SecretStr | None, PlainSerializer(get_secret_value)]
|
nat/data_models/component.py
CHANGED
|
@@ -27,6 +27,7 @@ class ComponentEnum(StrEnum):
|
|
|
27
27
|
EVALUATOR = "evaluator"
|
|
28
28
|
FRONT_END = "front_end"
|
|
29
29
|
FUNCTION = "function"
|
|
30
|
+
FUNCTION_GROUP = "function_group"
|
|
30
31
|
TTC_STRATEGY = "ttc_strategy"
|
|
31
32
|
LLM_CLIENT = "llm_client"
|
|
32
33
|
LLM_PROVIDER = "llm_provider"
|
|
@@ -47,6 +48,7 @@ class ComponentGroup(StrEnum):
|
|
|
47
48
|
AUTHENTICATION = "authentication"
|
|
48
49
|
EMBEDDERS = "embedders"
|
|
49
50
|
FUNCTIONS = "functions"
|
|
51
|
+
FUNCTION_GROUPS = "function_groups"
|
|
50
52
|
TTC_STRATEGIES = "ttc_strategies"
|
|
51
53
|
LLMS = "llms"
|
|
52
54
|
MEMORY = "memory"
|
nat/data_models/component_ref.py
CHANGED
|
@@ -102,6 +102,17 @@ class FunctionRef(ComponentRef):
|
|
|
102
102
|
return ComponentGroup.FUNCTIONS
|
|
103
103
|
|
|
104
104
|
|
|
105
|
+
class FunctionGroupRef(ComponentRef):
|
|
106
|
+
"""
|
|
107
|
+
A reference to a function group in a NAT configuration object.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
@override
|
|
112
|
+
def component_group(self):
|
|
113
|
+
return ComponentGroup.FUNCTION_GROUPS
|
|
114
|
+
|
|
115
|
+
|
|
105
116
|
class LLMRef(ComponentRef):
|
|
106
117
|
"""
|
|
107
118
|
A reference to an LLM in a NAT configuration object.
|