agentex-sdk 0.1.0a6__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 (289) hide show
  1. agentex/__init__.py +103 -0
  2. agentex/_base_client.py +1992 -0
  3. agentex/_client.py +506 -0
  4. agentex/_compat.py +219 -0
  5. agentex/_constants.py +14 -0
  6. agentex/_exceptions.py +108 -0
  7. agentex/_files.py +123 -0
  8. agentex/_models.py +829 -0
  9. agentex/_qs.py +150 -0
  10. agentex/_resource.py +43 -0
  11. agentex/_response.py +830 -0
  12. agentex/_streaming.py +333 -0
  13. agentex/_types.py +219 -0
  14. agentex/_utils/__init__.py +57 -0
  15. agentex/_utils/_logs.py +25 -0
  16. agentex/_utils/_proxy.py +65 -0
  17. agentex/_utils/_reflection.py +42 -0
  18. agentex/_utils/_resources_proxy.py +24 -0
  19. agentex/_utils/_streams.py +12 -0
  20. agentex/_utils/_sync.py +86 -0
  21. agentex/_utils/_transform.py +447 -0
  22. agentex/_utils/_typing.py +151 -0
  23. agentex/_utils/_utils.py +422 -0
  24. agentex/_version.py +4 -0
  25. agentex/lib/.keep +4 -0
  26. agentex/lib/__init__.py +0 -0
  27. agentex/lib/adk/__init__.py +41 -0
  28. agentex/lib/adk/_modules/__init__.py +0 -0
  29. agentex/lib/adk/_modules/acp.py +247 -0
  30. agentex/lib/adk/_modules/agent_task_tracker.py +176 -0
  31. agentex/lib/adk/_modules/agents.py +77 -0
  32. agentex/lib/adk/_modules/events.py +141 -0
  33. agentex/lib/adk/_modules/messages.py +285 -0
  34. agentex/lib/adk/_modules/state.py +291 -0
  35. agentex/lib/adk/_modules/streaming.py +75 -0
  36. agentex/lib/adk/_modules/tasks.py +124 -0
  37. agentex/lib/adk/_modules/tracing.py +194 -0
  38. agentex/lib/adk/providers/__init__.py +9 -0
  39. agentex/lib/adk/providers/_modules/__init__.py +0 -0
  40. agentex/lib/adk/providers/_modules/litellm.py +232 -0
  41. agentex/lib/adk/providers/_modules/openai.py +416 -0
  42. agentex/lib/adk/providers/_modules/sgp.py +85 -0
  43. agentex/lib/adk/utils/__init__.py +5 -0
  44. agentex/lib/adk/utils/_modules/__init__.py +0 -0
  45. agentex/lib/adk/utils/_modules/templating.py +94 -0
  46. agentex/lib/cli/__init__.py +0 -0
  47. agentex/lib/cli/commands/__init__.py +0 -0
  48. agentex/lib/cli/commands/agents.py +328 -0
  49. agentex/lib/cli/commands/init.py +227 -0
  50. agentex/lib/cli/commands/main.py +33 -0
  51. agentex/lib/cli/commands/secrets.py +169 -0
  52. agentex/lib/cli/commands/tasks.py +118 -0
  53. agentex/lib/cli/commands/uv.py +133 -0
  54. agentex/lib/cli/handlers/__init__.py +0 -0
  55. agentex/lib/cli/handlers/agent_handlers.py +160 -0
  56. agentex/lib/cli/handlers/cleanup_handlers.py +186 -0
  57. agentex/lib/cli/handlers/deploy_handlers.py +351 -0
  58. agentex/lib/cli/handlers/run_handlers.py +452 -0
  59. agentex/lib/cli/handlers/secret_handlers.py +670 -0
  60. agentex/lib/cli/templates/default/.dockerignore.j2 +43 -0
  61. agentex/lib/cli/templates/default/Dockerfile-uv.j2 +42 -0
  62. agentex/lib/cli/templates/default/Dockerfile.j2 +42 -0
  63. agentex/lib/cli/templates/default/README.md.j2 +193 -0
  64. agentex/lib/cli/templates/default/deploy/example.yaml.j2 +55 -0
  65. agentex/lib/cli/templates/default/manifest.yaml.j2 +116 -0
  66. agentex/lib/cli/templates/default/project/acp.py.j2 +29 -0
  67. agentex/lib/cli/templates/default/pyproject.toml.j2 +33 -0
  68. agentex/lib/cli/templates/default/requirements.txt.j2 +5 -0
  69. agentex/lib/cli/templates/deploy/Screenshot 2025-03-19 at 10.36.57/342/200/257AM.png +0 -0
  70. agentex/lib/cli/templates/deploy/example.yaml.j2 +55 -0
  71. agentex/lib/cli/templates/sync/.dockerignore.j2 +43 -0
  72. agentex/lib/cli/templates/sync/Dockerfile-uv.j2 +42 -0
  73. agentex/lib/cli/templates/sync/Dockerfile.j2 +42 -0
  74. agentex/lib/cli/templates/sync/README.md.j2 +293 -0
  75. agentex/lib/cli/templates/sync/deploy/example.yaml.j2 +55 -0
  76. agentex/lib/cli/templates/sync/manifest.yaml.j2 +116 -0
  77. agentex/lib/cli/templates/sync/project/acp.py.j2 +26 -0
  78. agentex/lib/cli/templates/sync/pyproject.toml.j2 +33 -0
  79. agentex/lib/cli/templates/sync/requirements.txt.j2 +5 -0
  80. agentex/lib/cli/templates/temporal/.dockerignore.j2 +43 -0
  81. agentex/lib/cli/templates/temporal/Dockerfile-uv.j2 +48 -0
  82. agentex/lib/cli/templates/temporal/Dockerfile.j2 +48 -0
  83. agentex/lib/cli/templates/temporal/README.md.j2 +316 -0
  84. agentex/lib/cli/templates/temporal/deploy/example.yaml.j2 +55 -0
  85. agentex/lib/cli/templates/temporal/manifest.yaml.j2 +137 -0
  86. agentex/lib/cli/templates/temporal/project/acp.py.j2 +30 -0
  87. agentex/lib/cli/templates/temporal/project/run_worker.py.j2 +33 -0
  88. agentex/lib/cli/templates/temporal/project/workflow.py.j2 +66 -0
  89. agentex/lib/cli/templates/temporal/pyproject.toml.j2 +34 -0
  90. agentex/lib/cli/templates/temporal/requirements.txt.j2 +5 -0
  91. agentex/lib/cli/utils/cli_utils.py +14 -0
  92. agentex/lib/cli/utils/credential_utils.py +103 -0
  93. agentex/lib/cli/utils/exceptions.py +6 -0
  94. agentex/lib/cli/utils/kubectl_utils.py +135 -0
  95. agentex/lib/cli/utils/kubernetes_secrets_utils.py +185 -0
  96. agentex/lib/core/__init__.py +0 -0
  97. agentex/lib/core/adapters/__init__.py +0 -0
  98. agentex/lib/core/adapters/llm/__init__.py +1 -0
  99. agentex/lib/core/adapters/llm/adapter_litellm.py +46 -0
  100. agentex/lib/core/adapters/llm/adapter_sgp.py +55 -0
  101. agentex/lib/core/adapters/llm/port.py +24 -0
  102. agentex/lib/core/adapters/streams/adapter_redis.py +128 -0
  103. agentex/lib/core/adapters/streams/port.py +50 -0
  104. agentex/lib/core/clients/__init__.py +1 -0
  105. agentex/lib/core/clients/temporal/__init__.py +0 -0
  106. agentex/lib/core/clients/temporal/temporal_client.py +181 -0
  107. agentex/lib/core/clients/temporal/types.py +47 -0
  108. agentex/lib/core/clients/temporal/utils.py +56 -0
  109. agentex/lib/core/services/__init__.py +0 -0
  110. agentex/lib/core/services/adk/__init__.py +0 -0
  111. agentex/lib/core/services/adk/acp/__init__.py +0 -0
  112. agentex/lib/core/services/adk/acp/acp.py +210 -0
  113. agentex/lib/core/services/adk/agent_task_tracker.py +85 -0
  114. agentex/lib/core/services/adk/agents.py +43 -0
  115. agentex/lib/core/services/adk/events.py +61 -0
  116. agentex/lib/core/services/adk/messages.py +164 -0
  117. agentex/lib/core/services/adk/providers/__init__.py +0 -0
  118. agentex/lib/core/services/adk/providers/litellm.py +256 -0
  119. agentex/lib/core/services/adk/providers/openai.py +723 -0
  120. agentex/lib/core/services/adk/providers/sgp.py +99 -0
  121. agentex/lib/core/services/adk/state.py +120 -0
  122. agentex/lib/core/services/adk/streaming.py +262 -0
  123. agentex/lib/core/services/adk/tasks.py +69 -0
  124. agentex/lib/core/services/adk/tracing.py +36 -0
  125. agentex/lib/core/services/adk/utils/__init__.py +0 -0
  126. agentex/lib/core/services/adk/utils/templating.py +58 -0
  127. agentex/lib/core/temporal/__init__.py +0 -0
  128. agentex/lib/core/temporal/activities/__init__.py +207 -0
  129. agentex/lib/core/temporal/activities/activity_helpers.py +37 -0
  130. agentex/lib/core/temporal/activities/adk/__init__.py +0 -0
  131. agentex/lib/core/temporal/activities/adk/acp/__init__.py +0 -0
  132. agentex/lib/core/temporal/activities/adk/acp/acp_activities.py +86 -0
  133. agentex/lib/core/temporal/activities/adk/agent_task_tracker_activities.py +76 -0
  134. agentex/lib/core/temporal/activities/adk/agents_activities.py +35 -0
  135. agentex/lib/core/temporal/activities/adk/events_activities.py +50 -0
  136. agentex/lib/core/temporal/activities/adk/messages_activities.py +94 -0
  137. agentex/lib/core/temporal/activities/adk/providers/__init__.py +0 -0
  138. agentex/lib/core/temporal/activities/adk/providers/litellm_activities.py +71 -0
  139. agentex/lib/core/temporal/activities/adk/providers/openai_activities.py +210 -0
  140. agentex/lib/core/temporal/activities/adk/providers/sgp_activities.py +42 -0
  141. agentex/lib/core/temporal/activities/adk/state_activities.py +85 -0
  142. agentex/lib/core/temporal/activities/adk/streaming_activities.py +33 -0
  143. agentex/lib/core/temporal/activities/adk/tasks_activities.py +48 -0
  144. agentex/lib/core/temporal/activities/adk/tracing_activities.py +55 -0
  145. agentex/lib/core/temporal/activities/adk/utils/__init__.py +0 -0
  146. agentex/lib/core/temporal/activities/adk/utils/templating_activities.py +41 -0
  147. agentex/lib/core/temporal/services/__init__.py +0 -0
  148. agentex/lib/core/temporal/services/temporal_task_service.py +69 -0
  149. agentex/lib/core/temporal/types/__init__.py +0 -0
  150. agentex/lib/core/temporal/types/workflow.py +5 -0
  151. agentex/lib/core/temporal/workers/__init__.py +0 -0
  152. agentex/lib/core/temporal/workers/worker.py +162 -0
  153. agentex/lib/core/temporal/workflows/workflow.py +26 -0
  154. agentex/lib/core/tracing/__init__.py +5 -0
  155. agentex/lib/core/tracing/processors/agentex_tracing_processor.py +117 -0
  156. agentex/lib/core/tracing/processors/sgp_tracing_processor.py +119 -0
  157. agentex/lib/core/tracing/processors/tracing_processor_interface.py +40 -0
  158. agentex/lib/core/tracing/trace.py +311 -0
  159. agentex/lib/core/tracing/tracer.py +70 -0
  160. agentex/lib/core/tracing/tracing_processor_manager.py +62 -0
  161. agentex/lib/environment_variables.py +87 -0
  162. agentex/lib/py.typed +0 -0
  163. agentex/lib/sdk/__init__.py +0 -0
  164. agentex/lib/sdk/config/__init__.py +0 -0
  165. agentex/lib/sdk/config/agent_config.py +61 -0
  166. agentex/lib/sdk/config/agent_manifest.py +219 -0
  167. agentex/lib/sdk/config/build_config.py +35 -0
  168. agentex/lib/sdk/config/deployment_config.py +117 -0
  169. agentex/lib/sdk/config/local_development_config.py +56 -0
  170. agentex/lib/sdk/config/project_config.py +103 -0
  171. agentex/lib/sdk/fastacp/__init__.py +3 -0
  172. agentex/lib/sdk/fastacp/base/base_acp_server.py +406 -0
  173. agentex/lib/sdk/fastacp/fastacp.py +74 -0
  174. agentex/lib/sdk/fastacp/impl/agentic_base_acp.py +72 -0
  175. agentex/lib/sdk/fastacp/impl/sync_acp.py +109 -0
  176. agentex/lib/sdk/fastacp/impl/temporal_acp.py +97 -0
  177. agentex/lib/sdk/fastacp/tests/README.md +297 -0
  178. agentex/lib/sdk/fastacp/tests/conftest.py +307 -0
  179. agentex/lib/sdk/fastacp/tests/pytest.ini +10 -0
  180. agentex/lib/sdk/fastacp/tests/run_tests.py +227 -0
  181. agentex/lib/sdk/fastacp/tests/test_base_acp_server.py +450 -0
  182. agentex/lib/sdk/fastacp/tests/test_fastacp_factory.py +344 -0
  183. agentex/lib/sdk/fastacp/tests/test_integration.py +477 -0
  184. agentex/lib/sdk/state_machine/__init__.py +6 -0
  185. agentex/lib/sdk/state_machine/noop_workflow.py +21 -0
  186. agentex/lib/sdk/state_machine/state.py +10 -0
  187. agentex/lib/sdk/state_machine/state_machine.py +189 -0
  188. agentex/lib/sdk/state_machine/state_workflow.py +16 -0
  189. agentex/lib/sdk/utils/__init__.py +0 -0
  190. agentex/lib/sdk/utils/messages.py +223 -0
  191. agentex/lib/types/__init__.py +0 -0
  192. agentex/lib/types/acp.py +94 -0
  193. agentex/lib/types/agent_configs.py +79 -0
  194. agentex/lib/types/agent_results.py +29 -0
  195. agentex/lib/types/credentials.py +34 -0
  196. agentex/lib/types/fastacp.py +61 -0
  197. agentex/lib/types/files.py +13 -0
  198. agentex/lib/types/json_rpc.py +49 -0
  199. agentex/lib/types/llm_messages.py +354 -0
  200. agentex/lib/types/task_message_updates.py +171 -0
  201. agentex/lib/types/tracing.py +34 -0
  202. agentex/lib/utils/__init__.py +0 -0
  203. agentex/lib/utils/completions.py +131 -0
  204. agentex/lib/utils/console.py +14 -0
  205. agentex/lib/utils/io.py +29 -0
  206. agentex/lib/utils/iterables.py +14 -0
  207. agentex/lib/utils/json_schema.py +23 -0
  208. agentex/lib/utils/logging.py +31 -0
  209. agentex/lib/utils/mcp.py +17 -0
  210. agentex/lib/utils/model_utils.py +46 -0
  211. agentex/lib/utils/parsing.py +15 -0
  212. agentex/lib/utils/regex.py +6 -0
  213. agentex/lib/utils/temporal.py +13 -0
  214. agentex/py.typed +0 -0
  215. agentex/resources/__init__.py +103 -0
  216. agentex/resources/agents.py +707 -0
  217. agentex/resources/events.py +294 -0
  218. agentex/resources/messages/__init__.py +33 -0
  219. agentex/resources/messages/batch.py +271 -0
  220. agentex/resources/messages/messages.py +492 -0
  221. agentex/resources/spans.py +557 -0
  222. agentex/resources/states.py +544 -0
  223. agentex/resources/tasks.py +615 -0
  224. agentex/resources/tracker.py +384 -0
  225. agentex/types/__init__.py +56 -0
  226. agentex/types/acp_type.py +7 -0
  227. agentex/types/agent.py +29 -0
  228. agentex/types/agent_list_params.py +13 -0
  229. agentex/types/agent_list_response.py +10 -0
  230. agentex/types/agent_rpc_by_name_params.py +21 -0
  231. agentex/types/agent_rpc_params.py +51 -0
  232. agentex/types/agent_rpc_params1.py +21 -0
  233. agentex/types/agent_rpc_response.py +20 -0
  234. agentex/types/agent_rpc_result.py +90 -0
  235. agentex/types/agent_task_tracker.py +34 -0
  236. agentex/types/data_content.py +30 -0
  237. agentex/types/data_content_param.py +31 -0
  238. agentex/types/data_delta.py +14 -0
  239. agentex/types/event.py +29 -0
  240. agentex/types/event_list_params.py +22 -0
  241. agentex/types/event_list_response.py +10 -0
  242. agentex/types/message_author.py +7 -0
  243. agentex/types/message_create_params.py +18 -0
  244. agentex/types/message_list_params.py +14 -0
  245. agentex/types/message_list_response.py +10 -0
  246. agentex/types/message_style.py +7 -0
  247. agentex/types/message_update_params.py +18 -0
  248. agentex/types/messages/__init__.py +8 -0
  249. agentex/types/messages/batch_create_params.py +16 -0
  250. agentex/types/messages/batch_create_response.py +10 -0
  251. agentex/types/messages/batch_update_params.py +16 -0
  252. agentex/types/messages/batch_update_response.py +10 -0
  253. agentex/types/shared/__init__.py +3 -0
  254. agentex/types/shared/task_message_update.py +83 -0
  255. agentex/types/span.py +36 -0
  256. agentex/types/span_create_params.py +40 -0
  257. agentex/types/span_list_params.py +12 -0
  258. agentex/types/span_list_response.py +10 -0
  259. agentex/types/span_update_params.py +37 -0
  260. agentex/types/state.py +25 -0
  261. agentex/types/state_create_params.py +16 -0
  262. agentex/types/state_list_params.py +16 -0
  263. agentex/types/state_list_response.py +10 -0
  264. agentex/types/state_update_params.py +16 -0
  265. agentex/types/task.py +23 -0
  266. agentex/types/task_delete_by_name_response.py +8 -0
  267. agentex/types/task_delete_response.py +8 -0
  268. agentex/types/task_list_response.py +10 -0
  269. agentex/types/task_message.py +33 -0
  270. agentex/types/task_message_content.py +16 -0
  271. agentex/types/task_message_content_param.py +17 -0
  272. agentex/types/task_message_delta.py +16 -0
  273. agentex/types/text_content.py +53 -0
  274. agentex/types/text_content_param.py +54 -0
  275. agentex/types/text_delta.py +14 -0
  276. agentex/types/tool_request_content.py +36 -0
  277. agentex/types/tool_request_content_param.py +37 -0
  278. agentex/types/tool_request_delta.py +18 -0
  279. agentex/types/tool_response_content.py +36 -0
  280. agentex/types/tool_response_content_param.py +36 -0
  281. agentex/types/tool_response_delta.py +18 -0
  282. agentex/types/tracker_list_params.py +16 -0
  283. agentex/types/tracker_list_response.py +10 -0
  284. agentex/types/tracker_update_params.py +19 -0
  285. agentex_sdk-0.1.0a6.dist-info/METADATA +426 -0
  286. agentex_sdk-0.1.0a6.dist-info/RECORD +289 -0
  287. agentex_sdk-0.1.0a6.dist-info/WHEEL +4 -0
  288. agentex_sdk-0.1.0a6.dist-info/entry_points.txt +2 -0
  289. agentex_sdk-0.1.0a6.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,189 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any, Generic, TypeVar
3
+
4
+ from agentex.lib import adk
5
+ from agentex.lib.sdk.state_machine.state import State
6
+ from agentex.lib.sdk.state_machine.state_workflow import StateWorkflow
7
+ from agentex.lib.utils.model_utils import BaseModel
8
+
9
+ T = TypeVar("T", bound=BaseModel)
10
+
11
+
12
+ class StateMachine(ABC, Generic[T]):
13
+ def __init__(
14
+ self,
15
+ initial_state: str,
16
+ states: list[State],
17
+ task_id: str | None = None,
18
+ state_machine_data: T | None = None,
19
+ trace_transitions: bool = False,
20
+ ):
21
+ self._task_id = task_id
22
+ self._state_map: dict[str, State] = {state.name: state for state in states}
23
+ self.state_machine_data = state_machine_data
24
+ self._initial_state = initial_state
25
+ self._trace_transitions = trace_transitions
26
+
27
+ # Validate that initial state exists
28
+ if initial_state not in self._state_map:
29
+ raise ValueError(f"Initial state '{initial_state}' not found in states")
30
+ self._current_state = self._state_map[initial_state]
31
+
32
+ def set_task_id(self, task_id: str):
33
+ self._task_id = task_id
34
+
35
+ def get_current_state(self) -> str:
36
+ return self._current_state.name
37
+
38
+ def get_current_workflow(self) -> StateWorkflow:
39
+ """
40
+ Get the workflow of the current state.
41
+
42
+ Returns:
43
+ The workflow of the current state
44
+
45
+ Raises:
46
+ ValueError: If the current state is not found in the state map
47
+ """
48
+ current_state = self._state_map.get(self.get_current_state())
49
+ if not current_state:
50
+ raise ValueError(f"State {self.get_current_state()} not found")
51
+ return current_state.workflow
52
+
53
+ async def transition(self, target_state_name: str):
54
+ if not self._state_map.get(target_state_name):
55
+ raise ValueError(f"State {target_state_name} not found")
56
+ self._current_state = self._state_map[target_state_name]
57
+
58
+ def get_state_machine_data(self) -> T:
59
+ return self.state_machine_data
60
+
61
+ @abstractmethod
62
+ async def terminal_condition(self) -> bool:
63
+ pass
64
+
65
+ # Overwrite this if you want to add more logic to the state machine
66
+ async def run(self):
67
+ while not await self.terminal_condition():
68
+ await self.step()
69
+
70
+ async def step(self) -> str:
71
+ current_state_name = self.get_current_state()
72
+ current_state = self._state_map.get(current_state_name)
73
+
74
+ if self._trace_transitions:
75
+ if self._task_id is None:
76
+ raise ValueError(
77
+ "Task ID is must be set before tracing can be enabled"
78
+ )
79
+ span = await adk.tracing.start_span(
80
+ trace_id=self._task_id,
81
+ name="state_transition",
82
+ input=self.state_machine_data.model_dump(),
83
+ data={"input_state": current_state_name},
84
+ )
85
+
86
+ next_state_name = await current_state.workflow.execute(
87
+ state_machine=self, state_machine_data=self.state_machine_data
88
+ )
89
+
90
+ if self._trace_transitions:
91
+ if self._task_id is None:
92
+ raise ValueError(
93
+ "Task ID is must be set before tracing can be enabled"
94
+ )
95
+ span.output = self.state_machine_data.model_dump()
96
+ span.data["output_state"] = next_state_name
97
+ await adk.tracing.end_span(trace_id=self._task_id, span=span)
98
+
99
+ await self.transition(next_state_name)
100
+
101
+ return next_state_name
102
+
103
+ async def reset_to_initial_state(self):
104
+ """
105
+ Reset the state machine to its initial state.
106
+ """
107
+ if self._trace_transitions:
108
+ if self._task_id is None:
109
+ raise ValueError(
110
+ "Task ID is must be set before tracing can be enabled"
111
+ )
112
+ span = await adk.tracing.start_span(
113
+ trace_id=self._task_id,
114
+ name="state_transition_reset",
115
+ input={"input_state": self.get_current_state()},
116
+ )
117
+
118
+ await self.transition(self._initial_state)
119
+
120
+ if self._trace_transitions:
121
+ span.output = {"output_state": self._initial_state}
122
+ await adk.tracing.end_span(trace_id=self._task_id, span=span)
123
+
124
+ def dump(self) -> dict[str, Any]:
125
+ """
126
+ Save the current state of the state machine to a serializable dictionary.
127
+ This includes the current state, task_id, state machine data, and initial state.
128
+
129
+ Returns:
130
+ Dict[str, Any]: A dictionary containing the serialized state machine state
131
+ """
132
+ return {
133
+ "task_id": self._task_id,
134
+ "current_state": self.get_current_state(),
135
+ "initial_state": self._initial_state,
136
+ "state_machine_data": self.state_machine_data.model_dump(mode="json")
137
+ if self.state_machine_data
138
+ else None,
139
+ "trace_transitions": self._trace_transitions,
140
+ }
141
+
142
+ @classmethod
143
+ async def load(cls, data: dict[str, Any], states: list[State]) -> "StateMachine[T]":
144
+ """
145
+ Load a state machine from a previously saved dictionary.
146
+
147
+ Args:
148
+ data: The dictionary containing the saved state machine state
149
+ states: List of all possible states
150
+
151
+ Returns:
152
+ StateMachine: A new state machine instance restored to the saved state
153
+
154
+ Raises:
155
+ ValueError: If the data is invalid or missing required fields
156
+ """
157
+ try:
158
+ task_id = data.get("task_id")
159
+ current_state_name = data.get("current_state")
160
+ initial_state = data.get("initial_state")
161
+ state_machine_data_dict = data.get("state_machine_data")
162
+ trace_transitions = data.get("trace_transitions")
163
+
164
+ if initial_state is None:
165
+ raise ValueError("Initial state not found in saved data")
166
+
167
+ # Reconstruct the state machine data into its Pydantic model
168
+ state_machine_data = None
169
+ if state_machine_data_dict is not None:
170
+ # Get the actual model type from the class's type parameters
171
+ model_type = cls.__orig_bases__[0].__args__[0]
172
+ state_machine_data = model_type.model_validate(state_machine_data_dict)
173
+
174
+ # Create a new instance
175
+ instance = cls(
176
+ initial_state=initial_state,
177
+ states=states,
178
+ task_id=task_id,
179
+ state_machine_data=state_machine_data,
180
+ trace_transitions=trace_transitions,
181
+ )
182
+
183
+ # If there's a saved state, transition to it
184
+ if current_state_name:
185
+ await instance.transition(target_state_name=current_state_name)
186
+
187
+ return instance
188
+ except Exception as e:
189
+ raise ValueError(f"Failed to restore state machine: {str(e)}") from e
@@ -0,0 +1,16 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import TYPE_CHECKING
3
+
4
+ from pydantic import BaseModel
5
+
6
+ # Import StateMachine only for type checking to avoid circular imports
7
+ if TYPE_CHECKING:
8
+ from agentex.lib.sdk.state_machine import StateMachine
9
+
10
+
11
+ class StateWorkflow(ABC):
12
+ @abstractmethod
13
+ async def execute(
14
+ self, state_machine: "StateMachine", state_machine_data: BaseModel | None = None
15
+ ) -> str:
16
+ pass
File without changes
@@ -0,0 +1,223 @@
1
+ import json
2
+ from abc import ABC, abstractmethod
3
+ from typing import Any, Literal, override
4
+
5
+ from agentex.lib.types.llm_messages import (
6
+ AssistantMessage,
7
+ Message,
8
+ ToolCall,
9
+ ToolCallRequest,
10
+ ToolMessage,
11
+ UserMessage,
12
+ )
13
+ from agentex.types.data_content import DataContent
14
+ from agentex.types.task_message import TaskMessage
15
+ from agentex.types.text_content import TextContent
16
+ from agentex.types.tool_request_content import ToolRequestContent
17
+ from agentex.types.tool_response_content import ToolResponseContent
18
+
19
+
20
+ class TaskMessageConverter(ABC):
21
+ """
22
+ Abstract base class for converting a specific type of TaskMessage to an LLM Message.
23
+
24
+ Each converter should be responsible for one content type.
25
+ """
26
+
27
+ @abstractmethod
28
+ def convert(self, task_message: TaskMessage) -> Message:
29
+ """
30
+ Convert a TaskMessage to an LLM Message.
31
+
32
+ Args:
33
+ task_message: The TaskMessage to convert
34
+
35
+ Returns:
36
+ A Message (Pydantic model)
37
+ """
38
+ pass
39
+
40
+
41
+ class DefaultTextContentConverter(TaskMessageConverter):
42
+ """Converter for TEXT content type."""
43
+
44
+ @override
45
+ def convert(self, task_message: TaskMessage) -> Message:
46
+ """Convert TEXT content to UserMessage or AssistantMessage based on author."""
47
+ if not isinstance(task_message.content, TextContent):
48
+ raise ValueError(f"Expected TextContent, got {type(task_message.content)}")
49
+ content = task_message.content
50
+ if content.author == "user":
51
+ return UserMessage(content=content.content)
52
+ else: # AGENT or custom author
53
+ return AssistantMessage(content=content.content)
54
+
55
+
56
+ class DefaultToolRequestConverter(TaskMessageConverter):
57
+ """Converter for TOOL_REQUEST content type."""
58
+
59
+ @override
60
+ def convert(self, task_message: TaskMessage) -> Message:
61
+ """Convert TOOL_REQUEST content to AssistantMessage with tool_calls."""
62
+ if not isinstance(task_message.content, ToolRequestContent):
63
+ raise ValueError(f"Expected ToolRequestContent, got {type(task_message.content)}")
64
+
65
+ content = task_message.content
66
+
67
+ # Ensure arguments are properly JSON serialized
68
+ arguments_str = json.dumps(content.arguments)
69
+
70
+ tool_call = ToolCallRequest(
71
+ id=content.tool_call_id,
72
+ function=ToolCall(name=content.name, arguments=arguments_str),
73
+ )
74
+ return AssistantMessage(content=None, tool_calls=[tool_call])
75
+
76
+
77
+ class DefaultToolResponseConverter(TaskMessageConverter):
78
+ """Converter for TOOL_RESPONSE content type."""
79
+
80
+ @override
81
+ def convert(self, task_message: TaskMessage) -> Message:
82
+ """Convert TOOL_RESPONSE content to ToolMessage."""
83
+ if not isinstance(task_message.content, ToolResponseContent):
84
+ raise ValueError(f"Expected ToolResponseContent, got {type(task_message.content)}")
85
+
86
+ content = task_message.content
87
+ return ToolMessage(
88
+ content=str(content.content),
89
+ tool_call_id=content.tool_call_id,
90
+ name=content.name,
91
+ )
92
+
93
+
94
+ class DefaultDataContentConverter(TaskMessageConverter):
95
+ """Converter for DATA content type."""
96
+
97
+ @override
98
+ def convert(self, task_message: TaskMessage) -> Message:
99
+ """Convert DATA content to UserMessage or AssistantMessage based on author."""
100
+ if not isinstance(task_message.content, DataContent):
101
+ raise ValueError(f"Expected DataContent, got {type(task_message.content)}")
102
+
103
+ content = task_message.content
104
+ content_str = str(content.data)
105
+ if content.author == "user":
106
+ return UserMessage(content=content_str)
107
+ else: # AGENT or custom author
108
+ return AssistantMessage(content=content_str)
109
+
110
+
111
+ class DefaultUnknownContentConverter(TaskMessageConverter):
112
+ """Converter for unknown content types."""
113
+
114
+ @override
115
+ def convert(self, task_message: TaskMessage) -> Message:
116
+ """Convert unknown content types to AssistantMessage with fallback text."""
117
+
118
+ content = task_message.content
119
+ fallback_content = f"Unknown message type: {content.type}"
120
+ return AssistantMessage(content=fallback_content)
121
+
122
+
123
+ def convert_task_message_to_llm_messages(
124
+ task_message: TaskMessage,
125
+ output_mode: Literal["pydantic", "dict"] = "pydantic",
126
+ text_converter: TaskMessageConverter | None = None,
127
+ tool_request_converter: TaskMessageConverter | None = None,
128
+ tool_response_converter: TaskMessageConverter | None = None,
129
+ data_converter: TaskMessageConverter | None = None,
130
+ unknown_converter: TaskMessageConverter | None = None,
131
+ ) -> Message | dict[str, Any]:
132
+ """
133
+ Convert a TaskMessage to an LLM Message format.
134
+
135
+ Args:
136
+ task_message: The TaskMessage to convert
137
+ output_mode: Whether to return a Pydantic model or dict
138
+ text_converter: Optional converter for TEXT content. Uses DefaultTextContentConverter if None.
139
+ tool_request_converter: Optional converter for TOOL_REQUEST content. Uses DefaultToolRequestConverter if None.
140
+ tool_response_converter: Optional converter for TOOL_RESPONSE content. Uses DefaultToolResponseConverter if None.
141
+ data_converter: Optional converter for DATA content. Uses DefaultDataContentConverter if None.
142
+ unknown_converter: Optional converter for unknown content. Uses DefaultUnknownContentConverter if None.
143
+
144
+ Returns:
145
+ Either a Message (Pydantic model) or dict representation
146
+ """
147
+ content = task_message.content
148
+
149
+ # Get the appropriate converter for this content type
150
+ if content.type == "text":
151
+ converter = (
152
+ text_converter
153
+ if text_converter is not None
154
+ else DefaultTextContentConverter()
155
+ )
156
+ elif content.type == "tool_request":
157
+ converter = (
158
+ tool_request_converter
159
+ if tool_request_converter is not None
160
+ else DefaultToolRequestConverter()
161
+ )
162
+ elif content.type == "tool_response":
163
+ converter = (
164
+ tool_response_converter
165
+ if tool_response_converter is not None
166
+ else DefaultToolResponseConverter()
167
+ )
168
+ elif content.type == "data":
169
+ converter = (
170
+ data_converter
171
+ if data_converter is not None
172
+ else DefaultDataContentConverter()
173
+ )
174
+ else:
175
+ converter = (
176
+ unknown_converter
177
+ if unknown_converter is not None
178
+ else DefaultUnknownContentConverter()
179
+ )
180
+
181
+ message = converter.convert(task_message)
182
+
183
+ if output_mode == "dict":
184
+ return message.model_dump()
185
+ return message
186
+
187
+
188
+ def convert_task_messages_to_llm_messages(
189
+ task_messages: list[TaskMessage],
190
+ output_mode: Literal["pydantic", "dict"] = "pydantic",
191
+ text_converter: TaskMessageConverter | None = None,
192
+ tool_request_converter: TaskMessageConverter | None = None,
193
+ tool_response_converter: TaskMessageConverter | None = None,
194
+ data_converter: TaskMessageConverter | None = None,
195
+ unknown_converter: TaskMessageConverter | None = None,
196
+ ) -> list[Message | dict[str, Any]]:
197
+ """
198
+ Convert a list of TaskMessages to LLM Message format.
199
+
200
+ Args:
201
+ task_messages: List of TaskMessages to convert
202
+ output_mode: Whether to return Pydantic models or dicts
203
+ text_converter: Optional converter for TEXT content. Uses DefaultTextContentConverter if None.
204
+ tool_request_converter: Optional converter for TOOL_REQUEST content. Uses DefaultToolRequestConverter if None.
205
+ tool_response_converter: Optional converter for TOOL_RESPONSE content. Uses DefaultToolResponseConverter if None.
206
+ data_converter: Optional converter for DATA content. Uses DefaultDataContentConverter if None.
207
+ unknown_converter: Optional converter for unknown content. Uses DefaultUnknownContentConverter if None.
208
+
209
+ Returns:
210
+ List of either Messages (Pydantic models) or dicts
211
+ """
212
+ return [
213
+ convert_task_message_to_llm_messages(
214
+ task_message,
215
+ output_mode,
216
+ text_converter,
217
+ tool_request_converter,
218
+ tool_response_converter,
219
+ data_converter,
220
+ unknown_converter,
221
+ )
222
+ for task_message in task_messages
223
+ ]
File without changes
@@ -0,0 +1,94 @@
1
+ from enum import Enum
2
+ from typing import Any
3
+
4
+ from pydantic import BaseModel, Field
5
+
6
+ from agentex.types.agent import Agent
7
+ from agentex.types.event import Event
8
+ from agentex.types.task_message_content import TaskMessageContent
9
+ from agentex.types.task import Task
10
+
11
+
12
+ class RPCMethod(str, Enum):
13
+ """Available JSON-RPC methods for agent communication."""
14
+
15
+ EVENT_SEND = "event/send"
16
+ MESSAGE_SEND = "message/send"
17
+ TASK_CANCEL = "task/cancel"
18
+ TASK_CREATE = "task/create"
19
+
20
+
21
+ class CreateTaskParams(BaseModel):
22
+ """Parameters for task/create method.
23
+
24
+ Attributes:
25
+ agent: The agent that the task was sent to.
26
+ task: The task to be created.
27
+ params: The parameters for the task as inputted by the user.
28
+ """
29
+
30
+ agent: Agent = Field(..., description="The agent that the task was sent to")
31
+ task: Task = Field(..., description="The task to be created")
32
+ params: dict[str, Any] | None = Field(
33
+ None,
34
+ description="The parameters for the task as inputted by the user",
35
+ )
36
+
37
+
38
+ class SendMessageParams(BaseModel):
39
+ """Parameters for message/send method.
40
+
41
+ Attributes:
42
+ agent: The agent that the message was sent to.
43
+ task: The task that the message was sent to.
44
+ content: The message that was sent to the agent.
45
+ stream: Whether to stream the message back to the agentex server from the agent.
46
+ """
47
+
48
+ agent: Agent = Field(..., description="The agent that the message was sent to")
49
+ task: Task = Field(..., description="The task that the message was sent to")
50
+ content: TaskMessageContent = Field(
51
+ ..., description="The message that was sent to the agent"
52
+ )
53
+ stream: bool = Field(
54
+ False,
55
+ description="Whether to stream the message back to the agentex server from the agent",
56
+ )
57
+
58
+
59
+ class SendEventParams(BaseModel):
60
+ """Parameters for event/send method.
61
+
62
+ Attributes:
63
+ agent: The agent that the event was sent to.
64
+ task: The task that the message was sent to.
65
+ event: The event that was sent to the agent.
66
+ """
67
+
68
+ agent: Agent = Field(..., description="The agent that the event was sent to")
69
+ task: Task = Field(..., description="The task that the message was sent to")
70
+ event: Event = Field(..., description="The event that was sent to the agent")
71
+
72
+
73
+ class CancelTaskParams(BaseModel):
74
+ """Parameters for task/cancel method.
75
+
76
+ Attributes:
77
+ agent: The agent that the task was sent to.
78
+ task: The task that was cancelled.
79
+ """
80
+
81
+ agent: Agent = Field(..., description="The agent that the task was sent to")
82
+ task: Task = Field(..., description="The task that was cancelled")
83
+
84
+
85
+ RPC_SYNC_METHODS = [
86
+ RPCMethod.MESSAGE_SEND,
87
+ ]
88
+
89
+ PARAMS_MODEL_BY_METHOD: dict[RPCMethod, type[BaseModel]] = {
90
+ RPCMethod.EVENT_SEND: SendEventParams,
91
+ RPCMethod.TASK_CANCEL: CancelTaskParams,
92
+ RPCMethod.MESSAGE_SEND: SendMessageParams,
93
+ RPCMethod.TASK_CREATE: CreateTaskParams,
94
+ }
@@ -0,0 +1,79 @@
1
+ from pydantic import BaseModel, Field, model_validator, validator
2
+
3
+
4
+ class TemporalWorkflowConfig(BaseModel):
5
+ """
6
+ Configuration for the temporal workflow that defines the agent.
7
+
8
+ Attributes:
9
+ name: The name of the temporal workflow that defines the agent.
10
+ queue_name: The name of the temporal queue to send tasks to.
11
+ """
12
+
13
+ name: str = Field(
14
+ ..., description="The name of the temporal workflow that defines the agent."
15
+ )
16
+ queue_name: str = Field(
17
+ ..., description="The name of the temporal queue to send tasks to."
18
+ )
19
+
20
+
21
+ # TODO: Remove this class when we remove the agentex agents create
22
+ class TemporalWorkerConfig(BaseModel):
23
+ """
24
+ Configuration for temporal worker deployment
25
+
26
+ Attributes:
27
+ image: The image to use for the temporal worker
28
+ workflow: The temporal workflow configuration
29
+ """
30
+
31
+ image: str | None = Field(
32
+ default=None, description="Image to use for the temporal worker"
33
+ )
34
+ workflow: TemporalWorkflowConfig | None = Field(
35
+ default=None,
36
+ description="Configuration for the temporal workflow that defines the agent. Only required for agents that leverage Temporal.",
37
+ )
38
+
39
+
40
+ class TemporalConfig(BaseModel):
41
+ """
42
+ Simplified temporal configuration for agents
43
+
44
+ Attributes:
45
+ enabled: Whether this agent uses Temporal workflows
46
+ workflow: The temporal workflow configuration
47
+ workflows: The list of temporal workflow configurations
48
+ """
49
+
50
+ enabled: bool = Field(
51
+ default=False, description="Whether this agent uses Temporal workflows"
52
+ )
53
+ workflow: TemporalWorkflowConfig | None = Field(
54
+ default=None,
55
+ description="Temporal workflow configuration. Required when enabled=True. (deprecated: use workflows instead)",
56
+ )
57
+ workflows: list[TemporalWorkflowConfig] | None = Field(
58
+ default=None,
59
+ description="List of temporal workflow configurations. Used when enabled=true.",
60
+ )
61
+
62
+ @validator("workflows")
63
+ def validate_workflows_not_empty(cls, v):
64
+ """Ensure workflows list is not empty when provided"""
65
+ if v is not None and len(v) == 0:
66
+ raise ValueError("workflows list cannot be empty when provided")
67
+ return v
68
+
69
+ @model_validator(mode="after")
70
+ def validate_temporal_config_when_enabled(self):
71
+ """Validate that workflow configuration exists when enabled=true"""
72
+ if self.enabled:
73
+ # Must have either workflow (legacy) or workflows (new)
74
+ if not self.workflow and (not self.workflows or len(self.workflows) == 0):
75
+ raise ValueError(
76
+ "When temporal.enabled=true, either 'workflow' or 'workflows' must be provided and non-empty"
77
+ )
78
+
79
+ return self
@@ -0,0 +1,29 @@
1
+ from typing import Any
2
+
3
+ from pydantic import BaseModel
4
+
5
+
6
+ class SerializableRunResult(BaseModel):
7
+ """
8
+ Serializable version of RunResult.
9
+
10
+ Attributes:
11
+ final_output: The final output of the run.
12
+ final_input_list: The final input list of the run.
13
+ """
14
+
15
+ final_output: Any
16
+ final_input_list: list[dict[str, Any]]
17
+
18
+
19
+ class SerializableRunResultStreaming(BaseModel):
20
+ """
21
+ Serializable version of RunResultStreaming.
22
+
23
+ Attributes:
24
+ final_output: The final output of the run.
25
+ final_input_list: The final input list of the run.
26
+ """
27
+
28
+ final_output: Any
29
+ final_input_list: list[dict[str, Any]]
@@ -0,0 +1,34 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+
4
+ class CredentialMapping(BaseModel):
5
+ """Maps a Kubernetes secret to an environment variable in the agent container.
6
+
7
+ This allows agents to securely access credentials stored in Kubernetes secrets
8
+ by mapping them to environment variables. For example, you can map a secret
9
+ containing an API key to an environment variable that your agent code expects.
10
+
11
+ Example:
12
+ A mapping of {"env_var_name": "OPENAI_API_KEY",
13
+ "secret_name": "ai-credentials",
14
+ "secret_key": "openai-key"}
15
+ will make the value from the "openai-key" field in the "ai-credentials"
16
+ Kubernetes secret available to the agent as OPENAI_API_KEY environment variable.
17
+
18
+ Attributes:
19
+ env_var_name: The name of the environment variable that will be available to the agent
20
+ secret_name: The name of the Kubernetes secret containing the credential
21
+ secret_key: The key within the Kubernetes secret that contains the credential value
22
+ """
23
+
24
+ env_var_name: str = Field(
25
+ ...,
26
+ description="Name of the environment variable that will be available to the agent",
27
+ )
28
+ secret_name: str = Field(
29
+ ..., description="Name of the Kubernetes secret containing the credential"
30
+ )
31
+ secret_key: str = Field(
32
+ ...,
33
+ description="Key within the Kubernetes secret that contains the credential value",
34
+ )