agentex-sdk 0.7.1__py3-none-any.whl → 0.7.2__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 (23) hide show
  1. agentex/_version.py +1 -1
  2. agentex/lib/adk/providers/_modules/sync_provider.py +116 -15
  3. agentex/lib/cli/commands/init.py +16 -1
  4. agentex/lib/cli/templates/temporal-openai-agents/.dockerignore.j2 +43 -0
  5. agentex/lib/cli/templates/temporal-openai-agents/Dockerfile-uv.j2 +48 -0
  6. agentex/lib/cli/templates/temporal-openai-agents/Dockerfile.j2 +48 -0
  7. agentex/lib/cli/templates/temporal-openai-agents/README.md.j2 +224 -0
  8. agentex/lib/cli/templates/temporal-openai-agents/dev.ipynb.j2 +126 -0
  9. agentex/lib/cli/templates/temporal-openai-agents/environments.yaml.j2 +64 -0
  10. agentex/lib/cli/templates/temporal-openai-agents/manifest.yaml.j2 +140 -0
  11. agentex/lib/cli/templates/temporal-openai-agents/project/acp.py.j2 +80 -0
  12. agentex/lib/cli/templates/temporal-openai-agents/project/activities.py.j2 +116 -0
  13. agentex/lib/cli/templates/temporal-openai-agents/project/run_worker.py.j2 +56 -0
  14. agentex/lib/cli/templates/temporal-openai-agents/project/workflow.py.j2 +169 -0
  15. agentex/lib/cli/templates/temporal-openai-agents/pyproject.toml.j2 +35 -0
  16. agentex/lib/cli/templates/temporal-openai-agents/requirements.txt.j2 +4 -0
  17. agentex/lib/cli/templates/temporal-openai-agents/test_agent.py.j2 +147 -0
  18. agentex/types/__init__.py +2 -2
  19. {agentex_sdk-0.7.1.dist-info → agentex_sdk-0.7.2.dist-info}/METADATA +1 -1
  20. {agentex_sdk-0.7.1.dist-info → agentex_sdk-0.7.2.dist-info}/RECORD +23 -9
  21. {agentex_sdk-0.7.1.dist-info → agentex_sdk-0.7.2.dist-info}/WHEEL +0 -0
  22. {agentex_sdk-0.7.1.dist-info → agentex_sdk-0.7.2.dist-info}/entry_points.txt +0 -0
  23. {agentex_sdk-0.7.1.dist-info → agentex_sdk-0.7.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,126 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "id": "36834357",
7
+ "metadata": {},
8
+ "outputs": [],
9
+ "source": [
10
+ "from agentex import Agentex\n",
11
+ "\n",
12
+ "client = Agentex(base_url=\"http://localhost:5003\")"
13
+ ]
14
+ },
15
+ {
16
+ "cell_type": "code",
17
+ "execution_count": null,
18
+ "id": "d1c309d6",
19
+ "metadata": {},
20
+ "outputs": [],
21
+ "source": [
22
+ "AGENT_NAME = \"{{ agent_name }}\""
23
+ ]
24
+ },
25
+ {
26
+ "cell_type": "code",
27
+ "execution_count": null,
28
+ "id": "9f6e6ef0",
29
+ "metadata": {},
30
+ "outputs": [],
31
+ "source": [
32
+ "# (REQUIRED) Create a new task. For Async agents, you must create a task for messages to be associated with.\n",
33
+ "import uuid\n",
34
+ "\n",
35
+ "rpc_response = client.agents.create_task(\n",
36
+ " agent_name=AGENT_NAME,\n",
37
+ " params={\n",
38
+ " \"name\": f\"{str(uuid.uuid4())[:8]}-task\",\n",
39
+ " \"params\": {}\n",
40
+ " }\n",
41
+ ")\n",
42
+ "\n",
43
+ "task = rpc_response.result\n",
44
+ "print(task)"
45
+ ]
46
+ },
47
+ {
48
+ "cell_type": "code",
49
+ "execution_count": null,
50
+ "id": "b03b0d37",
51
+ "metadata": {},
52
+ "outputs": [],
53
+ "source": [
54
+ "# Send an event to the agent\n",
55
+ "\n",
56
+ "# The response is expected to be a list of TaskMessage objects, which is a union of the following types:\n",
57
+ "# - TextContent: A message with just text content \n",
58
+ "# - DataContent: A message with JSON-serializable data content\n",
59
+ "# - ToolRequestContent: A message with a tool request, which contains a JSON-serializable request to call a tool\n",
60
+ "# - ToolResponseContent: A message with a tool response, which contains response object from a tool call in its content\n",
61
+ "\n",
62
+ "# When processing the message/send response, if you are expecting more than TextContent, such as DataContent, ToolRequestContent, or ToolResponseContent, you can process them as well\n",
63
+ "\n",
64
+ "rpc_response = client.agents.send_event(\n",
65
+ " agent_name=AGENT_NAME,\n",
66
+ " params={\n",
67
+ " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"Hello what can you do?\"},\n",
68
+ " \"task_id\": task.id,\n",
69
+ " }\n",
70
+ ")\n",
71
+ "\n",
72
+ "event = rpc_response.result\n",
73
+ "print(event)"
74
+ ]
75
+ },
76
+ {
77
+ "cell_type": "code",
78
+ "execution_count": null,
79
+ "id": "a6927cc0",
80
+ "metadata": {},
81
+ "outputs": [],
82
+ "source": [
83
+ "# Subscribe to the async task messages produced by the agent\n",
84
+ "from agentex.lib.utils.dev_tools import subscribe_to_async_task_messages\n",
85
+ "\n",
86
+ "task_messages = subscribe_to_async_task_messages(\n",
87
+ " client=client,\n",
88
+ " task=task, \n",
89
+ " only_after_timestamp=event.created_at, \n",
90
+ " print_messages=True,\n",
91
+ " rich_print=True,\n",
92
+ " timeout=5,\n",
93
+ ")"
94
+ ]
95
+ },
96
+ {
97
+ "cell_type": "code",
98
+ "execution_count": null,
99
+ "id": "4864e354",
100
+ "metadata": {},
101
+ "outputs": [],
102
+ "source": []
103
+ }
104
+ ],
105
+ "metadata": {
106
+ "kernelspec": {
107
+ "display_name": ".venv",
108
+ "language": "python",
109
+ "name": "python3"
110
+ },
111
+ "language_info": {
112
+ "codemirror_mode": {
113
+ "name": "ipython",
114
+ "version": 3
115
+ },
116
+ "file_extension": ".py",
117
+ "mimetype": "text/x-python",
118
+ "name": "python",
119
+ "nbconvert_exporter": "python",
120
+ "pygments_lexer": "ipython3",
121
+ "version": "3.12.9"
122
+ }
123
+ },
124
+ "nbformat": 4,
125
+ "nbformat_minor": 5
126
+ }
@@ -0,0 +1,64 @@
1
+ # Agent Environment Configuration
2
+ # ------------------------------
3
+ # This file defines environment-specific settings for your agent.
4
+ # This DIFFERS from the manifest.yaml file in that it is used to program things that are ONLY per environment.
5
+
6
+ # ********** EXAMPLE **********
7
+ # schema_version: "v1" # This is used to validate the file structure and is not used by the agentex CLI
8
+ # environments:
9
+ # dev:
10
+ # auth:
11
+ # principal:
12
+ # user_id: "1234567890"
13
+ # user_name: "John Doe"
14
+ # user_email: "john.doe@example.com"
15
+ # user_role: "admin"
16
+ # user_permissions: "read, write, delete"
17
+ # helm_overrides: # This is used to override the global helm values.yaml file in the agentex-agent helm charts
18
+ # replicas: 3
19
+ # resources:
20
+ # requests:
21
+ # cpu: "1000m"
22
+ # memory: "2Gi"
23
+ # limits:
24
+ # cpu: "2000m"
25
+ # memory: "4Gi"
26
+ # env:
27
+ # - name: LOG_LEVEL
28
+ # value: "DEBUG"
29
+ # - name: ENVIRONMENT
30
+ # value: "staging"
31
+ #
32
+ # kubernetes:
33
+ # # OPTIONAL - Otherwise it will be derived from separately. However, this can be used to override the derived
34
+ # # namespace and deploy it with in the same namespace that already exists for a separate agent.
35
+ # namespace: "team-{{agent_name}}"
36
+ # ********** END EXAMPLE **********
37
+
38
+ schema_version: "v1" # This is used to validate the file structure and is not used by the agentex CLI
39
+ environments:
40
+ dev:
41
+ auth:
42
+ principal:
43
+ user_id: # TODO: Fill in
44
+ account_id: # TODO: Fill in
45
+ helm_overrides:
46
+ # This is used to override the global helm values.yaml file in the agentex-agent helm charts
47
+ replicaCount: 2
48
+ resources:
49
+ requests:
50
+ cpu: "500m"
51
+ memory: "1Gi"
52
+ limits:
53
+ cpu: "1000m"
54
+ memory: "2Gi"
55
+ temporal-worker:
56
+ enabled: true
57
+ replicaCount: 2
58
+ resources:
59
+ requests:
60
+ cpu: "500m"
61
+ memory: "1Gi"
62
+ limits:
63
+ cpu: "1000m"
64
+ memory: "2Gi"
@@ -0,0 +1,140 @@
1
+ # Agent Manifest Configuration
2
+ # ---------------------------
3
+ # This file defines how your agent should be built and deployed.
4
+
5
+ # Build Configuration
6
+ # ------------------
7
+ # The build config defines what gets packaged into your agent's Docker image.
8
+ # This same configuration is used whether building locally or remotely.
9
+ #
10
+ # When building:
11
+ # 1. All files from include_paths are collected into a build context
12
+ # 2. The context is filtered by dockerignore rules
13
+ # 3. The Dockerfile uses this context to build your agent's image
14
+ # 4. The image is pushed to a registry and used to run your agent
15
+ build:
16
+ context:
17
+ # Root directory for the build context
18
+ root: ../ # Keep this as the default root
19
+
20
+ # Paths to include in the Docker build context
21
+ # Must include:
22
+ # - Your agent's directory (your custom agent code)
23
+ # These paths are collected and sent to the Docker daemon for building
24
+ include_paths:
25
+ - {{ project_path_from_build_root }}
26
+
27
+ # Path to your agent's Dockerfile
28
+ # This defines how your agent's image is built from the context
29
+ # Relative to the root directory
30
+ dockerfile: {{ project_path_from_build_root }}/Dockerfile
31
+
32
+ # Path to your agent's .dockerignore
33
+ # Filters unnecessary files from the build context
34
+ # Helps keep build context small and builds fast
35
+ dockerignore: {{ project_path_from_build_root }}/.dockerignore
36
+
37
+
38
+ # Local Development Configuration
39
+ # -----------------------------
40
+ # Only used when running the agent locally
41
+ local_development:
42
+ agent:
43
+ port: 8000 # Port where your local ACP server is running
44
+ host_address: host.docker.internal # Host address for Docker networking (host.docker.internal for Docker, localhost for direct)
45
+
46
+ # File paths for local development (relative to this manifest.yaml)
47
+ paths:
48
+ # Path to ACP server file
49
+ # Examples:
50
+ # project/acp.py (standard)
51
+ # src/server.py (custom structure)
52
+ # ../shared/acp.py (shared across projects)
53
+ # /absolute/path/acp.py (absolute path)
54
+ acp: project/acp.py
55
+
56
+ # Path to temporal worker file
57
+ # Examples:
58
+ # project/run_worker.py (standard)
59
+ # workers/temporal.py (custom structure)
60
+ # ../shared/worker.py (shared across projects)
61
+ worker: project/run_worker.py
62
+
63
+
64
+ # Agent Configuration
65
+ # -----------------
66
+ agent:
67
+ # Type of agent - either sync or async
68
+ acp_type: async
69
+
70
+ # Unique name for your agent
71
+ # Used for task routing and monitoring
72
+ name: {{ agent_name }}
73
+
74
+ # Description of what your agent does
75
+ # Helps with documentation and discovery
76
+ description: {{ description }}
77
+
78
+ # Temporal workflow configuration
79
+ # This enables your agent to run as a Temporal workflow for long-running tasks
80
+ temporal:
81
+ enabled: true
82
+ workflows:
83
+ # Name of the workflow class
84
+ # Must match the @workflow.defn name in your workflow.py
85
+ - name: {{ workflow_name }}
86
+
87
+ # Queue name for task distribution
88
+ # Used by Temporal to route tasks to your agent
89
+ # Convention: <agent_name>_task_queue
90
+ queue_name: {{ queue_name }}
91
+
92
+ # Optional: Health check port for temporal worker
93
+ # Defaults to 80 if not specified
94
+ # health_check_port: 80
95
+
96
+ # Optional: Credentials mapping
97
+ # Maps Kubernetes secrets to environment variables
98
+ # Common credentials include:
99
+ credentials:
100
+ - env_var_name: REDIS_URL
101
+ secret_name: redis-url-secret
102
+ secret_key: url
103
+ # - env_var_name: OPENAI_API_KEY
104
+ # secret_name: openai-api-key
105
+ # secret_key: api-key
106
+
107
+ # Optional: Set Environment variables for running your agent locally as well
108
+ # as for deployment later on
109
+ env: {}
110
+ # OPENAI_API_KEY: "<YOUR_OPENAI_API_KEY_HERE>"
111
+ # OPENAI_BASE_URL: "<YOUR_OPENAI_BASE_URL_HERE>"
112
+ # OPENAI_ORG_ID: "<YOUR_OPENAI_ORG_ID_HERE>"
113
+
114
+
115
+ # Deployment Configuration
116
+ # -----------------------
117
+ # Configuration for deploying your agent to Kubernetes clusters
118
+ deployment:
119
+ # Container image configuration
120
+ image:
121
+ repository: "" # Update with your container registry
122
+ tag: "latest" # Default tag, should be versioned in production
123
+
124
+ imagePullSecrets: [] # Update with your image pull secret name
125
+ # - name: my-registry-secret
126
+
127
+ # Global deployment settings that apply to all clusters
128
+ # These can be overridden in cluster-specific environments (environments.yaml)
129
+ global:
130
+ # Default replica count
131
+ replicaCount: 1
132
+
133
+ # Default resource requirements
134
+ resources:
135
+ requests:
136
+ cpu: "500m"
137
+ memory: "1Gi"
138
+ limits:
139
+ cpu: "1000m"
140
+ memory: "2Gi"
@@ -0,0 +1,80 @@
1
+ import os
2
+ import sys
3
+ from temporalio.contrib.openai_agents import OpenAIAgentsPlugin, ModelActivityParameters
4
+ from datetime import timedelta
5
+ from agentex.lib.core.temporal.plugins.openai_agents.interceptors.context_interceptor import ContextInterceptor
6
+ from agentex.lib.core.temporal.plugins.openai_agents.models.temporal_streaming_model import (
7
+ TemporalStreamingModelProvider,
8
+ )
9
+
10
+ # === DEBUG SETUP (AgentEx CLI Debug Support) ===
11
+ if os.getenv("AGENTEX_DEBUG_ENABLED") == "true":
12
+ try:
13
+ import debugpy
14
+ from agentex.lib.utils.logging import make_logger
15
+
16
+ logger = make_logger(__name__)
17
+ debug_port = int(os.getenv("AGENTEX_DEBUG_PORT", "5679"))
18
+ debug_type = os.getenv("AGENTEX_DEBUG_TYPE", "acp")
19
+ wait_for_attach = os.getenv("AGENTEX_DEBUG_WAIT_FOR_ATTACH", "false").lower() == "true"
20
+
21
+ # Configure debugpy
22
+ debugpy.configure(subProcess=False)
23
+ debugpy.listen(debug_port)
24
+
25
+ logger.info(f"[{debug_type.upper()}] Debug server listening on port {debug_port}")
26
+
27
+ if wait_for_attach:
28
+ logger.info(f"[{debug_type.upper()}] Waiting for debugger to attach...")
29
+ debugpy.wait_for_client()
30
+ logger.info(f"[{debug_type.upper()}] Debugger attached!")
31
+ else:
32
+ logger.info(f"[{debug_type.upper()}] Ready for debugger attachment")
33
+
34
+ except ImportError:
35
+ print("debugpy not available. Install with: pip install debugpy")
36
+ sys.exit(1)
37
+ except Exception as e:
38
+ print(f"Debug setup failed: {e}")
39
+ sys.exit(1)
40
+ # === END DEBUG SETUP ===
41
+
42
+ from agentex.lib.sdk.fastacp.fastacp import FastACP
43
+ from agentex.lib.types.fastacp import TemporalACPConfig
44
+
45
+ context_interceptor = ContextInterceptor()
46
+ streaming_model_provider = TemporalStreamingModelProvider()
47
+
48
+
49
+ # Create the ACP server
50
+ acp = FastACP.create(
51
+ acp_type="async",
52
+ config=TemporalACPConfig(
53
+ # When deployed to the cluster, the Temporal address will automatically be set to the cluster address
54
+ # For local development, we set the address manually to talk to the local Temporal service set up via docker compose
55
+ type="temporal",
56
+ temporal_address=os.getenv("TEMPORAL_ADDRESS", "localhost:7233"),
57
+ plugins=[OpenAIAgentsPlugin(
58
+ model_params=ModelActivityParameters(
59
+ start_to_close_timeout=timedelta(days=1)
60
+ ),
61
+ model_provider=streaming_model_provider
62
+ )],
63
+ interceptors=[context_interceptor]
64
+ )
65
+ )
66
+
67
+
68
+ # Notice that we don't need to register any handlers when we use type="temporal"
69
+ # If you look at the code in agentex.sdk.fastacp.impl.temporal_acp
70
+ # You can see that these handlers are automatically registered when the ACP is created
71
+
72
+ # @acp.on_task_create
73
+ # This will be handled by the method in your workflow that is decorated with @workflow.run
74
+
75
+ # @acp.on_task_event_send
76
+ # This will be handled by the method in your workflow that is decorated with @workflow.signal(name=SignalName.RECEIVE_MESSAGE)
77
+
78
+ # @acp.on_task_cancel
79
+ # This does not need to be handled by your workflow.
80
+ # It is automatically handled by the temporal client which cancels the workflow directly
@@ -0,0 +1,116 @@
1
+ """
2
+ Temporal Activities for OpenAI Agents SDK
3
+ ==========================================
4
+
5
+ WHAT ARE ACTIVITIES?
6
+ --------------------
7
+ Activities are functions that perform non-deterministic operations - things that
8
+ might have different results each time they run, such as:
9
+ - API calls (weather services, databases, external services)
10
+ - File I/O operations
11
+ - Current time/date lookups
12
+ - Random number generation
13
+ - Any operation with side effects
14
+
15
+ Temporal workflows must be deterministic (same input = same output every time).
16
+ Activities let you safely perform non-deterministic work while Temporal handles
17
+ retries, timeouts, and failure recovery automatically.
18
+
19
+
20
+ HOW TO ADD NEW ACTIVITIES:
21
+ --------------------------
22
+ Adding a new activity requires 3 steps:
23
+
24
+ 1. DEFINE the activity in this file with the @activity.defn decorator:
25
+
26
+ @activity.defn
27
+ async def my_new_activity(param: str) -> str:
28
+ # Your non-deterministic logic here
29
+ return result
30
+
31
+ 2. REGISTER it in run_worker.py by adding to the activities list:
32
+
33
+ from project.activities import get_weather, my_new_activity
34
+
35
+ all_activities = get_all_activities() + [
36
+ stream_lifecycle_content,
37
+ get_weather,
38
+ my_new_activity, # Add your new activity here
39
+ ]
40
+
41
+ 3. ADD it as a tool to your OpenAI agent in workflow.py:
42
+
43
+ from project.activities import get_weather, my_new_activity
44
+
45
+ agent = Agent(
46
+ name="...",
47
+ tools=[
48
+ openai_agents.workflow.activity_as_tool(
49
+ get_weather,
50
+ start_to_close_timeout=timedelta(minutes=5),
51
+ ),
52
+ openai_agents.workflow.activity_as_tool(
53
+ my_new_activity, # Add your new activity as a tool
54
+ start_to_close_timeout=timedelta(minutes=5),
55
+ ),
56
+ ],
57
+ )
58
+
59
+
60
+ RUNNING ACTIVITIES OUTSIDE OPENAI AGENT SDK:
61
+ --------------------------------------------
62
+ You can also call activities directly from your workflow without going through
63
+ the OpenAI agent. This is useful for setup/teardown operations or when you need
64
+ to run an activity before the agent starts:
65
+
66
+ from temporalio import workflow
67
+ from datetime import timedelta
68
+
69
+ # Inside your workflow method:
70
+ result = await workflow.execute_activity(
71
+ get_weather,
72
+ start_to_close_timeout=timedelta(minutes=5),
73
+ )
74
+
75
+ For activities with parameters:
76
+
77
+ result = await workflow.execute_activity(
78
+ my_activity_with_params,
79
+ "param_value", # positional args
80
+ start_to_close_timeout=timedelta(minutes=5),
81
+ )
82
+
83
+
84
+ TEMPORAL DASHBOARD:
85
+ -------------------
86
+ Monitor your workflows and activities in real-time at:
87
+
88
+ http://localhost:8080
89
+
90
+ The dashboard shows:
91
+ - Running and completed workflows
92
+ - Activity execution history
93
+ - Retries and failures
94
+ - Workflow state and signals
95
+ """
96
+
97
+ from temporalio import activity
98
+
99
+ from agentex.lib.utils.logging import make_logger
100
+
101
+ logger = make_logger(__name__)
102
+
103
+
104
+ @activity.defn
105
+ async def get_weather() -> str:
106
+ """
107
+ Get the current weather.
108
+
109
+ This is a dummy activity that returns a hardcoded string for demo purposes.
110
+ Replace this with a real weather API call in your implementation.
111
+
112
+ Returns:
113
+ A string describing the current weather conditions.
114
+ """
115
+ logger.info("get_weather activity called")
116
+ return "Sunny, 72°F"
@@ -0,0 +1,56 @@
1
+ import asyncio
2
+
3
+ from agentex.lib.core.temporal.activities import get_all_activities
4
+ from agentex.lib.core.temporal.workers.worker import AgentexWorker
5
+ from agentex.lib.utils.logging import make_logger
6
+ from agentex.lib.utils.debug import setup_debug_if_enabled
7
+ from agentex.lib.environment_variables import EnvironmentVariables
8
+ from temporalio.contrib.openai_agents import OpenAIAgentsPlugin, ModelActivityParameters
9
+ from datetime import timedelta
10
+ from agentex.lib.core.temporal.plugins.openai_agents.interceptors.context_interceptor import ContextInterceptor
11
+ from agentex.lib.core.temporal.plugins.openai_agents.hooks.activities import stream_lifecycle_content
12
+ from agentex.lib.core.temporal.plugins.openai_agents.models.temporal_streaming_model import (
13
+ TemporalStreamingModelProvider,
14
+ )
15
+ from project.workflow import {{ workflow_class }}
16
+ from project.activities import get_weather
17
+
18
+ environment_variables = EnvironmentVariables.refresh()
19
+
20
+ logger = make_logger(__name__)
21
+
22
+
23
+ async def main():
24
+ # Setup debug mode if enabled
25
+ setup_debug_if_enabled()
26
+
27
+ task_queue_name = environment_variables.WORKFLOW_TASK_QUEUE
28
+ if task_queue_name is None:
29
+ raise ValueError("WORKFLOW_TASK_QUEUE is not set")
30
+
31
+ # Register all activities here
32
+ # When you add new activities in activities.py, add them to this list
33
+ all_activities = get_all_activities() + [stream_lifecycle_content, get_weather]
34
+
35
+ context_interceptor = ContextInterceptor()
36
+ streaming_model_provider = TemporalStreamingModelProvider()
37
+
38
+ # Create a worker with automatic tracing
39
+ worker = AgentexWorker(
40
+ task_queue=task_queue_name,
41
+ plugins=[OpenAIAgentsPlugin(
42
+ model_params=ModelActivityParameters(
43
+ start_to_close_timeout=timedelta(days=1)
44
+ ),
45
+ model_provider=streaming_model_provider
46
+ )],
47
+ interceptors=[context_interceptor],
48
+ )
49
+
50
+ await worker.run(
51
+ activities=all_activities,
52
+ workflow={{ workflow_class }},
53
+ )
54
+
55
+ if __name__ == "__main__":
56
+ asyncio.run(main())