Skip to content

Commit c8c5d4d

Browse files
committed
adding the basic workflows
1 parent 0bd8ae6 commit c8c5d4d

File tree

3 files changed

+126
-18
lines changed

3 files changed

+126
-18
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Test Tutorial Agents
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
test-tutorials:
8+
timeout-minutes: 10
9+
name: test-tutorials
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
14+
- name: Install Rye
15+
run: |
16+
curl -sSf https://rye.astral.sh/get | bash
17+
echo "$HOME/.rye/shims" >> $GITHUB_PATH
18+
env:
19+
RYE_VERSION: "0.44.0"
20+
RYE_INSTALL_OPTION: "--yes"
21+
22+
- name: Bootstrap
23+
run: ./scripts/bootstrap
24+
25+
- name: Simple validation test
26+
run: |
27+
echo "✅ Tutorial test workflow is working!"
28+
echo "Rye version: $(rye --version)"
29+
echo "Python version: $(python --version)"

.github/workflows/build-and-push-tutorial-agent.yml

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,91 @@ on:
2424
required: true
2525
type: string
2626
default: "latest"
27+
28+
permissions:
29+
contents: read
30+
packages: write
31+
32+
jobs:
33+
build-and-push-agent:
34+
timeout-minutes: 10
35+
name: Build Tutorial Agent
36+
runs-on: ubuntu-latest
37+
38+
steps:
39+
- name: Checkout repository
40+
uses: actions/checkout@v4
41+
42+
- name: Validate agent path exists
43+
run: |
44+
if [ ! -d "${{ inputs.agent_path }}" ]; then
45+
echo "❌ Error: Agent path '${{ inputs.agent_path }}' does not exist"
46+
exit 1
47+
fi
48+
echo "✅ Agent path verified: ${{ inputs.agent_path }}"
49+
50+
- name: Validate manifest.yaml exists
51+
run: |
52+
if [ ! -f "${{ inputs.agent_path }}/manifest.yaml" ]; then
53+
echo "❌ Error: manifest.yaml not found in '${{ inputs.agent_path }}'"
54+
exit 1
55+
fi
56+
echo "✅ manifest.yaml found"
57+
echo "### Validation Summary" >> $GITHUB_STEP_SUMMARY
58+
echo "- **Agent Path**: ${{ inputs.agent_path }}" >> $GITHUB_STEP_SUMMARY
59+
echo "- **Version Tag**: ${{ inputs.version_tag }}" >> $GITHUB_STEP_SUMMARY
60+
echo "- **Status**: ✅ Validation passed" >> $GITHUB_STEP_SUMMARY
61+
62+
- name: Set up Docker Buildx
63+
uses: docker/setup-buildx-action@v3
64+
65+
- name: Set up Python
66+
uses: actions/setup-python@v4
67+
with:
68+
python-version: "3.12"
69+
70+
- name: Get latest agentex-sdk version from PyPI
71+
id: get-version
72+
run: |
73+
LATEST_VERSION=$(curl -s https://pypi.org/pypi/agentex-sdk/json | jq -r '.info.version')
74+
echo "Latest agentex-sdk version: $LATEST_VERSION"
75+
echo "AGENTEX_SDK_VERSION=$LATEST_VERSION" >> $GITHUB_ENV
76+
pip install agentex-sdk==$LATEST_VERSION
77+
echo "Installed agentex-sdk version $LATEST_VERSION"
78+
79+
- name: Generate Image name
80+
id: image-name
81+
run: |
82+
# Remove examples/tutorials/ prefix and replace / with -
83+
AGENT_NAME=$(echo "${{ inputs.agent_path }}" | sed 's|^examples/tutorials/||' | sed 's|/|-|g')
84+
echo "AGENT_NAME=$AGENT_NAME" >> $GITHUB_ENV
85+
echo "agent_name=$AGENT_NAME" >> $GITHUB_OUTPUT
86+
echo "Agent name set to $AGENT_NAME"
87+
88+
- name: Login to GitHub Container Registry
89+
uses: docker/login-action@v3
90+
with:
91+
registry: ghcr.io
92+
username: ${{ github.actor }}
93+
password: ${{ secrets.GITHUB_TOKEN }}
94+
95+
- name: Build and Push Agent Image
96+
env:
97+
REGISTRY: ghcr.io
98+
run: |
99+
AGENT_NAME="${{ steps.image-name.outputs.agent_name }}"
100+
VERSION_TAG="${{ inputs.version_tag }}"
101+
REPOSITORY_NAME="${{ github.repository }}/tutorial-agents/${AGENT_NAME}"
102+
FULL_IMAGE="${REGISTRY}/${REPOSITORY_NAME}:${VERSION_TAG}"
103+
104+
agentex agents build \
105+
--manifest "${{ inputs.agent_path }}/manifest.yaml" \
106+
--registry "${REGISTRY}" \
107+
--tag "${VERSION_TAG}" \
108+
--platforms "linux/amd64" \
109+
--repository-name "${REPOSITORY_NAME}" \
110+
--push
111+
112+
echo "Successfully built and pushed: ${FULL_IMAGE}"
113+
echo "### Build Complete" >> $GITHUB_STEP_SUMMARY
114+
echo "- **Image**: \`${FULL_IMAGE}\`" >> $GITHUB_STEP_SUMMARY

examples/tutorials/10_agentic/00_base/040_other_sdks/project/acp.py

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
config=AgenticACPConfig(type="base"),
4343
)
4444

45+
4546
class StateModel(BaseModel):
4647
input_list: List[dict]
4748
turn_number: int
@@ -53,11 +54,7 @@ class StateModel(BaseModel):
5354
args=["-y", "@modelcontextprotocol/server-sequential-thinking"],
5455
),
5556
StdioServerParameters(
56-
command="uvx",
57-
args=["openai-websearch-mcp"],
58-
env={
59-
"OPENAI_API_KEY": os.environ.get("OPENAI_API_KEY", "")
60-
}
57+
command="uvx", args=["openai-websearch-mcp"], env={"OPENAI_API_KEY": os.environ.get("OPENAI_API_KEY", "")}
6158
),
6259
]
6360

@@ -72,6 +69,7 @@ async def handle_task_create(params: CreateTaskParams):
7269
)
7370
await adk.state.create(task_id=params.task.id, agent_id=params.agent.id, state=state)
7471

72+
7573
@acp.on_task_event_send
7674
async def handle_event_send(params: SendEventParams):
7775
# !!! Warning: Because "Agentic" ACPs are designed to be fully asynchronous, race conditions can occur if parallel events are sent. It is highly recommended to use the "temporal" type in the AgenticACPConfig instead to handle complex use cases. The "base" ACP is only designed to be used for simple use cases and for learning purposes.
@@ -85,7 +83,6 @@ async def handle_event_send(params: SendEventParams):
8583
if params.event.content.author != "user":
8684
raise ValueError(f"Expected user message, got {params.event.content.author}")
8785

88-
8986
# Retrieve the task state. Each event is handled as a new turn, so we need to get the state for the current turn.
9087
task_state = await adk.state.get_by_task_and_agent(task_id=params.task.id, agent_id=params.agent.id)
9188
if not task_state:
@@ -94,12 +91,8 @@ async def handle_event_send(params: SendEventParams):
9491
state.turn_number += 1
9592
# Add the new user message to the message history
9693
state.input_list.append({"role": "user", "content": params.event.content.content})
97-
98-
async with adk.tracing.span(
99-
trace_id=params.task.id,
100-
name=f"Turn {state.turn_number}",
101-
input=state
102-
) as span:
94+
95+
async with adk.tracing.span(trace_id=params.task.id, name=f"Turn {state.turn_number}", input=state) as span:
10396
# Echo back the user's message so it shows up in the UI. This is not done by default so the agent developer has full control over what is shown to the user.
10497
await adk.messages.create(
10598
task_id=params.task.id,
@@ -156,6 +149,7 @@ async def handle_event_send(params: SendEventParams):
156149
if span:
157150
span.output = state
158151

152+
159153
@acp.on_task_cancel
160154
async def handle_task_cancel(params: CancelTaskParams):
161155
"""Default task cancel handler"""
@@ -173,8 +167,8 @@ async def mcp_server_context(mcp_server_params: list[StdioServerParameters]):
173167
servers = []
174168
for params in mcp_server_params:
175169
server = MCPServerStdio(
176-
name=f"Server: {params.command}",
177-
params=params.model_dump(),
170+
name=f"Server: {params.command}",
171+
params=params.model_dump(),
178172
cache_tools_list=True,
179173
client_session_timeout_seconds=60,
180174
)
@@ -253,7 +247,6 @@ async def run_openai_agent_with_custom_streaming(
253247
try:
254248
# Process streaming events with TaskMessage creation
255249
async for event in result.stream_events():
256-
257250
if event.type == "run_item_stream_event":
258251
if event.item.type == "tool_call_item":
259252
tool_call_item = event.item.raw_item
@@ -374,9 +367,7 @@ async def run_openai_agent_with_custom_streaming(
374367
if span:
375368
span.output = {
376369
"new_items": [
377-
item.raw_item.model_dump()
378-
if isinstance(item.raw_item, BaseModel)
379-
else item.raw_item
370+
item.raw_item.model_dump() if isinstance(item.raw_item, BaseModel) else item.raw_item
380371
for item in result.new_items
381372
],
382373
"final_output": result.final_output,

0 commit comments

Comments
 (0)