agentex-sdk 0.4.10__py3-none-any.whl → 0.4.12__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.
- agentex/_base_client.py +3 -3
- agentex/_compat.py +48 -48
- agentex/_models.py +41 -41
- agentex/_types.py +35 -1
- agentex/_utils/__init__.py +9 -2
- agentex/_utils/_compat.py +45 -0
- agentex/_utils/_datetime_parse.py +136 -0
- agentex/_utils/_transform.py +11 -1
- agentex/_utils/_typing.py +6 -1
- agentex/_utils/_utils.py +0 -1
- agentex/_version.py +1 -1
- agentex/lib/adk/_modules/acp.py +15 -3
- agentex/lib/adk/providers/_modules/openai.py +57 -0
- agentex/lib/cli/handlers/deploy_handlers.py +4 -1
- agentex/lib/cli/templates/temporal/README.md.j2 +18 -2
- agentex/lib/cli/templates/temporal/environments.yaml.j2 +1 -1
- agentex/lib/cli/templates/temporal/project/activities.py.j2 +77 -0
- agentex/lib/cli/templates/temporal/project/run_worker.py.j2 +3 -1
- agentex/lib/core/services/adk/acp/acp.py +27 -12
- agentex/lib/core/services/adk/providers/openai.py +272 -29
- agentex/lib/core/temporal/activities/adk/acp/acp_activities.py +6 -0
- agentex/lib/core/temporal/activities/adk/providers/openai_activities.py +451 -69
- agentex/types/reasoning_content_param.py +4 -3
- {agentex_sdk-0.4.10.dist-info → agentex_sdk-0.4.12.dist-info}/METADATA +1 -1
- {agentex_sdk-0.4.10.dist-info → agentex_sdk-0.4.12.dist-info}/RECORD +28 -25
- {agentex_sdk-0.4.10.dist-info → agentex_sdk-0.4.12.dist-info}/WHEEL +0 -0
- {agentex_sdk-0.4.10.dist-info → agentex_sdk-0.4.12.dist-info}/entry_points.txt +0 -0
- {agentex_sdk-0.4.10.dist-info → agentex_sdk-0.4.12.dist-info}/licenses/LICENSE +0 -0
@@ -1,33 +1,42 @@
|
|
1
1
|
# Standard library imports
|
2
2
|
import base64
|
3
|
-
from collections.abc import Callable
|
4
|
-
from contextlib import AsyncExitStack, asynccontextmanager
|
5
3
|
from enum import Enum
|
6
|
-
from typing import Any, Literal, Optional
|
7
|
-
|
8
|
-
from
|
4
|
+
from typing import Any, Literal, Optional
|
5
|
+
from contextlib import AsyncExitStack, asynccontextmanager
|
6
|
+
from collections.abc import Callable
|
9
7
|
|
10
8
|
import cloudpickle
|
11
|
-
from
|
9
|
+
from mcp import StdioServerParameters
|
10
|
+
from agents import RunResult, RunContextWrapper, RunResultStreaming
|
11
|
+
from pydantic import Field, PrivateAttr
|
12
12
|
from agents.mcp import MCPServerStdio, MCPServerStdioParams
|
13
|
+
from temporalio import activity
|
14
|
+
from agents.tool import (
|
15
|
+
ComputerTool as OAIComputerTool,
|
16
|
+
FunctionTool as OAIFunctionTool,
|
17
|
+
WebSearchTool as OAIWebSearchTool,
|
18
|
+
FileSearchTool as OAIFileSearchTool,
|
19
|
+
LocalShellTool as OAILocalShellTool,
|
20
|
+
CodeInterpreterTool as OAICodeInterpreterTool,
|
21
|
+
ImageGenerationTool as OAIImageGenerationTool,
|
22
|
+
)
|
23
|
+
from agents.guardrail import InputGuardrail, OutputGuardrail
|
24
|
+
from agents.exceptions import InputGuardrailTripwireTriggered, OutputGuardrailTripwireTriggered
|
13
25
|
from agents.model_settings import ModelSettings as OAIModelSettings
|
14
|
-
from agents.tool import FunctionTool as OAIFunctionTool
|
15
|
-
from mcp import StdioServerParameters
|
16
|
-
from openai.types.responses.response_includable import ResponseIncludable
|
17
26
|
from openai.types.shared.reasoning import Reasoning
|
18
|
-
from
|
27
|
+
from openai.types.responses.response_includable import ResponseIncludable
|
19
28
|
|
20
|
-
from agentex.lib.
|
29
|
+
from agentex.lib.utils import logging
|
30
|
+
|
31
|
+
# Third-party imports
|
32
|
+
from agentex.lib.types.tracing import BaseModelWithTraceParams
|
21
33
|
|
22
34
|
# Local imports
|
23
35
|
from agentex.lib.types.agent_results import (
|
24
36
|
SerializableRunResult,
|
25
37
|
SerializableRunResultStreaming,
|
26
38
|
)
|
27
|
-
|
28
|
-
# Third-party imports
|
29
|
-
from agentex.lib.types.tracing import BaseModelWithTraceParams
|
30
|
-
from agentex.lib.utils import logging
|
39
|
+
from agentex.lib.core.services.adk.providers.openai import OpenAIService
|
31
40
|
|
32
41
|
logger = logging.make_logger(__name__)
|
33
42
|
|
@@ -41,6 +50,147 @@ class OpenAIActivityName(str, Enum):
|
|
41
50
|
RUN_AGENT_STREAMED_AUTO_SEND = "run_agent_streamed_auto_send"
|
42
51
|
|
43
52
|
|
53
|
+
class WebSearchTool(BaseModelWithTraceParams):
|
54
|
+
"""Temporal-compatible wrapper for WebSearchTool."""
|
55
|
+
|
56
|
+
user_location: Optional[dict[str, Any]] = None # UserLocation object
|
57
|
+
search_context_size: Optional[Literal["low", "medium", "high"]] = "medium"
|
58
|
+
|
59
|
+
def to_oai_function_tool(self) -> OAIWebSearchTool:
|
60
|
+
kwargs = {}
|
61
|
+
if self.user_location is not None:
|
62
|
+
kwargs["user_location"] = self.user_location
|
63
|
+
if self.search_context_size is not None:
|
64
|
+
kwargs["search_context_size"] = self.search_context_size
|
65
|
+
return OAIWebSearchTool(**kwargs)
|
66
|
+
|
67
|
+
|
68
|
+
class FileSearchTool(BaseModelWithTraceParams):
|
69
|
+
"""Temporal-compatible wrapper for FileSearchTool."""
|
70
|
+
|
71
|
+
vector_store_ids: list[str]
|
72
|
+
max_num_results: Optional[int] = None
|
73
|
+
include_search_results: bool = False
|
74
|
+
ranking_options: Optional[dict[str, Any]] = None
|
75
|
+
filters: Optional[dict[str, Any]] = None
|
76
|
+
|
77
|
+
def to_oai_function_tool(self):
|
78
|
+
return OAIFileSearchTool(
|
79
|
+
vector_store_ids=self.vector_store_ids,
|
80
|
+
max_num_results=self.max_num_results,
|
81
|
+
include_search_results=self.include_search_results,
|
82
|
+
ranking_options=self.ranking_options,
|
83
|
+
filters=self.filters,
|
84
|
+
)
|
85
|
+
|
86
|
+
|
87
|
+
class ComputerTool(BaseModelWithTraceParams):
|
88
|
+
"""Temporal-compatible wrapper for ComputerTool."""
|
89
|
+
|
90
|
+
# We need to serialize the computer object and safety check function
|
91
|
+
computer_serialized: str = Field(default="", description="Serialized computer object")
|
92
|
+
on_safety_check_serialized: str = Field(default="", description="Serialized safety check function")
|
93
|
+
|
94
|
+
_computer: Any = PrivateAttr()
|
95
|
+
_on_safety_check: Optional[Callable] = PrivateAttr()
|
96
|
+
|
97
|
+
def __init__(
|
98
|
+
self,
|
99
|
+
*,
|
100
|
+
computer: Any = None,
|
101
|
+
on_safety_check: Optional[Callable] = None,
|
102
|
+
**data,
|
103
|
+
):
|
104
|
+
super().__init__(**data)
|
105
|
+
if computer is not None:
|
106
|
+
self.computer_serialized = self._serialize_callable(computer)
|
107
|
+
self._computer = computer
|
108
|
+
elif self.computer_serialized:
|
109
|
+
self._computer = self._deserialize_callable(self.computer_serialized)
|
110
|
+
|
111
|
+
if on_safety_check is not None:
|
112
|
+
self.on_safety_check_serialized = self._serialize_callable(on_safety_check)
|
113
|
+
self._on_safety_check = on_safety_check
|
114
|
+
elif self.on_safety_check_serialized:
|
115
|
+
self._on_safety_check = self._deserialize_callable(self.on_safety_check_serialized)
|
116
|
+
|
117
|
+
@classmethod
|
118
|
+
def _deserialize_callable(cls, serialized: str) -> Any:
|
119
|
+
encoded = serialized.encode()
|
120
|
+
serialized_bytes = base64.b64decode(encoded)
|
121
|
+
return cloudpickle.loads(serialized_bytes)
|
122
|
+
|
123
|
+
@classmethod
|
124
|
+
def _serialize_callable(cls, func: Any) -> str:
|
125
|
+
serialized_bytes = cloudpickle.dumps(func)
|
126
|
+
encoded = base64.b64encode(serialized_bytes)
|
127
|
+
return encoded.decode()
|
128
|
+
|
129
|
+
def to_oai_function_tool(self):
|
130
|
+
return OAIComputerTool(
|
131
|
+
computer=self._computer,
|
132
|
+
on_safety_check=self._on_safety_check,
|
133
|
+
)
|
134
|
+
|
135
|
+
|
136
|
+
class CodeInterpreterTool(BaseModelWithTraceParams):
|
137
|
+
"""Temporal-compatible wrapper for CodeInterpreterTool."""
|
138
|
+
|
139
|
+
tool_config: dict[str, Any] = Field(
|
140
|
+
default_factory=lambda: {"type": "code_interpreter"}, description="Tool configuration dict"
|
141
|
+
)
|
142
|
+
|
143
|
+
def to_oai_function_tool(self):
|
144
|
+
return OAICodeInterpreterTool(tool_config=self.tool_config)
|
145
|
+
|
146
|
+
|
147
|
+
class ImageGenerationTool(BaseModelWithTraceParams):
|
148
|
+
"""Temporal-compatible wrapper for ImageGenerationTool."""
|
149
|
+
|
150
|
+
tool_config: dict[str, Any] = Field(
|
151
|
+
default_factory=lambda: {"type": "image_generation"}, description="Tool configuration dict"
|
152
|
+
)
|
153
|
+
|
154
|
+
def to_oai_function_tool(self):
|
155
|
+
return OAIImageGenerationTool(tool_config=self.tool_config)
|
156
|
+
|
157
|
+
|
158
|
+
class LocalShellTool(BaseModelWithTraceParams):
|
159
|
+
"""Temporal-compatible wrapper for LocalShellTool."""
|
160
|
+
|
161
|
+
executor_serialized: str = Field(default="", description="Serialized LocalShellExecutor object")
|
162
|
+
|
163
|
+
_executor: Any = PrivateAttr()
|
164
|
+
|
165
|
+
def __init__(
|
166
|
+
self,
|
167
|
+
*,
|
168
|
+
executor: Any = None,
|
169
|
+
**data,
|
170
|
+
):
|
171
|
+
super().__init__(**data)
|
172
|
+
if executor is not None:
|
173
|
+
self.executor_serialized = self._serialize_callable(executor)
|
174
|
+
self._executor = executor
|
175
|
+
elif self.executor_serialized:
|
176
|
+
self._executor = self._deserialize_callable(self.executor_serialized)
|
177
|
+
|
178
|
+
@classmethod
|
179
|
+
def _deserialize_callable(cls, serialized: str) -> Any:
|
180
|
+
encoded = serialized.encode()
|
181
|
+
serialized_bytes = base64.b64decode(encoded)
|
182
|
+
return cloudpickle.loads(serialized_bytes)
|
183
|
+
|
184
|
+
@classmethod
|
185
|
+
def _serialize_callable(cls, func: Any) -> str:
|
186
|
+
serialized_bytes = cloudpickle.dumps(func)
|
187
|
+
encoded = base64.b64encode(serialized_bytes)
|
188
|
+
return encoded.decode()
|
189
|
+
|
190
|
+
def to_oai_function_tool(self):
|
191
|
+
return OAILocalShellTool(executor=self._executor)
|
192
|
+
|
193
|
+
|
44
194
|
class FunctionTool(BaseModelWithTraceParams):
|
45
195
|
name: str
|
46
196
|
description: str
|
@@ -78,22 +228,16 @@ class FunctionTool(BaseModelWithTraceParams):
|
|
78
228
|
super().__init__(**data)
|
79
229
|
if not on_invoke_tool:
|
80
230
|
if not self.on_invoke_tool_serialized:
|
81
|
-
raise ValueError(
|
82
|
-
"One of `on_invoke_tool` or `on_invoke_tool_serialized` should be set"
|
83
|
-
)
|
231
|
+
raise ValueError("One of `on_invoke_tool` or `on_invoke_tool_serialized` should be set")
|
84
232
|
else:
|
85
|
-
on_invoke_tool = self._deserialize_callable(
|
86
|
-
self.on_invoke_tool_serialized
|
87
|
-
)
|
233
|
+
on_invoke_tool = self._deserialize_callable(self.on_invoke_tool_serialized)
|
88
234
|
else:
|
89
235
|
self.on_invoke_tool_serialized = self._serialize_callable(on_invoke_tool)
|
90
236
|
|
91
237
|
self._on_invoke_tool = on_invoke_tool
|
92
238
|
|
93
239
|
@classmethod
|
94
|
-
def _deserialize_callable(
|
95
|
-
cls, serialized: str
|
96
|
-
) -> Callable[[RunContextWrapper, str], Any]:
|
240
|
+
def _deserialize_callable(cls, serialized: str) -> Callable[[RunContextWrapper, str], Any]:
|
97
241
|
encoded = serialized.encode()
|
98
242
|
serialized_bytes = base64.b64decode(encoded)
|
99
243
|
return cloudpickle.loads(serialized_bytes)
|
@@ -107,11 +251,9 @@ class FunctionTool(BaseModelWithTraceParams):
|
|
107
251
|
@property
|
108
252
|
def on_invoke_tool(self) -> Callable[[RunContextWrapper, str], Any]:
|
109
253
|
if self._on_invoke_tool is None and self.on_invoke_tool_serialized:
|
110
|
-
self._on_invoke_tool = self._deserialize_callable(
|
111
|
-
self.on_invoke_tool_serialized
|
112
|
-
)
|
254
|
+
self._on_invoke_tool = self._deserialize_callable(self.on_invoke_tool_serialized)
|
113
255
|
return self._on_invoke_tool
|
114
|
-
|
256
|
+
|
115
257
|
@on_invoke_tool.setter
|
116
258
|
def on_invoke_tool(self, value: Callable[[RunContextWrapper, str], Any]):
|
117
259
|
self.on_invoke_tool_serialized = self._serialize_callable(value)
|
@@ -133,6 +275,126 @@ class FunctionTool(BaseModelWithTraceParams):
|
|
133
275
|
return OAIFunctionTool(**data)
|
134
276
|
|
135
277
|
|
278
|
+
class TemporalInputGuardrail(BaseModelWithTraceParams):
|
279
|
+
"""Temporal-compatible wrapper for InputGuardrail with function
|
280
|
+
serialization."""
|
281
|
+
|
282
|
+
name: str
|
283
|
+
_guardrail_function: Callable = PrivateAttr()
|
284
|
+
guardrail_function_serialized: str = Field(
|
285
|
+
default="",
|
286
|
+
description=(
|
287
|
+
"Serialized guardrail function. Set automatically during initialization. "
|
288
|
+
"Pass `guardrail_function` to the constructor instead."
|
289
|
+
),
|
290
|
+
)
|
291
|
+
|
292
|
+
def __init__(
|
293
|
+
self,
|
294
|
+
*,
|
295
|
+
guardrail_function: Optional[Callable] = None,
|
296
|
+
**data,
|
297
|
+
):
|
298
|
+
"""Initialize with function serialization support for Temporal."""
|
299
|
+
super().__init__(**data)
|
300
|
+
if not guardrail_function:
|
301
|
+
if not self.guardrail_function_serialized:
|
302
|
+
raise ValueError("One of `guardrail_function` or `guardrail_function_serialized` should be set")
|
303
|
+
else:
|
304
|
+
guardrail_function = self._deserialize_callable(self.guardrail_function_serialized)
|
305
|
+
else:
|
306
|
+
self.guardrail_function_serialized = self._serialize_callable(guardrail_function)
|
307
|
+
|
308
|
+
self._guardrail_function = guardrail_function
|
309
|
+
|
310
|
+
@classmethod
|
311
|
+
def _deserialize_callable(cls, serialized: str) -> Callable:
|
312
|
+
encoded = serialized.encode()
|
313
|
+
serialized_bytes = base64.b64decode(encoded)
|
314
|
+
return cloudpickle.loads(serialized_bytes)
|
315
|
+
|
316
|
+
@classmethod
|
317
|
+
def _serialize_callable(cls, func: Callable) -> str:
|
318
|
+
serialized_bytes = cloudpickle.dumps(func)
|
319
|
+
encoded = base64.b64encode(serialized_bytes)
|
320
|
+
return encoded.decode()
|
321
|
+
|
322
|
+
@property
|
323
|
+
def guardrail_function(self) -> Callable:
|
324
|
+
if self._guardrail_function is None and self.guardrail_function_serialized:
|
325
|
+
self._guardrail_function = self._deserialize_callable(self.guardrail_function_serialized)
|
326
|
+
return self._guardrail_function
|
327
|
+
|
328
|
+
@guardrail_function.setter
|
329
|
+
def guardrail_function(self, value: Callable):
|
330
|
+
self.guardrail_function_serialized = self._serialize_callable(value)
|
331
|
+
self._guardrail_function = value
|
332
|
+
|
333
|
+
def to_oai_input_guardrail(self) -> InputGuardrail:
|
334
|
+
"""Convert to OpenAI InputGuardrail."""
|
335
|
+
return InputGuardrail(guardrail_function=self.guardrail_function, name=self.name)
|
336
|
+
|
337
|
+
|
338
|
+
class TemporalOutputGuardrail(BaseModelWithTraceParams):
|
339
|
+
"""Temporal-compatible wrapper for OutputGuardrail with function
|
340
|
+
serialization."""
|
341
|
+
|
342
|
+
name: str
|
343
|
+
_guardrail_function: Callable = PrivateAttr()
|
344
|
+
guardrail_function_serialized: str = Field(
|
345
|
+
default="",
|
346
|
+
description=(
|
347
|
+
"Serialized guardrail function. Set automatically during initialization. "
|
348
|
+
"Pass `guardrail_function` to the constructor instead."
|
349
|
+
),
|
350
|
+
)
|
351
|
+
|
352
|
+
def __init__(
|
353
|
+
self,
|
354
|
+
*,
|
355
|
+
guardrail_function: Optional[Callable] = None,
|
356
|
+
**data,
|
357
|
+
):
|
358
|
+
"""Initialize with function serialization support for Temporal."""
|
359
|
+
super().__init__(**data)
|
360
|
+
if not guardrail_function:
|
361
|
+
if not self.guardrail_function_serialized:
|
362
|
+
raise ValueError("One of `guardrail_function` or `guardrail_function_serialized` should be set")
|
363
|
+
else:
|
364
|
+
guardrail_function = self._deserialize_callable(self.guardrail_function_serialized)
|
365
|
+
else:
|
366
|
+
self.guardrail_function_serialized = self._serialize_callable(guardrail_function)
|
367
|
+
|
368
|
+
self._guardrail_function = guardrail_function
|
369
|
+
|
370
|
+
@classmethod
|
371
|
+
def _deserialize_callable(cls, serialized: str) -> Callable:
|
372
|
+
encoded = serialized.encode()
|
373
|
+
serialized_bytes = base64.b64decode(encoded)
|
374
|
+
return cloudpickle.loads(serialized_bytes)
|
375
|
+
|
376
|
+
@classmethod
|
377
|
+
def _serialize_callable(cls, func: Callable) -> str:
|
378
|
+
serialized_bytes = cloudpickle.dumps(func)
|
379
|
+
encoded = base64.b64encode(serialized_bytes)
|
380
|
+
return encoded.decode()
|
381
|
+
|
382
|
+
@property
|
383
|
+
def guardrail_function(self) -> Callable:
|
384
|
+
if self._guardrail_function is None and self.guardrail_function_serialized:
|
385
|
+
self._guardrail_function = self._deserialize_callable(self.guardrail_function_serialized)
|
386
|
+
return self._guardrail_function
|
387
|
+
|
388
|
+
@guardrail_function.setter
|
389
|
+
def guardrail_function(self, value: Callable):
|
390
|
+
self.guardrail_function_serialized = self._serialize_callable(value)
|
391
|
+
self._guardrail_function = value
|
392
|
+
|
393
|
+
def to_oai_output_guardrail(self) -> OutputGuardrail:
|
394
|
+
"""Convert to OpenAI OutputGuardrail."""
|
395
|
+
return OutputGuardrail(guardrail_function=self.guardrail_function, name=self.name)
|
396
|
+
|
397
|
+
|
136
398
|
class ModelSettings(BaseModelWithTraceParams):
|
137
399
|
temperature: float | None = None
|
138
400
|
top_p: float | None = None
|
@@ -152,9 +414,7 @@ class ModelSettings(BaseModelWithTraceParams):
|
|
152
414
|
extra_args: dict[str, Any] | None = None
|
153
415
|
|
154
416
|
def to_oai_model_settings(self) -> OAIModelSettings:
|
155
|
-
return OAIModelSettings(
|
156
|
-
**self.model_dump(exclude=["trace_id", "parent_span_id"])
|
157
|
-
)
|
417
|
+
return OAIModelSettings(**self.model_dump(exclude=["trace_id", "parent_span_id"]))
|
158
418
|
|
159
419
|
|
160
420
|
class RunAgentParams(BaseModelWithTraceParams):
|
@@ -168,10 +428,24 @@ class RunAgentParams(BaseModelWithTraceParams):
|
|
168
428
|
handoffs: list["RunAgentParams"] | None = None
|
169
429
|
model: str | None = None
|
170
430
|
model_settings: ModelSettings | None = None
|
171
|
-
tools:
|
431
|
+
tools: (
|
432
|
+
list[
|
433
|
+
FunctionTool
|
434
|
+
| WebSearchTool
|
435
|
+
| FileSearchTool
|
436
|
+
| ComputerTool
|
437
|
+
| CodeInterpreterTool
|
438
|
+
| ImageGenerationTool
|
439
|
+
| LocalShellTool
|
440
|
+
]
|
441
|
+
| None
|
442
|
+
) = None
|
172
443
|
output_type: Any = None
|
173
444
|
tool_use_behavior: Literal["run_llm_again", "stop_on_first_tool"] = "run_llm_again"
|
174
445
|
mcp_timeout_seconds: int | None = None
|
446
|
+
input_guardrails: list[TemporalInputGuardrail] | None = None
|
447
|
+
output_guardrails: list[TemporalOutputGuardrail] | None = None
|
448
|
+
max_turns: int | None = None
|
175
449
|
|
176
450
|
|
177
451
|
class RunAgentAutoSendParams(RunAgentParams):
|
@@ -214,6 +488,15 @@ class OpenAIActivities:
|
|
214
488
|
@activity.defn(name=OpenAIActivityName.RUN_AGENT)
|
215
489
|
async def run_agent(self, params: RunAgentParams) -> SerializableRunResult:
|
216
490
|
"""Run an agent without streaming or TaskMessage creation."""
|
491
|
+
# Convert Temporal guardrails to OpenAI guardrails
|
492
|
+
input_guardrails = None
|
493
|
+
if params.input_guardrails:
|
494
|
+
input_guardrails = [g.to_oai_input_guardrail() for g in params.input_guardrails]
|
495
|
+
|
496
|
+
output_guardrails = None
|
497
|
+
if params.output_guardrails:
|
498
|
+
output_guardrails = [g.to_oai_output_guardrail() for g in params.output_guardrails]
|
499
|
+
|
217
500
|
result = await self._openai_service.run_agent(
|
218
501
|
input_list=params.input_list,
|
219
502
|
mcp_server_params=params.mcp_server_params,
|
@@ -228,54 +511,153 @@ class OpenAIActivities:
|
|
228
511
|
tools=params.tools,
|
229
512
|
output_type=params.output_type,
|
230
513
|
tool_use_behavior=params.tool_use_behavior,
|
514
|
+
input_guardrails=input_guardrails,
|
515
|
+
output_guardrails=output_guardrails,
|
516
|
+
mcp_timeout_seconds=params.mcp_timeout_seconds,
|
517
|
+
max_turns=params.max_turns,
|
231
518
|
)
|
232
519
|
return self._to_serializable_run_result(result)
|
233
520
|
|
234
521
|
@activity.defn(name=OpenAIActivityName.RUN_AGENT_AUTO_SEND)
|
235
|
-
async def run_agent_auto_send(
|
236
|
-
self, params: RunAgentAutoSendParams
|
237
|
-
) -> SerializableRunResult:
|
522
|
+
async def run_agent_auto_send(self, params: RunAgentAutoSendParams) -> SerializableRunResult:
|
238
523
|
"""Run an agent with automatic TaskMessage creation."""
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
524
|
+
# Convert Temporal guardrails to OpenAI guardrails
|
525
|
+
input_guardrails = None
|
526
|
+
if params.input_guardrails:
|
527
|
+
input_guardrails = [g.to_oai_input_guardrail() for g in params.input_guardrails]
|
528
|
+
|
529
|
+
output_guardrails = None
|
530
|
+
if params.output_guardrails:
|
531
|
+
output_guardrails = [g.to_oai_output_guardrail() for g in params.output_guardrails]
|
532
|
+
|
533
|
+
try:
|
534
|
+
result = await self._openai_service.run_agent_auto_send(
|
535
|
+
task_id=params.task_id,
|
536
|
+
input_list=params.input_list,
|
537
|
+
mcp_server_params=params.mcp_server_params,
|
538
|
+
agent_name=params.agent_name,
|
539
|
+
agent_instructions=params.agent_instructions,
|
540
|
+
trace_id=params.trace_id,
|
541
|
+
parent_span_id=params.parent_span_id,
|
542
|
+
handoff_description=params.handoff_description,
|
543
|
+
handoffs=params.handoffs,
|
544
|
+
model=params.model,
|
545
|
+
model_settings=params.model_settings,
|
546
|
+
tools=params.tools,
|
547
|
+
output_type=params.output_type,
|
548
|
+
tool_use_behavior=params.tool_use_behavior,
|
549
|
+
input_guardrails=input_guardrails,
|
550
|
+
output_guardrails=output_guardrails,
|
551
|
+
mcp_timeout_seconds=params.mcp_timeout_seconds,
|
552
|
+
max_turns=params.max_turns,
|
553
|
+
)
|
554
|
+
return self._to_serializable_run_result(result)
|
555
|
+
except InputGuardrailTripwireTriggered as e:
|
556
|
+
# Handle guardrail trigger gracefully
|
557
|
+
rejection_message = (
|
558
|
+
"I'm sorry, but I cannot process this request due to a guardrail. Please try a different question."
|
559
|
+
)
|
560
|
+
|
561
|
+
# Try to extract rejection message from the guardrail result
|
562
|
+
if hasattr(e, "guardrail_result") and hasattr(e.guardrail_result, "output"):
|
563
|
+
output_info = getattr(e.guardrail_result.output, "output_info", {})
|
564
|
+
if isinstance(output_info, dict) and "rejection_message" in output_info:
|
565
|
+
rejection_message = output_info["rejection_message"]
|
566
|
+
|
567
|
+
# Build the final input list with the rejection message
|
568
|
+
final_input_list = list(params.input_list or [])
|
569
|
+
final_input_list.append({"role": "assistant", "content": rejection_message})
|
570
|
+
|
571
|
+
return SerializableRunResult(final_output=rejection_message, final_input_list=final_input_list)
|
572
|
+
except OutputGuardrailTripwireTriggered as e:
|
573
|
+
# Handle output guardrail trigger gracefully
|
574
|
+
rejection_message = (
|
575
|
+
"I'm sorry, but I cannot provide this response due to a guardrail. Please try a different question."
|
576
|
+
)
|
577
|
+
|
578
|
+
# Try to extract rejection message from the guardrail result
|
579
|
+
if hasattr(e, "guardrail_result") and hasattr(e.guardrail_result, "output"):
|
580
|
+
output_info = getattr(e.guardrail_result.output, "output_info", {})
|
581
|
+
if isinstance(output_info, dict) and "rejection_message" in output_info:
|
582
|
+
rejection_message = output_info["rejection_message"]
|
583
|
+
|
584
|
+
# Build the final input list with the rejection message
|
585
|
+
final_input_list = list(params.input_list or [])
|
586
|
+
final_input_list.append({"role": "assistant", "content": rejection_message})
|
587
|
+
|
588
|
+
return SerializableRunResult(final_output=rejection_message, final_input_list=final_input_list)
|
256
589
|
|
257
590
|
@activity.defn(name=OpenAIActivityName.RUN_AGENT_STREAMED_AUTO_SEND)
|
258
591
|
async def run_agent_streamed_auto_send(
|
259
592
|
self, params: RunAgentStreamedAutoSendParams
|
260
593
|
) -> SerializableRunResultStreaming:
|
261
594
|
"""Run an agent with streaming and automatic TaskMessage creation."""
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
595
|
+
|
596
|
+
# Convert Temporal guardrails to OpenAI guardrails
|
597
|
+
input_guardrails = None
|
598
|
+
if params.input_guardrails:
|
599
|
+
input_guardrails = [g.to_oai_input_guardrail() for g in params.input_guardrails]
|
600
|
+
|
601
|
+
output_guardrails = None
|
602
|
+
if params.output_guardrails:
|
603
|
+
output_guardrails = [g.to_oai_output_guardrail() for g in params.output_guardrails]
|
604
|
+
|
605
|
+
try:
|
606
|
+
result = await self._openai_service.run_agent_streamed_auto_send(
|
607
|
+
task_id=params.task_id,
|
608
|
+
input_list=params.input_list,
|
609
|
+
mcp_server_params=params.mcp_server_params,
|
610
|
+
agent_name=params.agent_name,
|
611
|
+
agent_instructions=params.agent_instructions,
|
612
|
+
trace_id=params.trace_id,
|
613
|
+
parent_span_id=params.parent_span_id,
|
614
|
+
handoff_description=params.handoff_description,
|
615
|
+
handoffs=params.handoffs,
|
616
|
+
model=params.model,
|
617
|
+
model_settings=params.model_settings,
|
618
|
+
tools=params.tools,
|
619
|
+
output_type=params.output_type,
|
620
|
+
tool_use_behavior=params.tool_use_behavior,
|
621
|
+
input_guardrails=input_guardrails,
|
622
|
+
output_guardrails=output_guardrails,
|
623
|
+
mcp_timeout_seconds=params.mcp_timeout_seconds,
|
624
|
+
max_turns=params.max_turns,
|
625
|
+
)
|
626
|
+
return self._to_serializable_run_result_streaming(result)
|
627
|
+
except InputGuardrailTripwireTriggered as e:
|
628
|
+
# Handle guardrail trigger gracefully
|
629
|
+
rejection_message = (
|
630
|
+
"I'm sorry, but I cannot process this request due to a guardrail. Please try a different question."
|
631
|
+
)
|
632
|
+
|
633
|
+
# Try to extract rejection message from the guardrail result
|
634
|
+
if hasattr(e, "guardrail_result") and hasattr(e.guardrail_result, "output"):
|
635
|
+
output_info = getattr(e.guardrail_result.output, "output_info", {})
|
636
|
+
if isinstance(output_info, dict) and "rejection_message" in output_info:
|
637
|
+
rejection_message = output_info["rejection_message"]
|
638
|
+
|
639
|
+
# Build the final input list with the rejection message
|
640
|
+
final_input_list = list(params.input_list or [])
|
641
|
+
final_input_list.append({"role": "assistant", "content": rejection_message})
|
642
|
+
|
643
|
+
return SerializableRunResultStreaming(final_output=rejection_message, final_input_list=final_input_list)
|
644
|
+
except OutputGuardrailTripwireTriggered as e:
|
645
|
+
# Handle output guardrail trigger gracefully
|
646
|
+
rejection_message = (
|
647
|
+
"I'm sorry, but I cannot provide this response due to a guardrail. Please try a different question."
|
648
|
+
)
|
649
|
+
|
650
|
+
# Try to extract rejection message from the guardrail result
|
651
|
+
if hasattr(e, "guardrail_result") and hasattr(e.guardrail_result, "output"):
|
652
|
+
output_info = getattr(e.guardrail_result.output, "output_info", {})
|
653
|
+
if isinstance(output_info, dict) and "rejection_message" in output_info:
|
654
|
+
rejection_message = output_info["rejection_message"]
|
655
|
+
|
656
|
+
# Build the final input list with the rejection message
|
657
|
+
final_input_list = list(params.input_list or [])
|
658
|
+
final_input_list.append({"role": "assistant", "content": rejection_message})
|
659
|
+
|
660
|
+
return SerializableRunResultStreaming(final_output=rejection_message, final_input_list=final_input_list)
|
279
661
|
|
280
662
|
@staticmethod
|
281
663
|
def _to_serializable_run_result(result: RunResult) -> SerializableRunResult:
|
@@ -2,9 +2,10 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
-
from typing import
|
5
|
+
from typing import Optional
|
6
6
|
from typing_extensions import Literal, Required, TypedDict
|
7
7
|
|
8
|
+
from .._types import SequenceNotStr
|
8
9
|
from .message_style import MessageStyle
|
9
10
|
from .message_author import MessageAuthor
|
10
11
|
|
@@ -18,10 +19,10 @@ class ReasoningContentParam(TypedDict, total=False):
|
|
18
19
|
`tool`.
|
19
20
|
"""
|
20
21
|
|
21
|
-
summary: Required[
|
22
|
+
summary: Required[SequenceNotStr[str]]
|
22
23
|
"""A list of short reasoning summaries"""
|
23
24
|
|
24
|
-
content: Optional[
|
25
|
+
content: Optional[SequenceNotStr[str]]
|
25
26
|
"""The reasoning content or chain-of-thought text"""
|
26
27
|
|
27
28
|
style: MessageStyle
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: agentex-sdk
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.12
|
4
4
|
Summary: The official Python library for the agentex API
|
5
5
|
Project-URL: Homepage, https://github.com/scaleapi/agentex-python
|
6
6
|
Project-URL: Repository, https://github.com/scaleapi/agentex-python
|