uipath-langchain 0.0.133__py3-none-any.whl → 0.1.28__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 (83) hide show
  1. uipath_langchain/_cli/cli_init.py +130 -191
  2. uipath_langchain/_cli/cli_new.py +2 -3
  3. uipath_langchain/_resources/AGENTS.md +21 -0
  4. uipath_langchain/_resources/REQUIRED_STRUCTURE.md +92 -0
  5. uipath_langchain/_tracing/__init__.py +3 -2
  6. uipath_langchain/_tracing/_instrument_traceable.py +11 -12
  7. uipath_langchain/_utils/_request_mixin.py +327 -51
  8. uipath_langchain/_utils/_settings.py +2 -2
  9. uipath_langchain/agent/exceptions/__init__.py +6 -0
  10. uipath_langchain/agent/exceptions/exceptions.py +11 -0
  11. uipath_langchain/agent/guardrails/__init__.py +21 -0
  12. uipath_langchain/agent/guardrails/actions/__init__.py +11 -0
  13. uipath_langchain/agent/guardrails/actions/base_action.py +24 -0
  14. uipath_langchain/agent/guardrails/actions/block_action.py +42 -0
  15. uipath_langchain/agent/guardrails/actions/escalate_action.py +499 -0
  16. uipath_langchain/agent/guardrails/actions/log_action.py +58 -0
  17. uipath_langchain/agent/guardrails/guardrail_nodes.py +173 -0
  18. uipath_langchain/agent/guardrails/guardrails_factory.py +70 -0
  19. uipath_langchain/agent/guardrails/guardrails_subgraph.py +283 -0
  20. uipath_langchain/agent/guardrails/types.py +20 -0
  21. uipath_langchain/agent/react/__init__.py +14 -0
  22. uipath_langchain/agent/react/agent.py +117 -0
  23. uipath_langchain/agent/react/constants.py +2 -0
  24. uipath_langchain/agent/react/init_node.py +20 -0
  25. uipath_langchain/agent/react/llm_node.py +43 -0
  26. uipath_langchain/agent/react/router.py +97 -0
  27. uipath_langchain/agent/react/terminate_node.py +82 -0
  28. uipath_langchain/agent/react/tools/__init__.py +7 -0
  29. uipath_langchain/agent/react/tools/tools.py +50 -0
  30. uipath_langchain/agent/react/types.py +39 -0
  31. uipath_langchain/agent/react/utils.py +49 -0
  32. uipath_langchain/agent/tools/__init__.py +17 -0
  33. uipath_langchain/agent/tools/context_tool.py +53 -0
  34. uipath_langchain/agent/tools/escalation_tool.py +111 -0
  35. uipath_langchain/agent/tools/integration_tool.py +181 -0
  36. uipath_langchain/agent/tools/process_tool.py +49 -0
  37. uipath_langchain/agent/tools/static_args.py +138 -0
  38. uipath_langchain/agent/tools/structured_tool_with_output_type.py +14 -0
  39. uipath_langchain/agent/tools/tool_factory.py +45 -0
  40. uipath_langchain/agent/tools/tool_node.py +22 -0
  41. uipath_langchain/agent/tools/utils.py +11 -0
  42. uipath_langchain/chat/__init__.py +4 -0
  43. uipath_langchain/chat/bedrock.py +187 -0
  44. uipath_langchain/chat/mapper.py +309 -0
  45. uipath_langchain/chat/models.py +248 -35
  46. uipath_langchain/chat/openai.py +133 -0
  47. uipath_langchain/chat/supported_models.py +42 -0
  48. uipath_langchain/chat/vertex.py +255 -0
  49. uipath_langchain/embeddings/embeddings.py +131 -34
  50. uipath_langchain/middlewares.py +0 -6
  51. uipath_langchain/retrievers/context_grounding_retriever.py +7 -9
  52. uipath_langchain/runtime/__init__.py +36 -0
  53. uipath_langchain/runtime/_serialize.py +46 -0
  54. uipath_langchain/runtime/config.py +61 -0
  55. uipath_langchain/runtime/errors.py +43 -0
  56. uipath_langchain/runtime/factory.py +315 -0
  57. uipath_langchain/runtime/graph.py +159 -0
  58. uipath_langchain/runtime/runtime.py +453 -0
  59. uipath_langchain/runtime/schema.py +386 -0
  60. uipath_langchain/runtime/storage.py +115 -0
  61. uipath_langchain/vectorstores/context_grounding_vectorstore.py +90 -110
  62. {uipath_langchain-0.0.133.dist-info → uipath_langchain-0.1.28.dist-info}/METADATA +44 -23
  63. uipath_langchain-0.1.28.dist-info/RECORD +76 -0
  64. {uipath_langchain-0.0.133.dist-info → uipath_langchain-0.1.28.dist-info}/WHEEL +1 -1
  65. uipath_langchain-0.1.28.dist-info/entry_points.txt +5 -0
  66. uipath_langchain/_cli/_runtime/_context.py +0 -21
  67. uipath_langchain/_cli/_runtime/_conversation.py +0 -298
  68. uipath_langchain/_cli/_runtime/_exception.py +0 -17
  69. uipath_langchain/_cli/_runtime/_input.py +0 -139
  70. uipath_langchain/_cli/_runtime/_output.py +0 -234
  71. uipath_langchain/_cli/_runtime/_runtime.py +0 -379
  72. uipath_langchain/_cli/_utils/_graph.py +0 -199
  73. uipath_langchain/_cli/cli_dev.py +0 -44
  74. uipath_langchain/_cli/cli_eval.py +0 -78
  75. uipath_langchain/_cli/cli_run.py +0 -82
  76. uipath_langchain/_tracing/_oteladapter.py +0 -222
  77. uipath_langchain/_tracing/_utils.py +0 -28
  78. uipath_langchain/builder/agent_config.py +0 -191
  79. uipath_langchain/tools/preconfigured.py +0 -191
  80. uipath_langchain-0.0.133.dist-info/RECORD +0 -41
  81. uipath_langchain-0.0.133.dist-info/entry_points.txt +0 -2
  82. /uipath_langchain/{tools/__init__.py → py.typed} +0 -0
  83. {uipath_langchain-0.0.133.dist-info → uipath_langchain-0.1.28.dist-info}/licenses/LICENSE +0 -0
@@ -1,82 +0,0 @@
1
- import asyncio
2
- import os
3
- from typing import Optional
4
-
5
- from openinference.instrumentation.langchain import (
6
- LangChainInstrumentor,
7
- get_current_span,
8
- )
9
- from uipath._cli._runtime._contracts import (
10
- UiPathRuntimeFactory,
11
- )
12
- from uipath._cli.middlewares import MiddlewareResult
13
-
14
- from .._tracing import LangChainExporter, _instrument_traceable_attributes
15
- from ._runtime._exception import LangGraphRuntimeError
16
- from ._runtime._runtime import ( # type: ignore[attr-defined]
17
- LangGraphRuntime,
18
- LangGraphRuntimeContext,
19
- )
20
- from ._utils._graph import LangGraphConfig
21
-
22
-
23
- def langgraph_run_middleware(
24
- entrypoint: Optional[str], input: Optional[str], resume: bool, **kwargs
25
- ) -> MiddlewareResult:
26
- """Middleware to handle LangGraph execution"""
27
- config = LangGraphConfig()
28
- if not config.exists:
29
- return MiddlewareResult(
30
- should_continue=True
31
- ) # Continue with normal flow if no langgraph.json
32
-
33
- try:
34
- context = LangGraphRuntimeContext.with_defaults(**kwargs)
35
- context.langgraph_config = config
36
- context.entrypoint = entrypoint
37
- context.input = input
38
- context.resume = resume
39
-
40
- _instrument_traceable_attributes()
41
-
42
- def generate_runtime(ctx: LangGraphRuntimeContext) -> LangGraphRuntime:
43
- runtime = LangGraphRuntime(ctx)
44
- # If not resuming and no job id, delete the previous state file
45
- if not ctx.resume and ctx.job_id is None:
46
- if os.path.exists(runtime.state_file_path):
47
- os.remove(runtime.state_file_path)
48
- return runtime
49
-
50
- async def execute():
51
- runtime_factory = UiPathRuntimeFactory(
52
- LangGraphRuntime,
53
- LangGraphRuntimeContext,
54
- runtime_generator=generate_runtime,
55
- )
56
-
57
- if context.job_id:
58
- runtime_factory.add_span_exporter(LangChainExporter())
59
-
60
- runtime_factory.add_instrumentor(LangChainInstrumentor, get_current_span)
61
-
62
- await runtime_factory.execute(context)
63
-
64
- asyncio.run(execute())
65
-
66
- return MiddlewareResult(
67
- should_continue=False,
68
- error_message=None,
69
- )
70
-
71
- except LangGraphRuntimeError as e:
72
- return MiddlewareResult(
73
- should_continue=False,
74
- error_message=e.error_info.detail,
75
- should_include_stacktrace=True,
76
- )
77
- except Exception as e:
78
- return MiddlewareResult(
79
- should_continue=False,
80
- error_message=f"Error: {str(e)}",
81
- should_include_stacktrace=True,
82
- )
@@ -1,222 +0,0 @@
1
- import json
2
- import logging
3
- from typing import Any, Dict, List
4
-
5
- from opentelemetry.sdk.trace.export import (
6
- SpanExportResult,
7
- )
8
- from uipath.tracing import LlmOpsHttpExporter
9
-
10
- logger = logging.getLogger(__name__)
11
-
12
-
13
- def _safe_parse_json(s: Any) -> Any:
14
- """Safely parse a JSON string, returning the original if not a string or on error."""
15
- if not isinstance(s, str):
16
- return s
17
- try:
18
- return json.loads(s)
19
- except (json.JSONDecodeError, TypeError):
20
- return s
21
-
22
-
23
- def _get_llm_messages(attributes: Dict[str, Any], prefix: str) -> List[Dict[str, Any]]:
24
- """Extracts and reconstructs LLM messages from flattened attributes."""
25
- messages: dict[int, dict[str, Any]] = {}
26
- message_prefix = f"{prefix}."
27
-
28
- for key, value in attributes.items():
29
- if key.startswith(message_prefix):
30
- parts = key[len(message_prefix) :].split(".")
31
- if len(parts) >= 2 and parts[0].isdigit():
32
- index = int(parts[0])
33
- if index not in messages:
34
- messages[index] = {}
35
- current: Any = messages[index]
36
-
37
- for i, part in enumerate(parts[1:-1]):
38
- key_part: str | int = part
39
- if part.isdigit() and (
40
- i + 2 < len(parts) and parts[i + 2].isdigit()
41
- ):
42
- key_part = int(part)
43
-
44
- if isinstance(current, dict):
45
- if key_part not in current:
46
- current[key_part] = {}
47
- current = current[key_part]
48
- elif isinstance(current, list) and isinstance(key_part, int):
49
- if key_part >= len(current):
50
- current.append({})
51
- current = current[key_part]
52
-
53
- current[parts[-1]] = value
54
-
55
- # Convert dict to list, ordered by index
56
- return [messages[i] for i in sorted(messages.keys())]
57
-
58
-
59
- class LangChainExporter(LlmOpsHttpExporter):
60
- # Mapping of old attribute names to new attribute names or (new name, function)
61
- ATTRIBUTE_MAPPING: dict[str, str | tuple[str, Any]] = {
62
- "input.value": ("input", _safe_parse_json),
63
- "output.value": ("output", _safe_parse_json),
64
- "llm.model_name": "model",
65
- }
66
-
67
- # Mapping of span types
68
- SPAN_TYPE_MAPPING: dict[str, str] = {
69
- "LLM": "completion",
70
- "TOOL": "toolCall",
71
- # Add more mappings as needed
72
- }
73
-
74
- def __init__(self, *args: Any, **kwargs: Any) -> None:
75
- super().__init__(*args, **kwargs)
76
-
77
- def _map_llm_call_attributes(self, attributes: Dict[str, Any]) -> Dict[str, Any]:
78
- """Maps attributes for LLM calls, handling flattened keys."""
79
- result = attributes.copy() # Keep original attributes including basic mappings
80
-
81
- # Token Usage
82
- token_keys = {
83
- "llm.token_count.prompt": "promptTokens",
84
- "llm.token_count.completion": "completionTokens",
85
- "llm.token_count.total": "totalTokens",
86
- }
87
- usage = {
88
- new_key: attributes.get(old_key)
89
- for old_key, new_key in token_keys.items()
90
- if old_key in attributes
91
- }
92
- if usage:
93
- result["usage"] = usage
94
-
95
- # Input/Output Messages
96
- result["input"] = _get_llm_messages(attributes, "llm.input_messages")
97
- output_messages = _get_llm_messages(attributes, "llm.output_messages")
98
- result["output"] = output_messages
99
-
100
- # Invocation Parameters
101
- invocation_params = _safe_parse_json(
102
- attributes.get("llm.invocation_parameters", "{}")
103
- )
104
- if isinstance(invocation_params, dict):
105
- result["model"] = invocation_params.get("model", result.get("model"))
106
- settings: dict[str, Any] = {}
107
- if "max_tokens" in invocation_params:
108
- settings["maxTokens"] = invocation_params["max_tokens"]
109
- if "temperature" in invocation_params:
110
- settings["temperature"] = invocation_params["temperature"]
111
- if settings:
112
- result["settings"] = settings
113
-
114
- # Tool Calls
115
- tool_calls: list[dict[str, Any]] = []
116
- for msg in output_messages:
117
- # Ensure msg is a dictionary before proceeding
118
- if not isinstance(msg, dict):
119
- continue
120
- msg_tool_calls = msg.get("message", {}).get("tool_calls", [])
121
-
122
- # Ensure msg_tool_calls is a list
123
- if not isinstance(msg_tool_calls, list):
124
- continue
125
-
126
- for tc in msg_tool_calls:
127
- if not isinstance(tc, dict):
128
- continue
129
- tool_call_data = tc.get("tool_call", {})
130
- if not isinstance(tool_call_data, dict):
131
- continue
132
- tool_calls.append(
133
- {
134
- "id": tool_call_data.get("id"),
135
- "name": tool_call_data.get("function", {}).get("name"),
136
- "arguments": _safe_parse_json(
137
- tool_call_data.get("function", {}).get("arguments", "{}")
138
- ),
139
- }
140
- )
141
- if tool_calls:
142
- result["toolCalls"] = tool_calls
143
-
144
- return result
145
-
146
- def _map_tool_call_attributes(self, attributes: Dict[str, Any]) -> Dict[str, Any]:
147
- """Maps attributes for tool calls."""
148
- result = attributes.copy() # Keep original attributes
149
-
150
- result["type"] = "toolCall"
151
- result["callId"] = attributes.get("call_id") or attributes.get("id")
152
- result["toolName"] = attributes.get("tool.name")
153
- result["arguments"] = _safe_parse_json(
154
- attributes.get("input", attributes.get("input.value", "{}"))
155
- )
156
- result["toolType"] = "Integration"
157
- result["result"] = _safe_parse_json(
158
- attributes.get("output", attributes.get("output.value"))
159
- )
160
- result["error"] = None
161
-
162
- return result
163
-
164
- def _process_span_attributes(self, span_data: Dict[str, Any]) -> Dict[str, Any]:
165
- """Extracts, transforms, and maps attributes for a span."""
166
- if "Attributes" not in span_data:
167
- return span_data
168
-
169
- logger.info(f"Processing span: {span_data}")
170
-
171
- attributes_val = span_data["Attributes"]
172
- if isinstance(attributes_val, str):
173
- try:
174
- attributes: Dict[str, Any] = json.loads(attributes_val)
175
- except json.JSONDecodeError as e:
176
- logger.warning(f"Failed to parse attributes JSON: {e}")
177
- return span_data
178
- elif isinstance(attributes_val, dict):
179
- attributes = attributes_val
180
- else:
181
- return span_data
182
-
183
- # Determine SpanType
184
- if "openinference.span.kind" in attributes:
185
- span_type = attributes["openinference.span.kind"]
186
- span_data["SpanType"] = self.SPAN_TYPE_MAPPING.get(span_type, span_type)
187
-
188
- # Apply basic attribute mapping
189
- for old_key, mapping in self.ATTRIBUTE_MAPPING.items():
190
- if old_key in attributes:
191
- if isinstance(mapping, tuple):
192
- new_key, func = mapping
193
- attributes[new_key] = func(attributes[old_key])
194
- else:
195
- new_key = mapping
196
- attributes[new_key] = attributes[old_key]
197
-
198
- # Apply detailed mapping based on SpanType
199
- span_type = span_data.get("SpanType")
200
- if span_type == "completion":
201
- processed_attributes = self._map_llm_call_attributes(attributes)
202
- elif span_type == "toolCall":
203
- processed_attributes = self._map_tool_call_attributes(attributes)
204
- else:
205
- processed_attributes = attributes.copy()
206
-
207
- span_data["Attributes"] = json.dumps(processed_attributes)
208
-
209
- logger.info(f"Transformed span: {span_data}")
210
- return span_data
211
-
212
- def _send_with_retries(
213
- self, url: str, payload: List[Dict[str, Any]], max_retries: int = 4
214
- ) -> SpanExportResult:
215
- # Transform attributes in each span's payload before sending
216
- transformed_payload = [self._process_span_attributes(span) for span in payload]
217
-
218
- return super()._send_with_retries(
219
- url=url,
220
- payload=transformed_payload,
221
- max_retries=max_retries,
222
- )
@@ -1,28 +0,0 @@
1
- import logging
2
-
3
-
4
- class IgnoreSpecificUrl(logging.Filter):
5
- def __init__(self, url_to_ignore):
6
- super().__init__()
7
- self.url_to_ignore = url_to_ignore
8
-
9
- def filter(self, record):
10
- try:
11
- if record.msg == 'HTTP Request: %s %s "%s %d %s"':
12
- # Ignore the log if the URL matches the one we want to ignore
13
- method = record.args[0]
14
- url = record.args[1]
15
-
16
- if method == "POST" and url.path.endswith(self.url_to_ignore):
17
- # Check if the URL contains the specific path we want to ignore
18
- return True
19
- return False
20
-
21
- except Exception:
22
- return False
23
-
24
-
25
- def _setup_tracer_httpx_logging(url: str):
26
- # Create a custom logger for httpx
27
- # Add the custom filter to the root logger
28
- logging.getLogger("httpx").addFilter(IgnoreSpecificUrl(url))
@@ -1,191 +0,0 @@
1
- from enum import Enum
2
- from typing import Annotated, Any, Dict, List, Literal, Optional, Union
3
-
4
- from pydantic import BaseModel, ConfigDict, Field
5
-
6
-
7
- class AgentMessageRole(str, Enum):
8
- """Enum for message roles"""
9
-
10
- SYSTEM = "System"
11
- USER = "User"
12
-
13
-
14
- class AgentMessage(BaseModel):
15
- """Message model for agent conversations"""
16
-
17
- role: AgentMessageRole
18
- content: str
19
-
20
- model_config = ConfigDict(
21
- validate_by_name=True, validate_by_alias=True, extra="allow"
22
- )
23
-
24
-
25
- class AgentSettings(BaseModel):
26
- """Settings for agent configuration"""
27
-
28
- engine: str = Field(..., description="Engine type, e.g., 'basic-v1'")
29
- model: str = Field(..., description="LLM model identifier")
30
- max_tokens: int = Field(
31
- ..., alias="maxTokens", description="Maximum number of tokens"
32
- )
33
- temperature: float = Field(..., description="Temperature for response generation")
34
-
35
- model_config = ConfigDict(
36
- validate_by_name=True, validate_by_alias=True, extra="allow"
37
- )
38
-
39
-
40
- class AgentResourceType(str, Enum):
41
- """Enum for resource types"""
42
-
43
- TOOL = "tool"
44
- CONTEXT = "context"
45
- ESCALATION = "escalation"
46
-
47
-
48
- class AgentBaseResourceConfig(BaseModel):
49
- """Base resource model with common properties"""
50
-
51
- name: str
52
- description: str
53
-
54
- model_config = ConfigDict(
55
- validate_by_name=True, validate_by_alias=True, extra="allow"
56
- )
57
-
58
-
59
- class AgentUnknownResourceConfig(AgentBaseResourceConfig):
60
- """Fallback for unknown or future resource types"""
61
-
62
- resource_type: str = Field(alias="$resourceType")
63
-
64
- model_config = ConfigDict(extra="allow")
65
-
66
-
67
- class AgentToolSettings(BaseModel):
68
- """Settings for tool configuration"""
69
-
70
- max_attempts: int = Field(0, alias="maxAttempts")
71
- retry_delay: int = Field(0, alias="retryDelay")
72
- timeout: int = Field(0)
73
-
74
- model_config = ConfigDict(
75
- validate_by_name=True, validate_by_alias=True, extra="allow"
76
- )
77
-
78
-
79
- class AgentToolProperties(BaseModel):
80
- """Properties specific to tool configuration"""
81
-
82
- folder_path: Optional[str] = Field(None, alias="folderPath")
83
- process_name: Optional[str] = Field(None, alias="processName")
84
-
85
- model_config = ConfigDict(
86
- validate_by_name=True, validate_by_alias=True, extra="allow"
87
- )
88
-
89
-
90
- class AgentToolResourceConfig(AgentBaseResourceConfig):
91
- """Tool resource with tool-specific properties"""
92
-
93
- resource_type: Literal[AgentResourceType.TOOL] = Field(alias="$resourceType")
94
- type: str = Field(..., description="Tool type")
95
- arguments: Dict[str, Any] = Field(
96
- default_factory=dict, description="Tool arguments"
97
- )
98
- input_schema: Dict[str, Any] = Field(
99
- ..., alias="inputSchema", description="Input schema for the tool"
100
- )
101
- output_schema: Dict[str, Any] = Field(
102
- ..., alias="outputSchema", description="Output schema for the tool"
103
- )
104
- properties: AgentToolProperties = Field(..., description="Tool-specific properties")
105
- settings: AgentToolSettings = Field(
106
- default_factory=AgentToolSettings, description="Tool settings"
107
- )
108
-
109
- model_config = ConfigDict(
110
- validate_by_name=True, validate_by_alias=True, extra="allow"
111
- )
112
-
113
-
114
- class AgentContextSettings(BaseModel):
115
- """Settings for context configuration"""
116
-
117
- result_count: int = Field(alias="resultCount")
118
- retrieval_mode: Literal["Semantic", "Structured"] = Field(alias="retrievalMode")
119
- threshold: float = Field(default=0)
120
-
121
- model_config = ConfigDict(
122
- validate_by_name=True, validate_by_alias=True, extra="allow"
123
- )
124
-
125
-
126
- class AgentContextResourceConfig(AgentBaseResourceConfig):
127
- """Context resource with context-specific properties"""
128
-
129
- resource_type: Literal[AgentResourceType.CONTEXT] = Field(alias="$resourceType")
130
- folder_path: str = Field(alias="folderPath")
131
- index_name: str = Field(alias="indexName")
132
- settings: AgentContextSettings = Field(..., description="Context settings")
133
-
134
- model_config = ConfigDict(
135
- validate_by_name=True, validate_by_alias=True, extra="allow"
136
- )
137
-
138
-
139
- class AgentEscalationResourceConfig(AgentBaseResourceConfig):
140
- """Escalation resource with escalation-specific properties"""
141
-
142
- resource_type: Literal[AgentResourceType.ESCALATION] = Field(alias="$resourceType")
143
-
144
- model_config = ConfigDict(
145
- validate_by_name=True, validate_by_alias=True, extra="allow"
146
- )
147
-
148
-
149
- # Discriminated union for known types
150
- KnownAgentResourceConfig = Annotated[
151
- Union[
152
- AgentToolResourceConfig,
153
- AgentContextResourceConfig,
154
- AgentEscalationResourceConfig,
155
- ],
156
- Field(discriminator="resource_type"),
157
- ]
158
-
159
- # Final union includes unknowns as a catch-all
160
- AgentResourceConfig = Union[
161
- KnownAgentResourceConfig,
162
- AgentUnknownResourceConfig,
163
- ]
164
-
165
-
166
- class AgentConfig(BaseModel):
167
- """Main agent model"""
168
-
169
- id: str = Field(..., description="Agent id or project name")
170
- name: str = Field(..., description="Agent name or project name")
171
- input_schema: Dict[str, Any] = Field(
172
- ..., alias="inputSchema", description="JSON schema for input arguments"
173
- )
174
- output_schema: Dict[str, Any] = Field(
175
- ..., alias="outputSchema", description="JSON schema for output arguments"
176
- )
177
- messages: List[AgentMessage] = Field(
178
- ..., description="List of system and user messages"
179
- )
180
- features: List[Any] = Field(
181
- default_factory=list, description="Currently empty feature list"
182
- )
183
- version: str = Field("1.0.0", description="Agent version")
184
- settings: AgentSettings = Field(..., description="Agent settings configuration")
185
- resources: List[AgentResourceConfig] = Field(
186
- ..., description="List of tools, context, and escalation resources"
187
- )
188
-
189
- model_config = ConfigDict(
190
- validate_by_name=True, validate_by_alias=True, extra="allow"
191
- )