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,169 @@
1
+ from pathlib import Path
2
+
3
+ import questionary
4
+ import typer
5
+ from rich import print_json
6
+ from rich.console import Console
7
+ from rich.panel import Panel
8
+
9
+ from agentex.lib.cli.handlers.secret_handlers import (
10
+ delete_secret,
11
+ get_kubernetes_secrets_by_type,
12
+ get_secret,
13
+ sync_secrets,
14
+ )
15
+ from agentex.lib.cli.utils.cli_utils import handle_questionary_cancellation
16
+ from agentex.lib.cli.utils.kubectl_utils import (
17
+ check_and_switch_cluster_context,
18
+ validate_namespace,
19
+ )
20
+ from agentex.lib.sdk.config.agent_manifest import AgentManifest
21
+ from agentex.lib.utils.logging import make_logger
22
+
23
+ logger = make_logger(__name__)
24
+ console = Console()
25
+
26
+ secrets = typer.Typer()
27
+
28
+
29
+ @secrets.command()
30
+ def list(
31
+ namespace: str = typer.Option(
32
+ "agentex-agents", help="Kubernetes namespace to list secrets from"
33
+ ),
34
+ cluster: str | None = typer.Option(
35
+ None, help="Cluster context to use (defaults to current context)"
36
+ ),
37
+ ):
38
+ """List names of available secrets"""
39
+ logger.info(f"Listing secrets in namespace: {namespace}")
40
+
41
+ if cluster:
42
+ check_and_switch_cluster_context(cluster)
43
+ if not validate_namespace(namespace, cluster):
44
+ console.print(
45
+ f"[red]Error:[/red] Namespace '{namespace}' does not exist in cluster '{cluster}'"
46
+ )
47
+ raise typer.Exit(1)
48
+
49
+ secrets_list = get_kubernetes_secrets_by_type(namespace=namespace, context=cluster)
50
+ print_json(data=secrets_list)
51
+
52
+
53
+ @secrets.command()
54
+ def get(
55
+ name: str = typer.Argument(..., help="Name of the secret to get"),
56
+ namespace: str = typer.Option(
57
+ "agentex-agents", help="Kubernetes namespace for the secret"
58
+ ),
59
+ cluster: str | None = typer.Option(
60
+ None, help="Cluster context to use (defaults to current context)"
61
+ ),
62
+ ):
63
+ """Get details about a secret"""
64
+ logger.info(f"Getting secret: {name} from namespace: {namespace}")
65
+
66
+ if cluster:
67
+ check_and_switch_cluster_context(cluster)
68
+ if not validate_namespace(namespace, cluster):
69
+ console.print(
70
+ f"[red]Error:[/red] Namespace '{namespace}' does not exist in cluster '{cluster}'"
71
+ )
72
+ raise typer.Exit(1)
73
+
74
+ secret = get_secret(name=name, namespace=namespace, context=cluster)
75
+ print_json(data=secret)
76
+
77
+
78
+ @secrets.command()
79
+ def delete(
80
+ name: str = typer.Argument(..., help="Name of the secret to delete"),
81
+ namespace: str = typer.Option(
82
+ "agentex-agents", help="Kubernetes namespace for the secret"
83
+ ),
84
+ cluster: str | None = typer.Option(
85
+ None, help="Cluster context to use (defaults to current context)"
86
+ ),
87
+ ):
88
+ """Delete a secret"""
89
+ logger.info(f"Deleting secret: {name} from namespace: {namespace}")
90
+
91
+ if cluster:
92
+ check_and_switch_cluster_context(cluster)
93
+ if not validate_namespace(namespace, cluster):
94
+ console.print(
95
+ f"[red]Error:[/red] Namespace '{namespace}' does not exist in cluster '{cluster}'"
96
+ )
97
+ raise typer.Exit(1)
98
+
99
+ delete_secret(name=name, namespace=namespace, context=cluster)
100
+
101
+
102
+ @secrets.command()
103
+ def sync(
104
+ manifest: str = typer.Option(..., help="Path to the manifest file"),
105
+ # TODO: should cluster be here or be in manifest as well?
106
+ cluster: str = typer.Option(..., "--cluster", help="Cluster to sync secrets to"),
107
+ interactive: bool = typer.Option(
108
+ True, "--interactive/--no-interactive", help="Enable interactive prompts"
109
+ ),
110
+ namespace: str | None = typer.Option(
111
+ None,
112
+ help="Kubernetes namespace to deploy to (required in non-interactive mode)",
113
+ ),
114
+ values: str = typer.Option(None, "--values", help="Path to the values file"),
115
+ ):
116
+ """Sync secrets from the cluster to the local environment"""
117
+ console.print(
118
+ Panel.fit("🚀 [bold blue]Sync Secrets[/bold blue]", border_style="blue")
119
+ )
120
+
121
+ manifest_path = Path(manifest)
122
+ if not manifest_path.exists():
123
+ console.print(f"[red]Error:[/red] Manifest file not found: {manifest}")
124
+ raise typer.Exit(1)
125
+
126
+ # In non-interactive mode, require namespace
127
+ if not interactive and not namespace:
128
+ console.print(
129
+ "[red]Error:[/red] --namespace is required in non-interactive mode"
130
+ )
131
+ raise typer.Exit(1)
132
+
133
+ # Get namespace if not provided (only in interactive mode)
134
+ if not namespace:
135
+ namespace = questionary.text(
136
+ "Enter Kubernetes namespace:", default="default"
137
+ ).ask()
138
+ namespace = handle_questionary_cancellation(namespace, "namespace input")
139
+
140
+ if not namespace:
141
+ console.print("Deployment cancelled")
142
+ raise typer.Exit(0)
143
+
144
+ if values:
145
+ values_path = Path(values)
146
+ if not values_path.exists():
147
+ console.print(f"[red]Error:[/red] Values file not found: {values_path}")
148
+ raise typer.Exit(1)
149
+
150
+ # Validate cluster and namespace
151
+ check_and_switch_cluster_context(cluster)
152
+ if not validate_namespace(namespace, cluster):
153
+ console.print(
154
+ f"[red]Error:[/red] Namespace '{namespace}' does not exist in cluster '{cluster}'"
155
+ )
156
+ raise typer.Exit(1)
157
+
158
+ agent_manifest = AgentManifest.from_yaml(file_path=manifest)
159
+
160
+ # Always call sync_secrets - it will handle the case of no credentials
161
+ sync_secrets(
162
+ manifest_obj=agent_manifest,
163
+ cluster=cluster,
164
+ namespace=namespace,
165
+ interactive=interactive,
166
+ values_path=str(values) if values else None,
167
+ )
168
+
169
+ console.print("[green]Successfully synced secrets[/green]")
@@ -0,0 +1,118 @@
1
+ import typer
2
+ from rich import print_json
3
+ from rich.console import Console
4
+
5
+ from agentex import Agentex
6
+ from agentex.lib.cli.handlers.cleanup_handlers import cleanup_agent_workflows
7
+ from agentex.lib.utils.logging import make_logger
8
+
9
+ logger = make_logger(__name__)
10
+ console = Console()
11
+
12
+ tasks = typer.Typer()
13
+
14
+
15
+ @tasks.command()
16
+ def get(
17
+ task_id: str = typer.Argument(..., help="ID of the task to get"),
18
+ ):
19
+ """
20
+ Get the task with the given ID.
21
+ """
22
+ logger.info(f"Getting task: {task_id}")
23
+ client = Agentex()
24
+ task = client.tasks.retrieve(task_id=task_id)
25
+ print(f"Full Task {task_id}:")
26
+ print_json(data=task.to_dict())
27
+
28
+
29
+ @tasks.command()
30
+ def list():
31
+ """
32
+ List all tasks.
33
+ """
34
+ client = Agentex()
35
+ tasks = client.tasks.list()
36
+ print_json(data=[task.to_dict() for task in tasks])
37
+
38
+
39
+ @tasks.command()
40
+ def list_running(
41
+ agent_name: str = typer.Option(..., help="Name of the agent to list running tasks for"),
42
+ ):
43
+ """
44
+ List all currently running tasks for a specific agent.
45
+ """
46
+ client = Agentex()
47
+ all_tasks = client.tasks.list()
48
+ running_tasks = [task for task in all_tasks if hasattr(task, 'status') and task.status == "RUNNING"]
49
+
50
+ if not running_tasks:
51
+ console.print(f"[yellow]No running tasks found for agent '{agent_name}'[/yellow]")
52
+ return
53
+
54
+ console.print(f"[green]Found {len(running_tasks)} running task(s) for agent '{agent_name}':[/green]")
55
+
56
+ # Convert to dict with proper datetime serialization
57
+ serializable_tasks = []
58
+ for task in running_tasks:
59
+ try:
60
+ # Use model_dump with mode='json' for proper datetime handling
61
+ if hasattr(task, 'model_dump'):
62
+ serializable_tasks.append(task.model_dump(mode='json'))
63
+ else:
64
+ # Fallback for non-Pydantic objects
65
+ serializable_tasks.append({
66
+ "id": getattr(task, 'id', 'unknown'),
67
+ "status": getattr(task, 'status', 'unknown')
68
+ })
69
+ except Exception as e:
70
+ logger.warning(f"Failed to serialize task: {e}")
71
+ # Minimal fallback
72
+ serializable_tasks.append({
73
+ "id": getattr(task, 'id', 'unknown'),
74
+ "status": getattr(task, 'status', 'unknown')
75
+ })
76
+
77
+ print_json(data=serializable_tasks)
78
+
79
+
80
+ @tasks.command()
81
+ def delete(
82
+ task_id: str = typer.Argument(..., help="ID of the task to delete"),
83
+ ):
84
+ """
85
+ Delete the task with the given ID.
86
+ """
87
+ logger.info(f"Deleting task: {task_id}")
88
+ client = Agentex()
89
+ client.tasks.delete(task_id=task_id)
90
+ logger.info(f"Task deleted: {task_id}")
91
+
92
+
93
+ @tasks.command()
94
+ def cleanup(
95
+ agent_name: str = typer.Option(..., help="Name of the agent to cleanup tasks for"),
96
+ force: bool = typer.Option(False, help="Force cleanup using direct Temporal termination (bypasses development check)"),
97
+ ):
98
+ """
99
+ Clean up all running tasks/workflows for an agent.
100
+
101
+ By default, uses graceful cancellation via agent RPC.
102
+ With --force, directly terminates workflows via Temporal client.
103
+ """
104
+ try:
105
+ console.print(f"[blue]Starting cleanup for agent '{agent_name}'...[/blue]")
106
+
107
+ cleanup_agent_workflows(
108
+ agent_name=agent_name,
109
+ force=force,
110
+ development_only=True
111
+ )
112
+
113
+ console.print(f"[green]✓ Cleanup completed for agent '{agent_name}'[/green]")
114
+
115
+ except Exception as e:
116
+ console.print(f"[red]Cleanup failed: {str(e)}[/red]")
117
+ logger.exception("Task cleanup failed")
118
+ raise typer.Exit(1) from e
@@ -0,0 +1,133 @@
1
+ import os
2
+ import subprocess
3
+ import sys
4
+
5
+ import typer
6
+
7
+ from agentex.lib.utils.logging import make_logger
8
+
9
+ logger = make_logger(__name__)
10
+
11
+
12
+ uv = typer.Typer(
13
+ help="Wrapper for uv command with AgentEx-specific enhancements",
14
+ context_settings={"help_option_names": ["-h", "--help"]},
15
+ )
16
+
17
+ sync_args = typer.Argument(None, help="Additional arguments to pass to uv sync")
18
+
19
+
20
+ @uv.command()
21
+ def sync(
22
+ ctx: typer.Context,
23
+ index: str | None = typer.Option(
24
+ None, "--index", "-i", help="UV index URL to use for sync"
25
+ ),
26
+ group: str | None = typer.Option(
27
+ None,
28
+ "--group",
29
+ "-g",
30
+ help="Include dependencies from the specified dependency group",
31
+ ),
32
+ args: list[str] = sync_args,
33
+ ):
34
+ """Sync dependencies with optional UV_INDEX support"""
35
+ args = args or []
36
+
37
+ # Check if help was requested
38
+ if "--help" in args or "-h" in args:
39
+ # Show our custom help instead of passing to uv
40
+ typer.echo(ctx.get_help())
41
+ return
42
+
43
+ if index:
44
+ os.environ["UV_INDEX_URL"] = index
45
+ logger.info(f"Using provided UV_INDEX_URL: {index}")
46
+
47
+ # Build the uv sync command
48
+ cmd = ["uv", "sync"]
49
+
50
+ # Add group if specified
51
+ if group:
52
+ cmd.extend(["--group", group])
53
+ logger.info(f"Using dependency group: {group}")
54
+
55
+ # Add any additional arguments
56
+ cmd.extend(args)
57
+
58
+ try:
59
+ result = subprocess.run(cmd, check=True)
60
+ sys.exit(result.returncode)
61
+ except subprocess.CalledProcessError as e:
62
+ logger.error(f"uv sync failed with exit code {e.returncode}")
63
+ sys.exit(e.returncode)
64
+ except FileNotFoundError:
65
+ logger.error("uv command not found. Please install uv first.")
66
+ sys.exit(1)
67
+
68
+
69
+ add_args = typer.Argument(None, help="Additional arguments to pass to uv add")
70
+
71
+
72
+ @uv.command()
73
+ def add(
74
+ ctx: typer.Context,
75
+ index: str | None = typer.Option(
76
+ None, "--index", "-i", help="UV index URL to use for add"
77
+ ),
78
+ args: list[str] = add_args,
79
+ ):
80
+ """Add dependencies with optional UV_INDEX support"""
81
+
82
+ args = args or []
83
+
84
+ # Check if help was requested
85
+ if "--help" in args or "-h" in args:
86
+ # Show our custom help instead of passing to uv
87
+ typer.echo(ctx.get_help())
88
+ return
89
+
90
+ if index:
91
+ os.environ["UV_INDEX_URL"] = index
92
+ logger.info(f"Using provided UV_INDEX_URL: {index}")
93
+
94
+ # Build the uv add command
95
+ cmd = ["uv", "add"] + (args or [])
96
+
97
+ try:
98
+ result = subprocess.run(cmd, check=True)
99
+ sys.exit(result.returncode)
100
+ except subprocess.CalledProcessError as e:
101
+ logger.error(f"uv add failed with exit code {e.returncode}")
102
+ sys.exit(e.returncode)
103
+ except FileNotFoundError:
104
+ logger.error("uv command not found. Please install uv first.")
105
+ sys.exit(1)
106
+
107
+
108
+ run_args = typer.Argument(None, help="Arguments to pass to uv")
109
+
110
+
111
+ @uv.command()
112
+ def run(
113
+ ctx: typer.Context,
114
+ args: list[str] = run_args,
115
+ ):
116
+ """Run any uv command with arguments"""
117
+ if not args:
118
+ # If no arguments provided, show help
119
+ typer.echo(ctx.get_help())
120
+ return
121
+
122
+ # Build the uv command
123
+ cmd = ["uv"] + args
124
+
125
+ try:
126
+ result = subprocess.run(cmd, check=True)
127
+ sys.exit(result.returncode)
128
+ except subprocess.CalledProcessError as e:
129
+ logger.error(f"uv command failed with exit code {e.returncode}")
130
+ sys.exit(e.returncode)
131
+ except FileNotFoundError:
132
+ logger.error("uv command not found. Please install uv first.")
133
+ sys.exit(1)
File without changes
@@ -0,0 +1,160 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from python_on_whales import DockerException, docker
6
+ from rich.console import Console
7
+
8
+ from agentex.lib.cli.handlers.run_handlers import RunError
9
+ from agentex.lib.cli.handlers.run_handlers import run_agent as _run_agent
10
+ from agentex.lib.sdk.config.agent_manifest import AgentManifest
11
+ from agentex.lib.utils.logging import make_logger
12
+
13
+ logger = make_logger(__name__)
14
+ console = Console()
15
+
16
+
17
+ class DockerBuildError(Exception):
18
+ """An error occurred during docker build"""
19
+
20
+
21
+ def build_agent(
22
+ manifest_path: str,
23
+ registry_url: str,
24
+ repository_name: str,
25
+ platforms: list[str],
26
+ push: bool = False,
27
+ secret: str = None,
28
+ tag: str = None,
29
+ build_args: list[str] = None,
30
+ ) -> str:
31
+ """Build the agent locally and optionally push to registry
32
+
33
+ Args:
34
+ manifest_path: Path to the agent manifest file
35
+ registry_url: Registry URL for pushing the image
36
+ push: Whether to push the image to the registry
37
+ secret: Docker build secret in format 'id=secret-id,src=path-to-secret-file'
38
+ tag: Image tag to use (defaults to 'latest')
39
+ build_args: List of Docker build arguments in format 'KEY=VALUE'
40
+
41
+ Returns:
42
+ The image URL
43
+ """
44
+ agent_manifest = AgentManifest.from_yaml(file_path=manifest_path)
45
+ build_context_root = (
46
+ Path(manifest_path).parent / agent_manifest.build.context.root
47
+ ).resolve()
48
+
49
+ repository_name = repository_name or agent_manifest.agent.name
50
+
51
+ # Prepare image name
52
+ if registry_url:
53
+ image_name = f"{registry_url}/{repository_name}"
54
+ else:
55
+ image_name = repository_name
56
+
57
+ if tag:
58
+ image_name = f"{image_name}:{tag}"
59
+ else:
60
+ image_name = f"{image_name}:latest"
61
+
62
+ with agent_manifest.context_manager(build_context_root) as build_context:
63
+ logger.info(f"Building image {image_name} locally...")
64
+
65
+ # Log build context information for debugging
66
+ logger.info(f"Build context path: {build_context.path}")
67
+ logger.info(
68
+ f"Dockerfile path: {build_context.path / build_context.dockerfile_path}"
69
+ )
70
+
71
+ try:
72
+ # Prepare build arguments
73
+ docker_build_kwargs = {
74
+ "context_path": str(build_context.path),
75
+ "file": str(build_context.path / build_context.dockerfile_path),
76
+ "tags": [image_name],
77
+ "platforms": platforms,
78
+ }
79
+
80
+ # Add Docker build args if provided
81
+ if build_args:
82
+ docker_build_args = {}
83
+ for arg in build_args:
84
+ if "=" in arg:
85
+ key, value = arg.split("=", 1)
86
+ docker_build_args[key] = value
87
+ else:
88
+ logger.warning(
89
+ f"Invalid build arg format: {arg}. Expected KEY=VALUE"
90
+ )
91
+
92
+ if docker_build_args:
93
+ docker_build_kwargs["build_args"] = docker_build_args
94
+ logger.info(f"Using build args: {list(docker_build_args.keys())}")
95
+
96
+ # Add secret if provided
97
+ if secret:
98
+ docker_build_kwargs["secrets"] = [secret]
99
+
100
+ if push:
101
+ # Build and push in one step for multi-platform builds
102
+ logger.info("Building and pushing image...")
103
+ docker_build_kwargs["push"] = (
104
+ True # Push directly after build for multi-platform
105
+ )
106
+ docker.buildx.build(**docker_build_kwargs)
107
+
108
+ logger.info(f"Successfully built and pushed {image_name}")
109
+ else:
110
+ # Build only
111
+ logger.info("Building image...")
112
+ docker.buildx.build(**docker_build_kwargs)
113
+
114
+ logger.info(f"Successfully built {image_name}")
115
+
116
+ except DockerException as error:
117
+ error_msg = error.stderr if error.stderr else str(error)
118
+ action = "build or push" if push else "build"
119
+ logger.error(f"{action.capitalize()} failed: {error_msg}", exc_info=True)
120
+ raise DockerBuildError(
121
+ f"Docker {action} failed: {error_msg}\n"
122
+ f"Build context: {build_context.path}\n"
123
+ f"Dockerfile path: {build_context.dockerfile_path}"
124
+ ) from error
125
+
126
+ return image_name
127
+
128
+
129
+ def run_agent(manifest_path: str):
130
+ """Run an agent locally from the given manifest"""
131
+ import asyncio
132
+ import signal
133
+ import sys
134
+
135
+ # Flag to track if we're shutting down
136
+ shutting_down = False
137
+
138
+ def signal_handler(signum, frame):
139
+ """Handle signals by raising KeyboardInterrupt"""
140
+ nonlocal shutting_down
141
+ if shutting_down:
142
+ # If we're already shutting down and get another signal, force exit
143
+ print(f"\nForce exit on signal {signum}")
144
+ sys.exit(1)
145
+
146
+ shutting_down = True
147
+ print(f"\nReceived signal {signum}, shutting down...")
148
+ raise KeyboardInterrupt()
149
+
150
+ # Set up signal handling for the main thread
151
+ signal.signal(signal.SIGINT, signal_handler)
152
+ signal.signal(signal.SIGTERM, signal_handler)
153
+
154
+ try:
155
+ asyncio.run(_run_agent(manifest_path))
156
+ except KeyboardInterrupt:
157
+ print("Shutdown completed.")
158
+ sys.exit(0)
159
+ except RunError as e:
160
+ raise RuntimeError(str(e)) from e