agentex-sdk 0.2.0__py3-none-any.whl → 0.2.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.
- agentex/_version.py +1 -1
- agentex/lib/adk/_modules/acp.py +2 -1
- agentex/lib/adk/_modules/agent_task_tracker.py +2 -1
- agentex/lib/adk/_modules/agents.py +2 -1
- agentex/lib/adk/_modules/events.py +2 -1
- agentex/lib/adk/_modules/messages.py +4 -3
- agentex/lib/adk/_modules/state.py +2 -1
- agentex/lib/adk/_modules/streaming.py +4 -3
- agentex/lib/adk/_modules/tasks.py +2 -1
- agentex/lib/adk/_modules/tracing.py +2 -1
- agentex/lib/adk/providers/_modules/litellm.py +2 -2
- agentex/lib/adk/providers/_modules/openai.py +2 -2
- agentex/lib/adk/utils/_modules/client.py +12 -0
- agentex/lib/cli/commands/init.py +8 -4
- agentex/lib/cli/templates/default/README.md.j2 +23 -2
- agentex/lib/cli/templates/default/dev.ipynb.j2 +126 -0
- agentex/lib/cli/templates/sync/README.md.j2 +22 -2
- agentex/lib/cli/templates/sync/dev.ipynb.j2 +167 -0
- agentex/lib/cli/templates/sync/project/acp.py.j2 +63 -14
- agentex/lib/cli/templates/temporal/README.md.j2 +24 -3
- agentex/lib/cli/templates/temporal/dev.ipynb.j2 +126 -0
- agentex/lib/core/adapters/streams/adapter_redis.py +4 -4
- agentex/lib/core/adapters/streams/port.py +1 -1
- agentex/lib/core/services/adk/streaming.py +2 -3
- agentex/lib/core/temporal/activities/__init__.py +2 -2
- agentex/lib/sdk/fastacp/base/base_acp_server.py +11 -2
- agentex/lib/utils/dev_tools/__init__.py +9 -0
- agentex/lib/utils/dev_tools/async_messages.py +386 -0
- agentex/resources/agents.py +511 -3
- agentex/resources/tasks.py +4 -4
- agentex/types/agent_rpc_response.py +32 -4
- {agentex_sdk-0.2.0.dist-info → agentex_sdk-0.2.2.dist-info}/METADATA +1 -1
- {agentex_sdk-0.2.0.dist-info → agentex_sdk-0.2.2.dist-info}/RECORD +36 -30
- {agentex_sdk-0.2.0.dist-info → agentex_sdk-0.2.2.dist-info}/WHEEL +0 -0
- {agentex_sdk-0.2.0.dist-info → agentex_sdk-0.2.2.dist-info}/entry_points.txt +0 -0
- {agentex_sdk-0.2.0.dist-info → agentex_sdk-0.2.2.dist-info}/licenses/LICENSE +0 -0
agentex/_version.py
CHANGED
agentex/lib/adk/_modules/acp.py
CHANGED
@@ -4,6 +4,7 @@ from typing import Any
|
|
4
4
|
from temporalio.common import RetryPolicy
|
5
5
|
|
6
6
|
from agentex import AsyncAgentex
|
7
|
+
from agentex.lib.adk.utils._modules.client import create_async_agentex_client
|
7
8
|
from agentex.lib.core.services.adk.acp.acp import ACPService
|
8
9
|
from agentex.lib.core.temporal.activities.activity_helpers import ActivityHelpers
|
9
10
|
from agentex.lib.core.temporal.activities.adk.acp.acp_activities import (
|
@@ -40,7 +41,7 @@ class ACPModule:
|
|
40
41
|
acp_activities (Optional[ACPActivities]): Optional pre-configured ACP activities. If None, will be auto-initialized.
|
41
42
|
"""
|
42
43
|
if acp_service is None:
|
43
|
-
agentex_client =
|
44
|
+
agentex_client = create_async_agentex_client()
|
44
45
|
tracer = AsyncTracer(agentex_client)
|
45
46
|
self._acp_service = ACPService(agentex_client=agentex_client, tracer=tracer)
|
46
47
|
else:
|
@@ -3,6 +3,7 @@ from datetime import timedelta
|
|
3
3
|
from temporalio.common import RetryPolicy
|
4
4
|
|
5
5
|
from agentex import AsyncAgentex
|
6
|
+
from agentex.lib.adk.utils._modules.client import create_async_agentex_client
|
6
7
|
from agentex.lib.core.services.adk.agent_task_tracker import AgentTaskTrackerService
|
7
8
|
from agentex.lib.core.temporal.activities.activity_helpers import ActivityHelpers
|
8
9
|
from agentex.lib.core.temporal.activities.adk.agent_task_tracker_activities import (
|
@@ -33,7 +34,7 @@ class AgentTaskTrackerModule:
|
|
33
34
|
agent_task_tracker_service: AgentTaskTrackerService | None = None,
|
34
35
|
):
|
35
36
|
if agent_task_tracker_service is None:
|
36
|
-
agentex_client =
|
37
|
+
agentex_client = create_async_agentex_client()
|
37
38
|
tracer = AsyncTracer(agentex_client)
|
38
39
|
self._agent_task_tracker_service = AgentTaskTrackerService(
|
39
40
|
agentex_client=agentex_client, tracer=tracer
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from datetime import timedelta
|
2
2
|
from typing import Optional
|
3
3
|
|
4
|
+
from agentex.lib.adk.utils._modules.client import create_async_agentex_client
|
4
5
|
from agentex.lib.core.temporal.activities.adk.agents_activities import AgentsActivityName, GetAgentParams
|
5
6
|
from temporalio.common import RetryPolicy
|
6
7
|
|
@@ -28,7 +29,7 @@ class AgentsModule:
|
|
28
29
|
agents_service: Optional[AgentsService] = None,
|
29
30
|
):
|
30
31
|
if agents_service is None:
|
31
|
-
agentex_client =
|
32
|
+
agentex_client = create_async_agentex_client()
|
32
33
|
tracer = AsyncTracer(agentex_client)
|
33
34
|
self._agents_service = AgentsService(agentex_client=agentex_client, tracer=tracer)
|
34
35
|
else:
|
@@ -3,6 +3,7 @@ from datetime import timedelta
|
|
3
3
|
from temporalio.common import RetryPolicy
|
4
4
|
|
5
5
|
from agentex import AsyncAgentex
|
6
|
+
from agentex.lib.adk.utils._modules.client import create_async_agentex_client
|
6
7
|
from agentex.lib.core.services.adk.events import EventsService
|
7
8
|
from agentex.lib.core.temporal.activities.activity_helpers import ActivityHelpers
|
8
9
|
from agentex.lib.core.temporal.activities.adk.events_activities import (
|
@@ -32,7 +33,7 @@ class EventsModule:
|
|
32
33
|
events_service: EventsService | None = None,
|
33
34
|
):
|
34
35
|
if events_service is None:
|
35
|
-
agentex_client =
|
36
|
+
agentex_client = create_async_agentex_client()
|
36
37
|
tracer = AsyncTracer(agentex_client)
|
37
38
|
self._events_service = EventsService(
|
38
39
|
agentex_client=agentex_client, tracer=tracer
|
@@ -3,7 +3,8 @@ from datetime import timedelta
|
|
3
3
|
from temporalio.common import RetryPolicy
|
4
4
|
|
5
5
|
from agentex import AsyncAgentex
|
6
|
-
from agentex.lib.
|
6
|
+
from agentex.lib.adk.utils._modules.client import create_async_agentex_client
|
7
|
+
from agentex.lib.core.adapters.streams.adapter_redis import RedisStreamRepository
|
7
8
|
from agentex.lib.core.services.adk.messages import MessagesService
|
8
9
|
from agentex.lib.core.services.adk.streaming import StreamingService
|
9
10
|
from agentex.lib.core.temporal.activities.activity_helpers import ActivityHelpers
|
@@ -37,8 +38,8 @@ class MessagesModule:
|
|
37
38
|
messages_service: MessagesService | None = None,
|
38
39
|
):
|
39
40
|
if messages_service is None:
|
40
|
-
agentex_client =
|
41
|
-
stream_repository =
|
41
|
+
agentex_client = create_async_agentex_client()
|
42
|
+
stream_repository = RedisStreamRepository()
|
42
43
|
streaming_service = StreamingService(
|
43
44
|
agentex_client=agentex_client,
|
44
45
|
stream_repository=stream_repository,
|
@@ -5,6 +5,7 @@ from pydantic import BaseModel
|
|
5
5
|
from temporalio.common import RetryPolicy
|
6
6
|
|
7
7
|
from agentex import AsyncAgentex
|
8
|
+
from agentex.lib.adk.utils._modules.client import create_async_agentex_client
|
8
9
|
from agentex.lib.core.services.adk.state import StateService
|
9
10
|
from agentex.lib.core.temporal.activities.activity_helpers import ActivityHelpers
|
10
11
|
from agentex.lib.core.temporal.activities.adk.state_activities import (
|
@@ -36,7 +37,7 @@ class StateModule:
|
|
36
37
|
state_service: StateService | None = None,
|
37
38
|
):
|
38
39
|
if state_service is None:
|
39
|
-
agentex_client =
|
40
|
+
agentex_client = create_async_agentex_client()
|
40
41
|
tracer = AsyncTracer(agentex_client)
|
41
42
|
self._state_service = StateService(
|
42
43
|
agentex_client=agentex_client, tracer=tracer
|
@@ -1,7 +1,8 @@
|
|
1
1
|
from temporalio.common import RetryPolicy
|
2
2
|
|
3
3
|
from agentex import AsyncAgentex
|
4
|
-
from agentex.lib.
|
4
|
+
from agentex.lib.adk.utils._modules.client import create_async_agentex_client
|
5
|
+
from agentex.lib.core.adapters.streams.adapter_redis import RedisStreamRepository
|
5
6
|
from agentex.lib.core.services.adk.streaming import (
|
6
7
|
StreamingService,
|
7
8
|
StreamingTaskMessageContext,
|
@@ -33,8 +34,8 @@ class StreamingModule:
|
|
33
34
|
a new service will be created with default parameters.
|
34
35
|
"""
|
35
36
|
if streaming_service is None:
|
36
|
-
stream_repository =
|
37
|
-
agentex_client =
|
37
|
+
stream_repository = RedisStreamRepository()
|
38
|
+
agentex_client = create_async_agentex_client()
|
38
39
|
self._streaming_service = StreamingService(
|
39
40
|
agentex_client=agentex_client,
|
40
41
|
stream_repository=stream_repository,
|
@@ -3,6 +3,7 @@ from datetime import timedelta
|
|
3
3
|
from temporalio.common import RetryPolicy
|
4
4
|
|
5
5
|
from agentex import AsyncAgentex
|
6
|
+
from agentex.lib.adk.utils._modules.client import create_async_agentex_client
|
6
7
|
from agentex.lib.core.services.adk.tasks import TasksService
|
7
8
|
from agentex.lib.core.temporal.activities.activity_helpers import ActivityHelpers
|
8
9
|
from agentex.lib.core.temporal.activities.adk.tasks_activities import (
|
@@ -31,7 +32,7 @@ class TasksModule:
|
|
31
32
|
tasks_service: TasksService | None = None,
|
32
33
|
):
|
33
34
|
if tasks_service is None:
|
34
|
-
agentex_client =
|
35
|
+
agentex_client = create_async_agentex_client()
|
35
36
|
tracer = AsyncTracer(agentex_client)
|
36
37
|
self._tasks_service = TasksService(
|
37
38
|
agentex_client=agentex_client, tracer=tracer
|
@@ -6,6 +6,7 @@ from typing import Any
|
|
6
6
|
from temporalio.common import RetryPolicy
|
7
7
|
|
8
8
|
from agentex import AsyncAgentex
|
9
|
+
from agentex.lib.adk.utils._modules.client import create_async_agentex_client
|
9
10
|
from agentex.lib.core.services.adk.tracing import TracingService
|
10
11
|
from agentex.lib.core.temporal.activities.activity_helpers import ActivityHelpers
|
11
12
|
from agentex.lib.core.temporal.activities.adk.tracing_activities import (
|
@@ -38,7 +39,7 @@ class TracingModule:
|
|
38
39
|
tracing_activities (Optional[TracingActivities]): Optional pre-configured tracing activities. If None, will be auto-initialized.
|
39
40
|
"""
|
40
41
|
if tracing_service is None:
|
41
|
-
agentex_client =
|
42
|
+
agentex_client = create_async_agentex_client()
|
42
43
|
tracer = AsyncTracer(agentex_client)
|
43
44
|
self._tracing_service = TracingService(tracer=tracer)
|
44
45
|
else:
|
@@ -5,7 +5,7 @@ from temporalio.common import RetryPolicy
|
|
5
5
|
|
6
6
|
from agentex import AsyncAgentex
|
7
7
|
from agentex.lib.core.adapters.llm.adapter_litellm import LiteLLMGateway
|
8
|
-
from agentex.lib.core.adapters.streams.adapter_redis import
|
8
|
+
from agentex.lib.core.adapters.streams.adapter_redis import RedisStreamRepository
|
9
9
|
from agentex.lib.core.services.adk.providers.litellm import LiteLLMService
|
10
10
|
from agentex.lib.core.services.adk.streaming import StreamingService
|
11
11
|
from agentex.lib.core.temporal.activities.activity_helpers import ActivityHelpers
|
@@ -40,7 +40,7 @@ class LiteLLMModule:
|
|
40
40
|
if litellm_service is None:
|
41
41
|
# Create default service
|
42
42
|
agentex_client = AsyncAgentex()
|
43
|
-
stream_repository =
|
43
|
+
stream_repository = RedisStreamRepository()
|
44
44
|
streaming_service = StreamingService(
|
45
45
|
agentex_client=agentex_client,
|
46
46
|
stream_repository=stream_repository,
|
@@ -10,7 +10,7 @@ from mcp import StdioServerParameters
|
|
10
10
|
from temporalio.common import RetryPolicy
|
11
11
|
|
12
12
|
from agentex import AsyncAgentex
|
13
|
-
from agentex.lib.core.adapters.streams.adapter_redis import
|
13
|
+
from agentex.lib.core.adapters.streams.adapter_redis import RedisStreamRepository
|
14
14
|
from agentex.lib.core.services.adk.providers.openai import OpenAIService
|
15
15
|
from agentex.lib.core.services.adk.streaming import StreamingService
|
16
16
|
from agentex.lib.core.temporal.activities.activity_helpers import ActivityHelpers
|
@@ -47,7 +47,7 @@ class OpenAIModule:
|
|
47
47
|
if openai_service is None:
|
48
48
|
# Create default service
|
49
49
|
agentex_client = AsyncAgentex()
|
50
|
-
stream_repository =
|
50
|
+
stream_repository = RedisStreamRepository()
|
51
51
|
streaming_service = StreamingService(
|
52
52
|
agentex_client=agentex_client,
|
53
53
|
stream_repository=stream_repository,
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
from agentex import AsyncAgentex
|
4
|
+
from agentex.lib.environment_variables import refreshed_environment_variables
|
5
|
+
|
6
|
+
|
7
|
+
def create_async_agentex_client(**kwargs):
|
8
|
+
agent_id = refreshed_environment_variables.AGENT_ID
|
9
|
+
default_headers = {
|
10
|
+
"x-agent-identity": agent_id
|
11
|
+
}
|
12
|
+
return AsyncAgentex(default_headers=default_headers, **kwargs)
|
agentex/lib/cli/commands/init.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
from enum import Enum
|
2
2
|
from pathlib import Path
|
3
|
+
from typing import Any, Dict
|
3
4
|
|
4
5
|
import questionary
|
5
6
|
from jinja2 import Environment, FileSystemLoader
|
@@ -23,7 +24,7 @@ class TemplateType(str, Enum):
|
|
23
24
|
|
24
25
|
|
25
26
|
def render_template(
|
26
|
-
template_path: str, context:
|
27
|
+
template_path: str, context: Dict[str, Any], template_type: TemplateType
|
27
28
|
) -> str:
|
28
29
|
"""Render a template with the given context"""
|
29
30
|
env = Environment(loader=FileSystemLoader(TEMPLATES_DIR / template_type.value))
|
@@ -32,7 +33,7 @@ def render_template(
|
|
32
33
|
|
33
34
|
|
34
35
|
def create_project_structure(
|
35
|
-
path: Path, context:
|
36
|
+
path: Path, context: Dict[str, Any], template_type: TemplateType, use_uv: bool
|
36
37
|
):
|
37
38
|
"""Create the project structure from templates"""
|
38
39
|
# Create project directory
|
@@ -74,6 +75,9 @@ def create_project_structure(
|
|
74
75
|
root_templates["requirements.txt.j2"] = "requirements.txt"
|
75
76
|
root_templates["Dockerfile.j2"] = "Dockerfile"
|
76
77
|
|
78
|
+
# Add development notebook for agents
|
79
|
+
root_templates["dev.ipynb.j2"] = "dev.ipynb"
|
80
|
+
|
77
81
|
for template, output in root_templates.items():
|
78
82
|
output_path = project_dir / output
|
79
83
|
output_path.write_text(render_template(template, context, template_type))
|
@@ -81,7 +85,7 @@ def create_project_structure(
|
|
81
85
|
console.print(f"\n[green]✓[/green] Created project structure at: {project_dir}")
|
82
86
|
|
83
87
|
|
84
|
-
def get_project_context(answers:
|
88
|
+
def get_project_context(answers: Dict[str, Any], project_path: Path, manifest_root: Path) -> Dict[str, Any]:
|
85
89
|
"""Get the project context from user answers"""
|
86
90
|
# Use agent_directory_name as project_name
|
87
91
|
project_name = answers["agent_directory_name"].replace("-", "_")
|
@@ -112,7 +116,7 @@ def init():
|
|
112
116
|
)
|
113
117
|
|
114
118
|
# Use a Rich table for template descriptions
|
115
|
-
table = Table(show_header=True, header_style="bold
|
119
|
+
table = Table(show_header=True, header_style="bold blue")
|
116
120
|
table.add_column("Template", style="cyan", no_wrap=True)
|
117
121
|
table.add_column("Description", style="white")
|
118
122
|
table.add_row(
|
@@ -62,6 +62,7 @@ This file is essential for both local development and deployment of your agent.
|
|
62
62
|
│ └── acp.py # ACP server and event handlers
|
63
63
|
├── Dockerfile # Container definition
|
64
64
|
├── manifest.yaml # Deployment config
|
65
|
+
├── dev.ipynb # Development notebook for testing
|
65
66
|
{% if use_uv %}
|
66
67
|
└── pyproject.toml # Dependencies (uv)
|
67
68
|
{% else %}
|
@@ -76,7 +77,27 @@ This file is essential for both local development and deployment of your agent.
|
|
76
77
|
- Add your own tools and capabilities
|
77
78
|
- Implement custom state management
|
78
79
|
|
79
|
-
### 2.
|
80
|
+
### 2. Test Your Agent with the Development Notebook
|
81
|
+
Use the included `dev.ipynb` Jupyter notebook to test your agent interactively:
|
82
|
+
|
83
|
+
```bash
|
84
|
+
# Start Jupyter notebook (make sure you have jupyter installed)
|
85
|
+
jupyter notebook dev.ipynb
|
86
|
+
|
87
|
+
# Or use VS Code to open the notebook directly
|
88
|
+
code dev.ipynb
|
89
|
+
```
|
90
|
+
|
91
|
+
The notebook includes:
|
92
|
+
- **Setup**: Connect to your local AgentEx backend
|
93
|
+
- **Task creation**: Create a new task for the conversation
|
94
|
+
- **Event sending**: Send events to the agent and get responses
|
95
|
+
- **Async message subscription**: Subscribe to server-side events to receive agent responses
|
96
|
+
- **Rich message display**: Beautiful formatting with timestamps and author information
|
97
|
+
|
98
|
+
The notebook automatically uses your agent name (`{{ agent_name }}`) and demonstrates the agentic ACP workflow: create task → send event → subscribe to responses.
|
99
|
+
|
100
|
+
### 3. Manage Dependencies
|
80
101
|
|
81
102
|
{% if use_uv %}
|
82
103
|
You chose **uv** for package management. Here's how to work with dependencies:
|
@@ -115,7 +136,7 @@ pip install -r requirements.txt
|
|
115
136
|
- Wide compatibility
|
116
137
|
{% endif %}
|
117
138
|
|
118
|
-
###
|
139
|
+
### 4. Configure Credentials
|
119
140
|
Options:
|
120
141
|
1. Add any required credentials to your manifest.yaml via the `env` section
|
121
142
|
2. Export them in your shell: `export OPENAI_API_KEY=...`
|
@@ -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 Agentic 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
|
+
}
|
@@ -60,6 +60,7 @@ This file is essential for both local development and deployment of your agent.
|
|
60
60
|
│ └── acp.py # ACP server and event handlers
|
61
61
|
├── Dockerfile # Container definition
|
62
62
|
├── manifest.yaml # Deployment config
|
63
|
+
├── dev.ipynb # Development notebook for testing
|
63
64
|
{% if use_uv %}
|
64
65
|
└── pyproject.toml # Dependencies (uv)
|
65
66
|
{% else %}
|
@@ -74,7 +75,26 @@ This file is essential for both local development and deployment of your agent.
|
|
74
75
|
- Add your own tools and capabilities
|
75
76
|
- Implement custom response generation
|
76
77
|
|
77
|
-
### 2.
|
78
|
+
### 2. Test Your Agent with the Development Notebook
|
79
|
+
Use the included `dev.ipynb` Jupyter notebook to test your agent interactively:
|
80
|
+
|
81
|
+
```bash
|
82
|
+
# Start Jupyter notebook (make sure you have jupyter installed)
|
83
|
+
jupyter notebook dev.ipynb
|
84
|
+
|
85
|
+
# Or use VS Code to open the notebook directly
|
86
|
+
code dev.ipynb
|
87
|
+
```
|
88
|
+
|
89
|
+
The notebook includes:
|
90
|
+
- **Setup**: Connect to your local AgentEx backend
|
91
|
+
- **Non-streaming tests**: Send messages and get complete responses
|
92
|
+
- **Streaming tests**: Test real-time streaming responses
|
93
|
+
- **Task management**: Optional task creation and management
|
94
|
+
|
95
|
+
The notebook automatically uses your agent name (`{{ agent_name }}`) and provides examples for both streaming and non-streaming message handling.
|
96
|
+
|
97
|
+
### 3. Manage Dependencies
|
78
98
|
|
79
99
|
{% if use_uv %}
|
80
100
|
You chose **uv** for package management. Here's how to work with dependencies:
|
@@ -113,7 +133,7 @@ pip install -r requirements.txt
|
|
113
133
|
- Wide compatibility
|
114
134
|
{% endif %}
|
115
135
|
|
116
|
-
###
|
136
|
+
### 4. Configure Credentials
|
117
137
|
Options:
|
118
138
|
1. Add any required credentials to your manifest.yaml via the `env` section
|
119
139
|
2. Export them in your shell: `export OPENAI_API_KEY=...`
|
@@ -0,0 +1,167 @@
|
|
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
|
+
"# # (Optional) Create a new task. If you don't create a new task, each message will be sent to a new task. The server will create the task for you.\n",
|
33
|
+
"\n",
|
34
|
+
"# import uuid\n",
|
35
|
+
"\n",
|
36
|
+
"# TASK_ID = str(uuid.uuid4())[:8]\n",
|
37
|
+
"\n",
|
38
|
+
"# rpc_response = client.agents.rpc_by_name(\n",
|
39
|
+
"# agent_name=AGENT_NAME,\n",
|
40
|
+
"# method=\"task/create\",\n",
|
41
|
+
"# params={\n",
|
42
|
+
"# \"name\": f\"{TASK_ID}-task\",\n",
|
43
|
+
"# \"params\": {}\n",
|
44
|
+
"# }\n",
|
45
|
+
"# )\n",
|
46
|
+
"\n",
|
47
|
+
"# task = rpc_response.result\n",
|
48
|
+
"# print(task)"
|
49
|
+
]
|
50
|
+
},
|
51
|
+
{
|
52
|
+
"cell_type": "code",
|
53
|
+
"execution_count": null,
|
54
|
+
"id": "b03b0d37",
|
55
|
+
"metadata": {},
|
56
|
+
"outputs": [],
|
57
|
+
"source": [
|
58
|
+
"# Test non streaming response\n",
|
59
|
+
"from agentex.types import TextContent\n",
|
60
|
+
"\n",
|
61
|
+
"# The response is expected to be a list of TaskMessage objects, which is a union of the following types:\n",
|
62
|
+
"# - TextContent: A message with just text content \n",
|
63
|
+
"# - DataContent: A message with JSON-serializable data content\n",
|
64
|
+
"# - ToolRequestContent: A message with a tool request, which contains a JSON-serializable request to call a tool\n",
|
65
|
+
"# - ToolResponseContent: A message with a tool response, which contains response object from a tool call in its content\n",
|
66
|
+
"\n",
|
67
|
+
"# 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",
|
68
|
+
"\n",
|
69
|
+
"rpc_response = client.agents.send_message(\n",
|
70
|
+
" agent_name=AGENT_NAME,\n",
|
71
|
+
" params={\n",
|
72
|
+
" \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"Hello what can you do?\"},\n",
|
73
|
+
" \"stream\": False\n",
|
74
|
+
" }\n",
|
75
|
+
")\n",
|
76
|
+
"\n",
|
77
|
+
"if not rpc_response or not rpc_response.result:\n",
|
78
|
+
" raise ValueError(\"No result in response\")\n",
|
79
|
+
"\n",
|
80
|
+
"# Extract and print just the text content from the response\n",
|
81
|
+
"for task_message in rpc_response.result:\n",
|
82
|
+
" content = task_message.content\n",
|
83
|
+
" if isinstance(content, TextContent):\n",
|
84
|
+
" text = content.content\n",
|
85
|
+
" print(text)\n"
|
86
|
+
]
|
87
|
+
},
|
88
|
+
{
|
89
|
+
"cell_type": "code",
|
90
|
+
"execution_count": null,
|
91
|
+
"id": "79688331",
|
92
|
+
"metadata": {},
|
93
|
+
"outputs": [],
|
94
|
+
"source": [
|
95
|
+
"# Test streaming response\n",
|
96
|
+
"from agentex.types.task_message_update import StreamTaskMessageDelta, StreamTaskMessageFull\n",
|
97
|
+
"from agentex.types.text_delta import TextDelta\n",
|
98
|
+
"\n",
|
99
|
+
"\n",
|
100
|
+
"# The result object of message/send will be a TaskMessageUpdate which is a union of the following types:\n",
|
101
|
+
"# - StreamTaskMessageStart: \n",
|
102
|
+
"# - An indicator that a streaming message was started, doesn't contain any useful content\n",
|
103
|
+
"# - StreamTaskMessageDelta: \n",
|
104
|
+
"# - A delta of a streaming message, contains the text delta to aggregate\n",
|
105
|
+
"# - StreamTaskMessageDone: \n",
|
106
|
+
"# - An indicator that a streaming message was done, doesn't contain any useful content\n",
|
107
|
+
"# - StreamTaskMessageFull: \n",
|
108
|
+
"# - A non-streaming message, there is nothing to aggregate, since this contains the full message, not deltas\n",
|
109
|
+
"\n",
|
110
|
+
"# Whenn processing StreamTaskMessageDelta, if you are expecting more than TextDeltas, such as DataDelta, ToolRequestDelta, or ToolResponseDelta, you can process them as well\n",
|
111
|
+
"# Whenn processing StreamTaskMessageFull, if you are expecting more than TextContent, such as DataContent, ToolRequestContent, or ToolResponseContent, you can process them as well\n",
|
112
|
+
"\n",
|
113
|
+
"for agent_rpc_response_chunk in client.agents.send_message_stream(\n",
|
114
|
+
" agent_name=AGENT_NAME,\n",
|
115
|
+
" params={\n",
|
116
|
+
" \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"Hello what can you do?\"},\n",
|
117
|
+
" \"stream\": True\n",
|
118
|
+
" }\n",
|
119
|
+
"):\n",
|
120
|
+
" # We know that the result of the message/send when stream is set to True will be a TaskMessageUpdate\n",
|
121
|
+
" task_message_update = agent_rpc_response_chunk.result\n",
|
122
|
+
" # Print oly the text deltas as they arrive or any full messages\n",
|
123
|
+
" if isinstance(task_message_update, StreamTaskMessageDelta):\n",
|
124
|
+
" delta = task_message_update.delta\n",
|
125
|
+
" if isinstance(delta, TextDelta):\n",
|
126
|
+
" print(delta.text_delta, end=\"\", flush=True)\n",
|
127
|
+
" else:\n",
|
128
|
+
" print(f\"Found non-text {type(task_message)} object in streaming message.\")\n",
|
129
|
+
" elif isinstance(task_message_update, StreamTaskMessageFull):\n",
|
130
|
+
" content = task_message_update.content\n",
|
131
|
+
" if isinstance(content, TextContent):\n",
|
132
|
+
" print(content.content)\n",
|
133
|
+
" else:\n",
|
134
|
+
" print(f\"Found non-text {type(task_message)} object in full message.\")\n"
|
135
|
+
]
|
136
|
+
},
|
137
|
+
{
|
138
|
+
"cell_type": "code",
|
139
|
+
"execution_count": null,
|
140
|
+
"id": "c5e7e042",
|
141
|
+
"metadata": {},
|
142
|
+
"outputs": [],
|
143
|
+
"source": []
|
144
|
+
}
|
145
|
+
],
|
146
|
+
"metadata": {
|
147
|
+
"kernelspec": {
|
148
|
+
"display_name": ".venv",
|
149
|
+
"language": "python",
|
150
|
+
"name": "python3"
|
151
|
+
},
|
152
|
+
"language_info": {
|
153
|
+
"codemirror_mode": {
|
154
|
+
"name": "ipython",
|
155
|
+
"version": 3
|
156
|
+
},
|
157
|
+
"file_extension": ".py",
|
158
|
+
"mimetype": "text/x-python",
|
159
|
+
"name": "python",
|
160
|
+
"nbconvert_exporter": "python",
|
161
|
+
"pygments_lexer": "ipython3",
|
162
|
+
"version": "3.12.9"
|
163
|
+
}
|
164
|
+
},
|
165
|
+
"nbformat": 4,
|
166
|
+
"nbformat_minor": 5
|
167
|
+
}
|